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

DROID-3114 Analytics | Date as an Object (#1888)

This commit is contained in:
Konstantin Ivanov 2024-12-09 13:17:07 +01:00 committed by GitHub
parent 2f1bc2633b
commit a8df07b0ae
Signed by: github
GPG key ID: B5690EEEBB952194
7 changed files with 230 additions and 84 deletions

View file

@ -224,6 +224,14 @@ object EventsDictionary {
const val changeLibrarySort = "ChangeLibrarySort"//+
const val screenBin = "ScreenBin"//+
//Date Object
const val screenDate = "ScreenDate"
const val switchRelationDate = "SwitchRelationDate"
const val clickDateForward = "ClickDateForward"
const val clickDateBack = "ClickDateBack"
const val clickDateCalendarView = "ClickDateCalendarView"
const val objectListSort = "ObjectListSort"
const val searchBacklink = "SearchBacklink"
object SharingSpacesTypes {
@ -317,6 +325,7 @@ object EventsDictionary {
const val anytype = "Anytype"
const val localOnly = "LocalOnly"
const val selfHost = "SelfHost"
const val dateObject = "Date"
}
object BlockAction {

View file

@ -5,7 +5,6 @@ data class Props(val map: Map<String?, Any?>) {
companion object {
const val OBJ_TYPE_CUSTOM = "custom"
const val OBJ_LAYOUT_NONE = "none"
const val OBJ_RELATION_CUSTOM = "custom"
fun empty() = Props(emptyMap())

View file

@ -34,7 +34,13 @@ import com.anytypeio.anytype.feature_date.ui.models.DateEvent
import com.anytypeio.anytype.feature_date.viewmodel.UiContentState.*
import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate
import com.anytypeio.anytype.presentation.extension.sendAnalyticsAllContentScreen
import com.anytypeio.anytype.presentation.extension.sendAnalyticsClickDateBack
import com.anytypeio.anytype.presentation.extension.sendAnalyticsClickDateCalendarView
import com.anytypeio.anytype.presentation.extension.sendAnalyticsClickDateForward
import com.anytypeio.anytype.presentation.extension.sendAnalyticsObjectCreateEvent
import com.anytypeio.anytype.presentation.extension.sendAnalyticsObjectListSort
import com.anytypeio.anytype.presentation.extension.sendAnalyticsScreenDate
import com.anytypeio.anytype.presentation.extension.sendAnalyticsSwitchRelationDate
import com.anytypeio.anytype.presentation.home.OpenObjectNavigation
import com.anytypeio.anytype.presentation.home.navigation
import com.anytypeio.anytype.presentation.objects.getCreateObjectParams
@ -150,7 +156,7 @@ class DateObjectViewModel(
Timber.d("onStart")
setupUiStateFlow()
viewModelScope.launch {
sendAnalyticsAllContentScreen(
sendAnalyticsScreenDate(
analytics = analytics
)
}
@ -482,6 +488,12 @@ class DateObjectViewModel(
uiObjectsListState.value = UiObjectsListState.Empty
restartSubscription.value++
updateHorizontalListState(selectedItem = item, needToScroll = needToScroll)
viewModelScope.launch {
sendAnalyticsObjectListSort(
analytics = analytics,
sortType = _activeField.value?.sort ?: DEFAULT_SORT_TYPE
)
}
} else {
shouldScrollToTopItems = true
resetLimit()
@ -493,6 +505,13 @@ class DateObjectViewModel(
)
restartSubscription.value++
updateHorizontalListState(selectedItem = item, needToScroll = needToScroll)
viewModelScope.launch {
sendAnalyticsSwitchRelationDate(
analytics = analytics,
storeOfRelations = storeOfRelations,
relationKey = item.key
)
}
}
}
@ -691,6 +710,11 @@ class DateObjectViewModel(
when (event) {
is DateEvent.TopToolbar.OnCalendarClick -> {
proceedWithShowCalendar(timestampInSeconds = event.timestampInSeconds)
viewModelScope.launch {
sendAnalyticsClickDateCalendarView(
analytics = analytics
)
}
}
is DateEvent.TopToolbar.OnSyncStatusClick -> {
@ -721,13 +745,33 @@ class DateObjectViewModel(
private fun onHeaderEvent(event: DateEvent.Header) {
when (event) {
DateEvent.Header.OnNextClick -> proceedWithReopeningDate(offset = SECONDS_IN_DAY)
DateEvent.Header.OnPreviousClick -> proceedWithReopeningDate(offset = -SECONDS_IN_DAY)
DateEvent.Header.OnNextClick -> {
proceedWithReopeningDate(offset = SECONDS_IN_DAY)
viewModelScope.launch {
sendAnalyticsClickDateForward(
analytics = analytics
)
}
}
DateEvent.Header.OnPreviousClick -> {
proceedWithReopeningDate(offset = -SECONDS_IN_DAY)
viewModelScope.launch {
sendAnalyticsClickDateBack(
analytics = analytics
)
}
}
is DateEvent.Header.OnHeaderClick -> {
val timestampInSeconds = TimestampInSeconds(
time = event.timeInMillis / 1000
)
proceedWithShowCalendar(timestampInSeconds)
viewModelScope.launch {
sendAnalyticsClickDateCalendarView(
analytics = analytics
)
}
}
}
}

View file

@ -5,6 +5,7 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.analytics.base.EventsDictionary
import com.anytypeio.anytype.analytics.base.EventsDictionary.Routes.objDate
import com.anytypeio.anytype.analytics.base.EventsDictionary.searchScreenShow
import com.anytypeio.anytype.analytics.base.EventsPropertiesKey
import com.anytypeio.anytype.analytics.base.sendEvent
@ -21,6 +22,7 @@ import com.anytypeio.anytype.core_models.InternalFlags
import com.anytypeio.anytype.core_models.Key
import com.anytypeio.anytype.core_models.Marketplace.COLLECTION_MARKETPLACE_ID
import com.anytypeio.anytype.core_models.Marketplace.SET_MARKETPLACE_ID
import com.anytypeio.anytype.core_models.MarketplaceObjectTypeIds
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.ObjectTypeIds
import com.anytypeio.anytype.core_models.ObjectTypeUniqueKeys
@ -48,7 +50,6 @@ import com.anytypeio.anytype.core_models.ext.sortByType
import com.anytypeio.anytype.core_models.ext.supportNesting
import com.anytypeio.anytype.core_models.ext.title
import com.anytypeio.anytype.core_models.ext.updateTextContent
import com.anytypeio.anytype.core_models.getSingleValue
import com.anytypeio.anytype.core_models.multiplayer.SpaceSyncAndP2PStatusState
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.core_models.primitives.TypeId
@ -91,7 +92,6 @@ import com.anytypeio.anytype.domain.networkmode.GetNetworkMode
import com.anytypeio.anytype.domain.`object`.ConvertObjectToCollection
import com.anytypeio.anytype.domain.`object`.ConvertObjectToSet
import com.anytypeio.anytype.domain.`object`.UpdateDetail
import com.anytypeio.anytype.domain.objects.GetDateObjectByTimestamp
import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
import com.anytypeio.anytype.domain.objects.StoreOfRelations
import com.anytypeio.anytype.domain.page.CloseBlock
@ -266,7 +266,6 @@ import com.anytypeio.anytype.presentation.objects.toViews
import com.anytypeio.anytype.presentation.profile.ProfileIconView
import com.anytypeio.anytype.presentation.profile.profileIcon
import com.anytypeio.anytype.presentation.relations.ObjectRelationView
import com.anytypeio.anytype.presentation.relations.RelationListViewModel
import com.anytypeio.anytype.presentation.relations.getNotIncludedRecommendedRelations
import com.anytypeio.anytype.presentation.relations.getObjectRelations
import com.anytypeio.anytype.presentation.relations.views
@ -2066,10 +2065,12 @@ class EditorViewModel(
)
)
}
viewModelScope.sendAnalyticsUpdateTextMarkupEvent(
analytics = analytics,
type = type
)
viewModelScope.launch {
analytics.sendAnalyticsUpdateTextMarkupEvent(
markupType = type.toCoreModel(),
storeOfObjectTypes = storeOfObjectTypes
)
}
}
private fun proceedWithAlignmentUpdate(targets: List<Id>, alignment: Block.Align) {
@ -2102,10 +2103,12 @@ class EditorViewModel(
)
)
}
viewModelScope.sendAnalyticsUpdateTextMarkupEvent(
analytics = analytics,
type = Content.Text.Mark.Type.TEXT_COLOR
)
viewModelScope.launch {
analytics.sendAnalyticsUpdateTextMarkupEvent(
markupType = Block.Content.Text.Mark.Type.TEXT_COLOR,
storeOfObjectTypes = storeOfObjectTypes
)
}
}
private fun onBlockBackgroundColorAction(ids: List<Id>, color: String) {
@ -2154,9 +2157,11 @@ class EditorViewModel(
)
)
)
sendAnalyticsUpdateTextMarkupEvent(
analytics = analytics,
type = type
}
viewModelScope.launch {
analytics.sendAnalyticsUpdateTextMarkupEvent(
markupType = type.toCoreModel(),
storeOfObjectTypes = storeOfObjectTypes
)
}
}
@ -5035,9 +5040,9 @@ class EditorViewModel(
)
)
)
sendAnalyticsUpdateTextMarkupEvent(
analytics = analytics,
type = type
analytics.sendAnalyticsUpdateTextMarkupEvent(
markupType = type,
storeOfObjectTypes = storeOfObjectTypes
)
}
}
@ -5364,9 +5369,9 @@ class EditorViewModel(
)
}
is SlashItem.Color.Text -> {
sendAnalyticsUpdateTextMarkupEvent(
analytics = analytics,
type = Content.Text.Mark.Type.TEXT_COLOR
analytics.sendAnalyticsUpdateTextMarkupEvent(
markupType = Content.Text.Mark.Type.TEXT_COLOR,
storeOfObjectTypes = storeOfObjectTypes
)
}
}
@ -6170,13 +6175,14 @@ class EditorViewModel(
fun onMentionSuggestClick(mention: DefaultSearchItem, mentionTrigger: String, pos: Int) {
Timber.d("onMentionSuggestClick, mention:[$mention] mentionTrigger:[$mentionTrigger]")
if (mention is DefaultObjectView) {
viewModelScope.sendAnalyticsSearchResultEvent(
analytics = analytics,
pos = pos,
length = mentionTrigger.length - 1,
spaceParams = provideParams(vmParams.space.id)
)
onCreateMentionInText(id = mention.id, name = mention.name, mentionTrigger = mentionTrigger)
viewModelScope.launch {
analytics.sendAnalyticsUpdateTextMarkupEvent(
markupType = Content.Text.Mark.Type.MENTION,
typeId = mention.type,
storeOfObjectTypes = storeOfObjectTypes
)
}
}
if (mention is SelectDateItem) {
val targetId = orchestrator.stores.focus.current().targetOrNull()
@ -7793,15 +7799,26 @@ class EditorViewModel(
spaceId = vmParams.space,
actionSuccess = { obj ->
when (actionType) {
EditorCalendarActionType.MENTION -> onCreateMentionInText(
id = obj.id,
name = obj.name.orEmpty(),
mentionTrigger = mentionFilter.value
)
EditorCalendarActionType.LINK -> onCreateDateLink(
linkId = obj.id,
targetId = targetId
)
EditorCalendarActionType.MENTION -> {
onCreateMentionInText(
id = obj.id,
name = obj.name.orEmpty(),
mentionTrigger = mentionFilter.value
)
viewModelScope.launch {
analytics.sendAnalyticsUpdateTextMarkupEvent(
markupType = Content.Text.Mark.Type.MENTION,
typeId = ObjectTypeIds.DATE,
storeOfObjectTypes = storeOfObjectTypes
)
}
}
EditorCalendarActionType.LINK -> {
onCreateDateLink(
linkId = obj.id,
targetId = targetId
)
}
}
},
actionFailure = {
@ -7833,7 +7850,8 @@ class EditorViewModel(
target = targetId,
position = position,
prototype = Prototype.Link(target = linkId),
onSuccess = {}
onSuccess = {},
isDate = true
)
)
}

View file

@ -57,7 +57,8 @@ sealed class Intent {
val target: Id,
val position: Position,
val prototype: Block.Prototype,
val onSuccess: (() -> Unit)? = null
val onSuccess: (() -> Unit)? = null,
val isDate: Boolean = false
) : CRUD()
class Duplicate(

View file

@ -124,7 +124,8 @@ class Orchestrator(
prototype = intent.prototype,
startTime = startTime,
middlewareTime = middlewareTime,
spaceParams = spaceParams
spaceParams = spaceParams,
isDate = intent.isDate
)
},
onFailure = defaultOnError

View file

@ -40,8 +40,10 @@ import com.anytypeio.anytype.analytics.props.Props.Companion.OBJ_TYPE_CUSTOM
import com.anytypeio.anytype.analytics.props.UserProperty
import com.anytypeio.anytype.core_models.Block
import com.anytypeio.anytype.core_models.DVFilterCondition
import com.anytypeio.anytype.core_models.DVSortType
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.Key
import com.anytypeio.anytype.core_models.ObjectTypeIds
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.Relation
import com.anytypeio.anytype.core_models.TextStyle
@ -49,8 +51,11 @@ import com.anytypeio.anytype.core_models.ThemeMode
import com.anytypeio.anytype.core_models.WidgetLayout
import com.anytypeio.anytype.core_models.ext.mapToObjectWrapperType
import com.anytypeio.anytype.core_models.multiplayer.SpaceMemberPermissions
import com.anytypeio.anytype.core_models.primitives.RelationKey
import com.anytypeio.anytype.core_models.primitives.TypeKey
import com.anytypeio.anytype.core_utils.ext.Mimetype
import com.anytypeio.anytype.domain.config.ConfigStorage
import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
import com.anytypeio.anytype.domain.objects.StoreOfRelations
import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate
import com.anytypeio.anytype.presentation.editor.editor.Markup
@ -60,13 +65,15 @@ import com.anytypeio.anytype.presentation.sets.viewerByIdOrFirst
import com.anytypeio.anytype.presentation.widgets.Widget
import com.anytypeio.anytype.presentation.widgets.source.BundledWidgetSourceView
import kotlinx.coroutines.CoroutineScope
import timber.log.Timber
fun Block.Prototype.getAnalyticsEvent(
eventName: String,
startTime: Long,
middlewareTime: Long,
renderTime: Long,
spaceParams: AnalyticSpaceHelperDelegate.Params
spaceParams: AnalyticSpaceHelperDelegate.Params,
isDate: Boolean = false
): EventAnalytics.Anytype {
val props = when (this) {
is Block.Prototype.Text -> {
@ -99,10 +106,13 @@ fun Block.Prototype.getAnalyticsEvent(
render = renderTime
),
props = Props(
mapOf(
EventsPropertiesKey.permissions to spaceParams.permission,
EventsPropertiesKey.spaceType to spaceParams.spaceType
)
buildMap {
if (isDate) {
put(EventsPropertiesKey.type, "Date")
}
put(EventsPropertiesKey.permissions, spaceParams.permission)
put(EventsPropertiesKey.spaceType, spaceParams.spaceType)
}
)
)
}
@ -221,7 +231,7 @@ fun Block.Content.Text.Mark.Type.getPropName() = when (this) {
Block.Content.Text.Mark.Type.LINK -> "linkURL"
Block.Content.Text.Mark.Type.TEXT_COLOR -> "color"
Block.Content.Text.Mark.Type.BACKGROUND_COLOR -> "bgcolor"
Block.Content.Text.Mark.Type.MENTION -> "mention"
Block.Content.Text.Mark.Type.MENTION -> "Mention"
Block.Content.Text.Mark.Type.EMOJI -> "emoji"
Block.Content.Text.Mark.Type.OBJECT -> "linkObject"
}
@ -520,14 +530,16 @@ suspend fun Analytics.sendAnalyticsCreateBlockEvent(
prototype: Block.Prototype,
startTime: Long,
middlewareTime: Long,
spaceParams: AnalyticSpaceHelperDelegate.Params
spaceParams: AnalyticSpaceHelperDelegate.Params,
isDate: Boolean = false
) {
val event = prototype.getAnalyticsEvent(
eventName = EventsDictionary.blockCreate,
startTime = startTime,
middlewareTime = middlewareTime,
renderTime = System.currentTimeMillis(),
spaceParams = spaceParams
spaceParams = spaceParams,
isDate = isDate
)
registerEvent(event)
}
@ -562,10 +574,24 @@ suspend fun Analytics.sendAnalyticsRemoveObjects(
registerEvent(event)
}
suspend fun Analytics.sendAnalyticsUpdateTextMarkupEvent(type: Block.Content.Text.Mark.Type) {
suspend fun Analytics.sendAnalyticsUpdateTextMarkupEvent(
markupType: Block.Content.Text.Mark.Type,
typeId: Id? = null,
storeOfObjectTypes: StoreOfObjectTypes
) {
val objectType = when (typeId) {
null -> null
ObjectTypeIds.DATE -> "Date"
else -> storeOfObjectTypes.get(typeId)?.sourceObject ?: OBJ_TYPE_CUSTOM
}
val event = EventAnalytics.Anytype(
name = EventsDictionary.blockChangeTextStyle,
props = Props(mapOf(EventsPropertiesKey.type to type.getPropName()))
props = Props(
mapOf(
EventsPropertiesKey.type to markupType.getPropName(),
EventsPropertiesKey.objectType to objectType
)
)
)
registerEvent(event)
}
@ -840,36 +866,6 @@ fun CoroutineScope.sendAnalyticsSetDescriptionEvent(
)
}
fun CoroutineScope.sendAnalyticsUpdateTextMarkupEvent(
analytics: Analytics,
type: Block.Content.Text.Mark.Type
) {
sendEvent(
analytics = analytics,
eventName = EventsDictionary.blockChangeTextStyle,
props = Props(
mapOf(
EventsPropertiesKey.type to type.getPropName()
)
)
)
}
fun CoroutineScope.sendAnalyticsUpdateTextMarkupEvent(
analytics: Analytics,
type: Markup.Type
) {
sendEvent(
analytics = analytics,
eventName = EventsDictionary.blockChangeTextStyle,
props = Props(
mapOf(
EventsPropertiesKey.type to type.getPropName()
)
)
)
}
fun CoroutineScope.sendAnalyticsBlockReorder(
analytics: Analytics,
count: Int
@ -2010,7 +2006,6 @@ fun CoroutineScope.sendAnalyticsCreateLink(
)
}
//region Self-Hosting
fun CoroutineScope.sendAnalyticsSelectNetworkEvent(
analytics: Analytics,
@ -2210,4 +2205,83 @@ fun CoroutineScope.sendAnalyticsAllContentChangeSort(
)
)
)
}
}
//endregion
//region DateObject
fun CoroutineScope.sendAnalyticsScreenDate(
analytics: Analytics
) {
sendEvent(
analytics = analytics,
eventName = EventsDictionary.screenDate
)
}
suspend fun CoroutineScope.sendAnalyticsSwitchRelationDate(
analytics: Analytics,
storeOfRelations: StoreOfRelations,
relationKey: RelationKey
) {
val relation = storeOfRelations.getByKey(relationKey.key)
val sourceObject = relation?.sourceObject ?: OBJ_RELATION_CUSTOM
sendEvent(
analytics = analytics,
eventName = EventsDictionary.switchRelationDate,
props = Props(
buildMap {
put(EventsPropertiesKey.relationKey, sourceObject)
}
)
)
}
fun CoroutineScope.sendAnalyticsClickDateForward(
analytics: Analytics
) {
sendEvent(
analytics = analytics,
eventName = EventsDictionary.clickDateForward
)
}
fun CoroutineScope.sendAnalyticsClickDateBack(
analytics: Analytics
) {
sendEvent(
analytics = analytics,
eventName = EventsDictionary.clickDateBack
)
}
fun CoroutineScope.sendAnalyticsClickDateCalendarView(
analytics: Analytics
) {
sendEvent(
analytics = analytics,
eventName = EventsDictionary.clickDateCalendarView
)
}
fun CoroutineScope.sendAnalyticsObjectListSort(
analytics: Analytics,
sortType: DVSortType
) {
val sortType = when (sortType) {
DVSortType.ASC -> "Asc"
DVSortType.DESC -> "Desc"
DVSortType.CUSTOM -> "Custom"
}
sendEvent(
analytics = analytics,
eventName = EventsDictionary.objectListSort,
props = Props(
buildMap {
put(EventsPropertiesKey.type, sortType)
put(EventsPropertiesKey.route, "ScreenDate")
}
)
)
}
//endregion