diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionBottomSheet.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionBottomSheet.kt index cc971e16ba..c90a0e5acc 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionBottomSheet.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionBottomSheet.kt @@ -37,7 +37,6 @@ fun CustomReactionBottomSheet( CustomReactionState.Target.None, is CustomReactionState.Target.Loading -> Unit is CustomReactionState.Target.Success -> { - fun onEmojiSelectedDismiss(emoji: Emoji) { sheetState.hide(coroutineScope) { state.eventSink(CustomReactionEvent.DismissCustomReactionSheet) @@ -49,7 +48,6 @@ fun CustomReactionBottomSheet( state.eventSink(CustomReactionEvent.DismissCustomReactionSheet) } - ModalBottomSheet( onDismissRequest = ::onDismiss, sheetState = sheetState, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionPresenter.kt index 7a9f5fe4ff..fe68092be0 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionPresenter.kt @@ -17,12 +17,15 @@ import dev.zacsweers.metro.Inject import io.element.android.features.messages.impl.timeline.model.TimelineItem import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.emoji.api.picker.EmojiPickerPresenter +import io.element.android.libraries.emoji.api.recentemojis.GetRecentEmojis import kotlinx.collections.immutable.toImmutableSet @Inject class CustomReactionPresenter( - private val emojiPickerPresenter: EmojiPickerPresenter, + emojiPickerPresenterFactory: EmojiPickerPresenter.Factory, + getRecentEmojis: GetRecentEmojis, ) : Presenter { + private val emojiPickerPresenter = emojiPickerPresenterFactory.create(getRecentEmojis) @Composable override fun present(): CustomReactionState { var internalTarget by remember { mutableStateOf(InternalTarget.None) } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionPresenterTest.kt index be765554de..8ba316ea4d 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionPresenterTest.kt @@ -11,6 +11,8 @@ package io.element.android.features.messages.impl.timeline.components.customreac import com.google.common.truth.Truth.assertThat import io.element.android.features.messages.impl.timeline.aTimelineItemEvent import io.element.android.features.messages.impl.timeline.aTimelineItemReactions +import io.element.android.libraries.emoji.api.picker.EmojiPickerPresenter +import io.element.android.libraries.emoji.api.recentemojis.EmptyGetRecentEmojis import io.element.android.libraries.emoji.impl.picker.anEmojiPickerState import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.tests.testutils.WarmUpRule @@ -24,7 +26,8 @@ class CustomReactionPresenterTest { val warmUpRule = WarmUpRule() private val presenter = CustomReactionPresenter( - emojiPickerPresenter = { anEmojiPickerState() }, + emojiPickerPresenterFactory = EmojiPickerPresenter.Factory { EmojiPickerPresenter { anEmojiPickerState() } }, + getRecentEmojis = EmptyGetRecentEmojis, ) @Test @@ -36,8 +39,6 @@ class CustomReactionPresenterTest { initialState.eventSink(CustomReactionEvent.ShowCustomReactionSheet(event)) - assertThat(awaitItem().target).isEqualTo(CustomReactionState.Target.Loading(event)) - val eventId = (awaitItem().target as? CustomReactionState.Target.Success)?.event?.eventId assertThat(eventId).isEqualTo(AN_EVENT_ID) @@ -57,8 +58,6 @@ class CustomReactionPresenterTest { val key = reactions.reactions.first().key initialState.eventSink(CustomReactionEvent.ShowCustomReactionSheet(event)) - assertThat(awaitItem().target).isEqualTo(CustomReactionState.Target.Loading(event)) - val stateWithSelectedEmojis = awaitItem() val eventId = (stateWithSelectedEmojis.target as? CustomReactionState.Target.Success)?.event?.eventId assertThat(eventId).isEqualTo(AN_EVENT_ID) diff --git a/libraries/emoji/api/build.gradle.kts b/libraries/emoji/api/build.gradle.kts index 749e13a4c7..48143d9512 100644 --- a/libraries/emoji/api/build.gradle.kts +++ b/libraries/emoji/api/build.gradle.kts @@ -18,5 +18,5 @@ dependencies { implementation(projects.libraries.matrix.api) implementation(libs.kotlinx.collections.immutable) - implementation(libs.matrix.emojibase.bindings) + api(libs.matrix.emojibase.bindings) } diff --git a/libraries/emoji/api/src/main/kotlin/io/element/android/libraries/emoji/api/picker/EmojiPickerPresenter.kt b/libraries/emoji/api/src/main/kotlin/io/element/android/libraries/emoji/api/picker/EmojiPickerPresenter.kt index 5e29ee01ab..a20b53a480 100644 --- a/libraries/emoji/api/src/main/kotlin/io/element/android/libraries/emoji/api/picker/EmojiPickerPresenter.kt +++ b/libraries/emoji/api/src/main/kotlin/io/element/android/libraries/emoji/api/picker/EmojiPickerPresenter.kt @@ -8,5 +8,10 @@ package io.element.android.libraries.emoji.api.picker import io.element.android.libraries.architecture.Presenter +import io.element.android.libraries.emoji.api.recentemojis.GetRecentEmojis -fun interface EmojiPickerPresenter : Presenter +fun interface EmojiPickerPresenter : Presenter { + fun interface Factory { + fun create(getRecentEmojis: GetRecentEmojis): EmojiPickerPresenter + } +} diff --git a/libraries/emoji/api/src/main/kotlin/io/element/android/libraries/emoji/api/recentemojis/GetRecentEmojis.kt b/libraries/emoji/api/src/main/kotlin/io/element/android/libraries/emoji/api/recentemojis/GetRecentEmojis.kt index 9a9983805e..cf6015d799 100644 --- a/libraries/emoji/api/src/main/kotlin/io/element/android/libraries/emoji/api/recentemojis/GetRecentEmojis.kt +++ b/libraries/emoji/api/src/main/kotlin/io/element/android/libraries/emoji/api/recentemojis/GetRecentEmojis.kt @@ -9,6 +9,7 @@ package io.element.android.libraries.emoji.api.recentemojis import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf /** * Returns the list of recently used emojis for reactions. @@ -16,3 +17,11 @@ import kotlinx.collections.immutable.ImmutableList fun interface GetRecentEmojis { suspend operator fun invoke(): Result> } + +/** + * A [GetRecentEmojis] that never returns any recent emojis. Handy for pickers that don't want + * a "Recent" tab (e.g. the user-status picker). + */ +object EmptyGetRecentEmojis : GetRecentEmojis { + override suspend fun invoke(): Result> = Result.success(persistentListOf()) +} diff --git a/libraries/emoji/impl/src/main/kotlin/io/element/android/libraries/emoji/impl/picker/DefaultEmojiPickerPresenter.kt b/libraries/emoji/impl/src/main/kotlin/io/element/android/libraries/emoji/impl/picker/DefaultEmojiPickerPresenter.kt index e7afe50c0f..6a0c4924b3 100644 --- a/libraries/emoji/impl/src/main/kotlin/io/element/android/libraries/emoji/impl/picker/DefaultEmojiPickerPresenter.kt +++ b/libraries/emoji/impl/src/main/kotlin/io/element/android/libraries/emoji/impl/picker/DefaultEmojiPickerPresenter.kt @@ -17,8 +17,10 @@ import androidx.compose.runtime.produceState import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.platform.LocalInspectionMode +import dev.zacsweers.metro.Assisted +import dev.zacsweers.metro.AssistedFactory +import dev.zacsweers.metro.AssistedInject import dev.zacsweers.metro.ContributesBinding -import dev.zacsweers.metro.Inject import io.element.android.emojibasebindings.Emoji import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.designsystem.theme.components.IconSource @@ -37,13 +39,18 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.withContext import kotlin.time.Duration.Companion.milliseconds -@Inject -@ContributesBinding(SessionScope::class) +@AssistedInject class DefaultEmojiPickerPresenter( private val emojibaseProvider: EmojibaseProvider, - private val getRecentEmojis: GetRecentEmojis, + @Assisted private val getRecentEmojis: GetRecentEmojis, private val coroutineDispatchers: CoroutineDispatchers, ) : EmojiPickerPresenter { + @AssistedFactory + @ContributesBinding(SessionScope::class) + interface Factory : EmojiPickerPresenter.Factory { + override fun create(getRecentEmojis: GetRecentEmojis): DefaultEmojiPickerPresenter + } + @Composable override fun present(): EmojiPickerState { val queryState = rememberTextFieldState() @@ -86,7 +93,9 @@ class DefaultEmojiPickerPresenter( val searchQuery = queryState.text.toString() LaunchedEffect(searchQuery, data) { if (searchQuery.isEmpty() || data.allEmojis.isEmpty()) { - emojiResults = SearchBarResultState.Initial() + if (emojiResults !is SearchBarResultState.Initial) { + emojiResults = SearchBarResultState.Initial() + } return@LaunchedEffect } delay(100.milliseconds)