From 7448183ff422d5a832b8babacf6676d915ab04c1 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Fri, 13 Aug 2021 13:25:43 -0300 Subject: [PATCH] Update multi-forward work with tweaks from design. --- .../components/ContactFilterView.java | 11 ++++++++- ...dRoundedCornerBottomSheetDialogFragment.kt | 4 +++- .../conversation/ConversationItem.java | 10 ++++++-- .../mutiselect/MultiselectItemDecoration.kt | 23 +++++++++---------- .../forward/MultiselectForwardFragment.kt | 14 ++++++++++- .../layout/multiselect_forward_fragment.xml | 4 +++- ...ultiselect_forward_fragment_bottom_bar.xml | 1 + app/src/main/res/values/attrs.xml | 1 + 8 files changed, 50 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/ContactFilterView.java b/app/src/main/java/org/thoughtcrime/securesms/components/ContactFilterView.java index 92b22a9b6d..06701eab34 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/ContactFilterView.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/ContactFilterView.java @@ -15,6 +15,7 @@ import android.widget.ImageView; import android.widget.LinearLayout; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.core.widget.TextViewCompat; @@ -101,7 +102,6 @@ public final class ContactFilterView extends FrameLayout { expandTapArea(toggleContainer, dialpadToggle); applyAttributes(searchText, context, attrs, defStyleAttr); - searchText.requestFocus(); } private void applyAttributes(@NonNull EditText searchText, @@ -121,6 +121,11 @@ public final class ContactFilterView extends FrameLayout { if (!attributes.getBoolean(R.styleable.ContactFilterToolbar_showDialpad, true)) { dialpadToggle.setVisibility(GONE); } + + if (attributes.getBoolean(R.styleable.ContactFilterToolbar_cfv_autoFocus, true)) { + searchText.requestFocus(); + } + attributes.recycle(); } @@ -137,6 +142,10 @@ public final class ContactFilterView extends FrameLayout { this.listener = listener; } + public void setOnSearchInputFocusChangedListener(@Nullable OnFocusChangeListener listener) { + searchText.setOnFocusChangeListener(listener); + } + public void setHint(@StringRes int hint) { searchText.setHint(hint); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/FixedRoundedCornerBottomSheetDialogFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/FixedRoundedCornerBottomSheetDialogFragment.kt index 5c00b78cd4..b6ba345ee4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/FixedRoundedCornerBottomSheetDialogFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/FixedRoundedCornerBottomSheetDialogFragment.kt @@ -19,6 +19,8 @@ import org.thoughtcrime.securesms.util.ViewUtil */ abstract class FixedRoundedCornerBottomSheetDialogFragment : BottomSheetDialogFragment() { + protected open val peekHeightPercentage: Float = 0.5f + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setStyle(STYLE_NORMAL, R.style.Widget_Signal_FixedRoundedCorners) @@ -27,7 +29,7 @@ abstract class FixedRoundedCornerBottomSheetDialogFragment : BottomSheetDialogFr override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog - dialog.behavior.peekHeight = (resources.displayMetrics.heightPixels * 0.50).toInt() + dialog.behavior.peekHeight = (resources.displayMetrics.heightPixels * peekHeightPercentage).toInt() val shapeAppearanceModel = ShapeAppearanceModel.builder() .setTopLeftCorner(CornerFamily.ROUNDED, ViewUtil.dpToPx(requireContext(), 18).toFloat()) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java index 4d6d6734c1..f71a8e1df4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java @@ -541,8 +541,11 @@ public final class ConversationItem extends RelativeLayout implements BindableCo } else if (multiselectPart instanceof MultiselectPart.Text && hasThumbnail(messageRecord)) { Projection projection = Projection.relativeToViewRoot(mediaThumbnailStub.require(), null); return (int) projection.getY() + projection.getHeight(); - } else { + } else if (hasNoBubble(messageRecord)) { return getTop(); + } else { + Projection projection = Projection.relativeToViewRoot(bodyBubble, null); + return (int) projection.getY(); } } @@ -551,8 +554,11 @@ public final class ConversationItem extends RelativeLayout implements BindableCo if (multiselectPart instanceof MultiselectPart.Attachments && hasThumbnail(messageRecord)) { Projection projection = Projection.relativeToViewRoot(mediaThumbnailStub.require(), null); return (int) projection.getY() + projection.getHeight(); - } else { + } else if (hasNoBubble(messageRecord)) { return getBottom(); + } else { + Projection projection = Projection.relativeToViewRoot(bodyBubble, null); + return (int) projection.getY() + projection.getHeight(); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration.kt index 324d7d3671..8c654ea705 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/MultiselectItemDecoration.kt @@ -29,7 +29,6 @@ class MultiselectItemDecoration(context: Context, private val chatWallpaperProvi private val path = Path() private val rect = Rect() private val gutter = ViewUtil.dpToPx(48) - private val paddingBottom = ViewUtil.dpToPx(9) private val paddingStart = ViewUtil.dpToPx(17) private val circleRadius = ViewUtil.dpToPx(11) private val checkDrawable = requireNotNull(AppCompatResources.getDrawable(context, R.drawable.ic_check_circle_solid_24)).apply { @@ -37,7 +36,6 @@ class MultiselectItemDecoration(context: Context, private val chatWallpaperProvi } private val photoCircleRadius = ViewUtil.dpToPx(12) private val photoCirclePaddingStart = ViewUtil.dpToPx(16) - private val photoCirclePaddingBottom = ViewUtil.dpToPx(8) private val transparentBlack20 = ContextCompat.getColor(context, R.color.transparent_black_20) private val transparentWhite20 = ContextCompat.getColor(context, R.color.transparent_white_20) @@ -155,15 +153,16 @@ class MultiselectItemDecoration(context: Context, private val chatWallpaperProvi val parts: MultiselectCollection = child.conversationMessage.multiselectCollection parts.toSet().forEach { - val boundary = child.getBottomBoundaryOfMultiselectPart(it) + val topBoundary = child.getTopBoundaryOfMultiselectPart(it) + val bottomBoundary = child.getBottomBoundaryOfMultiselectPart(it) if (drawCircleBehindSelector) { - drawPhotoCircle(canvas, parent, boundary) + drawPhotoCircle(canvas, parent, topBoundary, bottomBoundary) } if (adapter.selectedItems.contains(it)) { - drawSelectedCircle(canvas, parent, boundary) + drawSelectedCircle(canvas, parent, topBoundary, bottomBoundary) } else { - drawUnselectedCircle(canvas, parent, boundary) + drawUnselectedCircle(canvas, parent, topBoundary, bottomBoundary) } } } @@ -173,14 +172,14 @@ class MultiselectItemDecoration(context: Context, private val chatWallpaperProvi * Draws an extra circle behind the selection circle. This is to make it easier to see and * is specifically for when a photo wallpaper is being used. */ - private fun drawPhotoCircle(canvas: Canvas, parent: RecyclerView, bottomBoundary: Int) { + private fun drawPhotoCircle(canvas: Canvas, parent: RecyclerView, topBoundary: Int, bottomBoundary: Int) { val centerX: Float = if (ViewUtil.isLtr(parent)) { photoCirclePaddingStart + photoCircleRadius } else { parent.right - photoCircleRadius - photoCirclePaddingStart }.toFloat() - val centerY: Float = bottomBoundary - photoCircleRadius - photoCirclePaddingBottom.toFloat() + val centerY: Float = topBoundary + (bottomBoundary - topBoundary).toFloat() / 2 canvas.drawCircle(centerX, centerY, photoCircleRadius.toFloat(), photoCirclePaint) } @@ -188,14 +187,14 @@ class MultiselectItemDecoration(context: Context, private val chatWallpaperProvi /** * Draws the checkmark for selected content */ - private fun drawSelectedCircle(canvas: Canvas, parent: RecyclerView, bottomBoundary: Int) { + private fun drawSelectedCircle(canvas: Canvas, parent: RecyclerView, topBoundary: Int, bottomBoundary: Int) { val topX: Float = if (ViewUtil.isLtr(parent)) { paddingStart } else { parent.right - paddingStart - circleRadius * 2 }.toFloat() - val topY: Float = bottomBoundary - circleRadius * 2 - paddingBottom.toFloat() + val topY: Float = topBoundary + (bottomBoundary - topBoundary).toFloat() / 2 - circleRadius canvas.save() canvas.translate(topX, topY) @@ -206,14 +205,14 @@ class MultiselectItemDecoration(context: Context, private val chatWallpaperProvi /** * Draws the empty circle for unselected content */ - private fun drawUnselectedCircle(c: Canvas, parent: RecyclerView, bottomBoundary: Int) { + private fun drawUnselectedCircle(c: Canvas, parent: RecyclerView, topBoundary: Int, bottomBoundary: Int) { val centerX: Float = if (ViewUtil.isLtr(parent)) { paddingStart + circleRadius } else { parent.right - circleRadius - paddingStart }.toFloat() - val centerY: Float = bottomBoundary - circleRadius - paddingBottom.toFloat() + val centerY: Float = topBoundary + (bottomBoundary - topBoundary).toFloat() / 2 c.drawCircle(centerX, centerY, circleRadius.toFloat(), unselectedPaint) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardFragment.kt index e7c79a599f..7aaa9d9ec5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardFragment.kt @@ -12,6 +12,8 @@ import androidx.core.view.isVisible import androidx.fragment.app.FragmentManager import androidx.fragment.app.viewModels import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.bottomsheet.BottomSheetBehavior +import com.google.android.material.bottomsheet.BottomSheetDialog import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.ContactSelectionListFragment import org.thoughtcrime.securesms.R @@ -35,9 +37,12 @@ private val TAG = Log.tag(MultiselectForwardFragment::class.java) class MultiselectForwardFragment : FixedRoundedCornerBottomSheetDialogFragment(), ContactSelectionListFragment.OnContactSelectedListener, ContactSelectionListFragment.OnSelectionLimitReachedListener { + override val peekHeightPercentage: Float = 0.67f + private val viewModel: MultiselectForwardViewModel by viewModels(factoryProducer = this::createViewModelFactory) private lateinit var selectionFragment: ContactSelectionListFragment + private lateinit var contactFilterView: ContactFilterView private fun createViewModelFactory(): MultiselectForwardViewModel.Factory { return MultiselectForwardViewModel.Factory(getMultiShareArgs(), MultiselectForwardRepository(requireContext())) @@ -70,7 +75,13 @@ class MultiselectForwardFragment : FixedRoundedCornerBottomSheetDialogFragment() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { selectionFragment = childFragmentManager.findFragmentById(R.id.contact_selection_list_fragment) as ContactSelectionListFragment - val contactFilterView: ContactFilterView = view.findViewById(R.id.contact_filter_edit_text) + contactFilterView = view.findViewById(R.id.contact_filter_edit_text) + + contactFilterView.setOnSearchInputFocusChangedListener { _, hasFocus -> + if (hasFocus) { + (requireDialog() as BottomSheetDialog).behavior.state = BottomSheetBehavior.STATE_EXPANDED + } + } contactFilterView.setOnFilterChangedListener { if (it.isNullOrEmpty()) { @@ -145,6 +156,7 @@ class MultiselectForwardFragment : FixedRoundedCornerBottomSheetDialogFragment() if (recipientId.isPresent) { viewModel.addSelectedContact(recipientId, null) callback.accept(true) + contactFilterView.clear() } else { Log.w(TAG, "Rejecting non-present recipient. Can't forward to an unknown contact.") callback.accept(false) diff --git a/app/src/main/res/layout/multiselect_forward_fragment.xml b/app/src/main/res/layout/multiselect_forward_fragment.xml index 658eaa513c..bd16db7218 100644 --- a/app/src/main/res/layout/multiselect_forward_fragment.xml +++ b/app/src/main/res/layout/multiselect_forward_fragment.xml @@ -2,6 +2,7 @@ + android:minHeight="44dp" + app:cfv_autoFocus="false" /> +