@momo-kits/native-kits 0.158.1-beta.1-debug → 0.158.1-beta.2-debug

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/compose/build.gradle.kts +1 -1
  2. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +15 -1
  3. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +15 -1
  4. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +1 -0
  5. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +4 -1
  6. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +11 -9
  7. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +56 -1
  8. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +167 -0
  9. package/example/ios/Example.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/Example.xcscheme +32 -0
  10. package/example/ios/Example.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  11. package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  12. package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/WorkspaceSettings.xcsettings +16 -0
  13. package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +6 -0
  14. package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +5 -0
  15. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/MoMoUIKits.xcscheme +58 -0
  16. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/Pods-Example.xcscheme +58 -0
  17. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/SDWebImage.xcscheme +58 -0
  18. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/SDWebImageSwiftUI.xcscheme +58 -0
  19. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/SkeletonUI.xcscheme +58 -0
  20. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/lottie-ios-LottiePrivacyInfo.xcscheme +58 -0
  21. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/lottie-ios.xcscheme +58 -0
  22. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +60 -0
  23. package/gradle.properties +1 -1
  24. package/local.properties +2 -2
  25. package/package.json +1 -1
  26. package/.claude/settings.local.json +0 -11
  27. package/.claude/skills/design-system/SKILL.md +0 -88
  28. package/.claude/skills/design-system/references/components/avatar.md +0 -134
  29. package/.claude/skills/design-system/references/components/badge.md +0 -127
  30. package/.claude/skills/design-system/references/components/bottom-tab.md +0 -177
  31. package/.claude/skills/design-system/references/components/bottomsheet.md +0 -170
  32. package/.claude/skills/design-system/references/components/button.md +0 -206
  33. package/.claude/skills/design-system/references/components/carousel.md +0 -117
  34. package/.claude/skills/design-system/references/components/checkbox.md +0 -98
  35. package/.claude/skills/design-system/references/components/chip.md +0 -146
  36. package/.claude/skills/design-system/references/components/collapse.md +0 -120
  37. package/.claude/skills/design-system/references/components/date-picker.md +0 -119
  38. package/.claude/skills/design-system/references/components/divider.md +0 -84
  39. package/.claude/skills/design-system/references/components/icon.md +0 -130
  40. package/.claude/skills/design-system/references/components/image.md +0 -81
  41. package/.claude/skills/design-system/references/components/information.md +0 -107
  42. package/.claude/skills/design-system/references/components/input-dropdown.md +0 -138
  43. package/.claude/skills/design-system/references/components/input-money.md +0 -157
  44. package/.claude/skills/design-system/references/components/input-otp.md +0 -132
  45. package/.claude/skills/design-system/references/components/input-phone-number.md +0 -140
  46. package/.claude/skills/design-system/references/components/input-search.md +0 -124
  47. package/.claude/skills/design-system/references/components/input-text-area.md +0 -133
  48. package/.claude/skills/design-system/references/components/input.md +0 -152
  49. package/.claude/skills/design-system/references/components/loader.md +0 -87
  50. package/.claude/skills/design-system/references/components/pagination.md +0 -105
  51. package/.claude/skills/design-system/references/components/popup-notify.md +0 -128
  52. package/.claude/skills/design-system/references/components/progress-info.md +0 -114
  53. package/.claude/skills/design-system/references/components/radio.md +0 -86
  54. package/.claude/skills/design-system/references/components/rating.md +0 -126
  55. package/.claude/skills/design-system/references/components/skeleton.md +0 -120
  56. package/.claude/skills/design-system/references/components/slider.md +0 -141
  57. package/.claude/skills/design-system/references/components/snackbar.md +0 -97
  58. package/.claude/skills/design-system/references/components/stepper.md +0 -100
  59. package/.claude/skills/design-system/references/components/steps.md +0 -91
  60. package/.claude/skills/design-system/references/components/suggest-action.md +0 -95
  61. package/.claude/skills/design-system/references/components/swipe.md +0 -121
  62. package/.claude/skills/design-system/references/components/switch.md +0 -98
  63. package/.claude/skills/design-system/references/components/tab-view.md +0 -120
  64. package/.claude/skills/design-system/references/components/tag.md +0 -118
  65. package/.claude/skills/design-system/references/components/text.md +0 -151
  66. package/.claude/skills/design-system/references/components/toast.md +0 -99
  67. package/.claude/skills/design-system/references/components/tooltip.md +0 -138
  68. package/.claude/skills/design-system/references/components/top-nav-miniapp.md +0 -94
  69. package/.claude/skills/design-system/references/components/top-nav.md +0 -226
  70. package/.claude/skills/design-system/references/components/uploader.md +0 -115
  71. package/.claude/skills/design-system/references/navigation/bottom-tab.md +0 -131
  72. package/.claude/skills/design-system/references/navigation/bottomsheet.md +0 -161
  73. package/.claude/skills/design-system/references/navigation/modal.md +0 -133
  74. package/.claude/skills/design-system/references/navigation/navigation-options.md +0 -225
  75. package/.claude/skills/design-system/references/navigation/navigator.md +0 -111
  76. package/.claude/skills/design-system/references/navigation/setup.md +0 -134
  77. package/.claude/skills/design-system/references/navigation/stack.md +0 -128
  78. package/.claude/skills/design-system/references/spec-convention.md +0 -80
  79. package/.claude/skills/design-system/references/tokens/colors.md +0 -131
  80. package/.claude/skills/design-system/references/tokens/spacing-radius.md +0 -144
  81. package/.claude/skills/design-system/references/tokens/theme.md +0 -125
  82. package/.claude/skills/design-system/references/tokens/typography.md +0 -135
  83. package/.claude/skills/design-system-kits/SKILL.md +0 -102
  84. package/.claude/skills/design-system-kits/references/code-convention.md +0 -118
  85. package/.claude/skills/design-system-kits/references/components/avatar.md +0 -45
  86. package/.claude/skills/design-system-kits/references/components/badge.md +0 -27
  87. package/.claude/skills/design-system-kits/references/components/button.md +0 -65
  88. package/.claude/skills/design-system-kits/references/components/carousel.md +0 -51
  89. package/.claude/skills/design-system-kits/references/components/checkbox.md +0 -39
  90. package/.claude/skills/design-system-kits/references/components/chip.md +0 -54
  91. package/.claude/skills/design-system-kits/references/components/collapse.md +0 -63
  92. package/.claude/skills/design-system-kits/references/components/date-picker.md +0 -36
  93. package/.claude/skills/design-system-kits/references/components/divider.md +0 -21
  94. package/.claude/skills/design-system-kits/references/components/icon.md +0 -382
  95. package/.claude/skills/design-system-kits/references/components/image.md +0 -62
  96. package/.claude/skills/design-system-kits/references/components/information.md +0 -61
  97. package/.claude/skills/design-system-kits/references/components/input-dropdown.md +0 -92
  98. package/.claude/skills/design-system-kits/references/components/input-money.md +0 -128
  99. package/.claude/skills/design-system-kits/references/components/input-otp.md +0 -85
  100. package/.claude/skills/design-system-kits/references/components/input-phone-number.md +0 -96
  101. package/.claude/skills/design-system-kits/references/components/input-search.md +0 -127
  102. package/.claude/skills/design-system-kits/references/components/input-text-area.md +0 -100
  103. package/.claude/skills/design-system-kits/references/components/input.md +0 -126
  104. package/.claude/skills/design-system-kits/references/components/loader.md +0 -41
  105. package/.claude/skills/design-system-kits/references/components/pagination.md +0 -47
  106. package/.claude/skills/design-system-kits/references/components/popup-notify.md +0 -69
  107. package/.claude/skills/design-system-kits/references/components/popup-promotion.md +0 -35
  108. package/.claude/skills/design-system-kits/references/components/progress-info.md +0 -55
  109. package/.claude/skills/design-system-kits/references/components/radio.md +0 -42
  110. package/.claude/skills/design-system-kits/references/components/rating.md +0 -36
  111. package/.claude/skills/design-system-kits/references/components/skeleton.md +0 -25
  112. package/.claude/skills/design-system-kits/references/components/slider.md +0 -53
  113. package/.claude/skills/design-system-kits/references/components/snackbar.md +0 -52
  114. package/.claude/skills/design-system-kits/references/components/stepper.md +0 -46
  115. package/.claude/skills/design-system-kits/references/components/steps.md +0 -57
  116. package/.claude/skills/design-system-kits/references/components/suggest-action.md +0 -44
  117. package/.claude/skills/design-system-kits/references/components/swipe.md +0 -44
  118. package/.claude/skills/design-system-kits/references/components/switch.md +0 -43
  119. package/.claude/skills/design-system-kits/references/components/tab-view.md +0 -56
  120. package/.claude/skills/design-system-kits/references/components/tag.md +0 -50
  121. package/.claude/skills/design-system-kits/references/components/text.md +0 -56
  122. package/.claude/skills/design-system-kits/references/components/toast.md +0 -51
  123. package/.claude/skills/design-system-kits/references/components/tooltip.md +0 -95
  124. package/.claude/skills/design-system-kits/references/components/uploader.md +0 -48
  125. package/.claude/skills/design-system-kits/references/design-spec-structure.md +0 -356
  126. package/.claude/skills/design-system-kits/references/design-spec-to-code.md +0 -596
  127. package/.claude/skills/design-system-kits/references/navigation/bottom-tab.md +0 -155
  128. package/.claude/skills/design-system-kits/references/navigation/bottomsheet.md +0 -94
  129. package/.claude/skills/design-system-kits/references/navigation/modal.md +0 -125
  130. package/.claude/skills/design-system-kits/references/navigation/navigation-options.md +0 -430
  131. package/.claude/skills/design-system-kits/references/navigation/navigator.md +0 -177
  132. package/.claude/skills/design-system-kits/references/navigation/setup.md +0 -94
  133. package/.claude/skills/design-system-kits/references/navigation/stack.md +0 -152
  134. package/.claude/skills/design-system-kits/references/screen-layout-rule.md +0 -125
  135. package/.claude/skills/design-system-kits/references/tokens/colors.md +0 -183
  136. package/.claude/skills/design-system-kits/references/tokens/spacing-radius.md +0 -45
  137. package/.claude/skills/design-system-kits/references/tokens/theme.md +0 -97
  138. package/.claude/skills/design-system-kits/references/tokens/typography.md +0 -105
  139. package/.claude/skills/vibe-design/SKILL.md +0 -306
