Merge tag 'v28.0' into develop

# Conflicts:
#	README.md
#	app/build.gradle
#	app/src/main/java/com/keylesspalace/tusky/ListsActivity.kt
#	app/src/main/java/com/keylesspalace/tusky/adapter/NotificationsAdapter.java
#	app/src/main/java/com/keylesspalace/tusky/components/account/AccountActivity.kt
#	app/src/main/java/com/keylesspalace/tusky/components/account/media/AccountMediaFragment.kt
#	app/src/main/java/com/keylesspalace/tusky/components/accountlist/AccountListFragment.kt
#	app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementsActivity.kt
#	app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt
#	app/src/main/java/com/keylesspalace/tusky/components/compose/view/ProgressImageView.kt
#	app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt
#	app/src/main/java/com/keylesspalace/tusky/components/filters/FiltersActivity.kt
#	app/src/main/java/com/keylesspalace/tusky/components/login/LoginActivity.kt
#	app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportStatusesFragment.kt
#	app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledStatusActivity.kt
#	app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchFragment.kt
#	app/src/main/java/com/keylesspalace/tusky/components/timeline/TimelineFragment.kt
#	app/src/main/java/com/keylesspalace/tusky/components/trending/TrendingTagsFragment.kt
#	app/src/main/java/com/keylesspalace/tusky/components/viewthread/ViewThreadFragment.kt
#	app/src/main/java/com/keylesspalace/tusky/components/viewthread/edits/ViewEditsFragment.kt
#	app/src/main/java/com/keylesspalace/tusky/view/GraphView.kt
#	app/src/main/res/color/compound_button_color.xml
#	app/src/main/res/color/text_input_layout_box_stroke_color.xml
#	app/src/main/res/drawable/ic_check_circle.xml
#	app/src/main/res/drawable/ic_flag_24dp.xml
#	app/src/main/res/drawable/ic_person_add_24dp.xml
#	app/src/main/res/drawable/ic_play_indicator.xml
#	app/src/main/res/drawable/ic_poll_24dp.xml
#	app/src/main/res/drawable/ic_reblog_active_24dp.xml
#	app/src/main/res/drawable/ic_reblog_private_active_24dp.xml
#	app/src/main/res/drawable/report_success_background.xml
#	app/src/main/res/layout-land/item_trending_cell.xml
#	app/src/main/res/layout/activity_account.xml
#	app/src/main/res/layout/activity_edit_filter.xml
#	app/src/main/res/layout/card_license.xml
#	app/src/main/res/layout/item_announcement.xml
#	app/src/main/res/layout/item_status.xml
#	app/src/main/res/layout/item_status_detailed.xml
#	app/src/main/res/layout/item_tab_preference.xml
#	app/src/main/res/layout/item_trending_cell.xml
#	app/src/main/res/values-cs/strings.xml
#	app/src/main/res/values-de/strings.xml
#	app/src/main/res/values-es/strings.xml
#	app/src/main/res/values-eu/strings.xml
#	app/src/main/res/values-fr/strings.xml
#	app/src/main/res/values-kab/strings.xml
#	app/src/main/res/values-lv/strings.xml
#	app/src/main/res/values-nb-rNO/strings.xml
#	app/src/main/res/values-night/theme_colors.xml
#	app/src/main/res/values/colors.xml
#	app/src/main/res/values/strings.xml
#	app/src/main/res/values/styles.xml
#	app/src/main/res/values/theme_colors.xml
This commit is contained in:
Mike Barnes 2026-01-03 09:57:39 +11:00
commit a66f7bb515
614 changed files with 52429 additions and 19916 deletions

View file

