Tweak emoji suggestions UX.

This commit is contained in:
Cody Henthorne 2022-08-02 23:26:58 -04:00 committed by Greyson Parrelli
parent 440d041402
commit d7d923c820
7 changed files with 23 additions and 16 deletions

View file

@ -52,7 +52,7 @@ import static org.thoughtcrime.securesms.database.MentionUtil.MENTION_STARTER;
public class ComposeText extends EmojiEditText { public class ComposeText extends EmojiEditText {
private static final char EMOJI_STARTER = ':'; private static final char EMOJI_STARTER = ':';
private static final long EMOJI_KEYWORD_DELAY = TimeUnit.SECONDS.toMillis(1); private static final long EMOJI_KEYWORD_DELAY = 1500;
private CharSequence hint; private CharSequence hint;
private SpannableString subHint; private SpannableString subHint;
@ -322,11 +322,9 @@ public class ComposeText extends EmojiEditText {
} }
private void doAfterCursorChange(@NonNull Editable text) { private void doAfterCursorChange(@NonNull Editable text) {
removeCallbacks(keywordSearchRunnable);
if (enoughToFilter(text, false)) { if (enoughToFilter(text, false)) {
performFiltering(text, false); performFiltering(text, false);
} else { } else {
postDelayed(keywordSearchRunnable, EMOJI_KEYWORD_DELAY);
clearInlineQuery(); clearInlineQuery();
} }
} }

View file

@ -2358,6 +2358,7 @@ public class ConversationParentFragment extends Fragment
composeText, composeText,
getViewLifecycleOwner() getViewLifecycleOwner()
); );
inlineQueryResultsController.onOrientationChange(getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE);
recipient.observe(getViewLifecycleOwner(), r -> { recipient.observe(getViewLifecycleOwner(), r -> {
if (r.isPushV2Group() && !mentionsSuggestions.resolved()) { if (r.isPushV2Group() && !mentionsSuggestions.resolved()) {

View file

@ -10,7 +10,7 @@ sealed class InlineQueryReplacement(@get:JvmName("isKeywordSearch") val keywordS
class Emoji(private val emoji: String, keywordSearch: Boolean) : InlineQueryReplacement(keywordSearch) { class Emoji(private val emoji: String, keywordSearch: Boolean) : InlineQueryReplacement(keywordSearch) {
override fun toCharSequence(context: Context): CharSequence { override fun toCharSequence(context: Context): CharSequence {
return "$emoji " return emoji
} }
} }
} }

View file

@ -10,7 +10,6 @@ import io.reactivex.rxjava3.kotlin.subscribeBy
import org.signal.core.util.DimensionUnit import org.signal.core.util.DimensionUnit
import org.thoughtcrime.securesms.components.ComposeText import org.thoughtcrime.securesms.components.ComposeText
import org.thoughtcrime.securesms.util.LifecycleDisposable import org.thoughtcrime.securesms.util.LifecycleDisposable
import org.thoughtcrime.securesms.util.VibrateUtil
import org.thoughtcrime.securesms.util.adapter.mapping.AnyMappingModel import org.thoughtcrime.securesms.util.adapter.mapping.AnyMappingModel
import org.thoughtcrime.securesms.util.doOnEachLayout import org.thoughtcrime.securesms.util.doOnEachLayout
@ -30,6 +29,7 @@ class InlineQueryResultsController(
private var popup: InlineQueryResultsPopup? = null private var popup: InlineQueryResultsPopup? = null
private var previousResults: List<AnyMappingModel>? = null private var previousResults: List<AnyMappingModel>? = null
private var canShow: Boolean = false private var canShow: Boolean = false
private var isLandscape: Boolean = false
init { init {
lifecycleDisposable.bindTo(lifecycleOwner) lifecycleDisposable.bindTo(lifecycleOwner)
@ -61,6 +61,8 @@ class InlineQueryResultsController(
} }
fun onOrientationChange(isLandscape: Boolean) { fun onOrientationChange(isLandscape: Boolean) {
this.isLandscape = isLandscape
if (isLandscape) { if (isLandscape) {
dismiss() dismiss()
} else { } else {
@ -70,7 +72,7 @@ class InlineQueryResultsController(
private fun updateList(results: List<AnyMappingModel>) { private fun updateList(results: List<AnyMappingModel>) {
previousResults = results previousResults = results
if (results.isEmpty() || !canShow) { if (results.isEmpty() || !canShow || isLandscape) {
dismiss() dismiss()
} else if (popup != null) { } else if (popup != null) {
popup?.setResults(results) popup?.setResults(results)
@ -82,7 +84,6 @@ class InlineQueryResultsController(
baseOffsetX = DimensionUnit.DP.toPixels(16f).toInt(), baseOffsetX = DimensionUnit.DP.toPixels(16f).toInt(),
callback = this callback = this
).show() ).show()
VibrateUtil.vibrateTick(context)
} }
} }

View file

@ -6,8 +6,8 @@ import android.os.Build
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewOutlineProvider
import android.widget.PopupWindow import android.widget.PopupWindow
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.util.ViewUtil import org.thoughtcrime.securesms.util.ViewUtil
@ -34,7 +34,11 @@ class InlineQueryResultsPopup(
private val adapter: MappingAdapter private val adapter: MappingAdapter
init { init {
setBackgroundDrawable(ContextCompat.getDrawable(context, R.drawable.signal_context_menu_background)) if (Build.VERSION.SDK_INT >= 21) {
contentView.outlineProvider = ViewOutlineProvider.BACKGROUND
contentView.clipToOutline = true
}
inputMethodMode = INPUT_METHOD_NOT_NEEDED inputMethodMode = INPUT_METHOD_NOT_NEEDED
setOnDismissListener { setOnDismissListener {

View file

@ -18,18 +18,20 @@ private const val MINIMUM_QUERY_THRESHOLD = 1
private const val MINIMUM_INLINE_QUERY_THRESHOLD = 2 private const val MINIMUM_INLINE_QUERY_THRESHOLD = 2
private const val EMOJI_SEARCH_LIMIT = 20 private const val EMOJI_SEARCH_LIMIT = 20
private val NOT_PUNCTUATION = "[A-Za-z0-9 ]".toRegex()
class EmojiSearchRepository(private val context: Context) { class EmojiSearchRepository(private val context: Context) {
private val emojiSearchDatabase: EmojiSearchDatabase = SignalDatabase.emojiSearch private val emojiSearchDatabase: EmojiSearchDatabase = SignalDatabase.emojiSearch
fun submitQuery(query: String, limit: Int = EMOJI_SEARCH_LIMIT): Single<List<String>> { fun submitQuery(query: String, limit: Int = EMOJI_SEARCH_LIMIT): Single<List<String>> {
if (query.length < MINIMUM_INLINE_QUERY_THRESHOLD) { val result = if (query.length >= MINIMUM_INLINE_QUERY_THRESHOLD && NOT_PUNCTUATION.matches(query.substring(query.lastIndex))) {
return Single.just(emptyList()) Single.fromCallable<List<String>> { emojiSearchDatabase.query(query, limit) }
} else {
Single.just(emptyList())
} }
return Single.fromCallable<List<String>> { return result.subscribeOn(Schedulers.io())
emojiSearchDatabase.query(query, limit)
}.subscribeOn(Schedulers.io())
} }
fun submitQuery(query: String, includeRecents: Boolean, limit: Int = EMOJI_SEARCH_LIMIT, consumer: Consumer<EmojiPageModel>) { fun submitQuery(query: String, includeRecents: Boolean, limit: Int = EMOJI_SEARCH_LIMIT, consumer: Consumer<EmojiPageModel>) {

View file

@ -2,16 +2,17 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
android:background="@drawable/signal_context_menu_background">
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/inline_query_results_list" android:id="@+id/inline_query_results_list"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:clipToPadding="false"
android:orientation="horizontal" android:orientation="horizontal"
android:paddingHorizontal="8dp" android:paddingHorizontal="8dp"
android:clipToPadding="false"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" /> app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
</FrameLayout> </FrameLayout>