save images to gallery (#124)

* popup menu xml and longclicklistener on postfragment

* modularize popup menu code and added listener on homefeed

* fixed position

* image download implemented

* added download state messages

* added test and applied some lint cleanup suggestions

* added functionality to albums

* added test for album
This commit is contained in:
Ulysse Widmer 2020-04-30 20:01:35 +02:00 committed by GitHub
parent ce0b914d78
commit 20a2fd51ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 311 additions and 290 deletions

View File

@ -105,7 +105,6 @@ dependencies {
def fragment_version = '1.2.4'
debugImplementation "androidx.fragment:fragment-testing:$fragment_version"
}
tasks.withType(Test) {

View File

@ -0,0 +1,103 @@
package com.h.pixeldroid
import android.content.Context
import android.content.Intent
import androidx.test.core.app.ActivityScenario
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.action.ViewActions.longClick
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.RootMatchers
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.h.pixeldroid.objects.Account
import com.h.pixeldroid.objects.Attachment
import com.h.pixeldroid.objects.Status
import com.h.pixeldroid.testUtility.MockServer
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.Timeout
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class PostTest {
private lateinit var context: Context
@get:Rule
var globalTimeout: Timeout = Timeout.seconds(100)
@Before
fun before(){
context = InstrumentationRegistry.getInstrumentation().targetContext
val mockServer = MockServer()
mockServer.start()
val baseUrl = mockServer.getUrl()
val preferences = context.getSharedPreferences(
"com.h.pixeldroid.pref",
Context.MODE_PRIVATE)
preferences.edit().putString("accessToken", "azerty").apply()
preferences.edit().putString("domain", baseUrl.toString()).apply()
}
@Test
fun saveToGalleryTestSimplePost() {
val attachment = Attachment(
id = "12",
url = "https://wiki.gnugen.ch/lib/tpl/gnugen/images/logo_web.png"
)
val post = Status(
id = "12",
account = Account(
id = "12",
username = "douze"
),
media_attachments = listOf(attachment)
)
val intent = Intent(context, PostActivity::class.java)
intent.putExtra(Status.POST_TAG, post)
ActivityScenario.launch<PostActivity>(intent)
onView(withId(R.id.postPicture)).perform(longClick())
onView(withText(R.string.save_to_gallery)).inRoot(RootMatchers.isPlatformPopup()).perform(click())
Thread.sleep(300)
onView(withText(R.string.image_download_downloading)).inRoot(
RootMatchers.hasWindowLayoutParams()
).check(matches(isDisplayed()))
Thread.sleep(5000)
}
@Test
fun saveToGalleryTestAlbum() {
val attachment1 = Attachment(
id = "12",
url = "https://wiki.gnugen.ch/lib/tpl/gnugen/images/logo_web.png"
)
val attachment2 = Attachment(
id = "13",
url = "https://wiki.gnugen.ch/lib/tpl/gnugen/images/logo_web.png"
)
val post = Status(
id = "12",
account = Account(
id = "12",
username = "douze"
),
media_attachments = listOf(attachment1, attachment2)
)
val intent = Intent(context, PostActivity::class.java)
intent.putExtra(Status.POST_TAG, post)
ActivityScenario.launch<PostActivity>(intent)
onView(withId(R.id.imageImageView)).perform(longClick())
onView(withText(R.string.save_to_gallery)).inRoot(RootMatchers.isPlatformPopup()).perform(click())
Thread.sleep(300)
onView(withText(R.string.image_download_downloading)).inRoot(
RootMatchers.hasWindowLayoutParams()
).check(matches(isDisplayed()))
Thread.sleep(5000)
}
}

View File

@ -8,10 +8,13 @@ import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.PopupMenu
import com.bumptech.glide.Glide
import com.bumptech.glide.RequestBuilder
import com.h.pixeldroid.utils.ImageConverter
import com.h.pixeldroid.utils.ImageUtils
import kotlinx.android.synthetic.main.post_fragment.view.*
import java.io.Serializable
@ -38,9 +41,26 @@ class ImageFragment : Fragment() {
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_image, container, false)
view.findViewById<ImageView>(R.id.imageImageView).setOnLongClickListener {
PopupMenu(view.context, it).apply {
setOnMenuItemClickListener { item ->
when (item.itemId) {
R.id.image_popup_menu_save_to_gallery -> {
ImageUtils.downloadImage(requireActivity(), view.context, imgUrl)
true
}
else -> false
}
}
inflate(R.menu.image_popup_menu)
show()
}
true
}
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_image, container, false)
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -52,6 +72,7 @@ class ImageFragment : Fragment() {
.placeholder(ColorDrawable(Color.GRAY))
picRequest.load(imgUrl).into(imageView)
}
companion object {

View File

@ -59,6 +59,8 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
setupTabs(tabs)
}
}
private fun setupTabs(tabs: Array<Fragment>){

View File

@ -6,8 +6,6 @@ import com.h.pixeldroid.fragments.PostFragment
import com.h.pixeldroid.objects.Status
import com.h.pixeldroid.objects.Status.Companion.POST_TAG
class PostActivity : AppCompatActivity() {
lateinit var postFragment : PostFragment

View File

@ -27,11 +27,6 @@ class ProfilePostsFragment : Fragment() {
private var columnCount = 3
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?

View File

@ -28,23 +28,23 @@ data class Account(
//Base attributes
override val id: String,
val username: String,
val acct: String,
val url: String, //HTTPS URL
val acct: String = "",
val url: String = "", //HTTPS URL
//Display attributes
val display_name: String?,
val note: String, //HTML
val avatar: String, //URL
val avatar_static: String, //URL
val header: String, //URL
val header_static: String, //URL
val locked: Boolean,
val emojis: List<Emoji>,
val discoverable: Boolean,
val display_name: String? = null,
val note: String = "", //HTML
val avatar: String = "", //URL
val avatar_static: String = "", //URL
val header: String = "", //URL
val header_static: String = "", //URL
val locked: Boolean = false,
val emojis: List<Emoji>? = null,
val discoverable: Boolean = true,
//Statistical attributes
val created_at: String, //ISO 8601 Datetime (maybe can use a date type)
val statuses_count: Int,
val followers_count: Int,
val following_count: Int,
val created_at: String = "", //ISO 8601 Datetime (maybe can use a date type)
val statuses_count: Int = 0,
val followers_count: Int = 0,
val following_count: Int = 0,
//Optional attributes
val moved: Account? = null,
val fields: List<Field>? = emptyList(),

View File

@ -5,9 +5,9 @@ import java.io.Serializable
data class Attachment(
//Required attributes
val id: String,
val type: AttachmentType,
val type: AttachmentType = AttachmentType.image,
val url: String, //URL
val preview_url: String, //URL
val preview_url: String = "", //URL
//Optional attributes
val remote_url: String? = null, //URL
val text_url: String? = null, //URL

View File

@ -1,5 +1,6 @@
package com.h.pixeldroid.objects
import android.app.Activity
import android.content.Context
import android.graphics.Typeface
import android.graphics.drawable.Drawable
@ -9,20 +10,27 @@ import android.util.Log
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.PopupMenu
import android.widget.TextView
import android.widget.Toast
import androidx.core.text.toSpanned
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import com.bumptech.glide.RequestBuilder
import com.google.android.material.tabs.TabLayoutMediator
import com.h.pixeldroid.ImageFragment
import com.h.pixeldroid.MainActivity
import com.h.pixeldroid.R
import com.h.pixeldroid.api.PixelfedAPI
import com.h.pixeldroid.fragments.feeds.PostViewHolder
import com.h.pixeldroid.utils.HtmlUtils.Companion.parseHTMLText
import com.h.pixeldroid.utils.ImageConverter
import com.h.pixeldroid.utils.ImageUtils.Companion.downloadImage
import com.h.pixeldroid.utils.PostUtils.Companion.likePostCall
import com.h.pixeldroid.utils.PostUtils.Companion.postComment
import com.h.pixeldroid.utils.PostUtils.Companion.reblogPost
@ -30,9 +38,10 @@ import com.h.pixeldroid.utils.PostUtils.Companion.retrieveComments
import com.h.pixeldroid.utils.PostUtils.Companion.toggleCommentInput
import com.h.pixeldroid.utils.PostUtils.Companion.unLikePostCall
import com.h.pixeldroid.utils.PostUtils.Companion.undoReblogPost
import kotlinx.android.synthetic.main.post_fragment.view.*
import kotlinx.android.synthetic.main.post_fragment.view.postPager
import kotlinx.android.synthetic.main.post_fragment.view.postPicture
import kotlinx.android.synthetic.main.post_fragment.view.postTabs
import kotlinx.android.synthetic.main.post_fragment.view.profilePic
import java.io.Serializable
/*
@ -42,38 +51,38 @@ https://docs.joinmastodon.org/entities/status/
data class Status(
//Base attributes
override val id: String,
val uri: String,
val created_at: String, //ISO 8601 Datetime (maybe can use a date type)
val uri: String = "",
val created_at: String = "", //ISO 8601 Datetime (maybe can use a date type)
val account: Account,
val content: String, //HTML
val visibility: Visibility,
val sensitive: Boolean,
val spoiler_text: String,
val media_attachments: List<Attachment>?,
val application: Application,
val content: String = "", //HTML
val visibility: Visibility = Visibility.public,
val sensitive: Boolean = false,
val spoiler_text: String = "",
val media_attachments: List<Attachment>? = null,
val application: Application? = null,
//Rendering attributes
val mentions: List<Mention>,
val tags: List<Tag>,
val emojis: List<Emoji>,
val mentions: List<Mention>? = null,
val tags: List<Tag>? = null,
val emojis: List<Emoji>? = null,
//Informational attributes
val reblogs_count: Int,
val favourites_count: Int,
val replies_count: Int,
val reblogs_count: Int = 0,
val favourites_count: Int = 0,
val replies_count: Int = 0,
//Nullable attributes
val url: String?, //URL
val in_reply_to_id: String?,
val in_reply_to_account: String?,
val reblog: Status?,
val poll: Poll?,
val card: Card?,
val language: String?, //ISO 639 Part 1 two-letter language code
val text: String?,
val url: String? = null, //URL
val in_reply_to_id: String? = null,
val in_reply_to_account: String? = null,
val reblog: Status? = null,
val poll: Poll? = null,
val card: Card? = null,
val language: String? = null, //ISO 639 Part 1 two-letter language code
val text: String? = null,
//Authorized user attributes
val favourited: Boolean,
val reblogged: Boolean,
val muted: Boolean,
val bookmarked: Boolean,
val pinned: Boolean
val favourited: Boolean = false,
val reblogged: Boolean = false,
val muted: Boolean = false,
val bookmarked: Boolean = false,
val pinned: Boolean = false
) : Serializable, FeedContent()
{
@ -194,6 +203,8 @@ data class Status(
//Set comment initial visibility
rootView.findViewById<LinearLayout>(R.id.commentIn).visibility = View.GONE
imagePopUpMenu(rootView, homeFragment.requireActivity())
}
fun setDescription(rootView: View, api : PixelfedAPI, credential: String) {
@ -292,4 +303,27 @@ data class Status(
enum class Visibility : Serializable {
public, unlisted, private, direct
}
fun imagePopUpMenu(view: View, activity: FragmentActivity) {
val anchor = view.findViewById<FrameLayout>(R.id.post_fragment_image_popup_menu_anchor)
if (!media_attachments.isNullOrEmpty() && media_attachments.size == 1) {
view.findViewById<ImageView>(R.id.postPicture).setOnLongClickListener {
PopupMenu(view.context, anchor).apply {
setOnMenuItemClickListener { item ->
when (item.itemId) {
R.id.image_popup_menu_save_to_gallery -> {
downloadImage(activity, view.context, getPostUrl()!!)
true
}
else -> false
}
}
inflate(R.menu.image_popup_menu)
show()
}
true
}
}
}
}

View File

@ -0,0 +1,77 @@
package com.h.pixeldroid.utils
import android.app.DownloadManager
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.os.Environment
import android.provider.Settings.Global.getString
import android.widget.Toast
import androidx.fragment.app.FragmentActivity
import com.h.pixeldroid.R
import java.io.File
class ImageUtils {
companion object {
fun downloadImage(activity: FragmentActivity, context: Context, url: String) {
var msg = ""
var lastMsg = ""
val directory = File(Environment.DIRECTORY_PICTURES)
if (!directory.exists()) {
directory.mkdirs()
}
val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE)
as DownloadManager
val downloadUri = Uri.parse(url)
val title = url.substring(url.lastIndexOf("/") + 1)
val request = DownloadManager.Request(downloadUri).apply {
setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI
or DownloadManager.Request.NETWORK_MOBILE)
setTitle(title)
setDestinationInExternalPublicDir(directory.toString(), title)
}
val downloadId = downloadManager.enqueue(request)
val query = DownloadManager.Query().setFilterById(downloadId)
Thread(Runnable {
var downloading = true
while (downloading) {
val cursor: Cursor = downloadManager.query(query)
cursor.moveToFirst()
if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))
== DownloadManager.STATUS_SUCCESSFUL) {
downloading = false
}
val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))
msg = when (status) {
DownloadManager.STATUS_FAILED ->
context.getString(R.string.image_download_failed)
DownloadManager.STATUS_RUNNING ->
context.getString(R.string.image_download_downloading)
DownloadManager.STATUS_SUCCESSFUL ->
context.getString(R.string.image_download_success)
else -> ""
}
if (msg != lastMsg && msg != "") {
activity.runOnUiThread {
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()
}
lastMsg = msg
}
cursor.close()
}
}).start()
}
private fun statusMessage(url: String, directory: File, status: Int, context: Context): String {
return when (status) {
DownloadManager.STATUS_FAILED -> context.getString(R.string.image_download_failed)
DownloadManager.STATUS_RUNNING -> "Downloading..."
DownloadManager.STATUS_SUCCESSFUL -> "Image downloaded successfully in $directory" + File.separator + url.substring(
url.lastIndexOf("/") + 1
)
else -> ""
}
}
}
}

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="-100%p"
android:toXDelta="0"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:duration="@integer/swipe_animation_duration"/>
</set>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="100%p"
android:toXDelta="0"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:duration="@integer/swipe_animation_duration"/>
</set>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="0"
android:toXDelta="-100%p"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:duration="@integer/swipe_animation_duration"/>
</set>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="0"
android:toXDelta="100%p"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:duration="@integer/swipe_animation_duration"/>
</set>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 11,14.41L11,22h1l5.71,-5.71 -4.3,-4.29 4.3,-4.29zM13,5.83l1.88,1.88L13,9.59L13,5.83zM14.88,16.29L13,18.17v-3.76l1.88,1.88z"/>
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M20,2H4c-1.1,0 -2,0.9 -2,2v18l4,-4h14c1.1,0 2,-0.9 2,-2V4c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>

View File

@ -1,5 +0,0 @@
<vector android:height="24dp" android:tint="#003DFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#010101" android:pathData="M12,12m-8,0a8,8 0,1 1,16 0a8,8 0,1 1,-16 0"/>
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M2.5,4v3h5v12h3L10.5,7h5L15.5,4h-13zM21.5,9h-9v3h3v7h3v-7h3L21.5,9z"/>
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M7.58,4.08L6.15,2.65C3.75,4.48 2.17,7.3 2.03,10.5h2c0.15,-2.65 1.51,-4.97 3.55,-6.42zM19.97,10.5h2c-0.15,-3.2 -1.73,-6.02 -4.12,-7.85l-1.42,1.43c2.02,1.45 3.39,3.77 3.54,6.42zM18,11c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2v-5zM12,22c0.14,0 0.27,-0.01 0.4,-0.04 0.65,-0.14 1.18,-0.58 1.44,-1.18 0.1,-0.24 0.15,-0.5 0.15,-0.78h-4c0.01,1.1 0.9,2 2.01,2z"/>
</vector>

View File

@ -1,5 +0,0 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z"/>
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM12.5,7H11v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z"/>
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12.87,15.07l-2.54,-2.51 0.03,-0.03c1.74,-1.94 2.98,-4.17 3.71,-6.53L17,6L17,4h-7L10,2L8,2v2L1,4v1.99h11.17C11.5,7.92 10.44,9.75 9,11.35 8.07,10.32 7.3,9.19 6.69,8h-2c0.73,1.63 1.73,3.17 2.98,4.56l-5.09,5.02L4,19l5,-5 3.11,3.11 0.76,-2.04zM18.5,10h-2L12,22h2l1.12,-3h4.75L21,22h2l-4.5,-12zM15.88,17l1.62,-4.33L19.12,17h-3.24z"/>
</vector>

View File

@ -1,57 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/camera_fragment_main_linear_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragments.NewPostFragment">
<TextureView
android:id="@+id/textureView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<Button
android:id="@+id/takePictureButton"
android:layout_width="36dp"
android:layout_height="30dp"
android:layout_margin="15dp"
android:layout_marginStart="14dp"
android:background="?android:attr/listChoiceIndicatorSingle"
android:gravity="center"
android:padding="15dp"
android:textColor="@color/cardview_light_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.517"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0"
tools:ignore="MissingConstraints,PrivateResource" />
<ImageView
android:id="@+id/uploadedPictureView"
android:layout_width="366dp"
android:layout_height="532dp"
android:layout_margin="15dp"
android:layout_marginStart="14dp"
android:layout_marginEnd="14dp"
android:contentDescription="@string/upload_a_picture"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/textureView"
app:layout_constraintHorizontal_bias="0.501"
app:layout_constraintStart_toEndOf="@+id/textureView"
app:layout_constraintTop_toTopOf="@+id/textureView"
app:layout_constraintVertical_bias="0.147"
tools:ignore="MissingConstraints"
tools:srcCompat="@tools:sample/avatars" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/followsFragment"
android:layout_width="match_parent"

View File

@ -20,7 +20,6 @@
android:orientation="vertical">
<ImageView
android:id="@+id/imageView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:tools="http://schemas.android.com/tools"
<merge xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
@ -18,7 +18,6 @@
android:background="#88000000">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/new_post_description_input_layout"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
@ -52,4 +51,4 @@
</LinearLayout>
</FrameLayout>
</merge>

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/feedList"
android:name="com.h.pixeldroid.FeedFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
app:layoutManager="LinearLayoutManager"
tools:listitem="@layout/post_fragment" />

View File

@ -7,7 +7,6 @@
android:layout_margin="5dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/notification"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp">

View File

@ -13,7 +13,6 @@
android:theme="@style/ThemeOverlay.AppCompat.Dark">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@mipmap/ic_launcher_round" />
@ -26,7 +25,6 @@
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/menu_subtitle" />

View File

@ -74,7 +74,19 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@color/browser_actions_bg_grey"/>
tools:src="@color/browser_actions_bg_grey"
android:longClickable="true"/>
<FrameLayout
android:id="@+id/post_fragment_image_popup_menu_anchor"
android:layout_width="1dp"
android:layout_height="1dp"
app:layout_constraintBottom_toBottomOf="@+id/postPicture"
app:layout_constraintEnd_toEndOf="@+id/postPicture"
app:layout_constraintHorizontal_bias="0.1"
app:layout_constraintStart_toStartOf="@+id/postPicture"
app:layout_constraintTop_toTopOf="@+id/postPicture"
app:layout_constraintVertical_bias="0.1" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -139,7 +139,6 @@
app:layout_constraintTop_toTopOf="parent">
<ImageButton
android:id="@+id/postsButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
@ -147,7 +146,6 @@
android:src="@android:drawable/ic_dialog_dialer" />
<ImageButton
android:id="@+id/collectionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/image_popup_menu_save_to_gallery"
android:title="@string/save_to_gallery"/>
</menu>

View File

@ -4,7 +4,5 @@
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="nav_header_vertical_spacing">8dp</dimen>
<dimen name="nav_header_height">176dp</dimen>
<dimen name="fab_margin">16dp</dimen>
<dimen name="text_margin">16dp</dimen>
</resources>

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="swipe_animation_duration">300</integer>
</resources>

View File

@ -1,37 +1,12 @@
<resources>
<string name="app_name">PixelDroid</string>
<string name="navigation_drawer_open">Open navigation drawer</string>
<string name="navigation_drawer_close">Close navigation drawer</string>
<string name="action_settings">Settings</string>
<string name="menu_slideshow">Account name</string>
<string name="menu_subtitle">Account informations</string>
<string name="menu_account">My Profile</string>
<string name="menu_settings">Settings</string>
<string name="menu_accessibility">Accessibility</string>
<string-array name="list_languages">
<item>English</item>
<item>Français</item>
<item>日本人</item>
</string-array>
<string-array name="list_font_size">
<item>Small</item>
<item>Medium</item>
<item>Big</item>
</string-array>
<string name="title_activity_login">Sign in</string>
<string name="prompt_email">Email</string>
<string name="prompt_password">Password</string>
<string name="action_sign_in">Sign in or register</string>
<string name="action_sign_in_short">Sign in</string>
<string name="welcome">"Welcome !"</string>
<string name="invalid_username">Not a valid username</string>
<string name="invalid_password">Password must be >5 characters</string>
<string name="login_failed">"Login failed"</string>
<string name="invalid_domain">"Invalid domain"</string>
<string name="registration_failed">"Could not register the application with this server"</string>
<string name="browser_launch_failed">"Could not launch a browser, do you have one?"</string>
@ -54,8 +29,6 @@
</string>
<string name="attachment_summary_off">Only download attachments when manually requested</string>
<string name="start_login">Start Login</string>
<string name="no_username">No Username</string>
<string name="followed_notification">%1$s followed you</string>
<string name="mention_notification">%1$s mentioned you</string>
<string name="shared_notification">%1$s shared your post</string>
@ -67,11 +40,13 @@
<string name="or">or</string>
<string name="description">Description…</string>
<string name="upload">upload</string>
<string name="send">send</string>
<string name="reconnect">Reconnect</string>
<string name="whats_an_instance">What\'s an instance?</string>
<string name="logout">Logout</string>
<string name="save_to_gallery">Save to Gallery…</string>
<string name="image_download_failed">Download has been failed, please try again</string>
<string name="image_download_downloading">Downloading…</string>
<string name="image_download_success">Image downloaded successfully</string>
</resources>

View File

@ -15,16 +15,4 @@
<item name="windowNoTitle">true</item>
</style>
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
<style name="posts_title">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_marginBottom">8dp</item>
<item name="android:paddingLeft">8dp</item>
<item name="android:background">@android:color/holo_orange_light</item>
<item name="android:textAppearance">@android:style/TextAppearance.Large</item>
</style>
</resources>

View File

@ -215,9 +215,9 @@ fun assertStatusEqualsToReference(actual: Status){
assert(attchmnt.id == "15888" && attchmnt.type == Attachment.AttachmentType.image && attchmnt.url=="https://pixelfed.de/storage/m/113a3e2124a33b1f5511e531953f5ee48456e0c7/34dd6d9fb1762dac8c7ddeeaf789d2d8fa083c9f/JtjO0eAbELpgO1UZqF5ydrKbCKRVyJUM1WAaqIeB.jpeg" &&
attchmnt.preview_url =="https://pixelfed.de/storage/m/113a3e2124a33b1f5511e531953f5ee48456e0c7/34dd6d9fb1762dac8c7ddeeaf789d2d8fa083c9f/JtjO0eAbELpgO1UZqF5ydrKbCKRVyJUM1WAaqIeB_thumb.jpeg" &&
attchmnt.remote_url ==null && attchmnt.text_url==null && attchmnt.description==null && attchmnt.blurhash==null )
assert( actual.application.name=="web" && actual.application.website==null && actual.application.vapid_key==null && actual.mentions==emptyList<Mention>())
assert( actual.application!!.name=="web" && actual.application!!.website==null && actual.application!!.vapid_key==null && actual.mentions==emptyList<Mention>())
val firstTag =actual.tags[0]
val firstTag =actual.tags!![0]
assert(firstTag.name=="hiking" && firstTag.url=="https://pixelfed.de/discover/tags/hiking" && firstTag.history==null &&
actual.emojis== emptyList<Emoji>() && actual.reblogs_count==0 && actual.favourites_count==0&& actual.replies_count==0 && actual.url=="https://pixelfed.de/p/Miike/140364967936397312")