Browse Source

allow viewing media fullscreen in edge to edge mode (#5067)

This will change the image viewer layout so the image wil occupy a
larger portion of the screen when zoomed in and even the whole screen in
edge to edge mode. I think this is really nice.

Before / After:
<img
src="https://github.com/user-attachments/assets/2220b663-458e-4162-b70c-b0cebb37a387"
width="320"/> <img
src="https://github.com/user-attachments/assets/5f9e344b-67e4-495e-a393-c2ff8275d1ea"
width="320"/>

~~Currently blocked by a bug in the TouchImageView library we are using.
https://github.com/MikeOrtiz/TouchImageView/issues/654~~ They accepted
my PR and made a new release, nice
pull/5074/head^2
Konrad Pozniak 11 months ago committed by GitHub
parent
commit
95c7be4051
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 39
      app/src/main/java/com/keylesspalace/tusky/ViewMediaActivity.kt
  2. 2
      app/src/main/java/com/keylesspalace/tusky/components/account/media/AccountMediaFragment.kt
  3. 2
      app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportStatusesFragment.kt
  4. 2
      app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt
  5. 2
      app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.kt
  6. 12
      app/src/main/java/com/keylesspalace/tusky/fragment/ViewImageFragment.kt
  7. 12
      app/src/main/res/layout/activity_view_media.xml
  8. 8
      app/src/main/res/layout/fragment_view_image.xml
  9. 3
      app/src/main/res/values/dimens.xml
  10. 2
      gradle/libs.versions.toml
  11. 16
      gradle/verification-metadata.xml

39
app/src/main/java/com/keylesspalace/tusky/ViewMediaActivity.kt

@ -38,6 +38,7 @@ import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.app.ShareCompat
import androidx.core.content.FileProvider
import androidx.core.net.toUri
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.lifecycleScope
import androidx.viewpager2.adapter.FragmentStateAdapter
@ -63,7 +64,6 @@ import dagger.hilt.android.AndroidEntryPoint
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.util.Locale
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.launch
@ -77,9 +77,6 @@ class ViewMediaActivity :
private val binding by viewBinding(ActivityViewMediaBinding::inflate)
val toolbar: View
get() = binding.toolbar
var isToolbarVisible = true
private set
@ -114,9 +111,6 @@ class ViewMediaActivity :
attachments = intent.getParcelableArrayListExtraCompat(EXTRA_ATTACHMENTS)
val initialPosition = intent.getIntExtra(EXTRA_ATTACHMENT_INDEX, 0)
// Adapter is actually of existential type PageAdapter & SharedElementsTransitionListener
// but it cannot be expressed and if I don't specify type explicitly compilation fails
// (probably a bug in compiler)
val adapter: ViewMediaAdapter = if (attachments != null) {
val realAttachs = attachments!!.map(AttachmentViewData::attachment)
// Setup the view pager.
@ -139,11 +133,10 @@ class ViewMediaActivity :
// Setup the toolbar.
setSupportActionBar(binding.toolbar)
val actionBar = supportActionBar
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true)
actionBar.setDisplayShowHomeEnabled(true)
actionBar.title = getPageTitle(initialPosition)
supportActionBar?.run {
setDisplayHomeAsUpEnabled(true)
setDisplayShowHomeEnabled(true)
title = getPageTitle(initialPosition)
}
binding.toolbar.setNavigationOnClickListener { supportFinishAfterTransition() }
binding.toolbar.setOnMenuItemClickListener { item: MenuItem ->
@ -203,14 +196,14 @@ class ViewMediaActivity :
val alpha = if (isToolbarVisible) 1.0f else 0.0f
if (isToolbarVisible) {
// If to be visible, need to make visible immediately and animate alpha
binding.toolbar.alpha = 0.0f
binding.toolbar.visibility = visibility
binding.appBarLayout.alpha = 0.0f
binding.appBarLayout.visibility = visibility
}
binding.toolbar.animate().alpha(alpha)
binding.appBarLayout.animate().alpha(alpha)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
binding.toolbar.visibility = visibility
binding.appBarLayout.visibility = visibility
animation.removeListener(this)
}
})
@ -221,20 +214,20 @@ class ViewMediaActivity :
if (attachments == null) {
return ""
}
return String.format(Locale.getDefault(), "%d/%d", position + 1, attachments?.size)
return "${position + 1}/${attachments?.size}"
}
private fun downloadMedia() {
val url = imageUrl ?: attachments!![binding.viewPager.currentItem].attachment.url
val filename = Uri.parse(url).lastPathSegment
val filename = url.toUri().lastPathSegment
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))
val downloadManager = getSystemService(DOWNLOAD_SERVICE) as DownloadManager
val request = DownloadManager.Request(url.toUri())
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename)
downloadManager.enqueue(request)
}
@ -303,7 +296,7 @@ class ViewMediaActivity :
val file = File(directory, getTemporaryMediaFilename("png"))
val result = try {
val bitmap =
Glide.with(applicationContext).asBitmap().load(Uri.parse(url)).submitAsync()
Glide.with(applicationContext).asBitmap().load(url.toUri()).submitAsync()
try {
FileOutputStream(file).use { stream ->
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream)
@ -332,7 +325,7 @@ class ViewMediaActivity :
}
private fun shareMediaFile(directory: File, url: String) {
val uri = Uri.parse(url)
val uri = url.toUri()
val mimeTypeMap = MimeTypeMap.getSingleton()
val extension = MimeTypeMap.getFileExtensionFromUrl(url)
val mimeType = mimeTypeMap.getMimeTypeFromExtension(extension)
@ -367,7 +360,7 @@ class ViewMediaActivity :
@JvmStatic
fun newIntent(
context: Context?,
context: Context,
attachments: List<AttachmentViewData>,
index: Int
): Intent {

2
app/src/main/java/com/keylesspalace/tusky/components/account/media/AccountMediaFragment.kt

@ -182,7 +182,7 @@ class AccountMediaFragment :
Attachment.Type.VIDEO,
Attachment.Type.AUDIO -> {
val intent = ViewMediaActivity.newIntent(
context,
view.context,
attachmentsFromSameStatus,
currentIndex
)

2
app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportStatusesFragment.kt

@ -83,7 +83,7 @@ class ReportStatusesFragment :
when (status.attachments[idx].type) {
Attachment.Type.GIFV, Attachment.Type.VIDEO, Attachment.Type.IMAGE, Attachment.Type.AUDIO -> {
val attachments = AttachmentViewData.list(status)
val intent = ViewMediaActivity.newIntent(context, attachments, idx)
val intent = ViewMediaActivity.newIntent(requireContext(), attachments, idx)
if (v != null) {
val url = status.attachments[idx].url
ViewCompat.setTransitionName(v, url)

2
app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt

@ -197,7 +197,7 @@ class SearchStatusesFragment : SearchFragment<StatusViewData.Concrete>(), Status
Attachment.Type.GIFV, Attachment.Type.VIDEO, Attachment.Type.IMAGE, Attachment.Type.AUDIO -> {
val attachments = AttachmentViewData.list(status)
val intent = ViewMediaActivity.newIntent(
context,
requireContext(),
attachments,
attachmentIndex
)

2
app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.kt

@ -398,7 +398,7 @@ abstract class SFragment(@LayoutRes contentLayoutId: Int) : Fragment(contentLayo
val (attachment) = attachments[urlIndex]
when (attachment.type) {
Attachment.Type.GIFV, Attachment.Type.VIDEO, Attachment.Type.IMAGE, Attachment.Type.AUDIO -> {
val intent = newIntent(context, attachments, urlIndex)
val intent = newIntent(requireContext(), attachments, urlIndex)
if (view != null) {
val url = attachment.url
view.transitionName = url

12
app/src/main/java/com/keylesspalace/tusky/fragment/ViewImageFragment.kt

@ -28,8 +28,8 @@ import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat.Type.displayCutout
import androidx.core.view.WindowInsetsCompat.Type.systemBars
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.lifecycle.lifecycleScope
import com.bumptech.glide.Glide
@ -115,14 +115,18 @@ class ViewImageFragment : ViewMediaFragment() {
val descriptionBottomSheet = BottomSheetBehavior.from(binding.captionSheet)
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, insets ->
val topInsets = insets.getInsets(displayCutout()).top
val bottomInsets = insets.getInsets(systemBars()).bottom
val mediaDescriptionBottomPadding = requireContext().resources.getDimensionPixelSize(R.dimen.media_description_sheet_bottom_padding)
val mediaDescriptionPeekHeight = requireContext().resources.getDimensionPixelSize(R.dimen.media_description_sheet_peek_height)
val imageViewBottomMargin = requireContext().resources.getDimensionPixelSize(R.dimen.media_image_view_bottom_margin)
binding.mediaDescription.updatePadding(bottom = mediaDescriptionBottomPadding + bottomInsets)
descriptionBottomSheet.setPeekHeight(mediaDescriptionPeekHeight + bottomInsets, false)
binding.photoView.updateLayoutParams<ViewGroup.MarginLayoutParams> { bottomMargin = imageViewBottomMargin + bottomInsets }
insets.inset(0, 0, 0, bottomInsets)
binding.photoView.updatePadding(
top = topInsets,
bottom = bottomInsets
)
binding.photoView.invalidate()
insets.inset(0, topInsets, 0, bottomInsets)
}
val singleTapDetector = GestureDetector(

12
app/src/main/res/layout/activity_view_media.xml

@ -5,7 +5,13 @@
android:layout_height="match_parent"
android:background="@color/black">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/transparent_black"
@ -22,12 +28,6 @@
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager"
android:layout_width="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
android:layout_height="match_parent" />
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/progressBarShare"
android:layout_width="wrap_content"

8
app/src/main/res/layout/fragment_view_image.xml

@ -10,8 +10,7 @@
<com.ortiz.touchview.TouchImageView
android:id="@+id/photoView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="@dimen/media_image_view_bottom_margin"/>
android:layout_height="match_parent"/>
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/progressBar"
@ -50,9 +49,8 @@
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"

3
app/src/main/res/values/dimens.xml

@ -79,9 +79,8 @@
<dimen name="dialog_inset">24dp</dimen>
<dimen name="media_description_sheet_bottom_padding">8dp</dimen>
<dimen name="media_description_sheet_bottom_padding">16dp</dimen>
<dimen name="media_description_sheet_peek_height">90dp</dimen>
<dimen name="media_image_view_bottom_margin">24dp</dimen>
<dimen name="bottomAppBarHeight">64dp</dimen>

2
gradle/libs.versions.toml

@ -45,7 +45,7 @@ okio = "3.11.0"
retrofit = "2.11.0"
robolectric = "4.14.1"
sparkbutton = "4.2.0"
touchimageview = "3.6"
touchimageview = "3.7"
turbine = "1.2.0"
unified-push = "2.4.0"
xmlwriter = "1.0.4"

16
gradle/verification-metadata.xml

@ -12090,6 +12090,14 @@
<sha256 value="607d0ebabb05336bdb48aec46cfdae2f684f4ff1d0ea0c65d0a62e033e9d7698" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.MikeOrtiz" name="TouchImageView" version="3.7">
<artifact name="TouchImageView-3.7.aar">
<sha256 value="171efea56d1a738efa756a710a90d6096ecc7f45756381e283fd6a28c6caea2b" origin="Generated by Gradle"/>
</artifact>
<artifact name="TouchImageView-3.7.module">
<sha256 value="6fab7c4ca2686574858118f24730ebd642534b41cc16ec1419bb28b5430796c0" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.UnifiedPush" name="android-connector" version="2.4.0">
<artifact name="android-connector-2.4.0.aar">
<sha256 value="6ac50fd9acac605939bf818d0c2355ed783fbeef00ea351ed8e14cceb6ef2238" origin="Generated by Gradle"/>
@ -18337,6 +18345,14 @@
<sha256 value="06fbc14ecb14a0af47b5a3f8d34763f4933d5cba5a3d245045bfe2f2bdb91b1e" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.jetbrains.kotlin" name="kotlin-stdlib-jdk7" version="2.1.20">
<artifact name="kotlin-stdlib-jdk7-2.1.20.jar">
<sha256 value="5343bf795783932e5fa538b0bca05af810bb07213edb9baa770c784068f57867" origin="Generated by Gradle"/>
</artifact>
<artifact name="kotlin-stdlib-jdk7-2.1.20.pom">
<sha256 value="dcf3de1ba53393a449c789f1e515f9aa88c603a6d356a480ea42ff7d4a98b737" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.jetbrains.kotlin" name="kotlin-stdlib-jdk8" version="1.8.20">
<artifact name="kotlin-stdlib-jdk8-1.8.20.jar">
<sha256 value="e398b67977622718bf18ff99b739c7d9da060f33fb458a2e25203221c16af010" origin="Generated by Gradle"/>

Loading…
Cancel
Save