@@ -40,7 +40,7 @@ kotlin {
40
40
  }
41
41
 
42
42
  cocoapods {
43
- version = "0.158.1-beta.1-debug"
43
+ version = "0.158.1-beta.2-debug"
44
44
  summary = "IOS Shared module"
45
45
  homepage = "https://momo.vn"
46
46
  ios.deploymentTarget = "15.0"
@@ -41,8 +41,10 @@ import vn.momo.kits.const.AppTheme
41
41
  import vn.momo.kits.const.Colors
42
42
  import vn.momo.kits.const.Radius
43
43
  import vn.momo.kits.const.Spacing
44
+ import vn.momo.kits.application.ApplicationContext
44
45
  import vn.momo.kits.application.IsShowBaseLineDebug
45
46
  import vn.momo.kits.const.Typography
47
+ import vn.momo.kits.navigation.tracking.ScreenTracker
46
48
  import vn.momo.kits.modifier.conditional
47
49
  import vn.momo.kits.modifier.noFeedbackClickable
48
50
  import vn.momo.kits.platform.BackHandler
@@ -70,6 +72,18 @@ internal fun BottomSheet(
70
72
 
71
73
  val coroutineScope = rememberCoroutineScope()
72
74
 
75
+ val maxApi = LocalMaxApi.current
76
+ val context = ApplicationContext.current
77
+
78
+ DisposableEffect(Unit) {
79
+ ScreenTracker.trackPopupDisplayed(
80
+ maxApi = maxApi,
81
+ context = context,
82
+ parentScreenName = ScreenTracker.getLastScreenName()
83
+ )
84
+ onDispose { }
85
+ }
86
+
73
87
  suspend fun openEvent(){
74
88
  backgroundAlpha.animateTo(
75
89
  targetValue = 0.3f,
@@ -236,4 +250,4 @@ sealed class BottomHeader {
236
250
  data class Custom(
237
251
  val content: @Composable () -> Unit
238
252
  ) : BottomHeader()
239
- }
253
+ }
@@ -22,10 +22,12 @@ import androidx.compose.ui.draw.scale
22
22
  import androidx.compose.ui.graphics.Color
23
23
  import androidx.compose.ui.unit.dp
24
24
  import kotlinx.coroutines.launch
25
+ import vn.momo.kits.application.ApplicationContext
25
26
  import vn.momo.kits.application.IsShowBaseLineDebug
26
27
  import vn.momo.kits.const.Colors
27
28
  import vn.momo.kits.modifier.conditional
28
29
  import vn.momo.kits.modifier.noFeedbackClickable
30
+ import vn.momo.kits.navigation.tracking.ScreenTracker
29
31
  import vn.momo.kits.platform.BackHandler
30
32
 
31
33
  @Composable
@@ -41,6 +43,18 @@ internal fun ModalScreen(
41
43
 
42
44
  val coroutineScope = rememberCoroutineScope()
43
45
 
46
+ val maxApi = LocalMaxApi.current
47
+ val context = ApplicationContext.current
48
+
49
+ DisposableEffect(Unit) {
50
+ ScreenTracker.trackPopupDisplayed(
51
+ maxApi = maxApi,
52
+ context = context,
53
+ parentScreenName = ScreenTracker.getLastScreenName()
54
+ )
55
+ onDispose { }
56
+ }
57
+
44
58
  fun openEvent() {
45
59
  coroutineScope.launch {
46
60
  launch {
@@ -116,4 +130,4 @@ internal fun ModalScreen(
116
130
  content()
117
131
  }
118
132
  }
119
- }
133
+ }
@@ -72,6 +72,7 @@ val LocalNavigation = staticCompositionLocalOf<Navigation> {
72
72
 
73
73
  @Stable
74
74
  data class NavigationOptions(
75
+ val screenName: String? = null,
75
76
  val onBackHandler: (() -> Unit)? = null,
76
77
  val hiddenBack: Boolean = false,
77
78
  val headerBackProps: HeaderBackProps = HeaderBackProps(),
@@ -38,6 +38,7 @@ import vn.momo.maxapi.IMaxApi
38
38
 
39
39
  @Composable
40
40
  fun NavigationContainer(
41
+ initialScreenName: String,
41
42
  initialScreen: @Composable () -> Unit,
42
43
  options: NavigationOptions? = null,
43
44
  initialTheme: Theme = defaultTheme,
@@ -73,7 +74,7 @@ fun NavigationContainer(
73
74
  }
74
75
  }
75
76
 
76
- val startDestination = DynamicScreenRegistry.register(initialScreen, options)
77
+ val startDestination = DynamicScreenRegistry.register(initialScreenName, initialScreen, options)
77
78
 
78
79
  CompositionLocalProvider(
79
80
  LocalNavigator provides navigator,
@@ -112,6 +113,7 @@ fun NavigationContainer(
112
113
  if (screen != null){
113
114
  StackScreen(
114
115
  id = route.id,
116
+ name = screen.name,
115
117
  content = screen.content,
116
118
  navigationOptions = screen.options
117
119
  )
@@ -140,6 +142,7 @@ fun NavigationContainer(
140
142
  if (screen != null){
141
143
  StackScreen(
142
144
  id = route.id,
145
+ name = screen.name,
143
146
  content = screen.content,
144
147
  navigationOptions = screen.options
145
148
  )
@@ -28,17 +28,17 @@ class Navigator(
28
28
  ) {
29
29
  private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
30
30
 
31
- fun push(content: @Composable () -> Unit, options: NavigationOptions? = null) {
32
- val route = DynamicScreenRegistry.register(content, options)
31
+ fun push(screenName: String, content: @Composable () -> Unit, options: NavigationOptions? = null) {
32
+ val route = DynamicScreenRegistry.register(screenName, content, options)
33
33
  navController.navigate(DynamicScreenRoute(route.id))
34
34
  }
35
35
 
36
- fun replace(content: @Composable () -> Unit, options: NavigationOptions? = null) {
36
+ fun replace(screenName: String, content: @Composable () -> Unit, options: NavigationOptions? = null) {
37
37
  if (navController.previousBackStackEntry != null){
38
38
  val latestScreen = DynamicScreenRegistry.getLatestScreen()
39
39
  latestScreen?.let { DynamicScreenRegistry.unregisterScreen(it.id) }
40
40
  navController.popBackStack()
41
- push(content, options)
41
+ push(screenName, content, options)
42
42
  }
43
43
  }
44
44
 
@@ -103,15 +103,15 @@ class Navigator(
103
103
  }
104
104
  }
105
105
 
106
- fun present(content: @Composable () -> Unit, options: NavigationOptions? = null) {
107
- val route = DynamicScreenRegistry.register(content, options)
106
+ fun present(screenName: String, content: @Composable () -> Unit, options: NavigationOptions? = null) {
107
+ val route = DynamicScreenRegistry.register(screenName, content, options)
108
108
  navController.navigate(DynamicDialogRoute(route.id))
109
109
  }
110
110
 
111
- fun reset(content: @Composable () -> Unit, options: NavigationOptions? = null) {
111
+ fun reset(screenName: String, content: @Composable () -> Unit, options: NavigationOptions? = null) {
112
112
  DynamicScreenRegistry.unregisterAll()
113
113
 
114
- val route = DynamicScreenRegistry.register(content, options)
114
+ val route = DynamicScreenRegistry.register(screenName, content, options)
115
115
  navController.navigate(DynamicScreenRoute(route.id)) {
116
116
  popUpTo(0) { inclusive = true }
117
117
  }
@@ -176,6 +176,7 @@ data class DynamicDialogRoute(val id: Int)
176
176
 
177
177
  data class DynamicScreen(
178
178
  val id: Int,
179
+ val name: String,
179
180
  val content: @Composable () -> Unit,
180
181
  var options: NavigationOptions? = null
181
182
  )
@@ -184,10 +185,11 @@ object DynamicScreenRegistry {
184
185
  private val screens = mutableMapOf<Int, DynamicScreen>()
185
186
  private var idCounter = 1
186
187
 
187
- fun register(content: @Composable () -> Unit, options: NavigationOptions?): DynamicScreenRoute {
188
+ fun register(screenName: String, content: @Composable () -> Unit, options: NavigationOptions?): DynamicScreenRoute {
188
189
  val id = idCounter++
189
190
  screens[id] = DynamicScreen(
190
191
  id = id,
192
+ name = screenName,
191
193
  content = content,
192
194
  options = options
193
195
  )
@@ -63,26 +63,81 @@ import vn.momo.kits.navigation.component.HeaderType
63
63
  import vn.momo.kits.navigation.component.InputSearchType
64
64
  import vn.momo.kits.platform.BackHandler
65
65
  import vn.momo.kits.platform.getAndroidBuildVersion
66
+ import vn.momo.kits.navigation.tracking.ScreenTracker
67
+ import vn.momo.kits.navigation.tracking.ScreenTrackingState
68
+ import kotlinx.coroutines.delay
69
+ import vn.momo.kits.application.ApplicationContext
70
+ import kotlin.time.Clock
71
+ import kotlin.time.ExperimentalTime
66
72
 
67
73
  internal val LocalFooterHeightPx = staticCompositionLocalOf { mutableIntStateOf(0) }
68
74
  internal val LocalHeaderRightWidthPx = staticCompositionLocalOf { mutableIntStateOf(0) }
69
75
 
70
- @OptIn(ExperimentalMaterialApi::class)
76
+ @OptIn(ExperimentalMaterialApi::class, ExperimentalTime::class)
71
77
  @Composable
72
78
  internal fun StackScreen(
73
79
  content: @Composable () -> Unit,
74
80
  navigationOptions: NavigationOptions? = null,
75
81
  id: Int = -1,
82
+ name: String = "",
76
83
  bottomTabIndex: Int = -1,
77
84
  onBackHandler: (() -> Unit)? = null,
78
85
  ) {
79
86
  val navigator = LocalNavigator.current
87
+ val maxApi = LocalMaxApi.current
88
+ val context = ApplicationContext.current
80
89
  val statusBar = AppStatusBar.current
81
90
  val density = LocalDensity.current
82
91
  val navigation = remember { Navigation(id = id, bottomTabIndex = bottomTabIndex, initOptions = navigationOptions) }
83
92
 
84
93
  val options by navigation.currentOptions
85
94
 
95
+ // Auto tracking state
96
+ val trackingState = remember {
97
+ ScreenTrackingState().apply {
98
+ startTime = Clock.System.now().toEpochMilliseconds()
99
+ }
100
+ }
101
+
102
+ // Determine action: push or back
103
+ val action = remember {
104
+ if (ScreenTracker.getLastScreenName() != null) "push" else "back"
105
+ }
106
+
107
+ // Auto tracking effects
108
+ LaunchedEffect(name) {
109
+ // Track screen navigated immediately
110
+ ScreenTracker.trackScreenNavigated(
111
+ maxApi = maxApi,
112
+ context = context,
113
+ screenName = name,
114
+ action = action,
115
+ state = trackingState
116
+ )
117
+
118
+ // Track screen displayed after 2 seconds (debounce)
119
+ delay(2000)
120
+ val loadTime = Clock.System.now().toEpochMilliseconds() - trackingState.startTime
121
+ ScreenTracker.trackScreenDisplayed(
122
+ maxApi = maxApi,
123
+ context = context,
124
+ screenName = name,
125
+ duration = loadTime,
126
+ state = trackingState
127
+ )
128
+
129
+ // Track screen interacted after displayed
130
+ val interactionTime = Clock.System.now().toEpochMilliseconds() - trackingState.startTime
131
+ ScreenTracker.trackScreenInteracted(
132
+ maxApi = maxApi,
133
+ context = context,
134
+ screenName = name,
135
+ duration = interactionTime - loadTime,
136
+ totalDuration = interactionTime,
137
+ state = trackingState
138
+ )
139
+ }
140
+
86
141
  val limit = with(density) {
87
142
  (statusBar).toPx() + HEADER_HEIGHT
88
143
  }.toInt()
@@ -0,0 +1,167 @@
1
+ package vn.momo.kits.navigation.tracking
2
+
3
+ import vn.momo.kits.application.MiniAppContext
4
+ import vn.momo.maxapi.IMaxApi
5
+ import kotlin.time.Clock
6
+ import kotlin.time.ExperimentalTime
7
+
8
+ /**
9
+ * Screen tracking state holder
10
+ */
11
+ class ScreenTrackingState {
12
+ @OptIn(ExperimentalTime::class)
13
+ var startTime: Long = Clock.System.now().toEpochMilliseconds()
14
+ var endTime: Long = startTime
15
+ var releaseNavigated: Boolean = false
16
+ var releaseLoad: Boolean = false
17
+ var releaseInteraction: Boolean = false
18
+ var previousScreenName: String? = null
19
+ var action: String = "push"
20
+ }
21
+
22
+ /**
23
+ * Screen tracker for auto tracking events
24
+ *
25
+ * Tracks 3 main events:
26
+ * - auto_screen_navigated: When screen is focused
27
+ * - auto_screen_displayed: When screen finished loading
28
+ * - auto_screen_interacted: When screen is ready for interaction
29
+ */
30
+ object ScreenTracker {
31
+
32
+ private var lastScreenName: String? = null
33
+
34
+ /**
35
+ * Track screen navigation event
36
+ * Called when screen is focused
37
+ */
38
+ fun trackScreenNavigated(
39
+ maxApi: IMaxApi?,
40
+ context: MiniAppContext?,
41
+ screenName: String,
42
+ action: String,
43
+ state: ScreenTrackingState
44
+ ) {
45
+ if (state.releaseNavigated) return
46
+
47
+ val previousScreen = lastScreenName
48
+ lastScreenName = screenName
49
+
50
+ println("Tracking screen navigated native kit: $screenName")
51
+ maxApi?.track(
52
+ eventName = "auto_screen_navigated",
53
+ params = buildBaseParams(context, screenName).apply {
54
+ put("pre_screen_name", previousScreen)
55
+ put("state", "navigated")
56
+ put("action", action)
57
+ }
58
+ )
59
+
60
+ state.releaseNavigated = true
61
+ state.previousScreenName = previousScreen
62
+ }
63
+
64
+ /**
65
+ * Track screen displayed event
66
+ * Called when screen finished loading all elements
67
+ */
68
+ fun trackScreenDisplayed(
69
+ maxApi: IMaxApi?,
70
+ context: MiniAppContext?,
71
+ screenName: String,
72
+ duration: Long,
73
+ state: ScreenTrackingState
74
+ ) {
75
+ if (state.releaseLoad) return
76
+
77
+ maxApi?.track(
78
+ eventName = "auto_screen_displayed",
79
+ params = buildBaseParams(context, screenName).apply {
80
+ put("state", "load")
81
+ put("duration", duration)
82
+ }
83
+ )
84
+
85
+ state.releaseLoad = true
86
+ }
87
+
88
+ /**
89
+ * Track screen interacted event
90
+ * Called when screen is ready for user interaction
91
+ */
92
+ fun trackScreenInteracted(
93
+ maxApi: IMaxApi?,
94
+ context: MiniAppContext?,
95
+ screenName: String,
96
+ duration: Long,
97
+ totalDuration: Long,
98
+ state: ScreenTrackingState
99
+ ) {
100
+ if (state.releaseInteraction) return
101
+
102
+ maxApi?.track(
103
+ eventName = "auto_screen_interacted",
104
+ params = buildBaseParams(context, screenName).apply {
105
+ put("state", "interaction")
106
+ put("duration", duration)
107
+ put("total_duration", totalDuration)
108
+ }
109
+ )
110
+
111
+ state.releaseInteraction = true
112
+ }
113
+
114
+ /**
115
+ * Build base tracking params from MiniAppContext
116
+ */
117
+ private fun buildBaseParams(
118
+ context: MiniAppContext?,
119
+ screenName: String,
120
+ componentName: String = "Screen"
121
+ ): MutableMap<String, Any?> {
122
+ return mutableMapOf(
123
+ "app_id" to context?.appId,
124
+ "feature_code" to context?.appCode,
125
+ "screen_name" to screenName,
126
+ "component_name" to componentName,
127
+ "tracking_source" to 1
128
+ )
129
+ }
130
+
131
+ /**
132
+ * Track popup/modal displayed event
133
+ *
134
+ * @param popupName name of the popup/modal
135
+ * @param parentScreenName the screen that shows the popup
136
+ */
137
+ fun trackPopupDisplayed(
138
+ maxApi: IMaxApi?,
139
+ context: MiniAppContext?,
140
+ parentScreenName: String?
141
+ ) {
142
+ maxApi?.track(
143
+ eventName = "auto_popup_displayed",
144
+ params = mutableMapOf<String, Any?>(
145
+ "screen_name" to parentScreenName,
146
+ "tracking_source" to 1,
147
+ "app_id" to context?.appId,
148
+ "feature_code" to context?.appCode,
149
+ "kits_version" to null,
150
+ "component_name" to "Modal"
151
+ )
152
+ )
153
+ }
154
+
155
+ /**
156
+ * Get previous screen name for back navigation detection
157
+ */
158
+ fun getLastScreenName(): String? = lastScreenName
159
+
160
+ /**
161
+ * Reset tracker (for testing or cleanup)
162
+ */
163
+ @Suppress("UNUSED")
164
+ fun reset() {
165
+ lastScreenName = null
166
+ }
167
+ }
@@ -0,0 +1,32 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Scheme
3
+ version = "1.3">
4
+ <BuildAction>
5
+ <BuildActionEntries>
6
+ <BuildActionEntry
7
+ buildForRunning = "YES">
8
+ <BuildableReference
9
+ BuildableIdentifier = "primary"
10
+ BlueprintIdentifier = "A6A920D22B2ADD1E00C1A11F"
11
+ BuildableName = "Example"
12
+ BlueprintName = "Example"
13
+ ReferencedContainer = "container:Example.xcodeproj">
14
+ </BuildableReference>
15
+ </BuildActionEntry>
16
+ </BuildActionEntries>
17
+ </BuildAction>
18
+ <LaunchAction
19
+ useCustomWorkingDirectory = "NO"
20
+ buildConfiguration = "Debug"
21
+ allowLocationSimulation = "YES">
22
+ <BuildableProductRunnable>
23
+ <BuildableReference
24
+ BuildableIdentifier = "primary"
25
+ BlueprintIdentifier = "A6A920D22B2ADD1E00C1A11F"
26
+ BuildableName = "Example"
27
+ BlueprintName = "Example"
28
+ ReferencedContainer = "container:Example.xcodeproj">
29
+ </BuildableReference>
30
+ </BuildableProductRunnable>
31
+ </LaunchAction>
32
+ </Scheme>
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>SchemeUserState</key>
6
+ <dict>
7
+ <key>Example.xcscheme</key>
8
+ <dict>
9
+ <key>orderHint</key>
10
+ <integer>7</integer>
11
+ </dict>
12
+ </dict>
13
+ </dict>
14
+ </plist>
@@ -0,0 +1,16 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>BuildLocationStyle</key>
6
+ <string>UseAppPreferences</string>
7
+ <key>CustomBuildLocationType</key>
8
+ <string>RelativeToDerivedData</string>
9
+ <key>DerivedDataCustomLocation</key>
10
+ <string>DerivedData</string>
11
+ <key>DerivedDataLocationStyle</key>
12
+ <string>WorkspaceRelativePath</string>
13
+ <key>ShowSharedSchemesAutomaticallyEnabled</key>
14
+ <true/>
15
+ </dict>
16
+ </plist>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Bucket
3
+ uuid = "6B3C387A-E951-41D1-A42C-FB6E447A46BA"
4
+ type = "0"
5
+ version = "2.0">
6
+ </Bucket>
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict />
5
+ </plist>
@@ -0,0 +1,58 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Scheme
3
+ LastUpgradeVersion = "1600"
4
+ version = "1.3">
5
+ <BuildAction
6
+ parallelizeBuildables = "YES"
7
+ buildImplicitDependencies = "YES">
8
+ <BuildActionEntries>
9
+ <BuildActionEntry
10
+ buildForTesting = "YES"
11
+ buildForRunning = "YES"
12
+ buildForProfiling = "YES"
13
+ buildForArchiving = "YES"
14
+ buildForAnalyzing = "YES">
15
+ <BuildableReference
16
+ BuildableIdentifier = "primary"
17
+ BlueprintIdentifier = "3B6FB503A75BF5BC1FA6F30BC06B9D28"
18
+ BuildableName = "MoMoUIKits.framework"
19
+ BlueprintName = "MoMoUIKits"
20
+ ReferencedContainer = "container:Pods.xcodeproj">
21
+ </BuildableReference>
22
+ </BuildActionEntry>
23
+ </BuildActionEntries>
24
+ </BuildAction>
25
+ <TestAction
26
+ buildConfiguration = "Debug"
27
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29
+ shouldUseLaunchSchemeArgsEnv = "YES">
30
+ <Testables>
31
+ </Testables>
32
+ </TestAction>
33
+ <LaunchAction
34
+ buildConfiguration = "Debug"
35
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
36
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
37
+ launchStyle = "0"
38
+ useCustomWorkingDirectory = "NO"
39
+ ignoresPersistentStateOnLaunch = "NO"
40
+ debugDocumentVersioning = "YES"
41
+ debugServiceExtension = "internal"
42
+ allowLocationSimulation = "YES">
43
+ </LaunchAction>
44
+ <ProfileAction
45
+ buildConfiguration = "Release"
46
+ shouldUseLaunchSchemeArgsEnv = "YES"
47
+ savedToolIdentifier = ""
48
+ useCustomWorkingDirectory = "NO"
49
+ debugDocumentVersioning = "YES">
50
+ </ProfileAction>
51
+ <AnalyzeAction
52
+ buildConfiguration = "Debug">
53
+ </AnalyzeAction>
54
+ <ArchiveAction
55
+ buildConfiguration = "Release"
56
+ revealArchiveInOrganizer = "YES">
57
+ </ArchiveAction>
58
+ </Scheme>
@@ -0,0 +1,58 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Scheme
3
+ LastUpgradeVersion = "1600"
4
+ version = "1.3">
5
+ <BuildAction
6
+ parallelizeBuildables = "YES"
7
+ buildImplicitDependencies = "YES">
8
+ <BuildActionEntries>
9
+ <BuildActionEntry
10
+ buildForTesting = "YES"
11
+ buildForRunning = "YES"
12
+ buildForProfiling = "YES"
13
+ buildForArchiving = "YES"
14
+ buildForAnalyzing = "YES">
15
+ <BuildableReference
16
+ BuildableIdentifier = "primary"
17
+ BlueprintIdentifier = "0AEE99A309977BD12A049FF48AF9BA4B"
18
+ BuildableName = "Pods_Example.framework"
19
+ BlueprintName = "Pods-Example"
20
+ ReferencedContainer = "container:Pods.xcodeproj">
21
+ </BuildableReference>
22
+ </BuildActionEntry>
23
+ </BuildActionEntries>
24
+ </BuildAction>
25
+ <TestAction
26
+ buildConfiguration = "Debug"
27
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29
+ shouldUseLaunchSchemeArgsEnv = "YES">
30
+ <Testables>
31
+ </Testables>
32
+ </TestAction>
33
+ <LaunchAction
34
+ buildConfiguration = "Debug"
35
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
36
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
37
+ launchStyle = "0"
38
+ useCustomWorkingDirectory = "NO"
39
+ ignoresPersistentStateOnLaunch = "NO"
40
+ debugDocumentVersioning = "YES"
41
+ debugServiceExtension = "internal"
42
+ allowLocationSimulation = "YES">
43
+ </LaunchAction>
44
+ <ProfileAction
45
+ buildConfiguration = "Release"
46
+ shouldUseLaunchSchemeArgsEnv = "YES"
47
+ savedToolIdentifier = ""
48
+ useCustomWorkingDirectory = "NO"
49
+ debugDocumentVersioning = "YES">
50
+ </ProfileAction>
51
+ <AnalyzeAction
52
+ buildConfiguration = "Debug">
53
+ </AnalyzeAction>
54
+ <ArchiveAction
55
+ buildConfiguration = "Release"
56
+ revealArchiveInOrganizer = "YES">
57
+ </ArchiveAction>
58
+ </Scheme>