Material 3 media gallery refresh.

This commit is contained in:
Alex Hart
2022-07-18 10:08:07 -03:00
committed by Cody Henthorne
parent b78633f9a7
commit 359a39ddaf
56 changed files with 423 additions and 303 deletions

View File

@@ -13,7 +13,6 @@ import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
@@ -156,8 +155,6 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment {
super.onResume();
camera.bindToLifecycle(getViewLifecycleOwner(), this::handleCameraInitializationError);
requireActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
requireActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
requireActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
}

View File

@@ -42,6 +42,7 @@ import org.thoughtcrime.securesms.mediasend.v2.text.send.TextStoryPostSendReposi
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.safety.SafetyNumberBottomSheet
import org.thoughtcrime.securesms.stories.Stories
import org.thoughtcrime.securesms.util.FullscreenHelper
import org.thoughtcrime.securesms.util.navigation.safeNavigate
import org.thoughtcrime.securesms.util.visible
@@ -155,6 +156,8 @@ class MediaSelectionActivity :
}
onBackPressedDispatcher.addCallback(OnBackPressed())
FullscreenHelper.setLowProfileMode(window)
}
private fun animateTextStyling(selectedSwitch: TextView, unselectedSwitch: TextView, duration: Long) {

View File

@@ -132,7 +132,7 @@ class MediaGalleryFragment : Fragment(R.layout.v2_media_gallery_fragment) {
}
viewModel.state.observe(viewLifecycleOwner) { state ->
toolbar.title = state.bucketTitle
toolbar.title = state.bucketTitle ?: requireContext().getString(R.string.AttachmentKeyboard_gallery)
}
val galleryItemsWithSelection = LiveDataUtil.combineLatest(
@@ -141,7 +141,7 @@ class MediaGalleryFragment : Fragment(R.layout.v2_media_gallery_fragment) {
) { galleryItems, selectedMedia ->
galleryItems.map {
if (it is MediaGallerySelectableItem.FileModel) {
it.copy(isSelected = selectedMedia.contains(it.media))
it.copy(isSelected = selectedMedia.contains(it.media), selectionOneBasedIndex = selectedMedia.indexOf(it.media) + 1)
} else {
it
}

View File

@@ -1,14 +1,17 @@
package org.thoughtcrime.securesms.mediasend.v2.gallery
import android.animation.ValueAnimator
import android.graphics.drawable.Drawable
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.core.view.setPadding
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout
import com.google.android.material.imageview.ShapeableImageView
import org.signal.core.util.DimensionUnit
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.mediasend.Media
@@ -26,6 +29,8 @@ typealias OnMediaFolderClicked = (MediaFolder) -> Unit
typealias OnMediaClicked = (Media, Boolean) -> Unit
private val FILE_VIEW_HOLDER_TAG = Log.tag(MediaGallerySelectableItem.FileViewHolder::class.java)
private const val PAYLOAD_CHECK_CHANGED = 0
private const val PAYLOAD_INDEX_CHANGED = 1
object MediaGallerySelectableItem {
@@ -51,14 +56,10 @@ object MediaGallerySelectableItem {
}
abstract class BaseViewHolder<T : MappingModel<T>>(itemView: View) : MappingViewHolder<T>(itemView) {
protected val imageView: ImageView = itemView.findViewById(R.id.media_gallery_image)
protected val imageView: ShapeableImageView = itemView.findViewById(R.id.media_gallery_image)
protected val playOverlay: ImageView = itemView.findViewById(R.id.media_gallery_play_overlay)
protected val checkView: ImageView? = itemView.findViewById(R.id.media_gallery_check)
protected val checkView: TextView? = itemView.findViewById(R.id.media_gallery_check)
protected val title: TextView? = itemView.findViewById(R.id.media_gallery_title)
init {
(itemView as AspectRatioFrameLayout).setAspectRatio(1f)
}
}
class FolderViewHolder(itemView: View, private val onMediaFolderClicked: OnMediaFolderClicked) : BaseViewHolder<FolderModel>(itemView) {
@@ -74,27 +75,81 @@ object MediaGallerySelectableItem {
}
}
data class FileModel(val media: Media, val isSelected: Boolean) : MappingModel<FileModel> {
data class FileModel(val media: Media, val isSelected: Boolean, val selectionOneBasedIndex: Int) : MappingModel<FileModel> {
override fun areItemsTheSame(newItem: FileModel): Boolean {
return newItem.media == media
}
override fun areContentsTheSame(newItem: FileModel): Boolean {
return newItem.media == media && isSelected == newItem.isSelected
return newItem.media == media && isSelected == newItem.isSelected && selectionOneBasedIndex == newItem.selectionOneBasedIndex
}
override fun getChangePayload(newItem: FileModel): Any? {
return when {
newItem.media != media -> null
newItem.isSelected != isSelected -> PAYLOAD_CHECK_CHANGED
newItem.selectionOneBasedIndex != selectionOneBasedIndex -> PAYLOAD_INDEX_CHANGED
else -> null
}
}
}
class FileViewHolder(itemView: View, private val onMediaClicked: OnMediaClicked) : BaseViewHolder<FileModel>(itemView) {
private val selectedPadding = DimensionUnit.DP.toPixels(12f)
private val selectedRadius = DimensionUnit.DP.toPixels(12f)
private var animator: ValueAnimator? = null
override fun bind(model: FileModel) {
checkView?.visible = model.isSelected
checkView?.text = "${model.selectionOneBasedIndex}"
itemView.setOnClickListener { onMediaClicked(model.media, model.isSelected) }
playOverlay.visible = MediaUtil.isVideo(model.media.mimeType) && !model.media.isVideoGif
title?.visible = false
if (PAYLOAD_INDEX_CHANGED in payload) {
return
}
if (PAYLOAD_CHECK_CHANGED in payload) {
animateCheckState(model.isSelected)
return
} else {
animator?.cancel()
updateImageView(if (model.isSelected) 1f else 0f)
}
GlideApp.with(imageView)
.load(DecryptableStreamUriLoader.DecryptableUri(model.media.uri))
.addListener(ErrorLoggingRequestListener(FILE_VIEW_HOLDER_TAG))
.into(imageView)
}
checkView?.isSelected = model.isSelected
playOverlay.visible = MediaUtil.isVideo(model.media.mimeType) && !model.media.isVideoGif
itemView.setOnClickListener { onMediaClicked(model.media, model.isSelected) }
title?.visible = false
private fun animateCheckState(isSelected: Boolean) {
animator?.cancel()
val start = if (isSelected) 0f else 1f
val end = if (isSelected) 1f else 0f
animator = ValueAnimator.ofFloat(start, end).apply {
addUpdateListener { animator ->
val fraction = animator.animatedValue as Float
updateImageView(fraction)
}
start()
}
}
override fun onDetachedFromWindow() {
animator?.cancel()
}
private fun updateImageView(fraction: Float) {
val padding = selectedPadding * fraction
imageView.setPadding(padding.toInt())
val corners = selectedRadius * fraction
imageView.shapeAppearanceModel = imageView.shapeAppearanceModel.withCornerSize(corners)
}
}

View File

@@ -47,7 +47,7 @@ class MediaGalleryViewModel(bucketId: String?, bucketTitle: String?, private val
state.copy(
bucketId = bucketId, bucketTitle = bucketTitle,
items = media.map {
MediaGallerySelectableItem.FileModel(it, false)
MediaGallerySelectableItem.FileModel(it, false, 0)
}
)
}

View File

@@ -283,8 +283,8 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment) {
private fun presentImageQualityToggle(quality: SentMediaQuality) {
qualityButton.setImageResource(
when (quality) {
SentMediaQuality.STANDARD -> R.drawable.ic_sq_36
SentMediaQuality.HIGH -> R.drawable.ic_hq_36
SentMediaQuality.STANDARD -> R.drawable.ic_sq_24
SentMediaQuality.HIGH -> R.drawable.ic_hq_24
}
)
}

View File

@@ -34,7 +34,6 @@ object MediaReviewSelectedItem {
private val imageView: ImageView = itemView.findViewById(R.id.media_review_selected_image)
private val playOverlay: ImageView = itemView.findViewById(R.id.media_review_play_overlay)
private val selectedOverlay: ImageView = itemView.findViewById(R.id.media_review_selected_overlay)
override fun bind(model: Model) {
Glide.with(imageView)
@@ -43,7 +42,7 @@ object MediaReviewSelectedItem {
.into(imageView)
playOverlay.visible = MediaUtil.isNonGifVideo(model.media) && !model.isSelected
selectedOverlay.isSelected = model.isSelected
imageView.isSelected = model.isSelected
itemView.contentDescription = if (model.isSelected) {
context.getString(R.string.MediaReviewSelectedItem__tap_to_remove)

View File

@@ -17,10 +17,12 @@ import android.view.ViewGroup;
import android.widget.Toast;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import com.bumptech.glide.load.DataSource;
@@ -249,16 +251,17 @@ public final class ImageEditorFragment extends Fragment implements ImageEditorHu
restoredModel = null;
}
@ColorInt int blackoutColor = ContextCompat.getColor(requireContext(), R.color.signal_colorBackground);
if (editorModel == null) {
switch (mode) {
case AVATAR_EDIT:
editorModel = EditorModel.createForAvatarEdit();
editorModel = EditorModel.createForAvatarEdit(blackoutColor);
break;
case AVATAR_CAPTURE:
editorModel = EditorModel.createForAvatarCapture();
editorModel = EditorModel.createForAvatarCapture(blackoutColor);
break;
default:
editorModel = EditorModel.create();
editorModel = EditorModel.create(blackoutColor);
break;
}

View File

@@ -169,4 +169,8 @@ public final class FullscreenHelper {
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
public static void setLowProfileMode(@NonNull Window window) {
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
}
}

View File

@@ -179,7 +179,7 @@ public final class WallpaperCropActivity extends BaseActivity {
int width = displayMetrics.widthPixels;
float ratio = width / (float) height;
EditorModel editorModel = EditorModel.createForWallpaperEditing(ratio);
EditorModel editorModel = EditorModel.createForWallpaperEditing(ratio, ContextCompat.getColor(this, R.color.signal_colorBackground));
EditorElement image = new EditorElement(new UriGlideRenderer(imageUri, true, width, height, UriGlideRenderer.WEAK_BLUR));
image.getFlags()