From d6d8e11a1165c9bfdf14e788e6687ef2d96abb62 Mon Sep 17 00:00:00 2001 From: Yamil Medina Date: Thu, 12 Sep 2024 07:03:31 +0000 Subject: [PATCH 1/2] Commit with unresolved merge conflicts outside of submodules --- .../kotlin/com/wire/android/di/AppModule.kt | 5 + .../home/conversations/ConversationScreen.kt | 43 +++-- .../sendmessage/SendMessageViewModel.kt | 42 +++++ .../conversationslist/ConversationRouter.kt | 3 + .../backup/BackupAndRestoreViewModel.kt | 11 ++ .../SendMessageViewModelArrangement.kt | 7 +- .../sendmessage/SendMessageViewModelTest.kt | 110 +++++++++++ .../feature/analytics/model/AnalyticsEvent.kt | 173 +++++++++++++++++- 8 files changed, 375 insertions(+), 19 deletions(-) diff --git a/app/src/main/kotlin/com/wire/android/di/AppModule.kt b/app/src/main/kotlin/com/wire/android/di/AppModule.kt index 868ef9db4ae..82aed26f4ee 100644 --- a/app/src/main/kotlin/com/wire/android/di/AppModule.kt +++ b/app/src/main/kotlin/com/wire/android/di/AppModule.kt @@ -25,6 +25,8 @@ import android.media.AudioAttributes import android.media.MediaPlayer import androidx.core.app.NotificationManagerCompat import com.wire.android.BuildConfig +import com.wire.android.feature.analytics.AnonymousAnalyticsManager +import com.wire.android.feature.analytics.AnonymousAnalyticsManagerImpl import com.wire.android.mapper.MessageResourceProvider import com.wire.android.ui.analytics.AnalyticsConfiguration import com.wire.android.ui.home.appLock.CurrentTimestampProvider @@ -95,4 +97,7 @@ object AppModule { @Provides fun provideAnalyticsConfiguration() = if (BuildConfig.ANALYTICS_ENABLED) AnalyticsConfiguration.Enabled else AnalyticsConfiguration.Disabled + + @Provides + fun provideAnonymousAnalyticsManager(): AnonymousAnalyticsManager = AnonymousAnalyticsManagerImpl } diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/ConversationScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/ConversationScreen.kt index 09c28968e9b..ee7ce2834df 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/ConversationScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/ConversationScreen.kt @@ -80,9 +80,14 @@ import com.ramcosta.composedestinations.result.ResultBackNavigator import com.ramcosta.composedestinations.result.ResultRecipient import com.wire.android.R import com.wire.android.appLogger +<<<<<<< HEAD import com.wire.android.feature.sketch.destinations.DrawingCanvasScreenDestination import com.wire.android.feature.sketch.model.DrawingCanvasNavArgs import com.wire.android.feature.sketch.model.DrawingCanvasNavBackArgs +======= +import com.wire.android.feature.analytics.AnonymousAnalyticsManagerImpl +import com.wire.android.feature.analytics.model.AnalyticsEvent +>>>>>>> 7a6f0681c (feat: add analytics initial events (WPB-10589) (#3428)) import com.wire.android.mapper.MessageDateTimeGroup import com.wire.android.media.audiomessage.AudioState import com.wire.android.model.Clickable @@ -309,6 +314,7 @@ fun ConversationScreen( getOngoingCallIntent(activity, it.toString()).run { activity.startActivity(this) } + AnonymousAnalyticsManagerImpl.sendEvent(event = AnalyticsEvent.CallJoined()) } } ) @@ -322,6 +328,7 @@ fun ConversationScreen( getOutgoingCallIntent(activity, conversationListCallViewModel.conversationId.toString()).run { activity.startActivity(this) } + AnonymousAnalyticsManagerImpl.sendEvent(event = AnalyticsEvent.CallJoined()) } showDialog.value = ConversationScreenDialogType.NONE }, onDialogDismiss = { @@ -348,12 +355,13 @@ fun ConversationScreen( getOutgoingCallIntent(activity, it.toString()).run { activity.startActivity(this) } + }, + onOpenOngoingCallScreen = { + getOngoingCallIntent(activity, it.toString()).run { + activity.startActivity(this) + } } - ) { - getOngoingCallIntent(activity, it.toString()).run { - activity.startActivity(this) - } - } + ) }, onDialogDismiss = { showDialog.value = ConversationScreenDialogType.NONE @@ -393,12 +401,13 @@ fun ConversationScreen( getOutgoingCallIntent(activity, it.toString()).run { activity.startActivity(this) } + }, + onOpenOngoingCallScreen = { + getOngoingCallIntent(activity, it.toString()).run { + activity.startActivity(this) + } } - ) { - getOngoingCallIntent(activity, it.toString()).run { - activity.startActivity(this) - } - } + ) }, onDialogDismiss = { showDialog.value = ConversationScreenDialogType.NONE } ) @@ -477,15 +486,17 @@ fun ConversationScreen( getOutgoingCallIntent(activity, it.toString()).run { activity.startActivity(this) } + }, + onOpenOngoingCallScreen = { + getOngoingCallIntent(activity, it.toString()).run { + activity.startActivity(this) + } } - ) { - getOngoingCallIntent(activity, it.toString()).run { - activity.startActivity(this) - } - } + ) }, onJoinCall = { conversationListCallViewModel.joinOngoingCall { + AnonymousAnalyticsManagerImpl.sendEvent(event = AnalyticsEvent.CallJoined()) getOngoingCallIntent(activity, it.toString()).run { activity.startActivity(this) } @@ -743,6 +754,7 @@ private fun startCallIfPossible( } else { conversationListCallViewModel.endEstablishedCallIfAny { onOpenOutgoingCallScreen(conversationListCallViewModel.conversationId) + AnonymousAnalyticsManagerImpl.sendEvent(event = AnalyticsEvent.CallInitiated()) } ConversationScreenDialogType.NONE } @@ -750,6 +762,7 @@ private fun startCallIfPossible( ConferenceCallingResult.Disabled.Established -> { onOpenOngoingCallScreen(conversationListCallViewModel.conversationId) + AnonymousAnalyticsManagerImpl.sendEvent(event = AnalyticsEvent.CallJoined()) ConversationScreenDialogType.NONE } diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/sendmessage/SendMessageViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/sendmessage/SendMessageViewModel.kt index a8cfac343cc..cdb58847461 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/sendmessage/SendMessageViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/sendmessage/SendMessageViewModel.kt @@ -25,6 +25,8 @@ import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope import com.wire.android.R import com.wire.android.appLogger +import com.wire.android.feature.analytics.AnonymousAnalyticsManager +import com.wire.android.feature.analytics.model.AnalyticsEvent import com.wire.android.media.PingRinger import com.wire.android.model.SnackBarMessage import com.wire.android.navigation.SavedStateViewModel @@ -65,6 +67,7 @@ import com.wire.kalium.logic.feature.message.SendTextMessageUseCase import com.wire.kalium.logic.feature.message.draft.RemoveMessageDraftUseCase import com.wire.kalium.logic.functional.Either import com.wire.kalium.logic.functional.onFailure +import com.wire.kalium.logic.functional.onSuccess import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableSharedFlow @@ -96,6 +99,7 @@ class SendMessageViewModel @Inject constructor( private val observeConversationUnderLegalHoldNotified: ObserveConversationUnderLegalHoldNotifiedUseCase, private val sendLocation: SendLocationUseCase, private val removeMessageDraft: RemoveMessageDraftUseCase, + private val analyticsManager: AnonymousAnalyticsManager ) : SavedStateViewModel(savedStateHandle) { private val conversationNavArgs: ConversationNavArgs = savedStateHandle.navArgs() @@ -199,6 +203,7 @@ class SendMessageViewModel @Inject constructor( mentions = newMentions.map { it.intoMessageMention() }, ) .handleLegalHoldFailureAfterSendingMessage(conversationId) + .handleNonAssetContributionEvent(messageBundle) } } @@ -231,6 +236,7 @@ class SendMessageViewModel @Inject constructor( quotedMessageId = quotedMessageId ) .handleLegalHoldFailureAfterSendingMessage(conversationId) + .handleNonAssetContributionEvent(messageBundle) } } @@ -238,6 +244,7 @@ class SendMessageViewModel @Inject constructor( with(messageBundle) { sendLocation(conversationId, location.latitude.toFloat(), location.longitude.toFloat(), locationName, zoom) .handleLegalHoldFailureAfterSendingMessage(conversationId) + .handleNonAssetContributionEvent(messageBundle) } } @@ -245,6 +252,7 @@ class SendMessageViewModel @Inject constructor( pingRinger.ping(R.raw.ping_from_me, isReceivingPing = false) sendKnock(conversationId = messageBundle.conversationId, hotKnock = false) .handleLegalHoldFailureAfterSendingMessage(messageBundle.conversationId) + .handleNonAssetContributionEvent(messageBundle) } } } @@ -297,6 +305,7 @@ class SendMessageViewModel @Inject constructor( audioLengthInMs = 0L ) .handleLegalHoldFailureAfterSendingMessage(conversationId) + .handleAssetContributionEvent(assetType) } AttachmentType.VIDEO, @@ -317,6 +326,7 @@ class SendMessageViewModel @Inject constructor( ) ) .handleLegalHoldFailureAfterSendingMessage(conversationId) + .handleAssetContributionEvent(assetType) } catch (e: OutOfMemoryError) { appLogger.e("There was an OutOfMemory error while uploading the asset") onSnackbarMessage(ConversationSnackbarMessages.ErrorSendingAsset) @@ -328,6 +338,37 @@ class SendMessageViewModel @Inject constructor( } } + private fun Either.handleAssetContributionEvent( + assetType: AttachmentType + ) = also { + onSuccess { + val event = when (assetType) { + AttachmentType.IMAGE -> AnalyticsEvent.Contributed.Photo() + AttachmentType.VIDEO -> AnalyticsEvent.Contributed.Video() + AttachmentType.GENERIC_FILE -> AnalyticsEvent.Contributed.File() + AttachmentType.AUDIO -> AnalyticsEvent.Contributed.Audio() + } + analyticsManager.sendEvent(event) + } + } + + private fun Either.handleNonAssetContributionEvent(messageBundle: MessageBundle) = also { + onSuccess { + val event = when (messageBundle) { + // assets are not handled here, as they need extra processing + is ComposableMessageBundle.UriPickedBundle, + is ComposableMessageBundle.AudioMessageBundle, + is ComposableMessageBundle.AttachmentPickedBundle -> return@also + + is ComposableMessageBundle.LocationBundle -> AnalyticsEvent.Contributed.Location() + is Ping -> AnalyticsEvent.Contributed.Ping() + is ComposableMessageBundle.EditMessageBundle, + is ComposableMessageBundle.SendTextMessageBundle -> AnalyticsEvent.Contributed.Text() + } + analyticsManager.sendEvent(event) + } + } + private fun CoreFailure.handleLegalHoldFailureAfterSendingMessage(conversationId: ConversationId) = also { if (this is LegalHoldEnabledForConversationFailure) { sureAboutMessagingDialogState = when (val currentState = sureAboutMessagingDialogState) { @@ -419,6 +460,7 @@ class SendMessageViewModel @Inject constructor( } sureAboutMessagingDialogState = SureAboutMessagingDialogState.Hidden } + private companion object { const val MAX_LIMIT_MESSAGE_SEND = 20 } diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversationslist/ConversationRouter.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversationslist/ConversationRouter.kt index bec58e79a88..1514eab0c22 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversationslist/ConversationRouter.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversationslist/ConversationRouter.kt @@ -28,6 +28,8 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.hilt.navigation.compose.hiltViewModel import com.wire.android.R +import com.wire.android.feature.analytics.AnonymousAnalyticsManagerImpl +import com.wire.android.feature.analytics.model.AnalyticsEvent import com.wire.android.navigation.NavigationCommand import com.wire.android.navigation.Navigator import com.wire.android.ui.LocalActivity @@ -151,6 +153,7 @@ fun ConversationRouterHomeBridge( } val onJoinedCall: (ConversationId) -> Unit = remember(navigator) { { + AnonymousAnalyticsManagerImpl.sendEvent(event = AnalyticsEvent.CallJoined()) getOngoingCallIntent(activity, it.toString()).run { activity.startActivity(this) } diff --git a/app/src/main/kotlin/com/wire/android/ui/home/settings/backup/BackupAndRestoreViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/home/settings/backup/BackupAndRestoreViewModel.kt index 588255ecb98..14e423ea9bd 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/settings/backup/BackupAndRestoreViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/settings/backup/BackupAndRestoreViewModel.kt @@ -30,6 +30,8 @@ import androidx.lifecycle.viewModelScope import com.wire.android.BuildConfig import com.wire.android.appLogger import com.wire.android.datastore.UserDataStore +import com.wire.android.feature.analytics.AnonymousAnalyticsManagerImpl +import com.wire.android.feature.analytics.model.AnalyticsEvent import com.wire.android.ui.common.textfield.textAsFlow import com.wire.android.util.FileManager import com.wire.android.util.dispatchers.DispatcherProvider @@ -124,6 +126,7 @@ class BackupAndRestoreViewModel is CreateBackupResult.Failure -> { state = state.copy(backupCreationProgress = BackupCreationProgress.Failed) appLogger.e("Failed to create backup: ${result.coreFailure}") + AnonymousAnalyticsManagerImpl.sendEvent(event = AnalyticsEvent.BackupExportFailed()) } } } @@ -185,6 +188,7 @@ class BackupAndRestoreViewModel importDatabase(importedBackupPath) } else { state = state.copy(restoreFileValidation = RestoreFileValidation.IncompatibleBackup) + AnonymousAnalyticsManagerImpl.sendEvent(event = AnalyticsEvent.BackupRestoreFailed()) } } } @@ -196,6 +200,8 @@ class BackupAndRestoreViewModel is VerifyBackupResult.Failure.Generic -> result.error.toString() VerifyBackupResult.Failure.InvalidBackupFile -> "No valid files found in the backup" } + + AnonymousAnalyticsManagerImpl.sendEvent(event = AnalyticsEvent.BackupRestoreFailed()) appLogger.e("Failed to extract backup files: $errorMessage") } } @@ -211,6 +217,7 @@ class BackupAndRestoreViewModel updateCreationProgress(PROGRESS_75) delay(SMALL_DELAY) state = state.copy(backupRestoreProgress = BackupRestoreProgress.Finished) + AnonymousAnalyticsManagerImpl.sendEvent(event = AnalyticsEvent.BackupRestoreSucceeded()) } is RestoreBackupResult.Failure -> { @@ -222,6 +229,7 @@ class BackupAndRestoreViewModel restoreFileValidation = RestoreFileValidation.IncompatibleBackup, backupRestoreProgress = BackupRestoreProgress.Failed ) + AnonymousAnalyticsManagerImpl.sendEvent(event = AnalyticsEvent.BackupRestoreFailed()) } } } @@ -242,14 +250,17 @@ class BackupAndRestoreViewModel restorePasswordValidation = PasswordValidation.Valid ) restoreBackupPasswordState.clearText() + AnonymousAnalyticsManagerImpl.sendEvent(event = AnalyticsEvent.BackupRestoreSucceeded()) } is RestoreBackupResult.Failure -> { mapBackupRestoreFailure(result.failure) + AnonymousAnalyticsManagerImpl.sendEvent(event = AnalyticsEvent.BackupRestoreFailed()) } } } else { state = state.copy(backupRestoreProgress = BackupRestoreProgress.Failed) + AnonymousAnalyticsManagerImpl.sendEvent(event = AnalyticsEvent.BackupRestoreFailed()) } } diff --git a/app/src/test/kotlin/com/wire/android/ui/home/conversations/sendmessage/SendMessageViewModelArrangement.kt b/app/src/test/kotlin/com/wire/android/ui/home/conversations/sendmessage/SendMessageViewModelArrangement.kt index 7c76c87b89e..d7f37d8b074 100644 --- a/app/src/test/kotlin/com/wire/android/ui/home/conversations/sendmessage/SendMessageViewModelArrangement.kt +++ b/app/src/test/kotlin/com/wire/android/ui/home/conversations/sendmessage/SendMessageViewModelArrangement.kt @@ -21,6 +21,7 @@ package com.wire.android.ui.home.conversations.sendmessage import androidx.lifecycle.SavedStateHandle import com.wire.android.config.TestDispatcherProvider import com.wire.android.config.mockUri +import com.wire.android.feature.analytics.AnonymousAnalyticsManager import com.wire.android.framework.FakeKaliumFileSystem import com.wire.android.media.PingRinger import com.wire.android.ui.home.conversations.ConversationNavArgs @@ -139,6 +140,9 @@ internal class SendMessageViewModelArrangement { private val fakeKaliumFileSystem = FakeKaliumFileSystem() + @MockK + lateinit var analyticsManager: AnonymousAnalyticsManager + private val viewModel by lazy { SendMessageViewModel( sendTextMessage = sendTextMessage, @@ -158,7 +162,8 @@ internal class SendMessageViewModelArrangement { observeConversationUnderLegalHoldNotified = observeConversationUnderLegalHoldNotified, sendLocation = sendLocation, removeMessageDraft = removeMessageDraftUseCase, - savedStateHandle = savedStateHandle + savedStateHandle = savedStateHandle, + analyticsManager = analyticsManager ) } diff --git a/app/src/test/kotlin/com/wire/android/ui/home/conversations/sendmessage/SendMessageViewModelTest.kt b/app/src/test/kotlin/com/wire/android/ui/home/conversations/sendmessage/SendMessageViewModelTest.kt index a962760a65b..77e3bf716b4 100644 --- a/app/src/test/kotlin/com/wire/android/ui/home/conversations/sendmessage/SendMessageViewModelTest.kt +++ b/app/src/test/kotlin/com/wire/android/ui/home/conversations/sendmessage/SendMessageViewModelTest.kt @@ -23,6 +23,7 @@ import androidx.core.net.toUri import app.cash.turbine.test import com.wire.android.config.CoroutineTestExtension import com.wire.android.config.NavigationTestExtension +import com.wire.android.feature.analytics.model.AnalyticsEvent import com.wire.android.ui.home.conversations.AssetTooLargeDialogState import com.wire.android.ui.home.conversations.ConversationSnackbarMessages import com.wire.android.ui.home.conversations.SureAboutMessagingDialogState @@ -86,6 +87,14 @@ class SendMessageViewModelTest { any() ) } + + verify(exactly = 1) { + arrangement.analyticsManager.sendEvent( + match { + it is AnalyticsEvent.Contributed.File + } + ) + } } @Test @@ -123,6 +132,14 @@ class SendMessageViewModelTest { any() ) } + + verify(exactly = 1) { + arrangement.analyticsManager.sendEvent( + match { + it is AnalyticsEvent.Contributed.Photo + } + ) + } } @Test @@ -150,6 +167,10 @@ class SendMessageViewModelTest { any() ) } + + verify(exactly = 0) { + arrangement.analyticsManager.sendEvent(any()) + } } @Test @@ -192,6 +213,9 @@ class SendMessageViewModelTest { ) } assert(viewModel.assetTooLargeDialogState is AssetTooLargeDialogState.Visible) + verify(exactly = 0) { + arrangement.analyticsManager.sendEvent(any()) + } } @Test @@ -234,6 +258,9 @@ class SendMessageViewModelTest { ) } assert(viewModel.assetTooLargeDialogState is AssetTooLargeDialogState.Visible) + verify(exactly = 0) { + arrangement.analyticsManager.sendEvent(any()) + } } @Test @@ -268,6 +295,9 @@ class SendMessageViewModelTest { ) } assertEquals(ConversationSnackbarMessages.ErrorPickingAttachment, awaitItem()) + verify(exactly = 0) { + arrangement.analyticsManager.sendEvent(any()) + } } } @@ -287,6 +317,13 @@ class SendMessageViewModelTest { // Then coVerify(exactly = 1) { arrangement.sendKnockUseCase.invoke(any(), any()) } verify(exactly = 1) { arrangement.pingRinger.ping(any(), isReceivingPing = false) } + verify(exactly = 1) { + arrangement.analyticsManager.sendEvent( + match { + it is AnalyticsEvent.Contributed.Ping + } + ) + } } @Test @@ -324,6 +361,13 @@ class SendMessageViewModelTest { any() ) } + verify(exactly = 1) { + arrangement.analyticsManager.sendEvent( + match { + it is AnalyticsEvent.Contributed.Audio + } + ) + } } @Test @@ -355,6 +399,13 @@ class SendMessageViewModelTest { coVerify(exactly = 1) { arrangement.removeMessageDraftUseCase.invoke(any()) } + verify(exactly = 1) { + arrangement.analyticsManager.sendEvent( + match { + it is AnalyticsEvent.Contributed.Text + } + ) + } } @Test @@ -395,6 +446,13 @@ class SendMessageViewModelTest { coVerify(exactly = 1) { arrangement.removeMessageDraftUseCase.invoke(any()) } + verify(exactly = 1) { + arrangement.analyticsManager.sendEvent( + match { + it is AnalyticsEvent.Contributed.Text + } + ) + } } @Test @@ -423,6 +481,9 @@ class SendMessageViewModelTest { SureAboutMessagingDialogState.Visible.ConversationVerificationDegraded(conversationId, listOf(messageBundle)), viewModel.sureAboutMessagingDialogState ) + verify(exactly = 0) { + arrangement.analyticsManager.sendEvent(any()) + } } @Test @@ -442,6 +503,9 @@ class SendMessageViewModelTest { SureAboutMessagingDialogState.Visible.ConversationUnderLegalHold.BeforeSending(conversationId, listOf(messageBundle)), viewModel.sureAboutMessagingDialogState ) + verify(exactly = 0) { + arrangement.analyticsManager.sendEvent(any()) + } } @Test @@ -461,6 +525,9 @@ class SendMessageViewModelTest { // then coVerify(exactly = 0) { arrangement.sendTextMessage.invoke(any(), any(), any(), any()) } assertEquals(SureAboutMessagingDialogState.Hidden, viewModel.sureAboutMessagingDialogState) + verify(exactly = 0) { + arrangement.analyticsManager.sendEvent(any()) + } } @Test @@ -481,6 +548,13 @@ class SendMessageViewModelTest { // then coVerify(exactly = 1) { arrangement.sendTextMessage.invoke(any(), any(), any(), any()) } assertEquals(SureAboutMessagingDialogState.Hidden, viewModel.sureAboutMessagingDialogState) + verify(exactly = 1) { + arrangement.analyticsManager.sendEvent( + match { + it is AnalyticsEvent.Contributed.Text + } + ) + } } @Test @@ -501,6 +575,9 @@ class SendMessageViewModelTest { SureAboutMessagingDialogState.Visible.ConversationUnderLegalHold.AfterSending(conversationId, listOf(messageId)), viewModel.sureAboutMessagingDialogState ) + verify(exactly = 0) { + arrangement.analyticsManager.sendEvent(any()) + } } @Test @@ -521,6 +598,9 @@ class SendMessageViewModelTest { // then coVerify(exactly = 0) { arrangement.retryFailedMessageUseCase.invoke(any(), any()) } assertEquals(SureAboutMessagingDialogState.Hidden, viewModel.sureAboutMessagingDialogState) + verify(exactly = 0) { + arrangement.analyticsManager.sendEvent(any()) + } } @Test @@ -541,6 +621,13 @@ class SendMessageViewModelTest { // then coVerify(exactly = 1) { arrangement.retryFailedMessageUseCase.invoke(eq(messageId), any()) } assertEquals(SureAboutMessagingDialogState.Hidden, viewModel.sureAboutMessagingDialogState) + verify(exactly = 0) { + arrangement.analyticsManager.sendEvent( + match { + it is AnalyticsEvent.Contributed.Text + } + ) + } } @Test @@ -563,6 +650,13 @@ class SendMessageViewModelTest { // then coVerify(exactly = 1) { arrangement.sendLocation.invoke(any(), any(), any(), any(), any()) } assertEquals(SureAboutMessagingDialogState.Hidden, viewModel.sureAboutMessagingDialogState) + verify(exactly = 1) { + arrangement.analyticsManager.sendEvent( + match { + it is AnalyticsEvent.Contributed.Location + } + ) + } } @Test @@ -602,6 +696,9 @@ class SendMessageViewModelTest { ) } assertEquals(ConversationSnackbarMessages.ErrorAssetRestriction, awaitItem()) + verify(exactly = 0) { + arrangement.analyticsManager.sendEvent(any()) + } } } @@ -646,6 +743,9 @@ class SendMessageViewModelTest { ) } assertEquals(ConversationSnackbarMessages.ErrorAssetRestriction, awaitItem()) + verify(exactly = 0) { + arrangement.analyticsManager.sendEvent(any()) + } } } @@ -659,6 +759,13 @@ class SendMessageViewModelTest { .arrange() coVerify { arrangement.sendTextMessage(any(), eq(textToShare), any(), any()) } + verify(exactly = 1) { + arrangement.analyticsManager.sendEvent( + match { + it is AnalyticsEvent.Contributed.Text + } + ) + } } @Test @@ -701,6 +808,9 @@ class SendMessageViewModelTest { any() ) } + verify { + arrangement.analyticsManager.sendEvent(any()) + } } } diff --git a/core/analytics/src/main/kotlin/com/wire/android/feature/analytics/model/AnalyticsEvent.kt b/core/analytics/src/main/kotlin/com/wire/android/feature/analytics/model/AnalyticsEvent.kt index d1f60fd31f0..2953ab5ae9b 100644 --- a/core/analytics/src/main/kotlin/com/wire/android/feature/analytics/model/AnalyticsEvent.kt +++ b/core/analytics/src/main/kotlin/com/wire/android/feature/analytics/model/AnalyticsEvent.kt @@ -17,6 +17,9 @@ */ package com.wire.android.feature.analytics.model +import com.wire.android.feature.analytics.model.AnalyticsEventConstants.CONTRIBUTED_LOCATION +import com.wire.android.feature.analytics.model.AnalyticsEventConstants.MESSAGE_ACTION_KEY + interface AnalyticsEvent { /** * Key to be used to differentiate every event @@ -42,12 +45,146 @@ interface AnalyticsEvent { * } * } */ - fun toSegmentation(): Map + fun toSegmentation(): Map = mapOf() data class AppOpen( override val key: String = AnalyticsEventConstants.APP_OPEN - ) : AnalyticsEvent { - override fun toSegmentation(): Map = mapOf() + ) : AnalyticsEvent + + /** + * Calling + */ + data class CallInitiated( + override val key: String = AnalyticsEventConstants.CALLING_INITIATED + ) : AnalyticsEvent + + data class CallJoined( + override val key: String = AnalyticsEventConstants.CALLING_JOINED + ) : AnalyticsEvent + + /** + * Backup + */ + data class BackupExportFailed( + override val key: String = AnalyticsEventConstants.BACKUP_EXPORT_FAILED + ) : AnalyticsEvent + + data class BackupRestoreSucceeded( + override val key: String = AnalyticsEventConstants.BACKUP_RESTORE_SUCCEEDED + ) : AnalyticsEvent + + data class BackupRestoreFailed( + override val key: String = AnalyticsEventConstants.BACKUP_RESTORE_FAILED + ) : AnalyticsEvent + + /** + * Contributed, message action related + */ + sealed interface Contributed : AnalyticsEvent { + override val key: String + get() = AnalyticsEventConstants.CONTRIBUTED + + val messageAction: String + + data class Location( + override val messageAction: String = CONTRIBUTED_LOCATION + ) : Contributed { + override fun toSegmentation(): Map { + return mapOf( + MESSAGE_ACTION_KEY to messageAction + ) + } + } + + data class Text( + override val messageAction: String = AnalyticsEventConstants.CONTRIBUTED_TEXT + ) : Contributed { + override fun toSegmentation(): Map { + return mapOf( + MESSAGE_ACTION_KEY to messageAction + ) + } + } + + data class Photo( + override val messageAction: String = AnalyticsEventConstants.CONTRIBUTED_PHOTO + ) : Contributed { + override fun toSegmentation(): Map { + return mapOf( + MESSAGE_ACTION_KEY to messageAction + ) + } + } + + data class AudioCall( + override val messageAction: String = AnalyticsEventConstants.CONTRIBUTED_AUDIO_CALL + ) : Contributed { + override fun toSegmentation(): Map { + return mapOf( + MESSAGE_ACTION_KEY to messageAction + ) + } + } + + data class VideoCall( + override val messageAction: String = AnalyticsEventConstants.CONTRIBUTED_VIDEO_CALL + ) : Contributed { + override fun toSegmentation(): Map { + return mapOf( + MESSAGE_ACTION_KEY to messageAction + ) + } + } + + data class Gif( + override val messageAction: String = AnalyticsEventConstants.CONTRIBUTED_GIF + ) : Contributed { + override fun toSegmentation(): Map { + return mapOf( + MESSAGE_ACTION_KEY to messageAction + ) + } + } + + data class Ping( + override val messageAction: String = AnalyticsEventConstants.CONTRIBUTED_PING + ) : Contributed { + override fun toSegmentation(): Map { + return mapOf( + MESSAGE_ACTION_KEY to messageAction + ) + } + } + + data class File( + override val messageAction: String = AnalyticsEventConstants.CONTRIBUTED_FILE + ) : Contributed { + override fun toSegmentation(): Map { + return mapOf( + MESSAGE_ACTION_KEY to messageAction + ) + } + } + + data class Video( + override val messageAction: String = AnalyticsEventConstants.CONTRIBUTED_VIDEO + ) : Contributed { + override fun toSegmentation(): Map { + return mapOf( + MESSAGE_ACTION_KEY to messageAction + ) + } + } + + data class Audio( + override val messageAction: String = AnalyticsEventConstants.CONTRIBUTED_AUDIO + ) : Contributed { + override fun toSegmentation(): Map { + return mapOf( + MESSAGE_ACTION_KEY to messageAction + ) + } + } } } @@ -57,4 +194,34 @@ object AnalyticsEventConstants { const val APP_VERSION = "app_version" const val TEAM_IS_TEAM = "team_is_team" const val APP_OPEN = "app.open" + + /** + * Calling + */ + const val CALLING_INITIATED = "calling.initiated_call" + const val CALLING_JOINED = "calling.joined_call" + + /** + * Backup + */ + const val BACKUP_EXPORT_FAILED = "backup.export_failed" + const val BACKUP_RESTORE_SUCCEEDED = "backup.restore_succeeded" + const val BACKUP_RESTORE_FAILED = "backup.restore_failed" + + /** + * Contributed, message related + */ + const val CONTRIBUTED = "contributed" + const val MESSAGE_ACTION_KEY = "message_action" + + const val CONTRIBUTED_TEXT = "text" + const val CONTRIBUTED_PHOTO = "photo" + const val CONTRIBUTED_AUDIO_CALL = "audio_call" + const val CONTRIBUTED_VIDEO_CALL = "video_call" + const val CONTRIBUTED_GIF = "giphy" + const val CONTRIBUTED_PING = "ping" + const val CONTRIBUTED_FILE = "file" + const val CONTRIBUTED_VIDEO = "video" + const val CONTRIBUTED_AUDIO = "audio" + const val CONTRIBUTED_LOCATION = "location" } From e8de9057300e3d60f4c826f238f04553e6e7b120 Mon Sep 17 00:00:00 2001 From: alexandreferris Date: Thu, 12 Sep 2024 09:39:00 +0200 Subject: [PATCH 2/2] fix: merge conflicts Signed-off-by: alexandreferris --- .../wire/android/ui/home/conversations/ConversationScreen.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/ConversationScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/ConversationScreen.kt index ee7ce2834df..98b70758fdb 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/ConversationScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/ConversationScreen.kt @@ -80,14 +80,11 @@ import com.ramcosta.composedestinations.result.ResultBackNavigator import com.ramcosta.composedestinations.result.ResultRecipient import com.wire.android.R import com.wire.android.appLogger -<<<<<<< HEAD import com.wire.android.feature.sketch.destinations.DrawingCanvasScreenDestination import com.wire.android.feature.sketch.model.DrawingCanvasNavArgs import com.wire.android.feature.sketch.model.DrawingCanvasNavBackArgs -======= import com.wire.android.feature.analytics.AnonymousAnalyticsManagerImpl import com.wire.android.feature.analytics.model.AnalyticsEvent ->>>>>>> 7a6f0681c (feat: add analytics initial events (WPB-10589) (#3428)) import com.wire.android.mapper.MessageDateTimeGroup import com.wire.android.media.audiomessage.AudioState import com.wire.android.model.Clickable