1
0
Fork 0
mirror of https://github.com/anyproto/anytype-kotlin.git synced 2025-06-08 05:47:05 +09:00

DROID-796 | Added library analytics (#2995)

DROID-796 Library | Enhancement | Added library analytics
This commit is contained in:
Allan Quatermain 2023-03-10 13:56:13 +03:00 committed by GitHub
parent c8cabb84c1
commit 9a68347cbe
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 122 additions and 25 deletions

View file

@ -115,12 +115,18 @@ object EventsDictionary {
const val goBack = "HistoryBack"
const val bookmarkOpenUrl = "BlockBookmarkOpenUrl"
//Toolbars
// Toolbars
const val slashMenu = "KeyboardBarSlashMenu"
const val styleMenu = "KeyboardBarStyleMenu"
const val selectionMenu = "KeyboardBarSelectionMenu"
const val mentionMenu = "KeyboardBarMentionMenu"
// Library
const val libraryView = "LibraryView"
const val libraryScreenType = "ScreenType"
const val libraryScreenRelation = "ScreenRelation"
const val librarySetTypeName = "SetTypeName"
const val libraryCreateType = "CreateType"
// Routes
object Routes {

View file

@ -41,6 +41,7 @@ class AmplitudeTracker(
renderTime = event.duration?.render
)
tracker.logEvent(event.name, props)
Timber.d("Analytics Amplitude(event = $event)")
}
}
}

View file

@ -2,6 +2,7 @@ package com.anytypeio.anytype.di.feature.library
import android.content.Context
import androidx.lifecycle.ViewModelProvider
import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.core_utils.di.scope.PerScreen
import com.anytypeio.anytype.di.common.ComponentDependencies
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
@ -193,4 +194,6 @@ interface LibraryDependencies : ComponentDependencies {
fun channel(): SubscriptionEventChannel
fun dispatchers(): AppCoroutineDispatchers
fun userSettingsRepository(): UserSettingsRepository
fun analytics(): Analytics
}

View file

@ -1,6 +1,7 @@
package com.anytypeio.anytype.di.feature.types
import androidx.lifecycle.ViewModelProvider
import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.core_utils.di.scope.PerScreen
import com.anytypeio.anytype.di.common.ComponentDependencies
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
@ -65,4 +66,5 @@ interface TypeCreationDependencies : ComponentDependencies {
fun blockRepository(): BlockRepository
fun dispatchers(): AppCoroutineDispatchers
fun urlBuilder(): UrlBuilder
fun analytics(): Analytics
}

View file

