From 685d6843597952d7951fdd7347dae5b1463c0607 Mon Sep 17 00:00:00 2001 From: David Langley Date: Mon, 28 Aug 2023 16:45:42 +0100 Subject: [PATCH 1/9] Integrate emojibase - Integrate emojibase datasource - Use element category translations - Use Material emoji category logos --- app/build.gradle.kts | 2 +- .../element/android/x/ElementXApplication.kt | 2 - .../android/x/initializer/EmojiInitializer.kt | 29 ---------- features/messages/impl/build.gradle.kts | 2 +- .../messages/impl/MessagesStateProvider.kt | 3 + .../features/messages/impl/MessagesView.kt | 8 ++- .../CustomReactionBottomSheet.kt | 13 +++-- .../customreaction/CustomReactionEvents.kt | 3 +- .../customreaction/CustomReactionPresenter.kt | 34 +++++++++-- .../customreaction/CustomReactionState.kt | 3 + .../{ => customreaction}/EmojiPicker.kt | 27 +++++---- .../customreaction/EmojibaseExtensions.kt | 58 +++++++++++++++++++ .../CustomReactionPresenterTests.kt | 4 +- gradle/libs.versions.toml | 5 +- 14 files changed, 130 insertions(+), 63 deletions(-) delete mode 100644 app/src/main/kotlin/io/element/android/x/initializer/EmojiInitializer.kt rename features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/{ => customreaction}/EmojiPicker.kt (83%) create mode 100644 features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojibaseExtensions.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 19bb2ea84b..405054d837 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -220,7 +220,7 @@ dependencies { implementation(libs.network.okhttp.logging) implementation(libs.serialization.json) - implementation(libs.vanniktech.emoji) + implementation(libs.matrix.emojibase.bindings) implementation(libs.dagger) kapt(libs.dagger.compiler) diff --git a/app/src/main/kotlin/io/element/android/x/ElementXApplication.kt b/app/src/main/kotlin/io/element/android/x/ElementXApplication.kt index da8592771c..542ae7090d 100644 --- a/app/src/main/kotlin/io/element/android/x/ElementXApplication.kt +++ b/app/src/main/kotlin/io/element/android/x/ElementXApplication.kt @@ -23,7 +23,6 @@ import io.element.android.x.di.AppComponent import io.element.android.x.di.DaggerAppComponent import io.element.android.x.info.logApplicationInfo import io.element.android.x.initializer.CrashInitializer -import io.element.android.x.initializer.EmojiInitializer import io.element.android.x.initializer.TracingInitializer class ElementXApplication : Application(), DaggerComponentOwner { @@ -39,7 +38,6 @@ class ElementXApplication : Application(), DaggerComponentOwner { AppInitializer.getInstance(this).apply { initializeComponent(CrashInitializer::class.java) initializeComponent(TracingInitializer::class.java) - initializeComponent(EmojiInitializer::class.java) } logApplicationInfo() } diff --git a/app/src/main/kotlin/io/element/android/x/initializer/EmojiInitializer.kt b/app/src/main/kotlin/io/element/android/x/initializer/EmojiInitializer.kt deleted file mode 100644 index dd1e7455c6..0000000000 --- a/app/src/main/kotlin/io/element/android/x/initializer/EmojiInitializer.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2023 New Vector Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.element.android.x.initializer - -import androidx.startup.Initializer -import com.vanniktech.emoji.EmojiManager -import com.vanniktech.emoji.google.GoogleEmojiProvider - -class EmojiInitializer : Initializer { - override fun create(context: android.content.Context) { - EmojiManager.install(GoogleEmojiProvider()) - } - - override fun dependencies(): MutableList>> = mutableListOf() -} diff --git a/features/messages/impl/build.gradle.kts b/features/messages/impl/build.gradle.kts index 948bac4c57..bd8cbc3a11 100644 --- a/features/messages/impl/build.gradle.kts +++ b/features/messages/impl/build.gradle.kts @@ -60,7 +60,7 @@ dependencies { implementation(libs.accompanist.systemui) implementation(libs.vanniktech.blurhash) implementation(libs.telephoto.zoomableimage) - implementation(libs.vanniktech.emoji) + implementation(libs.matrix.emojibase.bindings) testImplementation(libs.test.junit) testImplementation(libs.coroutines.test) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt index 7da67d468c..6541d8abc8 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt @@ -16,7 +16,9 @@ package io.element.android.features.messages.impl +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import io.element.android.emojibasebindings.EmojibaseDatasource import io.element.android.features.messages.impl.actionlist.anActionListState import io.element.android.features.messages.impl.messagecomposer.aMessageComposerState import io.element.android.features.messages.impl.timeline.aTimelineItemList @@ -67,6 +69,7 @@ fun aMessagesState() = MessagesState( actionListState = anActionListState(), customReactionState = CustomReactionState( selectedEventId = null, + emojiProvider = Async.Uninitialized, eventSink = {}, ), reactionSummaryState = ReactionSummaryState( diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt index 34ac14af57..9190646ffc 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt @@ -135,7 +135,8 @@ fun MessagesView( } fun onMoreReactionsClicked(event: TimelineItem.Event) { - state.customReactionState.eventSink(CustomReactionEvents.UpdateSelectedEvent(event.eventId)) + if (event.eventId == null) return + state.customReactionState.eventSink(CustomReactionEvents.ShowCustomReactionSheet(event.eventId)) } Scaffold( @@ -187,7 +188,8 @@ fun MessagesView( state = state.actionListState, onActionSelected = ::onActionSelected, onCustomReactionClicked = { event -> - state.customReactionState.eventSink(CustomReactionEvents.UpdateSelectedEvent(event.eventId)) + if (event.eventId == null) return@ActionListView + state.customReactionState.eventSink(CustomReactionEvents.ShowCustomReactionSheet(event.eventId)) }, onEmojiReactionClicked = ::onEmojiReactionClicked, ) @@ -197,7 +199,7 @@ fun MessagesView( onEmojiSelected = { emoji -> state.customReactionState.selectedEventId?.let { eventId -> state.eventSink(MessagesEvents.ToggleReaction(emoji.unicode, eventId)) - state.customReactionState.eventSink(CustomReactionEvents.UpdateSelectedEvent(null)) + state.customReactionState.eventSink(CustomReactionEvents.DismissCustomReactionSheet) } } ) 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 70c2a7dc10..3bfe42cecf 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 @@ -22,8 +22,7 @@ import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier -import com.vanniktech.emoji.Emoji -import io.element.android.features.messages.impl.timeline.components.EmojiPicker +import io.element.android.emojibasebindings.Emoji import io.element.android.libraries.designsystem.theme.components.ModalBottomSheet import io.element.android.libraries.designsystem.theme.components.hide @@ -38,18 +37,19 @@ fun CustomReactionBottomSheet( val coroutineScope = rememberCoroutineScope() fun onDismiss() { - state.eventSink(CustomReactionEvents.UpdateSelectedEvent(null)) + state.eventSink(CustomReactionEvents.DismissCustomReactionSheet) } fun onEmojiSelectedDismiss(emoji: Emoji) { sheetState.hide(coroutineScope) { - state.eventSink(CustomReactionEvents.UpdateSelectedEvent(null)) + state.eventSink(CustomReactionEvents.DismissCustomReactionSheet) onEmojiSelected(emoji) } } - val isVisible = state.selectedEventId != null - if (isVisible) { + val emojiProvider = state.emojiProvider.dataOrNull() + val selectedEventId = state.selectedEventId + if (emojiProvider != null && selectedEventId != null) { ModalBottomSheet( onDismissRequest = ::onDismiss, sheetState = sheetState, @@ -57,6 +57,7 @@ fun CustomReactionBottomSheet( ) { EmojiPicker( onEmojiSelected = ::onEmojiSelectedDismiss, + emojiProvider = emojiProvider, modifier = Modifier.fillMaxSize() ) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionEvents.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionEvents.kt index b7c210553e..1126474b8a 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionEvents.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionEvents.kt @@ -19,5 +19,6 @@ package io.element.android.features.messages.impl.timeline.components.customreac import io.element.android.libraries.matrix.api.core.EventId sealed interface CustomReactionEvents { - data class UpdateSelectedEvent(val eventId: EventId?) : CustomReactionEvents + data class ShowCustomReactionSheet(val eventId: EventId) : CustomReactionEvents + object DismissCustomReactionSheet : CustomReactionEvents } 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 0a23d42085..a000a780ae 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 @@ -20,9 +20,15 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue +import androidx.compose.ui.platform.LocalContext +import io.element.android.emojibasebindings.EmojibaseDatasource +import io.element.android.emojibasebindings.EmojibaseStore +import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.matrix.api.core.EventId +import kotlinx.coroutines.launch import javax.inject.Inject class CustomReactionPresenter @Inject constructor() : Presenter { @@ -30,13 +36,31 @@ class CustomReactionPresenter @Inject constructor() : Presenter(null) } - - fun handleEvents(event: CustomReactionEvents) { - when (event) { - is CustomReactionEvents.UpdateSelectedEvent -> selectedEventId = event.eventId + var emojiState: Async by remember { + mutableStateOf(Async.Uninitialized) + } + val localCoroutineScope = rememberCoroutineScope() + val context = LocalContext.current + fun handleShowCustomReactionSheet(eventId: EventId) { + selectedEventId = eventId + emojiState = Async.Loading() + localCoroutineScope.launch { + emojiState = Async.Success(EmojibaseDatasource().load(context)) } } - return CustomReactionState(selectedEventId = selectedEventId, eventSink = ::handleEvents) + fun handleDismissCustomReactionSheet() { + selectedEventId = null + emojiState = Async.Uninitialized + } + + fun handleEvents(event: CustomReactionEvents) { + when (event) { + is CustomReactionEvents.ShowCustomReactionSheet -> handleShowCustomReactionSheet(event.eventId) + is CustomReactionEvents.DismissCustomReactionSheet -> handleDismissCustomReactionSheet() + } + } + + return CustomReactionState(selectedEventId = selectedEventId, emojiProvider = emojiState, eventSink = ::handleEvents) } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionState.kt index 6c0c7f3599..9641f2d31a 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionState.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionState.kt @@ -16,9 +16,12 @@ package io.element.android.features.messages.impl.timeline.components.customreaction +import io.element.android.emojibasebindings.EmojibaseStore +import io.element.android.libraries.architecture.Async import io.element.android.libraries.matrix.api.core.EventId data class CustomReactionState( val selectedEventId: EventId?, + val emojiProvider: Async, val eventSink: (CustomReactionEvents) -> Unit, ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/EmojiPicker.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojiPicker.kt similarity index 83% rename from features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/EmojiPicker.kt rename to features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojiPicker.kt index 6e121685f2..1fa238d5ba 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/EmojiPicker.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojiPicker.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.features.messages.impl.timeline.components +package io.element.android.features.messages.impl.timeline.components.customreaction import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.clickable @@ -39,10 +39,14 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.vanniktech.emoji.Emoji -import com.vanniktech.emoji.google.GoogleEmojiProvider +import io.element.android.emojibasebindings.Emoji +import io.element.android.emojibasebindings.EmojibaseCategory +import io.element.android.emojibasebindings.EmojibaseDatasource +import io.element.android.emojibasebindings.EmojibaseStore import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.theme.components.Icon @@ -54,23 +58,22 @@ import kotlinx.coroutines.launch @Composable fun EmojiPicker( onEmojiSelected: (Emoji) -> Unit, + emojiProvider: EmojibaseStore, modifier: Modifier = Modifier, ) { val coroutineScope = rememberCoroutineScope() - - val emojiProvider = remember { GoogleEmojiProvider() } val categories = remember { emojiProvider.categories } val pagerState = rememberPagerState() Column(modifier) { TabRow( selectedTabIndex = pagerState.currentPage, ) { - categories.forEachIndexed { index, category -> + EmojibaseCategory.values().forEachIndexed { index, category -> Tab( text = { Icon( - resourceId = emojiProvider.getIcon(category), - contentDescription = category.categoryNames["en"] + imageVector = category.icon, + contentDescription = stringResource(id = category.title) ) }, selected = pagerState.currentPage == index, @@ -82,18 +85,19 @@ fun EmojiPicker( } HorizontalPager( - pageCount = categories.size, + pageCount = EmojibaseCategory.values().size, state = pagerState, modifier = Modifier.fillMaxWidth(), ) { index -> - val category = categories[index] + val category = EmojibaseCategory.values()[index] + val emojis = categories[category] ?: listOf() LazyVerticalGrid( modifier = Modifier.fillMaxSize(), columns = GridCells.Adaptive(minSize = 40.dp), contentPadding = PaddingValues(vertical = 10.dp, horizontal = 16.dp), horizontalArrangement = Arrangement.SpaceEvenly, ) { - items(category.emojis, key = { it.unicode }) { item -> + items(emojis, key = { it.unicode }) { item -> Box( modifier = Modifier .size(40.dp) @@ -132,6 +136,7 @@ internal fun EmojiPickerDarkPreview() { private fun ContentToPreview() { EmojiPicker( onEmojiSelected = {}, + emojiProvider = EmojibaseDatasource().load(LocalContext.current), modifier = Modifier.fillMaxWidth() ) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojibaseExtensions.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojibaseExtensions.kt new file mode 100644 index 0000000000..c6e54953e6 --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojibaseExtensions.kt @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.messages.impl.timeline.components.customreaction + +import androidx.annotation.StringRes +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.EmojiEvents +import androidx.compose.material.icons.outlined.EmojiFlags +import androidx.compose.material.icons.outlined.EmojiFoodBeverage +import androidx.compose.material.icons.outlined.EmojiNature +import androidx.compose.material.icons.outlined.EmojiObjects +import androidx.compose.material.icons.outlined.EmojiPeople +import androidx.compose.material.icons.outlined.EmojiSymbols +import androidx.compose.material.icons.outlined.EmojiTransportation +import androidx.compose.ui.graphics.vector.ImageVector +import io.element.android.emojibasebindings.EmojibaseCategory +import io.element.android.libraries.ui.strings.R + +@get:StringRes +val EmojibaseCategory.title: Int get() = + when(this){ + EmojibaseCategory.People -> R.string.emoji_picker_category_people + EmojibaseCategory.Nature -> R.string.emoji_picker_category_nature + EmojibaseCategory.Foods -> R.string.emoji_picker_category_foods + EmojibaseCategory.Activity -> R.string.emoji_picker_category_activity + EmojibaseCategory.Places -> R.string.emoji_picker_category_places + EmojibaseCategory.Objects -> R.string.emoji_picker_category_objects + EmojibaseCategory.Symbols -> R.string.emoji_picker_category_symbols + EmojibaseCategory.Flags -> R.string.emoji_picker_category_flags + } + +val EmojibaseCategory.icon: ImageVector + get() = + when(this){ + EmojibaseCategory.People -> Icons.Outlined.EmojiPeople + EmojibaseCategory.Nature -> Icons.Outlined.EmojiNature + EmojibaseCategory.Foods -> Icons.Outlined.EmojiFoodBeverage + EmojibaseCategory.Activity -> Icons.Outlined.EmojiEvents + EmojibaseCategory.Places -> Icons.Outlined.EmojiTransportation + EmojibaseCategory.Objects -> Icons.Outlined.EmojiObjects + EmojibaseCategory.Symbols -> Icons.Outlined.EmojiSymbols + EmojibaseCategory.Flags -> Icons.Outlined.EmojiFlags + } + diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/timeline/components/customreaction/CustomReactionPresenterTests.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/timeline/components/customreaction/CustomReactionPresenterTests.kt index 1c40483ffe..0ea4ab79c8 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/timeline/components/customreaction/CustomReactionPresenterTests.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/timeline/components/customreaction/CustomReactionPresenterTests.kt @@ -38,10 +38,10 @@ class CustomReactionPresenterTests { val initialState = awaitItem() assertThat(initialState.selectedEventId).isNull() - initialState.eventSink(CustomReactionEvents.UpdateSelectedEvent(AN_EVENT_ID)) + initialState.eventSink(CustomReactionEvents.ShowCustomReactionSheet(AN_EVENT_ID)) assertThat(awaitItem().selectedEventId).isEqualTo(AN_EVENT_ID) - initialState.eventSink(CustomReactionEvents.UpdateSelectedEvent(null)) + initialState.eventSink(CustomReactionEvents.DismissCustomReactionSheet) assertThat(awaitItem().selectedEventId).isNull() } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7f3540a2e8..c4f5c8ae4f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -154,7 +154,6 @@ sqlite = "androidx.sqlite:sqlite:2.3.1" unifiedpush = "com.github.UnifiedPush:android-connector:2.1.1" otaliastudios_transcoder = "com.otaliastudios:transcoder:0.10.5" vanniktech_blurhash = "com.vanniktech:blurhash:0.1.0" -vanniktech_emoji = "com.vanniktech:emoji-google:0.16.0" telephoto_zoomableimage = { module = "me.saket.telephoto:zoomable-image-coil", version.ref = "telephoto" } statemachine = "com.freeletics.flowredux:compose:1.2.0" maplibre = "org.maplibre.gl:android-sdk:10.2.0" @@ -166,6 +165,9 @@ posthog = "com.posthog.android:posthog:2.0.3" sentry = "io.sentry:sentry-android:6.28.0" matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:42b2faa417c1e95f430bf8f6e379adba25ad5ef8" +# Emojibase +matrix_emojibase_bindings = "io.element.android:emojibase-bindings:1.0.5" + # Di inject = "javax.inject:javax.inject:1" dagger = { module = "com.google.dagger:dagger", version.ref = "dagger" } @@ -177,7 +179,6 @@ anvil_compiler_utils = { module = "com.squareup.anvil:compiler-utils", version.r google_autoservice = { module = "com.google.auto.service:auto-service", version.ref = "autoservice" } google_autoservice_annotations = { module = "com.google.auto.service:auto-service-annotations", version.ref = "autoservice" } - # Miscellaneous # Add unused dependency to androidx.compose.compiler:compiler to let Renovate create PR to change the # value of `composecompiler` (which is used to set composeOptions.kotlinCompilerExtensionVersion. From 3cf73cf5361348a8e58014a40612f19f35348d02 Mon Sep 17 00:00:00 2001 From: David Langley Date: Mon, 28 Aug 2023 18:11:17 +0100 Subject: [PATCH 2/9] lint --- .../features/messages/impl/MessagesStateProvider.kt | 2 -- .../customreaction/CustomReactionBottomSheet.kt | 2 +- .../components/customreaction/CustomReactionEvents.kt | 2 +- .../customreaction/CustomReactionPresenter.kt | 11 +++++++---- .../timeline/components/customreaction/EmojiPicker.kt | 9 ++++----- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt index 3423830f08..ecc9b1746a 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt @@ -16,9 +16,7 @@ package io.element.android.features.messages.impl -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.emojibasebindings.EmojibaseDatasource import io.element.android.features.messages.impl.actionlist.anActionListState import io.element.android.features.messages.impl.messagecomposer.aMessageComposerState import io.element.android.features.messages.impl.timeline.aTimelineItemList 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 bb02c36e31..05c2956316 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 @@ -57,9 +57,9 @@ fun CustomReactionBottomSheet( ) { EmojiPicker( onEmojiSelected = ::onEmojiSelectedDismiss, - modifier = Modifier.fillMaxSize(), emojiProvider = emojiProvider, selectedEmojis = state.selectedEmoji, + modifier = Modifier.fillMaxSize(), ) } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionEvents.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionEvents.kt index f9da2986d9..2458686a83 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionEvents.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionEvents.kt @@ -19,6 +19,6 @@ package io.element.android.features.messages.impl.timeline.components.customreac import io.element.android.features.messages.impl.timeline.model.TimelineItem sealed interface CustomReactionEvents { - data class ShowCustomReactionSheet(val event: TimelineItem.Event?) : CustomReactionEvents + data class ShowCustomReactionSheet(val event: TimelineItem.Event) : CustomReactionEvents object DismissCustomReactionSheet : CustomReactionEvents } 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 0aa1d06059..4ab94f1656 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 @@ -27,10 +27,8 @@ import io.element.android.emojibasebindings.EmojibaseDatasource import io.element.android.emojibasebindings.EmojibaseStore import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Presenter -import io.element.android.libraries.matrix.api.core.EventId import kotlinx.coroutines.launch import io.element.android.features.messages.impl.timeline.model.TimelineItem -import io.element.android.libraries.architecture.Presenter import kotlinx.collections.immutable.toImmutableSet import javax.inject.Inject @@ -59,11 +57,16 @@ class CustomReactionPresenter @Inject constructor() : Presenter handleShowCustomReactionSheet(event) + is CustomReactionEvents.ShowCustomReactionSheet -> handleShowCustomReactionSheet(event.event) is CustomReactionEvents.DismissCustomReactionSheet -> handleDismissCustomReactionSheet() } } val selectedEmoji = selectedEvent?.reactionsState?.reactions?.mapNotNull { if(it.isHighlighted) it.key else null }.orEmpty().toImmutableSet() - return CustomReactionState(selectedEventId = selectedEvent?.eventId, emojiProvider = emojiState, selectedEmoji = selectedEmoji, eventSink = ::handleEvents) + return CustomReactionState( + selectedEventId = selectedEvent?.eventId, + emojiProvider = emojiState, + selectedEmoji = selectedEmoji, + eventSink = ::handleEvents + ) } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojiPicker.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojiPicker.kt index c2259bdf09..edbd6aabc6 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojiPicker.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojiPicker.kt @@ -63,13 +63,13 @@ import kotlinx.coroutines.launch @Composable fun EmojiPicker( onEmojiSelected: (Emoji) -> Unit, - modifier: Modifier = Modifier, emojiProvider: EmojibaseStore, selectedEmojis: ImmutableSet, + modifier: Modifier = Modifier, ) { val coroutineScope = rememberCoroutineScope() val categories = remember { emojiProvider.categories } - val pagerState = rememberPagerState(pageCount = { emojiProvider.categories.size }) + val pagerState = rememberPagerState(pageCount = { EmojibaseCategory.values().size }) Column(modifier) { TabRow( selectedTabIndex = pagerState.currentPage, @@ -91,7 +91,6 @@ fun EmojiPicker( } HorizontalPager( - pageCount = EmojibaseCategory.values().size, state = pagerState, modifier = Modifier.fillMaxWidth(), ) { index -> @@ -150,8 +149,8 @@ internal fun EmojiPickerDarkPreview() { private fun ContentToPreview() { EmojiPicker( onEmojiSelected = {}, - modifier = Modifier.fillMaxWidth(), emojiProvider = EmojibaseDatasource().load(LocalContext.current), - selectedEmojis = persistentSetOf("😀", "😄", "😃") + selectedEmojis = persistentSetOf("😀", "😄", "😃"), + modifier = Modifier.fillMaxWidth(), ) } From a8ad5c5ec1eb8923b3a0461997c284e6e3bdf39f Mon Sep 17 00:00:00 2001 From: David Langley Date: Mon, 28 Aug 2023 18:20:48 +0100 Subject: [PATCH 3/9] Use CommonStrings --- .../customreaction/EmojibaseExtensions.kt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojibaseExtensions.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojibaseExtensions.kt index c6e54953e6..fb111cce97 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojibaseExtensions.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojibaseExtensions.kt @@ -28,19 +28,19 @@ import androidx.compose.material.icons.outlined.EmojiSymbols import androidx.compose.material.icons.outlined.EmojiTransportation import androidx.compose.ui.graphics.vector.ImageVector import io.element.android.emojibasebindings.EmojibaseCategory -import io.element.android.libraries.ui.strings.R +import io.element.android.libraries.ui.strings.CommonStrings @get:StringRes val EmojibaseCategory.title: Int get() = when(this){ - EmojibaseCategory.People -> R.string.emoji_picker_category_people - EmojibaseCategory.Nature -> R.string.emoji_picker_category_nature - EmojibaseCategory.Foods -> R.string.emoji_picker_category_foods - EmojibaseCategory.Activity -> R.string.emoji_picker_category_activity - EmojibaseCategory.Places -> R.string.emoji_picker_category_places - EmojibaseCategory.Objects -> R.string.emoji_picker_category_objects - EmojibaseCategory.Symbols -> R.string.emoji_picker_category_symbols - EmojibaseCategory.Flags -> R.string.emoji_picker_category_flags + EmojibaseCategory.People -> CommonStrings.emoji_picker_category_people + EmojibaseCategory.Nature -> CommonStrings.emoji_picker_category_nature + EmojibaseCategory.Foods -> CommonStrings.emoji_picker_category_foods + EmojibaseCategory.Activity -> CommonStrings.emoji_picker_category_activity + EmojibaseCategory.Places -> CommonStrings.emoji_picker_category_places + EmojibaseCategory.Objects -> CommonStrings.emoji_picker_category_objects + EmojibaseCategory.Symbols -> CommonStrings.emoji_picker_category_symbols + EmojibaseCategory.Flags -> CommonStrings.emoji_picker_category_flags } val EmojibaseCategory.icon: ImageVector From 19a6586880e9b66885d7aa6949e006c2831bf7bd Mon Sep 17 00:00:00 2001 From: David Langley Date: Mon, 28 Aug 2023 20:15:00 +0100 Subject: [PATCH 4/9] Fix test compilation. --- .../components/customreaction/CustomReactionPresenterTests.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/timeline/components/customreaction/CustomReactionPresenterTests.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/timeline/components/customreaction/CustomReactionPresenterTests.kt index 8246520d7c..9918a67296 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/timeline/components/customreaction/CustomReactionPresenterTests.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/timeline/components/customreaction/CustomReactionPresenterTests.kt @@ -57,7 +57,7 @@ class CustomReactionPresenterTests { assertThat(initialState.selectedEventId).isNull() val reactions = aTimelineItemReactions(count = 1, isHighlighted = true) val key = reactions.reactions.first().key - initialState.eventSink(CustomReactionEvents.UpdateSelectedEvent(aTimelineItemEvent(eventId = AN_EVENT_ID, timelineItemReactions = reactions))) + initialState.eventSink(CustomReactionEvents.ShowCustomReactionSheet(aTimelineItemEvent(eventId = AN_EVENT_ID, timelineItemReactions = reactions))) val stateWithSelectedEmojis = awaitItem() assertThat(stateWithSelectedEmojis.selectedEventId).isEqualTo(AN_EVENT_ID) assertThat(stateWithSelectedEmojis.selectedEmoji).contains(key) From a4e8f0c8fd0a5963487e0214e6b9fdf5624b3679 Mon Sep 17 00:00:00 2001 From: David Langley Date: Wed, 30 Aug 2023 12:47:31 +0100 Subject: [PATCH 5/9] Fix tests and improve structure of CustomReactionState - Fix tests - Improve structure of CustomReactionState --- .../io/element/android/x/di/AppModule.kt | 8 +++++ .../messages/impl/MessagesStateProvider.kt | 3 +- .../features/messages/impl/MessagesView.kt | 4 +-- .../CustomReactionBottomSheet.kt | 14 ++++---- .../customreaction/CustomReactionPresenter.kt | 34 +++++++++++-------- .../customreaction/CustomReactionState.kt | 20 +++++++++-- .../DefaultEmojibaseProvider.kt | 27 +++++++++++++++ .../components/customreaction/EmojiPicker.kt | 6 ++-- .../customreaction/EmojibaseProvider.kt | 23 +++++++++++++ .../messages/MessagesPresenterTest.kt | 3 +- .../CustomReactionPresenterTests.kt | 33 ++++++++++++------ .../customreaction/FakeEmojibaseProvider.kt | 26 ++++++++++++++ 12 files changed, 158 insertions(+), 43 deletions(-) create mode 100644 features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/DefaultEmojibaseProvider.kt create mode 100644 features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojibaseProvider.kt create mode 100644 features/messages/impl/src/test/kotlin/io/element/android/features/messages/timeline/components/customreaction/FakeEmojibaseProvider.kt diff --git a/app/src/main/kotlin/io/element/android/x/di/AppModule.kt b/app/src/main/kotlin/io/element/android/x/di/AppModule.kt index a1d0b50522..f8ab5532b0 100644 --- a/app/src/main/kotlin/io/element/android/x/di/AppModule.kt +++ b/app/src/main/kotlin/io/element/android/x/di/AppModule.kt @@ -23,6 +23,8 @@ import androidx.preference.PreferenceManager import com.squareup.anvil.annotations.ContributesTo import dagger.Module import dagger.Provides +import io.element.android.features.messages.impl.timeline.components.customreaction.DefaultEmojibaseProvider +import io.element.android.features.messages.impl.timeline.components.customreaction.EmojibaseProvider import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.core.meta.BuildType @@ -105,4 +107,10 @@ object AppModule { fun provideSnackbarDispatcher(): SnackbarDispatcher { return SnackbarDispatcher() } + + @Provides + @SingleIn(AppScope::class) + fun providesEmojibaseProvider(@ApplicationContext context: Context): EmojibaseProvider { + return DefaultEmojibaseProvider(context) + } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt index ecc9b1746a..7eb1a0984e 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt @@ -67,8 +67,7 @@ fun aMessagesState() = MessagesState( ), actionListState = anActionListState(), customReactionState = CustomReactionState( - selectedEventId = null, - emojiProvider = Async.Uninitialized, + target = CustomReactionState.Target.None, eventSink = {}, selectedEmoji = persistentSetOf(), ), diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt index 5608711171..74dcb610af 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt @@ -200,11 +200,9 @@ fun MessagesView( CustomReactionBottomSheet( state = state.customReactionState, - onEmojiSelected = { emoji -> - state.customReactionState.selectedEventId?.let { eventId -> + onEmojiSelected = { eventId, emoji -> state.eventSink(MessagesEvents.ToggleReaction(emoji.unicode, eventId)) state.customReactionState.eventSink(CustomReactionEvents.DismissCustomReactionSheet) - } } ) 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 05c2956316..ed78993716 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 @@ -23,33 +23,35 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import io.element.android.emojibasebindings.Emoji +import io.element.android.features.messages.impl.actionlist.ActionListState import io.element.android.libraries.designsystem.theme.components.ModalBottomSheet import io.element.android.libraries.designsystem.theme.components.hide +import io.element.android.libraries.matrix.api.core.EventId @OptIn(ExperimentalMaterial3Api::class) @Composable fun CustomReactionBottomSheet( state: CustomReactionState, - onEmojiSelected: (Emoji) -> Unit, + onEmojiSelected: (EventId, Emoji) -> Unit, modifier: Modifier = Modifier, ) { val sheetState = rememberModalBottomSheetState() val coroutineScope = rememberCoroutineScope() + val target = state.target as? CustomReactionState.Target.Success fun onDismiss() { state.eventSink(CustomReactionEvents.DismissCustomReactionSheet) } fun onEmojiSelectedDismiss(emoji: Emoji) { + if (target?.event?.eventId == null) return sheetState.hide(coroutineScope) { state.eventSink(CustomReactionEvents.DismissCustomReactionSheet) - onEmojiSelected(emoji) + onEmojiSelected(target.event.eventId, emoji) } } - val emojiProvider = state.emojiProvider.dataOrNull() - val selectedEventId = state.selectedEventId - if (emojiProvider != null && selectedEventId != null) { + if (target?.emojibaseStore != null && target.event.eventId != null) { ModalBottomSheet( onDismissRequest = ::onDismiss, sheetState = sheetState, @@ -57,7 +59,7 @@ fun CustomReactionBottomSheet( ) { EmojiPicker( onEmojiSelected = ::onEmojiSelectedDismiss, - emojiProvider = emojiProvider, + emojibaseStore = target.emojibaseStore, selectedEmojis = state.selectedEmoji, modifier = Modifier.fillMaxSize(), ) 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 4ab94f1656..8a331438a5 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,42 +17,46 @@ package io.element.android.features.messages.impl.timeline.components.customreaction import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue -import androidx.compose.ui.platform.LocalContext -import io.element.android.emojibasebindings.EmojibaseDatasource import io.element.android.emojibasebindings.EmojibaseStore +import io.element.android.features.messages.impl.actionlist.ActionListState import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Presenter import kotlinx.coroutines.launch import io.element.android.features.messages.impl.timeline.model.TimelineItem +import io.element.android.features.messages.impl.timeline.model.event.canReact import kotlinx.collections.immutable.toImmutableSet import javax.inject.Inject -class CustomReactionPresenter @Inject constructor() : Presenter { +class CustomReactionPresenter @Inject constructor( + private val emojibaseProvider: EmojibaseProvider +) : Presenter { @Composable override fun present(): CustomReactionState { - var selectedEvent by remember { mutableStateOf(null) } - var emojiState: Async by remember { - mutableStateOf(Async.Uninitialized) + val target: MutableState = remember { + mutableStateOf(CustomReactionState.Target.None) } + val localCoroutineScope = rememberCoroutineScope() - val context = LocalContext.current fun handleShowCustomReactionSheet(event: TimelineItem.Event) { - selectedEvent = event - emojiState = Async.Loading() + target.value = CustomReactionState.Target.Loading(event) localCoroutineScope.launch { - emojiState = Async.Success(EmojibaseDatasource().load(context)) + target.value = CustomReactionState.Target.Success( + event = event, + emojibaseStore = emojibaseProvider.loadEmojibase() + ) } } fun handleDismissCustomReactionSheet() { - selectedEvent = null - emojiState = Async.Uninitialized + target.value = CustomReactionState.Target.None } fun handleEvents(event: CustomReactionEvents) { @@ -61,10 +65,10 @@ class CustomReactionPresenter @Inject constructor() : Presenter handleDismissCustomReactionSheet() } } - val selectedEmoji = selectedEvent?.reactionsState?.reactions?.mapNotNull { if(it.isHighlighted) it.key else null }.orEmpty().toImmutableSet() + val event = (target.value as? CustomReactionState.Target.Success)?.event + val selectedEmoji = event?.reactionsState?.reactions?.mapNotNull { if(it.isHighlighted) it.key else null }.orEmpty().toImmutableSet() return CustomReactionState( - selectedEventId = selectedEvent?.eventId, - emojiProvider = emojiState, + target = target.value, selectedEmoji = selectedEmoji, eventSink = ::handleEvents ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionState.kt index 09d5392d32..400c34d6fa 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionState.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionState.kt @@ -17,13 +17,27 @@ package io.element.android.features.messages.impl.timeline.components.customreaction import io.element.android.emojibasebindings.EmojibaseStore +import io.element.android.features.messages.impl.actionlist.ActionListState +import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction +import io.element.android.features.messages.impl.timeline.model.TimelineItem import io.element.android.libraries.architecture.Async import io.element.android.libraries.matrix.api.core.EventId +import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableSet data class CustomReactionState( - val selectedEventId: EventId?, - val emojiProvider: Async, + val target: Target, val selectedEmoji: ImmutableSet, val eventSink: (CustomReactionEvents) -> Unit, -) +) { + sealed interface Target { + + data object None : Target + data class Loading(val event: TimelineItem.Event) : Target + data class Success( + val event: TimelineItem.Event, + val emojibaseStore: EmojibaseStore, + ) : Target + } +} + diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/DefaultEmojibaseProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/DefaultEmojibaseProvider.kt new file mode 100644 index 0000000000..2e66ea381e --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/DefaultEmojibaseProvider.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.messages.impl.timeline.components.customreaction + +import android.content.Context +import io.element.android.emojibasebindings.EmojibaseDatasource +import io.element.android.emojibasebindings.EmojibaseStore + +class DefaultEmojibaseProvider(val context: Context) :EmojibaseProvider { + override fun loadEmojibase(): EmojibaseStore { + return EmojibaseDatasource().load(context) + } +} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojiPicker.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojiPicker.kt index edbd6aabc6..1012d61020 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojiPicker.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojiPicker.kt @@ -63,12 +63,12 @@ import kotlinx.coroutines.launch @Composable fun EmojiPicker( onEmojiSelected: (Emoji) -> Unit, - emojiProvider: EmojibaseStore, + emojibaseStore: EmojibaseStore, selectedEmojis: ImmutableSet, modifier: Modifier = Modifier, ) { val coroutineScope = rememberCoroutineScope() - val categories = remember { emojiProvider.categories } + val categories = remember { emojibaseStore.categories } val pagerState = rememberPagerState(pageCount = { EmojibaseCategory.values().size }) Column(modifier) { TabRow( @@ -149,7 +149,7 @@ internal fun EmojiPickerDarkPreview() { private fun ContentToPreview() { EmojiPicker( onEmojiSelected = {}, - emojiProvider = EmojibaseDatasource().load(LocalContext.current), + emojibaseStore = EmojibaseDatasource().load(LocalContext.current), selectedEmojis = persistentSetOf("😀", "😄", "😃"), modifier = Modifier.fillMaxWidth(), ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojibaseProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojibaseProvider.kt new file mode 100644 index 0000000000..39739538d2 --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojibaseProvider.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.messages.impl.timeline.components.customreaction + +import io.element.android.emojibasebindings.EmojibaseStore + +interface EmojibaseProvider { + fun loadEmojibase(): EmojibaseStore +} diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt index 2c542e0054..c9f9bec3f8 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt @@ -41,6 +41,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent import io.element.android.features.messages.media.FakeLocalMediaFactory +import io.element.android.features.messages.timeline.components.customreaction.FakeEmojibaseProvider import io.element.android.features.messages.utils.messagesummary.FakeMessageSummaryFormatter import io.element.android.features.networkmonitor.test.FakeNetworkMonitor import io.element.android.libraries.androidutils.clipboard.FakeClipboardHelper @@ -584,7 +585,7 @@ class MessagesPresenterTest { ) val buildMeta = aBuildMeta() val actionListPresenter = ActionListPresenter(buildMeta = buildMeta) - val customReactionPresenter = CustomReactionPresenter() + val customReactionPresenter = CustomReactionPresenter(emojibaseProvider = FakeEmojibaseProvider()) val reactionSummaryPresenter = ReactionSummaryPresenter(room = matrixRoom) val retrySendMenuPresenter = RetrySendMenuPresenter(room = matrixRoom) return MessagesPresenter( diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/timeline/components/customreaction/CustomReactionPresenterTests.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/timeline/components/customreaction/CustomReactionPresenterTests.kt index 9918a67296..bb77605132 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/timeline/components/customreaction/CustomReactionPresenterTests.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/timeline/components/customreaction/CustomReactionPresenterTests.kt @@ -24,27 +24,34 @@ import io.element.android.features.messages.impl.timeline.aTimelineItemEvent import io.element.android.features.messages.impl.timeline.aTimelineItemReactions import io.element.android.features.messages.impl.timeline.components.customreaction.CustomReactionEvents import io.element.android.features.messages.impl.timeline.components.customreaction.CustomReactionPresenter +import io.element.android.features.messages.impl.timeline.components.customreaction.CustomReactionState import io.element.android.libraries.matrix.test.AN_EVENT_ID import kotlinx.coroutines.test.runTest import org.junit.Test class CustomReactionPresenterTests { - private val presenter = CustomReactionPresenter() + private val presenter = CustomReactionPresenter(emojibaseProvider = FakeEmojibaseProvider()) @Test fun `present - handle selecting and de-selecting an event`() = runTest { moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { - val initialState = awaitItem() - assertThat(initialState.selectedEventId).isNull() - initialState.eventSink(CustomReactionEvents.ShowCustomReactionSheet(aTimelineItemEvent(eventId = AN_EVENT_ID))) - assertThat(awaitItem().selectedEventId).isEqualTo(AN_EVENT_ID) + val event = aTimelineItemEvent(eventId = AN_EVENT_ID) + val initialState = awaitItem() + assertThat(initialState.target).isEqualTo(CustomReactionState.Target.None) + + initialState.eventSink(CustomReactionEvents.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) initialState.eventSink(CustomReactionEvents.DismissCustomReactionSheet) - assertThat(awaitItem().selectedEventId).isNull() + assertThat(awaitItem().target).isEqualTo(CustomReactionState.Target.None) } } @@ -53,13 +60,19 @@ class CustomReactionPresenterTests { moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { - val initialState = awaitItem() - assertThat(initialState.selectedEventId).isNull() val reactions = aTimelineItemReactions(count = 1, isHighlighted = true) + val event = aTimelineItemEvent(eventId = AN_EVENT_ID, timelineItemReactions = reactions) + val initialState = awaitItem() + assertThat(initialState.target).isEqualTo(CustomReactionState.Target.None) + val key = reactions.reactions.first().key - initialState.eventSink(CustomReactionEvents.ShowCustomReactionSheet(aTimelineItemEvent(eventId = AN_EVENT_ID, timelineItemReactions = reactions))) + initialState.eventSink(CustomReactionEvents.ShowCustomReactionSheet(event)) + + assertThat(awaitItem().target).isEqualTo(CustomReactionState.Target.Loading(event)) + val stateWithSelectedEmojis = awaitItem() - assertThat(stateWithSelectedEmojis.selectedEventId).isEqualTo(AN_EVENT_ID) + val eventId = (stateWithSelectedEmojis.target as? CustomReactionState.Target.Success)?.event?.eventId + assertThat(eventId).isEqualTo(AN_EVENT_ID) assertThat(stateWithSelectedEmojis.selectedEmoji).contains(key) } } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/timeline/components/customreaction/FakeEmojibaseProvider.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/timeline/components/customreaction/FakeEmojibaseProvider.kt new file mode 100644 index 0000000000..434212030a --- /dev/null +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/timeline/components/customreaction/FakeEmojibaseProvider.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.messages.timeline.components.customreaction + +import io.element.android.emojibasebindings.EmojibaseStore +import io.element.android.features.messages.impl.timeline.components.customreaction.EmojibaseProvider + +class FakeEmojibaseProvider: EmojibaseProvider { + override fun loadEmojibase(): EmojibaseStore { + return EmojibaseStore(mapOf()) + } +} From 188df7a4fcd3c1921f9986289a44c6ceeba4ea29 Mon Sep 17 00:00:00 2001 From: David Langley Date: Wed, 30 Aug 2023 12:55:50 +0100 Subject: [PATCH 6/9] lint --- .../components/customreaction/CustomReactionBottomSheet.kt | 1 - .../components/customreaction/CustomReactionPresenter.kt | 7 ------- .../components/customreaction/CustomReactionState.kt | 5 ----- 3 files changed, 13 deletions(-) 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 ed78993716..3fe739a592 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 @@ -23,7 +23,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import io.element.android.emojibasebindings.Emoji -import io.element.android.features.messages.impl.actionlist.ActionListState import io.element.android.libraries.designsystem.theme.components.ModalBottomSheet import io.element.android.libraries.designsystem.theme.components.hide import io.element.android.libraries.matrix.api.core.EventId 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 8a331438a5..6831ca7dfa 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 @@ -18,19 +18,12 @@ package io.element.android.features.messages.impl.timeline.components.customreac import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue -import io.element.android.emojibasebindings.EmojibaseStore -import io.element.android.features.messages.impl.actionlist.ActionListState -import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Presenter import kotlinx.coroutines.launch import io.element.android.features.messages.impl.timeline.model.TimelineItem -import io.element.android.features.messages.impl.timeline.model.event.canReact import kotlinx.collections.immutable.toImmutableSet import javax.inject.Inject diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionState.kt index 400c34d6fa..f6f7d2b0f9 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionState.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionState.kt @@ -17,12 +17,7 @@ package io.element.android.features.messages.impl.timeline.components.customreaction import io.element.android.emojibasebindings.EmojibaseStore -import io.element.android.features.messages.impl.actionlist.ActionListState -import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction import io.element.android.features.messages.impl.timeline.model.TimelineItem -import io.element.android.libraries.architecture.Async -import io.element.android.libraries.matrix.api.core.EventId -import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableSet data class CustomReactionState( From 2855f69b20816134d73045ce960a253f845849aa Mon Sep 17 00:00:00 2001 From: ElementBot Date: Wed, 30 Aug 2023 12:38:04 +0000 Subject: [PATCH 7/9] Update screenshots --- ...tomreaction_null_EmojiPickerDark_0_null,NEXUS_5,1.0,en].png | 3 +++ ...omreaction_null_EmojiPickerLight_0_null,NEXUS_5,1.0,en].png | 3 +++ ....components_null_EmojiPickerDark_0_null,NEXUS_5,1.0,en].png | 3 --- ...components_null_EmojiPickerLight_0_null,NEXUS_5,1.0,en].png | 3 --- 4 files changed, 6 insertions(+), 6 deletions(-) create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.customreaction_null_EmojiPickerDark_0_null,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.customreaction_null_EmojiPickerLight_0_null,NEXUS_5,1.0,en].png delete mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components_null_EmojiPickerDark_0_null,NEXUS_5,1.0,en].png delete mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components_null_EmojiPickerLight_0_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.customreaction_null_EmojiPickerDark_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.customreaction_null_EmojiPickerDark_0_null,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..aaab9d35c1 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.customreaction_null_EmojiPickerDark_0_null,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5ea42394330d37a0aa5ba8940e023fc4454d902caf6d265adec0e11c8a34d85f +size 187744 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.customreaction_null_EmojiPickerLight_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.customreaction_null_EmojiPickerLight_0_null,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..65a27f228d --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.customreaction_null_EmojiPickerLight_0_null,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1fb074cd58034c90010dc437fc01d6ea77a2a22aa07bc1d4cf0c1730b543b41a +size 186707 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components_null_EmojiPickerDark_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components_null_EmojiPickerDark_0_null,NEXUS_5,1.0,en].png deleted file mode 100644 index 8838c1cbf2..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components_null_EmojiPickerDark_0_null,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cd761ca4ff5a70770869780c2575006ed8bd187ed4b3f197ffe1e4ea18d8390b -size 189559 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components_null_EmojiPickerLight_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components_null_EmojiPickerLight_0_null,NEXUS_5,1.0,en].png deleted file mode 100644 index 80a5da9cd1..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components_null_EmojiPickerLight_0_null,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d8c6e3f139ca634c47c45fbeeaccf3e7e903fb8f83a88fdf8d7247455e76e4a9 -size 188653 From f8de314c935e89362038f867854539e202073702 Mon Sep 17 00:00:00 2001 From: David Langley Date: Thu, 31 Aug 2023 11:37:08 +0100 Subject: [PATCH 8/9] Fix colon aligment and load emojis lazily. - Fix colon aligment - Load emojis lazily. --- .../components/customreaction/CustomReactionPresenter.kt | 2 +- .../components/customreaction/DefaultEmojibaseProvider.kt | 8 +++++--- .../components/customreaction/EmojibaseProvider.kt | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) 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 6831ca7dfa..b048383b1f 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 @@ -43,7 +43,7 @@ class CustomReactionPresenter @Inject constructor( localCoroutineScope.launch { target.value = CustomReactionState.Target.Success( event = event, - emojibaseStore = emojibaseProvider.loadEmojibase() + emojibaseStore = emojibaseProvider.emojibaseStore ) } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/DefaultEmojibaseProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/DefaultEmojibaseProvider.kt index 2e66ea381e..a68d6f0d4e 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/DefaultEmojibaseProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/DefaultEmojibaseProvider.kt @@ -20,8 +20,10 @@ import android.content.Context import io.element.android.emojibasebindings.EmojibaseDatasource import io.element.android.emojibasebindings.EmojibaseStore -class DefaultEmojibaseProvider(val context: Context) :EmojibaseProvider { - override fun loadEmojibase(): EmojibaseStore { - return EmojibaseDatasource().load(context) +class DefaultEmojibaseProvider(val context: Context): EmojibaseProvider { + + override val emojibaseStore: EmojibaseStore by lazy { + EmojibaseDatasource().load(context) } + } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojibaseProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojibaseProvider.kt index 39739538d2..6a4f48a806 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojibaseProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/EmojibaseProvider.kt @@ -19,5 +19,5 @@ package io.element.android.features.messages.impl.timeline.components.customreac import io.element.android.emojibasebindings.EmojibaseStore interface EmojibaseProvider { - fun loadEmojibase(): EmojibaseStore + val emojibaseStore: EmojibaseStore } From 8c5a8e8a043a9b2abd530b6f05b1be5f12e18abf Mon Sep 17 00:00:00 2001 From: David Langley Date: Thu, 31 Aug 2023 11:41:06 +0100 Subject: [PATCH 9/9] Fix FakeEmojibaseProvider --- .../components/customreaction/FakeEmojibaseProvider.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/timeline/components/customreaction/FakeEmojibaseProvider.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/timeline/components/customreaction/FakeEmojibaseProvider.kt index 434212030a..7bf993e2a4 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/timeline/components/customreaction/FakeEmojibaseProvider.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/timeline/components/customreaction/FakeEmojibaseProvider.kt @@ -20,7 +20,6 @@ import io.element.android.emojibasebindings.EmojibaseStore import io.element.android.features.messages.impl.timeline.components.customreaction.EmojibaseProvider class FakeEmojibaseProvider: EmojibaseProvider { - override fun loadEmojibase(): EmojibaseStore { - return EmojibaseStore(mapOf()) - } + override val emojibaseStore: EmojibaseStore + get() = EmojibaseStore(mapOf()) }