From cf2723ac7f82df9d0f2880a6467778e1ca2d350f Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Fri, 23 Jun 2023 16:39:07 +0200 Subject: [PATCH] [Message Actions] Copy events to clipboard (#665) * Add `Copy` action for text events * Remove 'Copy' action from the list for non-text events * Use `@ContributesBinding` to inject `AndroidClipboardHelper`. --- app/build.gradle.kts | 1 - changelog.d/663.feature | 1 + .../impl/src/main/res/values/localazy.xml | 2 +- .../messages/impl/MessagesPresenter.kt | 21 +++++++++- .../features/messages/impl/MessagesView.kt | 14 +------ .../impl/actionlist/ActionListPresenter.kt | 9 ++++- .../model/event/TimelineItemEventContent.kt | 11 +++++ .../impl/src/main/res/values/localazy.xml | 1 + .../messages/MessagesPresenterTest.kt | 11 ++++- .../actionlist/ActionListPresenterTest.kt | 34 ++++++++++++++++ .../impl/src/main/res/values/localazy.xml | 3 +- libraries/androidutils/build.gradle.kts | 12 +++++- .../clipboard/AndroidClipboardHelper.kt | 40 +++++++++++++++++++ .../androidutils/clipboard/ClipboardHelper.kt | 25 ++++++++++++ .../clipboard/FakeClipboardHelper.kt | 26 ++++++++++++ .../src/main/res/values/localazy.xml | 2 + .../kotlin/extension/DependencyHandleScope.kt | 2 + 17 files changed, 193 insertions(+), 22 deletions(-) create mode 100644 changelog.d/663.feature create mode 100644 libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/clipboard/AndroidClipboardHelper.kt create mode 100644 libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/clipboard/ClipboardHelper.kt create mode 100644 libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/clipboard/FakeClipboardHelper.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a5ca187027..333a9e5793 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -198,7 +198,6 @@ dependencies { allLibrariesImpl() allServicesImpl() allFeaturesImpl(rootDir, logger) - implementation(projects.libraries.deeplink) implementation(projects.tests.uitests) implementation(projects.anvilannotations) implementation(projects.appnav) diff --git a/changelog.d/663.feature b/changelog.d/663.feature new file mode 100644 index 0000000000..daabb76560 --- /dev/null +++ b/changelog.d/663.feature @@ -0,0 +1 @@ +Add 'Copy' action to timeline item context menu, for text events diff --git a/features/login/impl/src/main/res/values/localazy.xml b/features/login/impl/src/main/res/values/localazy.xml index 145ac2d238..55324613ed 100644 --- a/features/login/impl/src/main/res/values/localazy.xml +++ b/features/login/impl/src/main/res/values/localazy.xml @@ -38,4 +38,4 @@ "Password" "Continue" "Username" - \ No newline at end of file + diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt index e305b916cd..01c3dc12d1 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt @@ -16,6 +16,7 @@ package io.element.android.features.messages.impl +import android.os.Build import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState @@ -50,11 +51,13 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt import io.element.android.features.messages.impl.utils.messagesummary.MessageSummaryFormatter import io.element.android.features.networkmonitor.api.NetworkMonitor import io.element.android.features.networkmonitor.api.NetworkStatus +import io.element.android.libraries.androidutils.clipboard.ClipboardHelper import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.utils.SnackbarDispatcher +import io.element.android.libraries.designsystem.utils.SnackbarMessage import io.element.android.libraries.designsystem.utils.handleSnackbarMessage import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.room.MatrixRoom @@ -66,7 +69,6 @@ import io.element.android.libraries.textcomposer.MessageComposerMode import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import timber.log.Timber -import javax.inject.Inject class MessagesPresenter @AssistedInject constructor( private val room: MatrixRoom, @@ -79,6 +81,7 @@ class MessagesPresenter @AssistedInject constructor( private val snackbarDispatcher: SnackbarDispatcher, private val messageSummaryFormatter: MessageSummaryFormatter, private val dispatchers: CoroutineDispatchers, + private val clipboardHelper: ClipboardHelper, @Assisted private val navigator: MessagesNavigator, ) : Presenter { @@ -155,7 +158,7 @@ class MessagesPresenter @AssistedInject constructor( composerState: MessageComposerState, ) = launch { when (action) { - TimelineItemAction.Copy -> notImplementedYet() + TimelineItemAction.Copy -> handleCopyContents(targetEvent) TimelineItemAction.Redact -> handleActionRedact(targetEvent) TimelineItemAction.Edit -> handleActionEdit(targetEvent, composerState) TimelineItemAction.Reply -> handleActionReply(targetEvent, composerState) @@ -246,4 +249,18 @@ class MessagesPresenter @AssistedInject constructor( if (event.eventId == null) return navigator.onReportContentClicked(event.eventId, event.senderId) } + + private suspend fun handleCopyContents(event: TimelineItem.Event) { + val content = when (event.content) { + is TimelineItemTextBasedContent -> event.content.body + is TimelineItemStateContent -> event.content.body + else -> return + } + + clipboardHelper.copyPlainText(content) + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { + snackbarDispatcher.post(SnackbarMessage(R.string.screen_room_message_copied)) + } + } } 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 d9504894e8..8e2558770d 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 @@ -33,8 +33,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.wrapContentHeight -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.SnackbarHost @@ -69,18 +67,15 @@ import io.element.android.libraries.androidutils.ui.hideKeyboard import io.element.android.libraries.designsystem.components.ProgressDialog import io.element.android.libraries.designsystem.components.avatar.Avatar import io.element.android.libraries.designsystem.components.avatar.AvatarData +import io.element.android.libraries.designsystem.components.button.BackButton 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 -import io.element.android.libraries.designsystem.theme.components.IconButton import io.element.android.libraries.designsystem.theme.components.Scaffold import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.designsystem.utils.LogCompositions import io.element.android.libraries.designsystem.utils.rememberSnackbarHostState -import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo import io.element.android.libraries.matrix.api.timeline.item.event.EventSendState import kotlinx.collections.immutable.ImmutableList import timber.log.Timber @@ -255,12 +250,7 @@ fun MessagesViewTopBar( TopAppBar( modifier = modifier, navigationIcon = { - IconButton(onClick = onBackPressed) { - Icon( - imageVector = Icons.Filled.ArrowBack, - contentDescription = "Back" - ) - } + BackButton(onClick = onBackPressed) }, title = { Row( diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt index 56de0214ec..26ab4fc217 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt @@ -25,6 +25,7 @@ import io.element.android.features.messages.impl.actionlist.model.TimelineItemAc import io.element.android.features.messages.impl.timeline.model.TimelineItem import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent +import io.element.android.features.messages.impl.timeline.model.event.canBeCopied import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.meta.BuildMeta import kotlinx.collections.immutable.toImmutableList @@ -64,7 +65,9 @@ class ActionListPresenter @Inject constructor( is TimelineItemRedactedContent, is TimelineItemStateContent -> { buildList { - add(TimelineItemAction.Copy) + if (timelineItem.content.canBeCopied()) { + add(TimelineItemAction.Copy) + } if (buildMeta.isDebuggable) { add(TimelineItemAction.Developer) } @@ -76,7 +79,9 @@ class ActionListPresenter @Inject constructor( if (timelineItem.isMine) { add(TimelineItemAction.Edit) } - add(TimelineItemAction.Copy) + if (timelineItem.content.canBeCopied()) { + add(TimelineItemAction.Copy) + } if (buildMeta.isDebuggable) { add(TimelineItemAction.Developer) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContent.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContent.kt index 233f51a5a2..0ff67e481f 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContent.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContent.kt @@ -22,3 +22,14 @@ import androidx.compose.runtime.Immutable sealed interface TimelineItemEventContent { val type: String } + +/** + * Only text based content and states can be copied. + */ +fun TimelineItemEventContent.canBeCopied(): Boolean = + when (this) { + is TimelineItemTextBasedContent, + is TimelineItemStateContent, + is TimelineItemRedactedContent -> true + else -> false + } diff --git a/features/messages/impl/src/main/res/values/localazy.xml b/features/messages/impl/src/main/res/values/localazy.xml index 557b6ccd90..508acf0e33 100644 --- a/features/messages/impl/src/main/res/values/localazy.xml +++ b/features/messages/impl/src/main/res/values/localazy.xml @@ -12,6 +12,7 @@ "Could not retrieve user details" "Would you like to invite them back?" "You are alone in this chat" + "Message copied" "You do not have permission to post to this room" "Send again" "Your message failed to send" 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 40af424406..8ec76c6aa4 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 @@ -34,10 +34,12 @@ import io.element.android.features.messages.impl.timeline.components.customreact import io.element.android.features.messages.impl.timeline.components.retrysendmenu.RetrySendMenuPresenter import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent +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.utils.messagesummary.FakeMessageSummaryFormatter import io.element.android.features.networkmonitor.test.FakeNetworkMonitor +import io.element.android.libraries.androidutils.clipboard.FakeClipboardHelper import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.core.meta.BuildType @@ -115,14 +117,17 @@ class MessagesPresenterTest { @Test fun `present - handle action copy`() = runTest { - val presenter = createMessagePresenter() + val clipboardHelper = FakeClipboardHelper() + val event = aMessageEvent() + val presenter = createMessagePresenter(clipboardHelper = clipboardHelper) moleculeFlow(RecompositionClock.Immediate) { presenter.present() }.test { skipItems(1) val initialState = awaitItem() - initialState.eventSink.invoke(MessagesEvents.HandleAction(TimelineItemAction.Copy, aMessageEvent())) + initialState.eventSink.invoke(MessagesEvents.HandleAction(TimelineItemAction.Copy, event)) assertThat(awaitItem().actionListState.target).isEqualTo(ActionListState.Target.None) + assertThat(clipboardHelper.clipboardContents).isEqualTo((event.content as TimelineItemTextContent).body) } } @@ -355,6 +360,7 @@ class MessagesPresenterTest { coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers(), matrixRoom: MatrixRoom = FakeMatrixRoom(), navigator: FakeMessagesNavigator = FakeMessagesNavigator(), + clipboardHelper: FakeClipboardHelper = FakeClipboardHelper(), ): MessagesPresenter { val messageComposerPresenter = MessageComposerPresenter( appCoroutineScope = this, @@ -396,6 +402,7 @@ class MessagesPresenterTest { snackbarDispatcher = SnackbarDispatcher(), messageSummaryFormatter = FakeMessageSummaryFormatter(), navigator = navigator, + clipboardHelper = clipboardHelper, dispatchers = coroutineDispatchers, ) } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/actionlist/ActionListPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/actionlist/ActionListPresenterTest.kt index 7af17d193f..88334737d7 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/actionlist/ActionListPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/actionlist/ActionListPresenterTest.kt @@ -25,8 +25,10 @@ import io.element.android.features.messages.impl.actionlist.ActionListEvents import io.element.android.features.messages.impl.actionlist.ActionListPresenter 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.event.TimelineItemImageContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent +import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemImageContent import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.core.meta.BuildType import io.element.android.libraries.matrix.test.A_MESSAGE @@ -164,6 +166,38 @@ class ActionListPresenterTest { } } + @Test + fun `present - compute for a media item`() = runTest { + val presenter = anActionListPresenter(isBuildDebuggable = true) + moleculeFlow(RecompositionClock.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + val messageEvent = aMessageEvent( + isMine = true, + content = aTimelineItemImageContent(), + ) + initialState.eventSink.invoke(ActionListEvents.ComputeForMessage(messageEvent)) + // val loadingState = awaitItem() + // assertThat(loadingState.target).isEqualTo(ActionListState.Target.Loading(messageEvent)) + val successState = awaitItem() + assertThat(successState.target).isEqualTo( + ActionListState.Target.Success( + messageEvent, + persistentListOf( + TimelineItemAction.Reply, + TimelineItemAction.Forward, + TimelineItemAction.Edit, + TimelineItemAction.Developer, + TimelineItemAction.Redact, + ) + ) + ) + initialState.eventSink.invoke(ActionListEvents.Clear) + assertThat(awaitItem().target).isEqualTo(ActionListState.Target.None) + } + } + @Test fun `present - compute message in non-debuggable build`() = runTest { val presenter = anActionListPresenter(isBuildDebuggable = false) diff --git a/features/onboarding/impl/src/main/res/values/localazy.xml b/features/onboarding/impl/src/main/res/values/localazy.xml index bad5b524da..cdb258cdad 100644 --- a/features/onboarding/impl/src/main/res/values/localazy.xml +++ b/features/onboarding/impl/src/main/res/values/localazy.xml @@ -4,6 +4,7 @@ "Sign in with QR code" "Create account" "Communicate and collaborate securely" + "Welcome to the fastest Element ever. Supercharged for speed and simplicity." "Welcome to %1$s. Supercharged, for speed and simplicity." - "Be in your Element" + "Be in your element" diff --git a/libraries/androidutils/build.gradle.kts b/libraries/androidutils/build.gradle.kts index f98914e08a..92e3c46126 100644 --- a/libraries/androidutils/build.gradle.kts +++ b/libraries/androidutils/build.gradle.kts @@ -16,18 +16,28 @@ */ plugins { id("io.element.android-library") + alias(libs.plugins.anvil) } android { namespace = "io.element.android.libraries.androidutils" } +anvil { + generateDaggerFactories.set(true) +} + dependencies { + anvil(projects.anvilcodegen) + implementation(projects.anvilannotations) + implementation(projects.libraries.di) + + implementation(projects.libraries.core) + implementation(libs.dagger) implementation(libs.timber) implementation(libs.androidx.corektx) implementation(libs.androidx.activity.activity) implementation(libs.androidx.exifinterface) implementation(libs.androidx.security.crypto) implementation(libs.androidx.browser) - implementation(projects.libraries.core) } diff --git a/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/clipboard/AndroidClipboardHelper.kt b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/clipboard/AndroidClipboardHelper.kt new file mode 100644 index 0000000000..cecf47eb1b --- /dev/null +++ b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/clipboard/AndroidClipboardHelper.kt @@ -0,0 +1,40 @@ +/* + * 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.libraries.androidutils.clipboard + +import android.content.ClipData +import android.content.ClipboardManager +import android.content.Context +import androidx.core.content.getSystemService +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.di.ApplicationContext +import io.element.android.libraries.di.SingleIn +import javax.inject.Inject + +@ContributesBinding(AppScope::class) +@SingleIn(AppScope::class) +class AndroidClipboardHelper @Inject constructor( + @ApplicationContext private val context: Context, +) : ClipboardHelper { + + private val clipboardManager = requireNotNull(context.getSystemService()) + + override fun copyPlainText(text: String) { + clipboardManager.setPrimaryClip(ClipData.newPlainText("", text)) + } +} diff --git a/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/clipboard/ClipboardHelper.kt b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/clipboard/ClipboardHelper.kt new file mode 100644 index 0000000000..39cb719d48 --- /dev/null +++ b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/clipboard/ClipboardHelper.kt @@ -0,0 +1,25 @@ +/* + * 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.libraries.androidutils.clipboard + +/** + * Wrapper class for handling clipboard operations so it can be used in JVM environments. + */ +interface ClipboardHelper { + fun copyPlainText(text: String) + +} diff --git a/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/clipboard/FakeClipboardHelper.kt b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/clipboard/FakeClipboardHelper.kt new file mode 100644 index 0000000000..03cd70c768 --- /dev/null +++ b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/clipboard/FakeClipboardHelper.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.libraries.androidutils.clipboard + +class FakeClipboardHelper : ClipboardHelper { + + var clipboardContents: Any? = null + + override fun copyPlainText(text: String) { + clipboardContents = text + } +} diff --git a/libraries/ui-strings/src/main/res/values/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml index ffbc7aded4..bcd90cb160 100644 --- a/libraries/ui-strings/src/main/res/values/localazy.xml +++ b/libraries/ui-strings/src/main/res/values/localazy.xml @@ -28,6 +28,7 @@ "Invite" "Invite friends" "Invite friends to %1$s" + "Invite people to %1$s" "Invites" "Learn more" "Leave" @@ -108,6 +109,7 @@ "Server not supported" "Server URL" "Settings" + "Shared location" "Starting chat…" "Sticker" "Success" diff --git a/plugins/src/main/kotlin/extension/DependencyHandleScope.kt b/plugins/src/main/kotlin/extension/DependencyHandleScope.kt index 51c568960d..88f499b993 100644 --- a/plugins/src/main/kotlin/extension/DependencyHandleScope.kt +++ b/plugins/src/main/kotlin/extension/DependencyHandleScope.kt @@ -75,6 +75,8 @@ private fun DependencyHandlerScope.addImplementationProjects( } fun DependencyHandlerScope.allLibrariesImpl() { + implementation(project(":libraries:androidutils")) + implementation(project(":libraries:deeplink")) implementation(project(":libraries:designsystem")) implementation(project(":libraries:matrix:impl")) implementation(project(":libraries:matrixui"))