@ -1,7 +1,7 @@
package com.anytypeio.anytype.di.feature.types
import androidx.lifecycle.ViewModelProvider
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.core_utils.di.scope.PerScreen
import com.anytypeio.anytype.di.common.ComponentDependencies
import com.anytypeio.anytype.domain.block.repo.BlockRepository
@ -71,4 +71,5 @@ object TypeEditModule {
interface TypeEditDependencies : ComponentDependencies {
fun blockRepository(): BlockRepository
fun urlBuilder(): UrlBuilder
fun analytics(): Analytics
}

View file

@ -21,6 +21,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextLayoutResult
import androidx.compose.ui.unit.dp
import com.anytypeio.anytype.R
import com.anytypeio.anytype.presentation.library.LibraryEvent
import com.anytypeio.anytype.ui.library.LibraryConfiguration
import com.anytypeio.anytype.ui.library.LibraryScreenConfig
import com.anytypeio.anytype.ui.library.ScreenState
@ -36,7 +37,7 @@ fun LibraryTabs(
modifier: Modifier,
pagerState: PagerState,
configuration: LibraryConfiguration,
screenState: MutableState<ScreenState>,
screenState: MutableState<ScreenState>
) = WrapWithLibraryAnimation(visible = screenState.value.visible()) {
val coroutineScope = rememberCoroutineScope()

View file

@ -87,8 +87,22 @@ fun LibraryListTabsContent(
userScrollEnabled = screenState.value == ScreenState.CONTENT
) { index ->
val data = when (configuration[index]) {
is LibraryListConfig.Types, is LibraryListConfig.Relations -> tabs.my
is LibraryListConfig.TypesLibrary, is LibraryListConfig.RelationsLibrary -> tabs.lib
is LibraryListConfig.Types -> {
vmEventStream.invoke(LibraryEvent.Ui.ViewTypes)
tabs.my
}
is LibraryListConfig.Relations -> {
vmEventStream.invoke(LibraryEvent.Ui.ViewRelations)
tabs.my
}
is LibraryListConfig.TypesLibrary -> {
vmEventStream.invoke(LibraryEvent.Ui.ViewLibTypes)
tabs.lib
}
is LibraryListConfig.RelationsLibrary -> {
vmEventStream.invoke(LibraryEvent.Ui.ViewLibRelations)
tabs.lib
}
}
val itemsListState = rememberLazyListState()
Column(

View file

@ -4,8 +4,8 @@ sealed class LibraryEvent {
sealed class BottomMenu : LibraryEvent() {
class Back : BottomMenu()
class Search: BottomMenu()
class AddDoc: BottomMenu()
class Search : BottomMenu()
class AddDoc : BottomMenu()
}
sealed class Query(open val query: String) : LibraryEvent() {
@ -20,14 +20,26 @@ sealed class LibraryEvent {
class Relation(override val item: LibraryView) : ToggleInstall(item)
}
sealed class Type: LibraryEvent() {
sealed class Type : LibraryEvent() {
class Create(val name: String = "") : Type()
class Edit(val item: LibraryView.MyTypeView) : Type()
}
sealed class Relation: LibraryEvent() {
sealed class Relation : LibraryEvent() {
class Create(val name: String = "") : Relation()
class Edit(val item: LibraryView.MyRelationView) : Relation()
}
}
sealed class Ui(val type: String, val view: String) : LibraryEvent() {
object ViewTypes : Ui(type = TypeType, view = ViewYour)
object ViewRelations : Ui(type = TypeRelation, view = ViewYour)
object ViewLibTypes : Ui(type = TypeType, view = ViewLibrary)
object ViewLibRelations : Ui(type = TypeRelation, view = ViewLibrary)
}
}
private const val TypeType = "type"
private const val TypeRelation = "relation"
private const val ViewYour = "your"
private const val ViewLibrary = "library"

View file

@ -3,6 +3,12 @@ package com.anytypeio.anytype.presentation.library
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.analytics.base.EventsDictionary.libraryScreenRelation
import com.anytypeio.anytype.analytics.base.EventsDictionary.libraryScreenType
import com.anytypeio.anytype.analytics.base.EventsDictionary.libraryView
import com.anytypeio.anytype.analytics.base.sendEvent
import com.anytypeio.anytype.analytics.props.Props
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.core_utils.ext.orNull
@ -34,7 +40,8 @@ class LibraryViewModel(
private val removeObjectsFromWorkspace: RemoveObjectsFromWorkspace,
private val resourceManager: LibraryResourceManager,
private val setObjectDetails: SetObjectDetails,
private val createObject: CreateObject
private val createObject: CreateObject,
private val analytics: Analytics
) : NavigationViewModel<LibraryViewModel.Navigation>() {
private val uiEvents = MutableStateFlow<LibraryEvent>(LibraryEvent.Query.MyTypes(""))
@ -86,11 +93,25 @@ class LibraryViewModel(
is LibraryEvent.Type -> proceedWithTypeActions(it)
is LibraryEvent.Relation -> proceedWithRelationActions(it)
is LibraryEvent.BottomMenu -> proceedWithBottomMenuActions(it)
is LibraryEvent.Ui -> proceedWithViewAnalytics(it)
}
}
}
}
private fun proceedWithViewAnalytics(it: LibraryEvent.Ui) {
viewModelScope.sendEvent(
analytics = analytics,
eventName = libraryView,
props = Props(
mapOf(
"type" to it.type,
"view" to it.view
)
)
)
}
private fun proceedWithBottomMenuActions(it: LibraryEvent.BottomMenu) {
when (it) {
is LibraryEvent.BottomMenu.Back -> navigate(Navigation.Back())
@ -104,7 +125,7 @@ class LibraryViewModel(
createObject.execute(CreateObject.Param(type = null))
.fold(
onSuccess = { result ->
navigate(Navigation.CreateDoc(result.objectId))
navigate(Navigation.CreateDoc(result.objectId))
},
onFailure = { e -> Timber.e(e, "Error while creating a new page") }
)
@ -137,15 +158,35 @@ class LibraryViewModel(
private fun proceedWithTypeActions(event: LibraryEvent.Type) {
when (event) {
is LibraryEvent.Type.Create -> navigate(Navigation.OpenTypeCreation(event.name))
is LibraryEvent.Type.Edit -> navigate(Navigation.OpenTypeEditing(event.item))
is LibraryEvent.Type.Create -> {
navigate(Navigation.OpenTypeCreation(event.name))
}
is LibraryEvent.Type.Edit -> {
viewModelScope.sendEvent(
analytics = analytics,
eventName = libraryScreenType,
props = Props(
map = mapOf("objectType" to event.item.id)
)
)
navigate(Navigation.OpenTypeEditing(event.item))
}
}
}
private fun proceedWithRelationActions(event: LibraryEvent.Relation) {
when (event) {
is LibraryEvent.Relation.Create -> navigate(Navigation.OpenRelationCreation(event.name))
is LibraryEvent.Relation.Edit -> navigate(Navigation.OpenRelationEditing(event.item))
is LibraryEvent.Relation.Edit -> {
viewModelScope.sendEvent(
analytics = analytics,
eventName = libraryScreenRelation,
props = Props(
map = mapOf("relationKey" to event.item.id)
)
)
navigate(Navigation.OpenRelationEditing(event.item))
}
}
}
@ -308,7 +349,8 @@ class LibraryViewModel(
private val removeObjectsFromWorkspace: RemoveObjectsFromWorkspace,
private val resourceManager: LibraryResourceManager,
private val setObjectDetails: SetObjectDetails,
private val createObject: CreateObject
private val createObject: CreateObject,
private val analytics: Analytics
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
@ -321,7 +363,8 @@ class LibraryViewModel(
removeObjectsFromWorkspace,
resourceManager,
setObjectDetails,
createObject
createObject,
analytics
) as T
}
}
@ -345,9 +388,9 @@ class LibraryViewModel(
class Back : Navigation()
class Search: Navigation()
class Search : Navigation()
class CreateDoc(val id: Id): Navigation()
class CreateDoc(val id: Id) : Navigation()
}
sealed class Effect {

View file

@ -3,6 +3,9 @@ package com.anytypeio.anytype.presentation.types
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.analytics.base.EventsDictionary.libraryCreateType
import com.anytypeio.anytype.analytics.base.sendEvent
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.ObjectWrapper
@ -26,7 +29,8 @@ import timber.log.Timber
class TypeCreationViewModel(
private val createTypeInteractor: CreateType,
private val urlBuilder: UrlBuilder,
private val emojiProvider: EmojiProvider
private val emojiProvider: EmojiProvider,
private val analytics: Analytics
) : NavigationViewModel<TypeCreationViewModel.Navigation>() {
private val unicodeIconFlow = MutableStateFlow("")
@ -59,6 +63,7 @@ class TypeCreationViewModel(
)
).fold(
onSuccess = {
viewModelScope.sendEvent(analytics = analytics, eventName = libraryCreateType)
navigate(Navigation.BackWithCreatedType)
},
onFailure = {
@ -96,14 +101,16 @@ class TypeCreationViewModel(
class Factory @Inject constructor(
private val createType: CreateType,
private val urlBuilder: UrlBuilder,
private val emojiProvider: EmojiProvider
private val emojiProvider: EmojiProvider,
private val analytics: Analytics
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return TypeCreationViewModel(
createTypeInteractor = createType,
urlBuilder = urlBuilder,
emojiProvider = emojiProvider
emojiProvider = emojiProvider,
analytics = analytics
) as T
}
}

View file

@ -3,6 +3,9 @@ package com.anytypeio.anytype.presentation.types
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.analytics.base.EventsDictionary.librarySetTypeName
import com.anytypeio.anytype.analytics.base.sendEvent
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.ObjectWrapper
@ -23,7 +26,8 @@ class TypeEditViewModel(
private val urlBuilder: UrlBuilder,
private val id: Id,
private val name: String,
private val icon: String
private val icon: String,
private val analytics: Analytics
) : NavigationViewModel<TypeEditViewModel.Navigation>() {
private val unicodeIconFlow = MutableStateFlow(icon)
@ -68,6 +72,7 @@ class TypeEditViewModel(
}
fun updateObjectDetails(name: String) {
viewModelScope.sendEvent(analytics = analytics, eventName = librarySetTypeName)
navigate(Navigation.BackWithModify(id, name, unicodeIconFlow.value))
}
@ -86,7 +91,8 @@ class TypeEditViewModel(
private val urlBuilder: UrlBuilder,
@TypeId private val id: Id,
@TypeName private val name: String,
@TypeIcon private val icon: String
@TypeIcon private val icon: String,
private val analytics: Analytics
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
@ -94,7 +100,8 @@ class TypeEditViewModel(
urlBuilder = urlBuilder,
id = id,
name = name,
icon = icon
icon = icon,
analytics = analytics
) as T
}
}