From b237b123c7dd49b5bd362d137975c60aa757372d Mon Sep 17 00:00:00 2001 From: Johannes Marbach Date: Sat, 17 Jun 2023 21:11:44 +0200 Subject: [PATCH 1/4] Add analytics events for room creation --- changelog.d/627.feature | 1 + features/createroom/impl/build.gradle.kts | 2 ++ .../impl/configureroom/ConfigureRoomPresenter.kt | 8 +++++++- .../createroom/impl/root/CreateRoomRootPresenter.kt | 4 ++++ .../impl/configureroom/ConfigureRoomPresenterTests.kt | 4 ++++ .../createroom/impl/root/CreateRoomRootPresenterTests.kt | 6 +++++- 6 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 changelog.d/627.feature diff --git a/changelog.d/627.feature b/changelog.d/627.feature new file mode 100644 index 0000000000..0b875fc536 --- /dev/null +++ b/changelog.d/627.feature @@ -0,0 +1 @@ +Add analytics events for room creation diff --git a/features/createroom/impl/build.gradle.kts b/features/createroom/impl/build.gradle.kts index f203501315..fd7a6d6f5e 100644 --- a/features/createroom/impl/build.gradle.kts +++ b/features/createroom/impl/build.gradle.kts @@ -49,6 +49,7 @@ dependencies { implementation(projects.libraries.mediapickers.api) implementation(projects.libraries.mediaupload.api) implementation(projects.libraries.usersearch.impl) + implementation(projects.services.analytics.api) implementation(libs.coil.compose) api(projects.features.createroom.api) @@ -59,6 +60,7 @@ dependencies { testImplementation(libs.test.truth) testImplementation(libs.test.turbine) testImplementation(libs.test.robolectric) + testImplementation(projects.features.analytics.test) testImplementation(projects.libraries.matrix.test) testImplementation(projects.libraries.mediapickers.test) testImplementation(projects.libraries.mediaupload.test) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt index ca714b1e59..8879f4be1c 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt @@ -25,6 +25,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import im.vector.app.features.analytics.plan.CreatedRoom import io.element.android.features.createroom.impl.CreateRoomConfig import io.element.android.features.createroom.impl.CreateRoomDataStore import io.element.android.libraries.architecture.Async @@ -39,6 +40,7 @@ import io.element.android.libraries.matrix.api.createroom.RoomVisibility import io.element.android.libraries.matrix.ui.media.AvatarAction import io.element.android.libraries.mediapickers.api.PickerProvider import io.element.android.libraries.mediaupload.api.MediaPreProcessor +import io.element.android.services.analytics.api.AnalyticsService import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -49,6 +51,7 @@ class ConfigureRoomPresenter @Inject constructor( private val matrixClient: MatrixClient, private val mediaPickerProvider: PickerProvider, private val mediaPreProcessor: MediaPreProcessor, + private val analyticsService: AnalyticsService, ) : Presenter { @Composable @@ -124,7 +127,10 @@ class ConfigureRoomPresenter @Inject constructor( avatar = avatarUrl, ) matrixClient.createRoom(params).getOrThrow() - .also { dataStore.clearCachedData() } + .also { + dataStore.clearCachedData() + analyticsService.capture(CreatedRoom(isDM = false)) + } }.execute(createRoomAction) } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenter.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenter.kt index 7b5c6b7cf1..9e9b3b28a4 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenter.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenter.kt @@ -21,6 +21,7 @@ import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import im.vector.app.features.analytics.plan.CreatedRoom import io.element.android.features.createroom.impl.userlist.SelectionMode import io.element.android.features.createroom.impl.userlist.UserListDataStore import io.element.android.features.createroom.impl.userlist.UserListPresenter @@ -32,6 +33,7 @@ import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.usersearch.api.UserRepository +import io.element.android.services.analytics.api.AnalyticsService import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import javax.inject.Inject @@ -41,6 +43,7 @@ class CreateRoomRootPresenter @Inject constructor( private val userRepository: UserRepository, private val userListDataStore: UserListDataStore, private val matrixClient: MatrixClient, + private val analyticsService: AnalyticsService, ) : Presenter { private val presenter by lazy { @@ -88,6 +91,7 @@ class CreateRoomRootPresenter @Inject constructor( private fun CoroutineScope.createDM(user: MatrixUser, startDmAction: MutableState>) = launch { suspend { matrixClient.createDM(user.userId).getOrThrow() + .also { analyticsService.capture(CreatedRoom(isDM = true)) } }.execute(startDmAction) } } diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt index 736fca9cb4..0c73d16a7e 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt +++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt @@ -21,6 +21,7 @@ import app.cash.molecule.RecompositionClock import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat +import io.element.android.features.analytics.test.FakeAnalyticsService import io.element.android.features.createroom.impl.CreateRoomConfig import io.element.android.features.createroom.impl.CreateRoomDataStore import io.element.android.features.createroom.impl.userlist.UserListDataStore @@ -62,6 +63,7 @@ class ConfigureRoomPresenterTests { private lateinit var fakeMatrixClient: FakeMatrixClient private lateinit var fakePickerProvider: FakePickerProvider private lateinit var fakeMediaPreProcessor: FakeMediaPreProcessor + private lateinit var fakeAnalyticsService: FakeAnalyticsService @Before fun setup() { @@ -70,11 +72,13 @@ class ConfigureRoomPresenterTests { createRoomDataStore = CreateRoomDataStore(userListDataStore) fakePickerProvider = FakePickerProvider() fakeMediaPreProcessor = FakeMediaPreProcessor() + fakeAnalyticsService = FakeAnalyticsService() presenter = ConfigureRoomPresenter( dataStore = createRoomDataStore, matrixClient = fakeMatrixClient, mediaPickerProvider = fakePickerProvider, mediaPreProcessor = fakeMediaPreProcessor, + analyticsService = fakeAnalyticsService, ) mockkStatic(File::readBytes) diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenterTests.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenterTests.kt index 0d0fdcce44..a2c1cf96a9 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenterTests.kt +++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenterTests.kt @@ -20,6 +20,7 @@ import app.cash.molecule.RecompositionClock import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat +import io.element.android.features.analytics.test.FakeAnalyticsService import io.element.android.features.createroom.impl.userlist.FakeUserListPresenter import io.element.android.features.createroom.impl.userlist.FakeUserListPresenterFactory import io.element.android.features.createroom.impl.userlist.UserListDataStore @@ -43,17 +44,20 @@ class CreateRoomRootPresenterTests { private lateinit var presenter: CreateRoomRootPresenter private lateinit var fakeUserListPresenter: FakeUserListPresenter private lateinit var fakeMatrixClient: FakeMatrixClient + private lateinit var fakeAnalyticsService: FakeAnalyticsService @Before fun setup() { fakeUserListPresenter = FakeUserListPresenter() fakeMatrixClient = FakeMatrixClient() + fakeAnalyticsService = FakeAnalyticsService() userRepository = FakeUserRepository() presenter = CreateRoomRootPresenter( presenterFactory = FakeUserListPresenterFactory(fakeUserListPresenter), userRepository = userRepository, userListDataStore = UserListDataStore(), - matrixClient = fakeMatrixClient + matrixClient = fakeMatrixClient, + analyticsService = fakeAnalyticsService, ) } From 318db6f44c56267e7c60d896c5879e775dc194a5 Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Fri, 23 Jun 2023 11:53:54 +0100 Subject: [PATCH 2/4] Add some tests for create room analytics --- .../analytics/test/FakeAnalyticsService.kt | 2 ++ .../ConfigureRoomPresenterTests.kt | 21 ++++++++++++++++ .../impl/root/CreateRoomRootPresenterTests.kt | 25 +++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/features/analytics/test/src/main/kotlin/io/element/android/features/analytics/test/FakeAnalyticsService.kt b/features/analytics/test/src/main/kotlin/io/element/android/features/analytics/test/FakeAnalyticsService.kt index 47eba919ed..3d969567f7 100644 --- a/features/analytics/test/src/main/kotlin/io/element/android/features/analytics/test/FakeAnalyticsService.kt +++ b/features/analytics/test/src/main/kotlin/io/element/android/features/analytics/test/FakeAnalyticsService.kt @@ -31,6 +31,7 @@ class FakeAnalyticsService( private var isEnabledFlow = MutableStateFlow(isEnabled) private var didAskUserConsentFlow = MutableStateFlow(didAskUserConsent) + var capturedEvents = mutableListOf() override fun getAvailableAnalyticsProviders(): List = emptyList() @@ -55,6 +56,7 @@ class FakeAnalyticsService( } override fun capture(event: VectorAnalyticsEvent) { + capturedEvents += event } override fun screen(screen: VectorAnalyticsScreen) { diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt index 0c73d16a7e..9b6ac2e067 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt +++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt @@ -21,6 +21,7 @@ import app.cash.molecule.RecompositionClock import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat +import im.vector.app.features.analytics.plan.CreatedRoom import io.element.android.features.analytics.test.FakeAnalyticsService import io.element.android.features.createroom.impl.CreateRoomConfig import io.element.android.features.createroom.impl.CreateRoomDataStore @@ -218,6 +219,25 @@ class ConfigureRoomPresenterTests { } } + @Test + fun `present - record analytics when creating room`() = runTest { + moleculeFlow(RecompositionClock.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + val createRoomResult = Result.success(RoomId("!createRoomResult:domain")) + + fakeMatrixClient.givenCreateRoomResult(createRoomResult) + + initialState.eventSink(ConfigureRoomEvents.CreateRoom(initialState.config)) + skipItems(2) + + val analyticsEvent = fakeAnalyticsService.capturedEvents.filterIsInstance().firstOrNull() + assertThat(analyticsEvent).isNotNull() + assertThat(analyticsEvent?.isDM).isFalse() + } + } + @Test fun `present - trigger create room with upload error and retry`() = runTest { moleculeFlow(RecompositionClock.Immediate) { @@ -233,6 +253,7 @@ class ConfigureRoomPresenterTests { assertThat(awaitItem().createRoomAction).isInstanceOf(Async.Loading::class.java) val stateAfterCreateRoom = awaitItem() assertThat(stateAfterCreateRoom.createRoomAction).isInstanceOf(Async.Failure::class.java) + assertThat(fakeAnalyticsService.capturedEvents.filterIsInstance()).isEmpty() fakeMatrixClient.givenUploadMediaResult(Result.success(AN_AVATAR_URL)) stateAfterCreateRoom.eventSink(ConfigureRoomEvents.CreateRoom(initialState.config)) diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenterTests.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenterTests.kt index a2c1cf96a9..38d563c33c 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenterTests.kt +++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenterTests.kt @@ -20,6 +20,7 @@ import app.cash.molecule.RecompositionClock import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat +import im.vector.app.features.analytics.plan.CreatedRoom import io.element.android.features.analytics.test.FakeAnalyticsService import io.element.android.features.createroom.impl.userlist.FakeUserListPresenter import io.element.android.features.createroom.impl.userlist.FakeUserListPresenterFactory @@ -91,6 +92,27 @@ class CreateRoomRootPresenterTests { } } + @Test + fun `present - creating a DM records analytics event`() = runTest { + moleculeFlow(RecompositionClock.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + val matrixUser = MatrixUser(UserId("@name:domain")) + val createDmResult = Result.success(RoomId("!createDmResult:domain")) + + fakeMatrixClient.givenFindDmResult(null) + fakeMatrixClient.givenCreateDmResult(createDmResult) + + initialState.eventSink(CreateRoomRootEvents.StartDM(matrixUser)) + skipItems(2) + + val analyticsEvent = fakeAnalyticsService.capturedEvents.filterIsInstance().firstOrNull() + assertThat(analyticsEvent).isNotNull() + assertThat(analyticsEvent?.isDM).isTrue() + } + } + @Test fun `present - trigger retrieve DM action`() = runTest { moleculeFlow(RecompositionClock.Immediate) { @@ -106,6 +128,7 @@ class CreateRoomRootPresenterTests { val stateAfterStartDM = awaitItem() assertThat(stateAfterStartDM.startDmAction).isInstanceOf(Async.Success::class.java) assertThat(stateAfterStartDM.startDmAction.dataOrNull()).isEqualTo(fakeDmResult.roomId) + assertThat(fakeAnalyticsService.capturedEvents.filterIsInstance()).isEmpty() } } @@ -128,6 +151,7 @@ class CreateRoomRootPresenterTests { assertThat(awaitItem().startDmAction).isInstanceOf(Async.Loading::class.java) val stateAfterStartDM = awaitItem() assertThat(stateAfterStartDM.startDmAction).isInstanceOf(Async.Failure::class.java) + assertThat(fakeAnalyticsService.capturedEvents.filterIsInstance()).isEmpty() // Cancel stateAfterStartDM.eventSink(CreateRoomRootEvents.CancelStartDM) @@ -139,6 +163,7 @@ class CreateRoomRootPresenterTests { assertThat(awaitItem().startDmAction).isInstanceOf(Async.Loading::class.java) val stateAfterSecondAttempt = awaitItem() assertThat(stateAfterSecondAttempt.startDmAction).isInstanceOf(Async.Failure::class.java) + assertThat(fakeAnalyticsService.capturedEvents.filterIsInstance()).isEmpty() // Retry with success fakeMatrixClient.givenCreateDmError(null) From f0f1a026f7f591357a58a9cc0940815d64b89340 Mon Sep 17 00:00:00 2001 From: Johannes Marbach Date: Fri, 23 Jun 2023 13:27:48 +0200 Subject: [PATCH 3/4] Add (primitive) screen tracking for room & DM creation --- .../createroom/impl/configureroom/ConfigureRoomNode.kt | 5 ++++- .../createroom/impl/configureroom/ConfigureRoomView.kt | 9 +++++++++ .../features/createroom/impl/root/CreateRoomRootNode.kt | 5 ++++- .../features/createroom/impl/root/CreateRoomRootView.kt | 9 +++++++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomNode.kt index 2ac5b8691a..c313e8a992 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomNode.kt @@ -27,12 +27,14 @@ import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode import io.element.android.features.createroom.impl.di.CreateRoomScope import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.services.analytics.api.AnalyticsService @ContributesNode(CreateRoomScope::class) class ConfigureRoomNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, private val presenter: ConfigureRoomPresenter, + private val analyticsService: AnalyticsService, ) : Node(buildContext, plugins = plugins) { interface Callback : Plugin { @@ -50,7 +52,8 @@ class ConfigureRoomNode @AssistedInject constructor( state = state, modifier = modifier, onBackPressed = this::navigateUp, - onRoomCreated = this::onRoomCreated + onRoomCreated = this::onRoomCreated, + analyticsService = analyticsService, ) } } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt index 703fa268e2..48c8efc010 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt @@ -48,6 +48,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import im.vector.app.features.analytics.plan.MobileScreen import io.element.android.features.createroom.impl.R import io.element.android.features.createroom.impl.components.RoomPrivacyOption import io.element.android.libraries.architecture.Async @@ -65,6 +66,7 @@ import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.ui.components.AvatarActionBottomSheet import io.element.android.libraries.matrix.ui.components.SelectedUsersList import io.element.android.libraries.matrix.ui.components.UnsavedAvatar +import io.element.android.services.analytics.api.AnalyticsService import kotlinx.coroutines.launch import io.element.android.libraries.ui.strings.R as StringR @@ -75,7 +77,14 @@ fun ConfigureRoomView( modifier: Modifier = Modifier, onBackPressed: () -> Unit = {}, onRoomCreated: (RoomId) -> Unit = {}, + analyticsService: AnalyticsService? = null, ) { + analyticsService?.let { + LaunchedEffect(Unit) { + it.screen(MobileScreen(screenName = MobileScreen.ScreenName.CreateRoom)) + } + } + val coroutineScope = rememberCoroutineScope() val focusManager = LocalFocusManager.current val itemActionsBottomSheetState = rememberModalBottomSheetState( diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootNode.kt index 6b5ac667c5..df6e6cc8a7 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootNode.kt @@ -34,6 +34,7 @@ import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.permalink.PermalinkBuilder import io.element.android.libraries.ui.strings.R +import io.element.android.services.analytics.api.AnalyticsService import timber.log.Timber @ContributesNode(SessionScope::class) @@ -43,6 +44,7 @@ class CreateRoomRootNode @AssistedInject constructor( private val presenter: CreateRoomRootPresenter, private val matrixClient: MatrixClient, private val buildMeta: BuildMeta, + private val analyticsService: AnalyticsService, ) : Node(buildContext, plugins = plugins) { interface Callback : Plugin { @@ -70,7 +72,8 @@ class CreateRoomRootNode @AssistedInject constructor( onClosePressed = this::navigateUp, onNewRoomClicked = callback::onCreateNewRoom, onOpenDM = callback::onStartChatSuccess, - onInviteFriendsClicked = { invitePeople(context) } + onInviteFriendsClicked = { invitePeople(context) }, + analyticsService = analyticsService, ) } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt index 05dd8d04fb..a4b5b48511 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt @@ -41,6 +41,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import im.vector.app.features.analytics.plan.MobileScreen import io.element.android.features.createroom.impl.R import io.element.android.features.createroom.impl.components.UserListView import io.element.android.libraries.architecture.Async @@ -54,6 +55,7 @@ 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.matrix.api.core.RoomId +import io.element.android.services.analytics.api.AnalyticsService import io.element.android.libraries.designsystem.R as DrawableR import io.element.android.libraries.ui.strings.R as StringR @@ -66,7 +68,14 @@ fun CreateRoomRootView( onNewRoomClicked: () -> Unit = {}, onOpenDM: (RoomId) -> Unit = {}, onInviteFriendsClicked: () -> Unit = {}, + analyticsService: AnalyticsService? = null, ) { + analyticsService?.let { + LaunchedEffect(Unit) { + it.screen(MobileScreen(screenName = MobileScreen.ScreenName.StartChat)) + } + } + if (state.startDmAction is Async.Success) { LaunchedEffect(state.startDmAction) { onOpenDM(state.startDmAction.state) From 67587b836afc821e29b290fa50d0caff7f9211ba Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Fri, 23 Jun 2023 13:04:24 +0100 Subject: [PATCH 4/4] Keep screen analytics entirely in the node --- .../impl/configureroom/ConfigureRoomNode.kt | 11 ++++++++++- .../impl/configureroom/ConfigureRoomView.kt | 9 --------- .../createroom/impl/root/CreateRoomRootNode.kt | 9 ++++++++- .../createroom/impl/root/CreateRoomRootView.kt | 9 --------- 4 files changed, 18 insertions(+), 20 deletions(-) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomNode.kt index c313e8a992..b09863b205 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomNode.kt @@ -18,12 +18,14 @@ package io.element.android.features.createroom.impl.configureroom import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import com.bumble.appyx.core.lifecycle.subscribe import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.core.plugin.plugins import dagger.assisted.Assisted import dagger.assisted.AssistedInject +import im.vector.app.features.analytics.plan.MobileScreen import io.element.android.anvilannotations.ContributesNode import io.element.android.features.createroom.impl.di.CreateRoomScope import io.element.android.libraries.matrix.api.core.RoomId @@ -37,6 +39,14 @@ class ConfigureRoomNode @AssistedInject constructor( private val analyticsService: AnalyticsService, ) : Node(buildContext, plugins = plugins) { + init { + lifecycle.subscribe( + onResume = { + analyticsService.screen(MobileScreen(screenName = MobileScreen.ScreenName.CreateRoom)) + } + ) + } + interface Callback : Plugin { fun onCreateRoomSuccess(roomId: RoomId) } @@ -53,7 +63,6 @@ class ConfigureRoomNode @AssistedInject constructor( modifier = modifier, onBackPressed = this::navigateUp, onRoomCreated = this::onRoomCreated, - analyticsService = analyticsService, ) } } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt index 48c8efc010..703fa268e2 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt @@ -48,7 +48,6 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import im.vector.app.features.analytics.plan.MobileScreen import io.element.android.features.createroom.impl.R import io.element.android.features.createroom.impl.components.RoomPrivacyOption import io.element.android.libraries.architecture.Async @@ -66,7 +65,6 @@ import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.ui.components.AvatarActionBottomSheet import io.element.android.libraries.matrix.ui.components.SelectedUsersList import io.element.android.libraries.matrix.ui.components.UnsavedAvatar -import io.element.android.services.analytics.api.AnalyticsService import kotlinx.coroutines.launch import io.element.android.libraries.ui.strings.R as StringR @@ -77,14 +75,7 @@ fun ConfigureRoomView( modifier: Modifier = Modifier, onBackPressed: () -> Unit = {}, onRoomCreated: (RoomId) -> Unit = {}, - analyticsService: AnalyticsService? = null, ) { - analyticsService?.let { - LaunchedEffect(Unit) { - it.screen(MobileScreen(screenName = MobileScreen.ScreenName.CreateRoom)) - } - } - val coroutineScope = rememberCoroutineScope() val focusManager = LocalFocusManager.current val itemActionsBottomSheetState = rememberModalBottomSheetState( diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootNode.kt index df6e6cc8a7..4089be0fa2 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootNode.kt @@ -20,12 +20,14 @@ import android.content.Context import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import com.bumble.appyx.core.lifecycle.subscribe import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.core.plugin.plugins import dagger.assisted.Assisted import dagger.assisted.AssistedInject +import im.vector.app.features.analytics.plan.MobileScreen import io.element.android.anvilannotations.ContributesNode import io.element.android.libraries.androidutils.system.startSharePlainTextIntent import io.element.android.libraries.core.meta.BuildMeta @@ -62,6 +64,12 @@ class CreateRoomRootNode @AssistedInject constructor( } } + init { + lifecycle.subscribe( + onResume = { analyticsService.screen(MobileScreen(screenName = MobileScreen.ScreenName.StartChat)) } + ) + } + @Composable override fun View(modifier: Modifier) { val state = presenter.present() @@ -73,7 +81,6 @@ class CreateRoomRootNode @AssistedInject constructor( onNewRoomClicked = callback::onCreateNewRoom, onOpenDM = callback::onStartChatSuccess, onInviteFriendsClicked = { invitePeople(context) }, - analyticsService = analyticsService, ) } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt index a4b5b48511..05dd8d04fb 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt @@ -41,7 +41,6 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import im.vector.app.features.analytics.plan.MobileScreen import io.element.android.features.createroom.impl.R import io.element.android.features.createroom.impl.components.UserListView import io.element.android.libraries.architecture.Async @@ -55,7 +54,6 @@ 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.matrix.api.core.RoomId -import io.element.android.services.analytics.api.AnalyticsService import io.element.android.libraries.designsystem.R as DrawableR import io.element.android.libraries.ui.strings.R as StringR @@ -68,14 +66,7 @@ fun CreateRoomRootView( onNewRoomClicked: () -> Unit = {}, onOpenDM: (RoomId) -> Unit = {}, onInviteFriendsClicked: () -> Unit = {}, - analyticsService: AnalyticsService? = null, ) { - analyticsService?.let { - LaunchedEffect(Unit) { - it.screen(MobileScreen(screenName = MobileScreen.ScreenName.StartChat)) - } - } - if (state.startDmAction is Async.Success) { LaunchedEffect(state.startDmAction) { onOpenDM(state.startDmAction.state)