Merge tag 'v25.2' into develop
# Conflicts: # README.md # app/build.gradle # app/lint-baseline.xml # app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationsFragment.kt # app/src/main/java/com/keylesspalace/tusky/components/notifications/StatusNotificationViewHolder.kt # app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesFragment.kt # app/src/main/java/com/keylesspalace/tusky/util/ThemeUtils.kt # app/src/main/res/layout/activity_about.xml # app/src/main/res/layout/item_emoji_pref.xml # app/src/main/res/values-ar/strings.xml # app/src/main/res/values-bg/strings.xml # app/src/main/res/values-cy/strings.xml # app/src/main/res/values-de/strings.xml # app/src/main/res/values-fa/strings.xml # app/src/main/res/values-gd/strings.xml # app/src/main/res/values-gl/strings.xml # app/src/main/res/values-hu/strings.xml # app/src/main/res/values-is/strings.xml # app/src/main/res/values-it/strings.xml # app/src/main/res/values-ja/strings.xml # app/src/main/res/values-nl/strings.xml # app/src/main/res/values-oc/strings.xml # app/src/main/res/values-pt-rBR/strings.xml # app/src/main/res/values-pt-rPT/strings.xml # app/src/main/res/values-ru/strings.xml # app/src/main/res/values-si/strings.xml # app/src/main/res/values-sv/strings.xml # app/src/main/res/values-tr/strings.xml # app/src/main/res/values-uk/strings.xml # app/src/main/res/values-vi/strings.xml # app/src/main/res/values-zh-rCN/strings.xml # app/src/main/res/values/strings.xml # fastlane/metadata/android/ru/full_description.txt # fastlane/metadata/android/zh-Hans/full_description.txt
This commit is contained in:
parent
84670dbc0b
commit
875013e47f
630 changed files with 22153 additions and 18732 deletions
|
|
@ -35,19 +35,17 @@ import android.util.Log
|
|||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.webkit.MimeTypeMap
|
||||
import android.widget.Toast
|
||||
import androidx.core.app.ShareCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.content.IntentCompat
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import autodispose2.androidx.lifecycle.AndroidLifecycleScopeProvider
|
||||
import autodispose2.autoDispose
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.request.FutureTarget
|
||||
import com.keylesspalace.tusky.BuildConfig.APPLICATION_ID
|
||||
import com.keylesspalace.tusky.components.viewthread.ViewThreadActivity
|
||||
import com.keylesspalace.tusky.databinding.ActivityViewMediaBinding
|
||||
|
|
@ -57,20 +55,30 @@ import com.keylesspalace.tusky.fragment.ViewVideoFragment
|
|||
import com.keylesspalace.tusky.pager.ImagePagerAdapter
|
||||
import com.keylesspalace.tusky.pager.SingleImagePagerAdapter
|
||||
import com.keylesspalace.tusky.util.getTemporaryMediaFilename
|
||||
import com.keylesspalace.tusky.util.startActivityWithSlideInAnimation
|
||||
import com.keylesspalace.tusky.util.submitAsync
|
||||
import com.keylesspalace.tusky.util.viewBinding
|
||||
import com.keylesspalace.tusky.viewdata.AttachmentViewData
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.core.Single
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import dagger.android.DispatchingAndroidInjector
|
||||
import dagger.android.HasAndroidInjector
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
typealias ToolbarVisibilityListener = (isVisible: Boolean) -> Unit
|
||||
|
||||
class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener, ViewVideoFragment.VideoActionsListener {
|
||||
class ViewMediaActivity :
|
||||
BaseActivity(),
|
||||
HasAndroidInjector,
|
||||
ViewImageFragment.PhotoActionsListener,
|
||||
ViewVideoFragment.VideoActionsListener {
|
||||
|
||||
@Inject
|
||||
lateinit var androidInjector: DispatchingAndroidInjector<Any>
|
||||
|
||||
private val binding by viewBinding(ActivityViewMediaBinding::inflate)
|
||||
|
||||
|
|
@ -97,7 +105,11 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
|
|||
supportPostponeEnterTransition()
|
||||
|
||||
// Gather the parameters.
|
||||
attachments = IntentCompat.getParcelableArrayListExtra(intent, EXTRA_ATTACHMENTS, AttachmentViewData::class.java)
|
||||
attachments = IntentCompat.getParcelableArrayListExtra(
|
||||
intent,
|
||||
EXTRA_ATTACHMENTS,
|
||||
AttachmentViewData::class.java
|
||||
)
|
||||
val initialPosition = intent.getIntExtra(EXTRA_ATTACHMENT_INDEX, 0)
|
||||
|
||||
// Adapter is actually of existential type PageAdapter & SharedElementsTransitionListener
|
||||
|
|
@ -119,6 +131,7 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
|
|||
binding.viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
binding.toolbar.title = getPageTitle(position)
|
||||
adjustScreenWakefulness()
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -150,6 +163,8 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
|
|||
window.sharedElementEnterTransition.removeListener(this)
|
||||
}
|
||||
})
|
||||
|
||||
adjustScreenWakefulness()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
|
|
@ -206,7 +221,11 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
|
|||
private fun downloadMedia() {
|
||||
val url = imageUrl ?: attachments!![binding.viewPager.currentItem].attachment.url
|
||||
val filename = Uri.parse(url).lastPathSegment
|
||||
Toast.makeText(applicationContext, resources.getString(R.string.download_image, filename), Toast.LENGTH_SHORT).show()
|
||||
Toast.makeText(
|
||||
applicationContext,
|
||||
resources.getString(R.string.download_image, filename),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
|
||||
val downloadManager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
||||
val request = DownloadManager.Request(Uri.parse(url))
|
||||
|
|
@ -216,8 +235,13 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
|
|||
|
||||
private fun requestDownloadMedia() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { _, grantResults ->
|
||||
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
requestPermissions(
|
||||
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
) { _, grantResults ->
|
||||
if (
|
||||
grantResults.isNotEmpty() &&
|
||||
grantResults[0] == PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
downloadMedia()
|
||||
} else {
|
||||
showErrorDialog(
|
||||
|
|
@ -234,7 +258,9 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
|
|||
|
||||
private fun onOpenStatus() {
|
||||
val attach = attachments!![binding.viewPager.currentItem]
|
||||
startActivityWithSlideInAnimation(ViewThreadActivity.startIntent(this, attach.statusId, attach.statusUrl))
|
||||
startActivityWithSlideInAnimation(
|
||||
ViewThreadActivity.startIntent(this, attach.statusId, attach.statusUrl)
|
||||
)
|
||||
}
|
||||
|
||||
private fun copyLink() {
|
||||
|
|
@ -267,7 +293,9 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
|
|||
private fun shareFile(file: File, mimeType: String?) {
|
||||
ShareCompat.IntentBuilder(this)
|
||||
.setType(mimeType)
|
||||
.addStream(FileProvider.getUriForFile(applicationContext, "$APPLICATION_ID.fileprovider", file))
|
||||
.addStream(
|
||||
FileProvider.getUriForFile(applicationContext, "$APPLICATION_ID.fileprovider", file)
|
||||
)
|
||||
.setChooserTitle(R.string.send_media_to)
|
||||
.startChooser()
|
||||
}
|
||||
|
|
@ -278,46 +306,37 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
|
|||
isCreating = true
|
||||
binding.progressBarShare.visibility = View.VISIBLE
|
||||
invalidateOptionsMenu()
|
||||
val file = File(directory, getTemporaryMediaFilename("png"))
|
||||
val futureTask: FutureTarget<Bitmap> =
|
||||
Glide.with(applicationContext).asBitmap().load(Uri.parse(url)).submit()
|
||||
Single.fromCallable {
|
||||
val bitmap = futureTask.get()
|
||||
try {
|
||||
val stream = FileOutputStream(file)
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream)
|
||||
stream.close()
|
||||
return@fromCallable true
|
||||
} catch (fnfe: FileNotFoundException) {
|
||||
Log.e(TAG, "Error writing temporary media.")
|
||||
} catch (ioe: IOException) {
|
||||
Log.e(TAG, "Error writing temporary media.")
|
||||
}
|
||||
return@fromCallable false
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnDispose {
|
||||
futureTask.cancel(true)
|
||||
}
|
||||
.autoDispose(AndroidLifecycleScopeProvider.from(this, Lifecycle.Event.ON_DESTROY))
|
||||
.subscribe(
|
||||
{ result ->
|
||||
Log.d(TAG, "Download image result: $result")
|
||||
isCreating = false
|
||||
invalidateOptionsMenu()
|
||||
binding.progressBarShare.visibility = View.GONE
|
||||
if (result) {
|
||||
shareFile(file, "image/png")
|
||||
|
||||
lifecycleScope.launch {
|
||||
val file = File(directory, getTemporaryMediaFilename("png"))
|
||||
val result = try {
|
||||
val bitmap =
|
||||
Glide.with(applicationContext).asBitmap().load(Uri.parse(url)).submitAsync()
|
||||
try {
|
||||
FileOutputStream(file).use { stream ->
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream)
|
||||
}
|
||||
},
|
||||
{ error ->
|
||||
isCreating = false
|
||||
invalidateOptionsMenu()
|
||||
binding.progressBarShare.visibility = View.GONE
|
||||
Log.e(TAG, "Failed to download image", error)
|
||||
true
|
||||
} catch (ioe: IOException) {
|
||||
// FileNotFoundException is covered by IOException
|
||||
Log.e(TAG, "Error writing temporary media.")
|
||||
false
|
||||
}.also { result -> Log.d(TAG, "Download image result: $result") }
|
||||
} catch (error: Throwable) {
|
||||
if (error is CancellationException) {
|
||||
throw error
|
||||
}
|
||||
)
|
||||
Log.e(TAG, "Failed to download image", error)
|
||||
false
|
||||
}
|
||||
|
||||
isCreating = false
|
||||
invalidateOptionsMenu()
|
||||
binding.progressBarShare.visibility = View.GONE
|
||||
if (result) {
|
||||
shareFile(file, "image/png")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun shareMediaFile(directory: File, url: String) {
|
||||
|
|
@ -337,6 +356,19 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
|
|||
shareFile(file, mimeType)
|
||||
}
|
||||
|
||||
// Prevent this activity from dimming or sleeping the screen if, and only if, it is playing video or audio
|
||||
private fun adjustScreenWakefulness() {
|
||||
attachments?.run {
|
||||
if (get(binding.viewPager.currentItem).attachment.type == Attachment.Type.IMAGE) {
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
} else {
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun androidInjector() = androidInjector
|
||||
|
||||
companion object {
|
||||
private const val EXTRA_ATTACHMENTS = "attachments"
|
||||
private const val EXTRA_ATTACHMENT_INDEX = "index"
|
||||
|
|
@ -344,7 +376,11 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
|
|||
private const val TAG = "ViewMediaActivity"
|
||||
|
||||
@JvmStatic
|
||||
fun newIntent(context: Context?, attachments: List<AttachmentViewData>, index: Int): Intent {
|
||||
fun newIntent(
|
||||
context: Context?,
|
||||
attachments: List<AttachmentViewData>,
|
||||
index: Int
|
||||
): Intent {
|
||||
val intent = Intent(context, ViewMediaActivity::class.java)
|
||||
intent.putParcelableArrayListExtra(EXTRA_ATTACHMENTS, ArrayList(attachments))
|
||||
intent.putExtra(EXTRA_ATTACHMENT_INDEX, index)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue