Skip to content

Commit de38264

Browse files
feat: analytics
1 parent a2f36a3 commit de38264

File tree

10 files changed

+136
-3
lines changed

10 files changed

+136
-3
lines changed

app/src/main/java/org/openedx/app/di/ScreenModule.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import org.openedx.course.data.repository.CourseRepository
2020
import org.openedx.course.domain.interactor.CourseInteractor
2121
import org.openedx.course.presentation.assignments.CourseAssignmentViewModel
2222
import org.openedx.course.presentation.container.CourseContainerViewModel
23+
import org.openedx.course.presentation.contenttab.ContentTabViewModel
2324
import org.openedx.course.presentation.dates.CourseDatesViewModel
2425
import org.openedx.course.presentation.handouts.HandoutsViewModel
2526
import org.openedx.course.presentation.offline.CourseOfflineViewModel
@@ -300,6 +301,13 @@ val screenModule = module {
300301
get(),
301302
)
302303
}
304+
viewModel { (courseId: String, courseTitle: String) ->
305+
ContentTabViewModel(
306+
courseId,
307+
courseTitle,
308+
get(),
309+
)
310+
}
303311
viewModel { (courseId: String) ->
304312
CourseSectionViewModel(
305313
courseId,
@@ -337,6 +345,7 @@ val screenModule = module {
337345
get(),
338346
get(),
339347
get(),
348+
get(),
340349
)
341350
}
342351
viewModel { (courseId: String) -> BaseVideoViewModel(courseId, get()) }
@@ -537,6 +546,7 @@ val screenModule = module {
537546
interactor = get(),
538547
courseRouter = get(),
539548
courseNotifier = get(),
549+
analytics = get()
540550
)
541551
}
542552
}

course/src/main/java/org/openedx/course/presentation/CourseAnalytics.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ enum class CourseAnalyticsEvent(val eventName: String, val biValue: String) {
6666
"Course:Handouts Tab",
6767
"edx.bi.app.course.handouts_tab"
6868
),
69+
OFFLINE_TAB(
70+
"Course:Offline Tab",
71+
"edx.bi.app.course.offline_tab"
72+
),
73+
CONTENT_TAB(
74+
"Course:Content Tab",
75+
"edx.bi.app.course.content_tab"
76+
),
6977
ANNOUNCEMENTS(
7078
"Course:Announcements",
7179
"edx.bi.app.course.announcements"
@@ -78,6 +86,10 @@ enum class CourseAnalyticsEvent(val eventName: String, val biValue: String) {
7886
"Course:Unit Detail",
7987
"edx.bi.app.course.unit_detail"
8088
),
89+
COURSE_CONTENT_TAB_CLICK(
90+
"Content Page:Section Click",
91+
"edx.bi.app.course.content.section.clicked"
92+
),
8193
VIEW_CERTIFICATE(
8294
"Course:View Certificate Clicked",
8395
"edx.bi.app.course.view_certificate.clicked"
@@ -110,6 +122,18 @@ enum class CourseAnalyticsEvent(val eventName: String, val biValue: String) {
110122
"Video:Completed",
111123
"edx.bi.app.videos.completed"
112124
),
125+
VIDEO_SHOW_COMPLETED(
126+
"Content Page:Show Completed Subsection Click",
127+
"edx.bi.app.course.content.show_completed_subsection.clicked"
128+
),
129+
COURSE_CONTENT_VIDEO_CLICK(
130+
"Course:Video click",
131+
"edx.bi.app.course.content.video.clicked"
132+
),
133+
COURSE_CONTENT_ASSIGNMENT_CLICK(
134+
"Course:Assignment click",
135+
"edx.bi.app.course.content.assignment.clicked"
136+
),
113137
CAST_CONNECTED(
114138
"Cast:Connected",
115139
"edx.bi.app.cast.connected"
@@ -168,6 +192,7 @@ enum class CourseAnalyticsKey(val key: String) {
168192
LINK("link"),
169193
SUPPORTED("supported"),
170194
BLOCK_ID("block_id"),
195+
TAB_NAME("tab_name"),
171196
BLOCK_NAME("block_name"),
172197
BLOCK_TYPE("block_type"),
173198
PLAY_MEDIUM("play_medium"),

course/src/main/java/org/openedx/course/presentation/assignments/CourseAssignmentViewModel.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,17 @@ import org.openedx.core.domain.model.Progress
1414
import org.openedx.core.system.notifier.CourseNotifier
1515
import org.openedx.core.system.notifier.CourseStructureUpdated
1616
import org.openedx.course.domain.interactor.CourseInteractor
17+
import org.openedx.course.presentation.CourseAnalytics
18+
import org.openedx.course.presentation.CourseAnalyticsEvent
19+
import org.openedx.course.presentation.CourseAnalyticsKey
1720
import org.openedx.course.presentation.CourseRouter
1821

1922
class CourseAssignmentViewModel(
2023
val courseId: String,
2124
val courseRouter: CourseRouter,
2225
private val interactor: CourseInteractor,
2326
private val courseNotifier: CourseNotifier,
27+
private val analytics: CourseAnalytics,
2428
) : ViewModel() {
2529
private val _uiState =
2630
MutableStateFlow<CourseAssignmentUIState>(CourseAssignmentUIState.Loading)
@@ -94,4 +98,18 @@ class CourseAssignmentViewModel(
9498
}
9599
}
96100
}
101+
102+
fun logAssignmentClick(blockId: String) {
103+
analytics.logEvent(
104+
CourseAnalyticsEvent.COURSE_CONTENT_ASSIGNMENT_CLICK.eventName,
105+
buildMap {
106+
put(
107+
CourseAnalyticsKey.NAME.key,
108+
CourseAnalyticsEvent.COURSE_CONTENT_ASSIGNMENT_CLICK.biValue
109+
)
110+
put(CourseAnalyticsKey.COURSE_ID.key, courseId)
111+
put(CourseAnalyticsKey.BLOCK_ID.key, blockId)
112+
}
113+
)
114+
}
97115
}

course/src/main/java/org/openedx/course/presentation/assignments/CourseContentAssignmentScreen.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ fun CourseContentAssignmentScreen(
9999
subSectionId = subSectionBlock.id,
100100
mode = CourseViewMode.FULL
101101
)
102+
viewModel.logAssignmentClick(subSectionBlock.id)
102103
},
103104
)
104105
}

course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,9 @@ private fun DashboardPager(
532532

533533
CourseContainerTab.CONTENT -> {
534534
ContentTabScreen(
535+
viewModel = koinViewModel(
536+
parameters = { parametersOf(viewModel.courseId, viewModel.courseName) }
537+
),
535538
windowSize = windowSize,
536539
fragmentManager = fragmentManager,
537540
courseId = viewModel.courseId,

course/src/main/java/org/openedx/course/presentation/container/CourseContainerViewModel.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,8 @@ class CourseContainerViewModel(
328328
CourseContainerTab.DISCUSSIONS -> discussionTabClickedEvent()
329329
CourseContainerTab.DATES -> datesTabClickedEvent()
330330
CourseContainerTab.MORE -> moreTabClickedEvent()
331-
CourseContainerTab.OFFLINE, CourseContainerTab.CONTENT -> {}
331+
CourseContainerTab.OFFLINE -> offlineTabClickedEvent()
332+
CourseContainerTab.CONTENT -> contentTabClickedEvent()
332333
}
333334
}
334335

@@ -376,6 +377,15 @@ class CourseContainerViewModel(
376377
logCourseContainerEvent(CourseAnalyticsEvent.MORE_TAB)
377378
}
378379

380+
private fun offlineTabClickedEvent() {
381+
logCourseContainerEvent(CourseAnalyticsEvent.OFFLINE_TAB)
382+
}
383+
384+
private fun contentTabClickedEvent() {
385+
logCourseContainerEvent(CourseAnalyticsEvent.CONTENT_TAB)
386+
}
387+
388+
379389
private fun logCourseContainerEvent(event: CourseAnalyticsEvent) {
380390
courseAnalytics.logScreenEvent(
381391
screenName = event.eventName,

course/src/main/java/org/openedx/course/presentation/contenttab/ContentTabScreen.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import org.openedx.foundation.presentation.windowSizeValue
4747

4848
@Composable
4949
fun ContentTabScreen(
50+
viewModel: ContentTabViewModel,
5051
windowSize: WindowSize,
5152
fragmentManager: FragmentManager,
5253
courseId: String,
@@ -110,6 +111,7 @@ fun ContentTabScreen(
110111
scope.launch {
111112
pagerState.scrollToPage(index)
112113
}
114+
viewModel.logTabClickEvent(CourseContentTab.entries[index])
113115
},
114116
contentAlignment = Alignment.Center
115117
) {
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package org.openedx.course.presentation.contenttab
2+
3+
import org.openedx.course.presentation.CourseAnalytics
4+
import org.openedx.course.presentation.CourseAnalyticsEvent
5+
import org.openedx.course.presentation.CourseAnalyticsKey
6+
import org.openedx.course.presentation.container.CourseContentTab
7+
import org.openedx.foundation.presentation.BaseViewModel
8+
9+
class ContentTabViewModel(
10+
val courseId: String,
11+
private val courseTitle: String,
12+
private val analytics: CourseAnalytics,
13+
) : BaseViewModel() {
14+
15+
fun logTabClickEvent(contentTab: CourseContentTab) {
16+
analytics.logEvent(
17+
CourseAnalyticsEvent.COURSE_CONTENT_TAB_CLICK.eventName,
18+
buildMap {
19+
put(
20+
CourseAnalyticsKey.NAME.key,
21+
CourseAnalyticsEvent.COURSE_CONTENT_TAB_CLICK.biValue
22+
)
23+
put(CourseAnalyticsKey.COURSE_ID.key, courseId)
24+
put(CourseAnalyticsKey.COURSE_NAME.key, courseTitle)
25+
put(CourseAnalyticsKey.TAB_NAME.key, contentTab.name)
26+
}
27+
)
28+
}
29+
}

course/src/main/java/org/openedx/course/presentation/videos/CourseContentVideoScreen.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ fun CourseContentVideoScreen(
7272
unitId = viewModel.getBlockParent(videoBlock.id)?.id ?: return@CourseVideosUI,
7373
mode = CourseViewMode.VIDEOS
7474
)
75+
viewModel.logVideoClick(videoBlock.id)
7576
},
7677
onDownloadClick = { blocksIds ->
7778
viewModel.downloadBlocks(
@@ -81,7 +82,7 @@ fun CourseContentVideoScreen(
8182
},
8283
onCompletedSectionVisibilityChange = {
8384
viewModel.onCompletedSectionVisibilityChange()
84-
}
85+
},
8586
)
8687
}
8788

course/src/main/java/org/openedx/course/presentation/videos/CourseVideoViewModel.kt

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.openedx.course.presentation.videos
22

3+
import android.annotation.SuppressLint
34
import android.content.Context
45
import androidx.fragment.app.FragmentManager
56
import androidx.lifecycle.viewModelScope
@@ -29,13 +30,18 @@ import org.openedx.core.system.notifier.CourseNotifier
2930
import org.openedx.core.system.notifier.CourseStructureUpdated
3031
import org.openedx.course.R
3132
import org.openedx.course.domain.interactor.CourseInteractor
33+
import org.openedx.course.presentation.CourseAnalytics
34+
import org.openedx.course.presentation.CourseAnalyticsEvent
35+
import org.openedx.course.presentation.CourseAnalyticsKey
3236
import org.openedx.course.presentation.CourseRouter
3337
import org.openedx.foundation.presentation.UIMessage
3438
import org.openedx.foundation.system.ResourceManager
3539
import org.openedx.foundation.utils.FileUtil
3640

41+
@SuppressLint("StaticFieldLeak")
3742
class CourseVideoViewModel(
3843
val courseId: String,
44+
private val context: Context,
3945
private val config: Config,
4046
private val interactor: CourseInteractor,
4147
private val resourceManager: ResourceManager,
@@ -44,8 +50,8 @@ class CourseVideoViewModel(
4450
private val courseNotifier: CourseNotifier,
4551
private val downloadDialogManager: DownloadDialogManager,
4652
private val fileUtil: FileUtil,
47-
private val context: Context,
4853
val courseRouter: CourseRouter,
54+
private val analytics: CourseAnalytics,
4955
coreAnalytics: CoreAnalytics,
5056
downloadDao: DownloadDao,
5157
workerController: DownloadWorkerController,
@@ -289,8 +295,36 @@ class CourseVideoViewModel(
289295
fun onCompletedSectionVisibilityChange() {
290296
if (_uiState.value is CourseVideoUIState.CourseData) {
291297
val state = _uiState.value as CourseVideoUIState.CourseData
298+
_uiState.value = state.copy(isCompletedSectionsShown = !state.isCompletedSectionsShown)
299+
300+
analytics.logEvent(
301+
CourseAnalyticsEvent.VIDEO_SHOW_COMPLETED.eventName,
302+
buildMap {
303+
put(
304+
CourseAnalyticsKey.NAME.key,
305+
CourseAnalyticsEvent.VIDEO_SHOW_COMPLETED.biValue
306+
)
307+
put(CourseAnalyticsKey.COURSE_ID.key, courseId)
308+
}
309+
)
310+
}
311+
}
292312

313+
fun logVideoClick(blockId: String) {
314+
if (_uiState.value is CourseVideoUIState.CourseData) {
315+
val state = _uiState.value as CourseVideoUIState.CourseData
293316
_uiState.value = state.copy(isCompletedSectionsShown = !state.isCompletedSectionsShown)
317+
analytics.logEvent(
318+
CourseAnalyticsEvent.COURSE_CONTENT_VIDEO_CLICK.eventName,
319+
buildMap {
320+
put(
321+
CourseAnalyticsKey.NAME.key,
322+
CourseAnalyticsEvent.COURSE_CONTENT_VIDEO_CLICK.biValue
323+
)
324+
put(CourseAnalyticsKey.COURSE_ID.key, courseId)
325+
put(CourseAnalyticsKey.BLOCK_ID.key, blockId)
326+
}
327+
)
294328
}
295329
}
296330

0 commit comments

Comments
 (0)