@ -19,11 +19,8 @@ import android.Manifest
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.app.DownloadManager
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.Color
import android.net.Uri
@ -38,14 +35,15 @@ import android.view.View
import android.view.WindowManager
import android.webkit.MimeTypeMap
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.app.ShareCompat
import androidx.core.content.FileProvider
import androidx.core.content.IntentCompat
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.lifecycleScope
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import com.bumptech.glide.Glide
import com.google.android.material.snackbar.Snackbar
import com.keylesspalace.tusky.BuildConfig.APPLICATION_ID
import com.keylesspalace.tusky.components.viewthread.ViewThreadActivity
import com.keylesspalace.tusky.databinding.ActivityViewMediaBinding
@ -54,32 +52,29 @@ import com.keylesspalace.tusky.fragment.ViewImageFragment
import com.keylesspalace.tusky.fragment.ViewVideoFragment
import com.keylesspalace.tusky.pager.ImagePagerAdapter
import com.keylesspalace.tusky.pager.SingleImagePagerAdapter
import com.keylesspalace.tusky.util.copyToClipboard
import com.keylesspalace.tusky.util.getParcelableArrayListExtraCompat
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 dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector
import dagger.hilt.android.AndroidEntryPoint
import java.io.File
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
@AndroidEntryPoint
class ViewMediaActivity :
BaseActivity(),
HasAndroidInjector,
ViewImageFragment.PhotoActionsListener,
ViewVideoFragment.VideoActionsListener {
@Inject
lateinit var androidInjector: DispatchingAndroidInjector<Any>
private val binding by viewBinding(ActivityViewMediaBinding::inflate)
val toolbar: View
@ -92,6 +87,17 @@ class ViewMediaActivity :
private val toolbarVisibilityListeners = mutableListOf<ToolbarVisibilityListener>()
private var imageUrl: String? = null
private val requestDownloadMediaPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
if (isGranted) {
downloadMedia()
} else {
Snackbar.make(binding.toolbar, getString(R.string.error_media_download_permission), Snackbar.LENGTH_SHORT)
.setAction(R.string.action_retry) { requestDownloadMedia() }
.show()
}
}
fun addToolbarVisibilityListener(listener: ToolbarVisibilityListener): Function0<Boolean> {
this.toolbarVisibilityListeners.add(listener)
listener(isToolbarVisible)
@ -105,11 +111,7 @@ class ViewMediaActivity :
supportPostponeEnterTransition()
// Gather the parameters.
attachments = IntentCompat.getParcelableArrayListExtra(
intent,
EXTRA_ATTACHMENTS,
AttachmentViewData::class.java
)
attachments = intent.getParcelableArrayListExtraCompat(EXTRA_ATTACHMENTS)
val initialPosition = intent.getIntExtra(EXTRA_ATTACHMENT_INDEX, 0)
// Adapter is actually of existential type PageAdapter & SharedElementsTransitionListener
@ -154,9 +156,13 @@ class ViewMediaActivity :
true
}
// yes it is deprecated, but it looks cool so it stays for now
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE
window.statusBarColor = Color.BLACK
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
@Suppress("DEPRECATION")
window.statusBarColor = Color.BLACK
}
window.sharedElementEnterTransition.addListener(object : NoopTransitionListener {
override fun onTransitionEnd(transition: Transition) {
adapter.onTransitionEnd(binding.viewPager.currentItem)
@ -235,22 +241,7 @@ class ViewMediaActivity :
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
) {
downloadMedia()
} else {
showErrorDialog(
binding.toolbar,
R.string.error_media_download_permission,
R.string.action_retry
) { requestDownloadMedia() }
}
}
requestDownloadMediaPermissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
} else {
downloadMedia()
}
@ -264,9 +255,10 @@ class ViewMediaActivity :
}
private fun copyLink() {
val url = imageUrl ?: attachments!![binding.viewPager.currentItem].attachment.url
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
clipboard.setPrimaryClip(ClipData.newPlainText(null, url))
copyToClipboard(
imageUrl ?: attachments!![binding.viewPager.currentItem].attachment.url,
getString(R.string.url_copied),
)
}
private fun shareMedia() {
@ -367,8 +359,6 @@ class ViewMediaActivity :
}
}
override fun androidInjector() = androidInjector
companion object {
private const val EXTRA_ATTACHMENTS = "attachments"
private const val EXTRA_ATTACHMENT_INDEX = "index"