diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiItemDecoration.kt b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiItemDecoration.kt index 6908752659..5ef015512a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiItemDecoration.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiItemDecoration.kt @@ -10,9 +10,10 @@ import org.thoughtcrime.securesms.components.emoji.EmojiPageViewGridAdapter.Emoj import org.thoughtcrime.securesms.util.InsetItemDecoration import org.thoughtcrime.securesms.util.ViewUtil -private val EDGE_LENGTH: Int = ViewUtil.dpToPx(7) -private val HORIZONTAL_INSET: Int = ViewUtil.dpToPx(8) -private val VERTICAL_INSET: Int = ViewUtil.dpToPx(8) +private val EDGE_LENGTH: Int = ViewUtil.dpToPx(6) +private val HORIZONTAL_INSET: Int = ViewUtil.dpToPx(6) +private val EMOJI_VERTICAL_INSET: Int = ViewUtil.dpToPx(5) +private val HEADER_VERTICAL_INSET: Int = ViewUtil.dpToPx(8) /** * Use super class to add insets to the emojis and use the [onDrawOver] to draw the variation @@ -41,11 +42,12 @@ class EmojiItemDecoration(private val allowVariations: Boolean, private val vari private class SetInset : InsetItemDecoration.SetInset() { override fun setInset(outRect: Rect, view: View, parent: RecyclerView) { - val isFirstHeader = view.javaClass == AppCompatTextView::class.java && getPosition(view, parent) == 0 + val isHeader = view.javaClass == AppCompatTextView::class.java + outRect.left = HORIZONTAL_INSET outRect.right = HORIZONTAL_INSET - outRect.top = if (isFirstHeader) 0 else VERTICAL_INSET - outRect.bottom = VERTICAL_INSET + outRect.top = if (isHeader) HEADER_VERTICAL_INSET else EMOJI_VERTICAL_INSET + outRect.bottom = if (isHeader) 0 else EMOJI_VERTICAL_INSET } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiPageView.java b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiPageView.java index 4037af4e3d..c7b664a203 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiPageView.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiPageView.java @@ -19,11 +19,9 @@ import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.components.emoji.EmojiPageViewGridAdapter.EmojiHeader; import org.thoughtcrime.securesms.components.emoji.EmojiPageViewGridAdapter.EmojiNoResultsModel; import org.thoughtcrime.securesms.components.emoji.EmojiPageViewGridAdapter.VariationSelectorListener; -import org.thoughtcrime.securesms.emoji.EmojiCategory; import org.thoughtcrime.securesms.util.ContextUtil; import org.thoughtcrime.securesms.util.DrawableUtil; import org.thoughtcrime.securesms.util.MappingModel; -import org.thoughtcrime.securesms.util.MappingModelList; import org.thoughtcrime.securesms.util.ViewUtil; import java.util.List; @@ -31,7 +29,6 @@ import java.util.Optional; public class EmojiPageView extends RecyclerView implements VariationSelectorListener { - private EmojiPageModel model; private AdapterFactory adapterFactory; private LinearLayoutManager layoutManager; private RecyclerView.OnItemTouchListener scrollDisabler; @@ -125,45 +122,15 @@ public class EmojiPageView extends RecyclerView implements VariationSelectorList } public void onSelected() { - if (getAdapter() != null && (model == null || model.isDynamic())) { + if (getAdapter() != null) { getAdapter().notifyDataSetChanged(); } } - public void setList(@NonNull List> list) { - this.model = null; + public void setList(@NonNull List> list, @Nullable Runnable commitCallback) { EmojiPageViewGridAdapter adapter = adapterFactory.create(); setAdapter(adapter); - adapter.submitList(list); - } - - public void setModel(@Nullable EmojiPageModel model) { - this.model = model; - - EmojiPageViewGridAdapter adapter = adapterFactory.create(); - setAdapter(adapter); - adapter.submitList(getMappingModelList()); - } - - public void bindSearchableAdapter(@Nullable EmojiPageModel model) { - this.model = model; - - EmojiPageViewGridAdapter adapter = adapterFactory.create(); - setAdapter(adapter); - adapter.submitList(getMappingModelList()); - } - - private @NonNull MappingModelList getMappingModelList() { - if (model != null) { - boolean emoticonPage = EmojiCategory.EMOTICONS.getKey().equals(model.getKey()); - return model.getDisplayEmoji() - .stream() - .map(e -> emoticonPage ? new EmojiPageViewGridAdapter.EmojiTextModel(model.getKey(), e) - : new EmojiPageViewGridAdapter.EmojiModel(model.getKey(), e)) - .collect(MappingModelList.collect()); - } - - return new MappingModelList(); + adapter.submitList(list, commitCallback); } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyboard/emoji/EmojiKeyboardPageFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/keyboard/emoji/EmojiKeyboardPageFragment.kt index cec0782e79..6611b9a521 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyboard/emoji/EmojiKeyboardPageFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/keyboard/emoji/EmojiKeyboardPageFragment.kt @@ -85,7 +85,7 @@ class EmojiKeyboardPageFragment : Fragment(R.layout.keyboard_pager_emoji_page_fr } viewModel.pages.observe(viewLifecycleOwner) { pages -> - emojiPageView.setList(pages) + emojiPageView.setList(pages) { (emojiPageView.layoutManager as? LinearLayoutManager)?.scrollToPositionWithOffset(1, 0) } } viewModel.selectedKey.observe(viewLifecycleOwner) { updateCategoryTab(it) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyboard/emoji/search/EmojiSearchFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/keyboard/emoji/search/EmojiSearchFragment.kt index 2f4ddae8ea..813e59b150 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyboard/emoji/search/EmojiSearchFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/keyboard/emoji/search/EmojiSearchFragment.kt @@ -56,7 +56,7 @@ class EmojiSearchFragment : Fragment(R.layout.emoji_search_fragment), EmojiPageV searchBar.callbacks = SearchCallbacks() viewModel.emojiList.observe(viewLifecycleOwner) { results -> - emojiPageView.setList(results.emojiList) + emojiPageView.setList(results.emojiList, null) if (results.emojiList.isNotEmpty() || results.isRecents) { emojiPageView.visibility = View.VISIBLE diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyboard/sticker/StickerInsetSetter.kt b/app/src/main/java/org/thoughtcrime/securesms/keyboard/sticker/StickerInsetSetter.kt new file mode 100644 index 0000000000..06f839c228 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/keyboard/sticker/StickerInsetSetter.kt @@ -0,0 +1,25 @@ +package org.thoughtcrime.securesms.keyboard.sticker + +import android.graphics.Rect +import android.view.View +import androidx.appcompat.widget.AppCompatTextView +import androidx.recyclerview.widget.RecyclerView +import org.thoughtcrime.securesms.util.InsetItemDecoration +import org.thoughtcrime.securesms.util.ViewUtil + +private val horizontalInset: Int = ViewUtil.dpToPx(8) +private val verticalInset: Int = ViewUtil.dpToPx(8) + +/** + * Set insets for sticker items in a [RecyclerView]. For use in [InsetItemDecoration]. + */ +class StickerInsetSetter : InsetItemDecoration.SetInset() { + override fun setInset(outRect: Rect, view: View, parent: RecyclerView) { + val isHeader = view.javaClass == AppCompatTextView::class.java + + outRect.left = horizontalInset + outRect.right = horizontalInset + outRect.top = verticalInset + outRect.bottom = if (isHeader) 0 else verticalInset + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyboard/sticker/StickerKeyboardPageFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/keyboard/sticker/StickerKeyboardPageFragment.kt index 1230da2a53..cc1e0c800c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyboard/sticker/StickerKeyboardPageFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/keyboard/sticker/StickerKeyboardPageFragment.kt @@ -21,11 +21,14 @@ import org.thoughtcrime.securesms.stickers.StickerEventListener import org.thoughtcrime.securesms.stickers.StickerRolloverTouchListener import org.thoughtcrime.securesms.stickers.StickerRolloverTouchListener.RolloverStickerRetriever import org.thoughtcrime.securesms.util.DeviceProperties +import org.thoughtcrime.securesms.util.InsetItemDecoration import org.thoughtcrime.securesms.util.MappingModel +import org.thoughtcrime.securesms.util.MappingModelList import org.thoughtcrime.securesms.util.Throttler import org.whispersystems.libsignal.util.Pair import java.util.Optional import kotlin.math.abs +import kotlin.math.max class StickerKeyboardPageFragment : LoggingFragment(R.layout.keyboard_pager_sticker_page_fragment), @@ -48,6 +51,7 @@ class StickerKeyboardPageFragment : private val packIdSelectionOnScroll: UpdatePackSelectionOnScroll = UpdatePackSelectionOnScroll() private val observerThrottler: Throttler = Throttler(500) private val stickerThrottler: Throttler = Throttler(100) + private var firstLoad: Boolean = true override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -72,6 +76,7 @@ class StickerKeyboardPageFragment : stickerList.adapter = stickerListAdapter stickerList.addOnItemTouchListener(listTouchListener) stickerList.addOnScrollListener(packIdSelectionOnScroll) + stickerList.addItemDecoration(InsetItemDecoration(StickerInsetSetter())) stickerPacksRecycler = view.findViewById(R.id.sticker_packs_recycler) @@ -106,13 +111,22 @@ class StickerKeyboardPageFragment : viewModel = ViewModelProviders.of(requireActivity(), StickerKeyboardPageViewModel.Factory(requireContext())) .get(StickerKeyboardPageViewModel::class.java) - viewModel.stickers.observe(viewLifecycleOwner, stickerListAdapter::submitList) + viewModel.stickers.observe(viewLifecycleOwner, this::updateStickerList) viewModel.packs.observe(viewLifecycleOwner, stickerPacksAdapter::submitList) viewModel.getSelectedPack().observe(viewLifecycleOwner, this::updateCategoryTab) viewModel.refreshStickers() } + private fun updateStickerList(stickers: MappingModelList) { + if (firstLoad) { + stickerListAdapter.submitList(stickers) { layoutManager.scrollToPositionWithOffset(1, 0) } + firstLoad = false + } else { + stickerListAdapter.submitList(stickers) + } + } + private fun onTabSelected(stickerPack: KeyboardStickerPackListAdapter.StickerPack) { scrollTo(stickerPack.packRecord.packId) viewModel.selectPack(stickerPack.packRecord.packId) @@ -188,9 +202,8 @@ class StickerKeyboardPageFragment : } private fun calculateColumnCount(@Px screenWidth: Int): Int { - val modifier = resources.getDimensionPixelOffset(R.dimen.sticker_page_item_padding).toFloat() - val divisor = resources.getDimensionPixelOffset(R.dimen.sticker_page_item_divisor).toFloat() - return ((screenWidth - modifier) / divisor).toInt() + val divisor = resources.getDimensionPixelOffset(R.dimen.sticker_page_item_width).toFloat() + resources.getDimensionPixelOffset(R.dimen.sticker_page_item_padding).toFloat() + return max(1, (screenWidth / divisor).toInt()) } private inner class UpdatePackSelectionOnScroll : RecyclerView.OnScrollListener() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyboard/sticker/StickerSearchDialogFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/keyboard/sticker/StickerSearchDialogFragment.kt index b8d33d5980..04c3bfb651 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyboard/sticker/StickerSearchDialogFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/keyboard/sticker/StickerSearchDialogFragment.kt @@ -16,7 +16,9 @@ import org.thoughtcrime.securesms.keyboard.findListener import org.thoughtcrime.securesms.mms.GlideApp import org.thoughtcrime.securesms.stickers.StickerEventListener import org.thoughtcrime.securesms.util.DeviceProperties +import org.thoughtcrime.securesms.util.InsetItemDecoration import org.thoughtcrime.securesms.util.ViewUtil +import kotlin.math.max /** * Search dialog for finding stickers. @@ -50,6 +52,7 @@ class StickerSearchDialogFragment : DialogFragment(), KeyboardStickerListAdapter list.layoutManager = layoutManager list.adapter = adapter + list.addItemDecoration(InsetItemDecoration(StickerInsetSetter())) val viewModel: StickerSearchViewModel = ViewModelProviders.of(this, StickerSearchViewModel.Factory(requireContext())).get(StickerSearchViewModel::class.java) @@ -80,9 +83,8 @@ class StickerSearchDialogFragment : DialogFragment(), KeyboardStickerListAdapter } private fun calculateColumnCount(@Px screenWidth: Int): Int { - val modifier = resources.getDimensionPixelOffset(R.dimen.sticker_page_item_padding).toFloat() - val divisor = resources.getDimensionPixelOffset(R.dimen.sticker_page_item_divisor).toFloat() - return ((screenWidth - modifier) / divisor).toInt() + val divisor = resources.getDimensionPixelOffset(R.dimen.sticker_page_item_width).toFloat() + resources.getDimensionPixelOffset(R.dimen.sticker_page_item_padding).toFloat() + return max(1, (screenWidth / divisor).toInt()) } override fun onStickerClicked(sticker: KeyboardStickerListAdapter.Sticker) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/reactions/any/ReactWithAnyEmojiBottomSheetDialogFragment.java b/app/src/main/java/org/thoughtcrime/securesms/reactions/any/ReactWithAnyEmojiBottomSheetDialogFragment.java index ccc7f3fc9f..f012709925 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/reactions/any/ReactWithAnyEmojiBottomSheetDialogFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/reactions/any/ReactWithAnyEmojiBottomSheetDialogFragment.java @@ -219,7 +219,7 @@ public final class ReactWithAnyEmojiBottomSheetDialogFragment extends BottomShee emojiPageView.addOnScrollListener(new TopAndBottomShadowHelper(requireView().findViewById(R.id.react_with_any_emoji_top_shadow), tabBar.findViewById(R.id.react_with_any_emoji_bottom_shadow))); - viewModel.getEmojiList().observe(getViewLifecycleOwner(), pages -> emojiPageView.setList(pages)); + viewModel.getEmojiList().observe(getViewLifecycleOwner(), pages -> emojiPageView.setList(pages, null)); viewModel.getCategories().observe(getViewLifecycleOwner(), categoriesAdapter::submitList); viewModel.getSelectedKey().observe(getViewLifecycleOwner(), key -> categoriesRecycler.post(() -> { int index = categoriesAdapter.indexOfFirst(EmojiKeyboardPageCategoryMappingModel.class, m -> m.getKey().equals(key)); diff --git a/app/src/main/res/drawable/keyboard_pager_fragment_category_selected.xml b/app/src/main/res/drawable/keyboard_pager_fragment_category_selected.xml index 3c788fbc37..bee692d1b5 100644 --- a/app/src/main/res/drawable/keyboard_pager_fragment_category_selected.xml +++ b/app/src/main/res/drawable/keyboard_pager_fragment_category_selected.xml @@ -2,7 +2,7 @@ - + diff --git a/app/src/main/res/drawable/keyboard_pager_fragment_emoji_icon.xml b/app/src/main/res/drawable/keyboard_pager_fragment_emoji_icon.xml index f2a6adffce..0b8c4dd086 100644 --- a/app/src/main/res/drawable/keyboard_pager_fragment_emoji_icon.xml +++ b/app/src/main/res/drawable/keyboard_pager_fragment_emoji_icon.xml @@ -2,9 +2,9 @@ + android:left="4dp" + android:right="4dp" + android:top="4dp" /> \ No newline at end of file diff --git a/app/src/main/res/drawable/keyboard_pager_fragment_gif_icon.xml b/app/src/main/res/drawable/keyboard_pager_fragment_gif_icon.xml index 992a63f701..050af02d47 100644 --- a/app/src/main/res/drawable/keyboard_pager_fragment_gif_icon.xml +++ b/app/src/main/res/drawable/keyboard_pager_fragment_gif_icon.xml @@ -2,9 +2,9 @@ + android:left="4dp" + android:right="4dp" + android:top="4dp" /> \ No newline at end of file diff --git a/app/src/main/res/drawable/keyboard_pager_fragment_sticker_icon.xml b/app/src/main/res/drawable/keyboard_pager_fragment_sticker_icon.xml index 6b56c88055..a483499fd0 100644 --- a/app/src/main/res/drawable/keyboard_pager_fragment_sticker_icon.xml +++ b/app/src/main/res/drawable/keyboard_pager_fragment_sticker_icon.xml @@ -2,9 +2,9 @@ + android:left="4dp" + android:right="4dp" + android:top="4dp" /> \ No newline at end of file diff --git a/app/src/main/res/layout/emoji_display_item_grid.xml b/app/src/main/res/layout/emoji_display_item_grid.xml index 16d617f838..9ce06a28d5 100644 --- a/app/src/main/res/layout/emoji_display_item_grid.xml +++ b/app/src/main/res/layout/emoji_display_item_grid.xml @@ -8,8 +8,8 @@ diff --git a/app/src/main/res/layout/gif_keyboard_page_fragment.xml b/app/src/main/res/layout/gif_keyboard_page_fragment.xml index 959c7d2f7a..39abaee665 100644 --- a/app/src/main/res/layout/gif_keyboard_page_fragment.xml +++ b/app/src/main/res/layout/gif_keyboard_page_fragment.xml @@ -35,7 +35,7 @@ diff --git a/app/src/main/res/layout/keyboard_pager_category_icon.xml b/app/src/main/res/layout/keyboard_pager_category_icon.xml index e9183e073e..5bb892dff0 100644 --- a/app/src/main/res/layout/keyboard_pager_category_icon.xml +++ b/app/src/main/res/layout/keyboard_pager_category_icon.xml @@ -4,12 +4,12 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:background="?selectableItemBackgroundBorderless"> + android:background="?selectableItemBackground"> + app:expanded="false" + tools:expanded="true"> @@ -34,15 +35,15 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:clipToPadding="false" - android:paddingStart="8dp" - android:paddingEnd="8dp" - android:paddingBottom="?actionBarSize" + android:paddingStart="10dp" + android:paddingEnd="10dp" + android:paddingBottom="@dimen/keyboard_toolbar_height" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> @@ -63,7 +64,7 @@ diff --git a/app/src/main/res/layout/keyboard_pager_fragment.xml b/app/src/main/res/layout/keyboard_pager_fragment.xml index de91c904ae..d0dd4062fb 100644 --- a/app/src/main/res/layout/keyboard_pager_fragment.xml +++ b/app/src/main/res/layout/keyboard_pager_fragment.xml @@ -8,14 +8,12 @@ tools:layout_gravity="bottom" tools:maxHeight="339dp"> - - - diff --git a/app/src/main/res/layout/keyboard_pager_sticker_page_fragment.xml b/app/src/main/res/layout/keyboard_pager_sticker_page_fragment.xml index ee07e793ef..eb483ce469 100644 --- a/app/src/main/res/layout/keyboard_pager_sticker_page_fragment.xml +++ b/app/src/main/res/layout/keyboard_pager_sticker_page_fragment.xml @@ -21,7 +21,7 @@ android:layout_height="wrap_content" android:layout_gravity="center" android:paddingTop="8dp" - android:paddingBottom="8dp" + android:paddingBottom="4dp" app:click_only="true" app:layout_scrollFlags="scroll|snap" app:search_hint="@string/StickerSearchDialogFragment_search_stickers" @@ -34,15 +34,15 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:clipToPadding="false" - android:paddingStart="16dp" - android:paddingEnd="16dp" - android:paddingBottom="?actionBarSize" + android:paddingStart="8dp" + android:paddingEnd="8dp" + android:paddingBottom="@dimen/keyboard_toolbar_height" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> @@ -63,7 +63,7 @@ diff --git a/app/src/main/res/layout/sticker_grid_header.xml b/app/src/main/res/layout/sticker_grid_header.xml index 06f31fe50f..92668e4626 100644 --- a/app/src/main/res/layout/sticker_grid_header.xml +++ b/app/src/main/res/layout/sticker_grid_header.xml @@ -6,8 +6,8 @@ android:layout_height="wrap_content" android:ellipsize="end" android:gravity="center_vertical" - android:minHeight="48dp" + android:minHeight="36dp" android:singleLine="true" - android:textAppearance="@style/TextAppearance.Signal.Body1.Bold" - android:textColor="@color/signal_text_primary" + android:textAppearance="@style/TextAppearance.Signal.Body2.Bold" + android:textColor="@color/signal_text_hint" tools:text="@string/ReactWithAnyEmojiBottomSheetDialogFragment__activities" /> diff --git a/app/src/main/res/layout/sticker_keyboard_page_list_item.xml b/app/src/main/res/layout/sticker_keyboard_page_list_item.xml index 3299035e5d..0df4042e84 100644 --- a/app/src/main/res/layout/sticker_keyboard_page_list_item.xml +++ b/app/src/main/res/layout/sticker_keyboard_page_list_item.xml @@ -7,8 +7,8 @@ 110dp 170dp 56dp - 48dp + 46dp 16sp 12sp 200sp @@ -14,6 +14,7 @@ 2dp 64dp 50dp + 44dp 210dp 105dp @@ -87,8 +88,8 @@ 72dp 8dp - 8dp - 88dp + 16dp + 72dp 8dp 16dp