diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java index 0519bf56..c159138b 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java @@ -753,7 +753,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { itemView.setAccessibilityDelegate(null); } else { if (payloads instanceof List) - for (Object item : (List) payloads) { + for (Object item : (List) payloads) { if (Key.KEY_CREATED.equals(item)) { setCreatedAt(status.getCreatedAt(), statusDisplayOptions); } diff --git a/app/src/main/java/com/keylesspalace/tusky/components/compose/dialog/CaptionDialog.kt b/app/src/main/java/com/keylesspalace/tusky/components/compose/dialog/CaptionDialog.kt index f1e4b3ea..bef6e95c 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/compose/dialog/CaptionDialog.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/compose/dialog/CaptionDialog.kt @@ -37,9 +37,8 @@ import com.github.chrisbanes.photoview.PhotoView import com.keylesspalace.tusky.R import com.keylesspalace.tusky.util.withLifecycleContext -// https://github.com/tootsuite/mastodon/blob/1656663/app/models/media_attachment.rb#L94 -private const val MEDIA_DESCRIPTION_CHARACTER_LIMIT = 420 - +// https://github.com/tootsuite/mastodon/blob/c6904c0d3766a2ea8a81ab025c127169ecb51373/app/models/media_attachment.rb#L32 +private const val MEDIA_DESCRIPTION_CHARACTER_LIMIT = 1500 fun T.makeCaptionDialog(existingDescription: String?, previewUri: Uri, diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/ViewImageFragment.kt b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewImageFragment.kt index 42513b23..1fae7c03 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/ViewImageFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewImageFragment.kt @@ -21,9 +21,11 @@ import android.annotation.SuppressLint import android.content.Context import android.graphics.drawable.Drawable import android.os.Bundle -import android.view.* +import android.view.LayoutInflater +import android.view.MotionEvent +import android.view.View +import android.view.ViewGroup import android.widget.ImageView -import android.widget.TextView import com.bumptech.glide.Glide import com.bumptech.glide.load.DataSource import com.bumptech.glide.load.engine.GlideException @@ -57,16 +59,52 @@ class ViewImageFragment : ViewMediaFragment() { @Volatile private var startedTransition = false - override lateinit var descriptionView: TextView override fun onAttach(context: Context) { super.onAttach(context) photoActionsListener = context as PhotoActionsListener } - @SuppressLint("ClickableViewAccessibility") - override fun setupMediaView(url: String, previewUrl: String?) { - descriptionView = mediaDescription + + override fun setupMediaView( + url: String, + previewUrl: String?, + description: String?, + showingDescription: Boolean + ) { photoView.transitionName = url + mediaDescription.text = description + captionSheet.visible(showingDescription) + + startedTransition = false + loadImageFromNetwork(url, previewUrl, photoView) + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + toolbar = requireActivity().toolbar + this.transition = BehaviorSubject.create() + return inflater.inflate(R.layout.fragment_view_image, container, false) + } + + @SuppressLint("ClickableViewAccessibility") + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val arguments = this.requireArguments() + val attachment = arguments.getParcelable(ARG_ATTACHMENT) + this.shouldStartTransition = arguments.getBoolean(ARG_START_POSTPONED_TRANSITION) + val url: String? + var description: String? = null + + if (attachment != null) { + url = attachment.url + description = attachment.description + } else { + url = arguments.getString(ARG_AVATAR_URL) + if (url == null) { + throw IllegalArgumentException("attachment or avatar url has to be set") + } + } + attacher = PhotoViewAttacher(photoView).apply { // This prevents conflicts with ViewPager setAllowParentInterceptOnEdge(true) @@ -87,21 +125,12 @@ class ViewImageFragment : ViewMediaFragment() { } } - val gestureDetector = GestureDetector(requireContext(), object : GestureDetector.SimpleOnGestureListener() { - override fun onSingleTapConfirmed(e: MotionEvent?): Boolean { - onMediaTap() - return true - } - }) - var lastY = 0f photoView.setOnTouchListener { v, event -> // This part is for scaling/translating on vertical move. // We use raw coordinates to get the correct ones during scaling - gestureDetector.onTouchEvent(event) - if (event.action == MotionEvent.ACTION_DOWN) { lastY = event.rawY } else if (event.pointerCount == 1 @@ -125,36 +154,6 @@ class ViewImageFragment : ViewMediaFragment() { attacher.onTouch(v, event) } - startedTransition = false - loadImageFromNetwork(url, previewUrl, photoView) - } - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - toolbar = requireActivity().toolbar - this.transition = BehaviorSubject.create() - return inflater.inflate(R.layout.fragment_view_image, container, false) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - - val arguments = this.requireArguments() - val attachment = arguments.getParcelable(ARG_ATTACHMENT) - this.shouldStartTransition = arguments.getBoolean(ARG_START_POSTPONED_TRANSITION) - val url: String? - var description: String? = null - - if (attachment != null) { - url = attachment.url - description = attachment.description - } else { - url = arguments.getString(ARG_AVATAR_URL) - if (url == null) { - throw IllegalArgumentException("attachment or avatar url has to be set") - } - } - finalizeViewSetup(url, attachment?.previewUrl, description) } @@ -176,10 +175,10 @@ class ViewImageFragment : ViewMediaFragment() { } isDescriptionVisible = showingDescription && visible val alpha = if (isDescriptionVisible) 1.0f else 0.0f - descriptionView.animate().alpha(alpha) + captionSheet.animate().alpha(alpha) .setListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { - descriptionView.visible(isDescriptionVisible) + captionSheet.visible(isDescriptionVisible) animation.removeListener(this) } }) diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/ViewMediaFragment.kt b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewMediaFragment.kt index 5a50fd18..9b51f285 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/ViewMediaFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewMediaFragment.kt @@ -17,18 +17,20 @@ package com.keylesspalace.tusky.fragment import android.os.Bundle import android.text.TextUtils -import android.widget.TextView - import com.keylesspalace.tusky.ViewMediaActivity import com.keylesspalace.tusky.entity.Attachment -import com.keylesspalace.tusky.util.visible abstract class ViewMediaFragment : BaseFragment() { private var toolbarVisibiltyDisposable: Function0? = null - abstract fun setupMediaView(url: String, previewUrl: String?) + abstract fun setupMediaView( + url: String, + previewUrl: String?, + description: String?, + showingDescription: Boolean + ) + abstract fun onToolbarVisibilityChange(visible: Boolean) - abstract val descriptionView: TextView protected var showingDescription = false protected var isDescriptionVisible = false @@ -36,6 +38,7 @@ abstract class ViewMediaFragment : BaseFragment() { companion object { @JvmStatic protected val ARG_START_POSTPONED_TRANSITION = "startPostponedTransition" + @JvmStatic protected val ARG_ATTACHMENT = "attach" @JvmStatic @@ -74,13 +77,10 @@ abstract class ViewMediaFragment : BaseFragment() { protected fun finalizeViewSetup(url: String, previewUrl: String?, description: String?) { val mediaActivity = activity as ViewMediaActivity - setupMediaView(url, previewUrl) - descriptionView.text = description ?: "" showingDescription = !TextUtils.isEmpty(description) isDescriptionVisible = showingDescription - - descriptionView.visible(showingDescription && mediaActivity.isToolbarVisible) + setupMediaView(url, previewUrl, description, showingDescription && mediaActivity.isToolbarVisible) toolbarVisibiltyDisposable = (activity as ViewMediaActivity) .addToolbarVisibilityListener { isVisible -> diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/ViewVideoFragment.kt b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewVideoFragment.kt index 09c29d47..9fd239ec 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/ViewVideoFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewVideoFragment.kt @@ -26,7 +26,6 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.MediaController -import android.widget.TextView import com.keylesspalace.tusky.R import com.keylesspalace.tusky.ViewMediaActivity import com.keylesspalace.tusky.entity.Attachment @@ -47,7 +46,6 @@ class ViewVideoFragment : ViewMediaFragment() { } private lateinit var mediaActivity: ViewMediaActivity private val TOOLBAR_HIDE_DELAY_MS = 3000L - override lateinit var descriptionView : TextView private lateinit var mediaController : MediaController private var isAudio = false @@ -71,8 +69,14 @@ class ViewVideoFragment : ViewMediaFragment() { } @SuppressLint("ClickableViewAccessibility") - override fun setupMediaView(url: String, previewUrl: String?) { - descriptionView = mediaDescription + override fun setupMediaView( + url: String, + previewUrl: String?, + description: String?, + showingDescription: Boolean + ) { + mediaDescription.text = description + mediaDescription.visible(showingDescription) videoView.transitionName = url videoView.setVideoPath(url) @@ -178,14 +182,14 @@ class ViewVideoFragment : ViewMediaFragment() { val alpha = if (isDescriptionVisible) 1.0f else 0.0f if (isDescriptionVisible) { // If to be visible, need to make visible immediately and animate alpha - descriptionView.alpha = 0.0f - descriptionView.visible(isDescriptionVisible) + mediaDescription.alpha = 0.0f + mediaDescription.visible(isDescriptionVisible) } - descriptionView.animate().alpha(alpha) + mediaDescription.animate().alpha(alpha) .setListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { - descriptionView.visible(isDescriptionVisible) + mediaDescription.visible(isDescriptionVisible) animation.removeListener(this) } }) diff --git a/app/src/main/res/drawable/description_bg_expanded.xml b/app/src/main/res/drawable/description_bg_expanded.xml new file mode 100644 index 00000000..db2eebde --- /dev/null +++ b/app/src/main/res/drawable/description_bg_expanded.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_drag_indicator_horiz_24dp.xml b/app/src/main/res/drawable/ic_drag_indicator_horiz_24dp.xml new file mode 100644 index 00000000..eb611224 --- /dev/null +++ b/app/src/main/res/drawable/ic_drag_indicator_horiz_24dp.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_view_image.xml b/app/src/main/res/layout/fragment_view_image.xml index 1c83b199..93cf2def 100644 --- a/app/src/main/res/layout/fragment_view_image.xml +++ b/app/src/main/res/layout/fragment_view_image.xml @@ -24,18 +24,56 @@ app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> - + + + + + + + + + + + + + \ No newline at end of file