Skip to content

Commit 44f4f4e

Browse files
feat: analytics
1 parent d8614c0 commit 44f4f4e

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
@@ -302,6 +303,13 @@ val screenModule = module {
302303
get(),
303304
)
304305
}
306+
viewModel { (courseId: String, courseTitle: String) ->
307+
ContentTabViewModel(
308+
courseId,
309+
courseTitle,
310+
get(),
311+
)
312+
}
305313
viewModel { (courseId: String) ->
306314
CourseSectionViewModel(
307315
courseId,
@@ -339,6 +347,7 @@ val screenModule = module {
339347
get(),
340348
get(),
341349
get(),
350+
get(),
342351
)
343352
}
344353
viewModel { (courseId: String) -> BaseVideoViewModel(courseId, get()) }
@@ -547,6 +556,7 @@ val screenModule = module {
547556
interactor = get(),
548557
courseRouter = get(),
549558
courseNotifier = get(),
559+
analytics = get()
550560
)
551561
}
552562
}

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,14 @@ enum class CourseAnalyticsEvent(val eventName: String, val biValue: String) {
7070
"Course:Progress Tab",
7171
"edx.bi.app.course.progress_tab"
7272
),
73+
OFFLINE_TAB(
74+
"Course:Offline Tab",
75+
"edx.bi.app.course.offline_tab"
76+
),
77+
CONTENT_TAB(
78+
"Course:Content Tab",
79+
"edx.bi.app.course.content_tab"
80+
),
7381
ANNOUNCEMENTS(
7482
"Course:Announcements",
7583
"edx.bi.app.course.announcements"
@@ -82,6 +90,10 @@ enum class CourseAnalyticsEvent(val eventName: String, val biValue: String) {
8290
"Course:Unit Detail",
8391
"edx.bi.app.course.unit_detail"
8492
),
93+
COURSE_CONTENT_TAB_CLICK(
94+
"Content Page:Section Click",
95+
"edx.bi.app.course.content.section.clicked"
96+
),
8597
VIEW_CERTIFICATE(
8698
"Course:View Certificate Clicked",
8799
"edx.bi.app.course.view_certificate.clicked"
@@ -114,6 +126,18 @@ enum class CourseAnalyticsEvent(val eventName: String, val biValue: String) {
114126
"Video:Completed",
115127
"edx.bi.app.videos.completed"
116128
),
129+
VIDEO_SHOW_COMPLETED(
130+
"Content Page:Show Completed Subsection Click",
131+
"edx.bi.app.course.content.show_completed_subsection.clicked"
132+
),
133+
COURSE_CONTENT_VIDEO_CLICK(
134+
"Course:Video click",
135+
"edx.bi.app.course.content.video.clicked"
136+
),
137+
COURSE_CONTENT_ASSIGNMENT_CLICK(
138+
"Course:Assignment click",
139+
"edx.bi.app.course.content.assignment.clicked"
140+
),
117141
CAST_CONNECTED(
118142
"Cast:Connected",
119143
"edx.bi.app.cast.connected"
@@ -172,6 +196,7 @@ enum class CourseAnalyticsKey(val key: String) {
172196
LINK("link"),
173197
SUPPORTED("supported"),
174198
BLOCK_ID("block_id"),
199+
TAB_NAME("tab_name"),
175200
BLOCK_NAME("block_name"),
176201
BLOCK_TYPE("block_type"),
177202
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
@@ -542,6 +542,9 @@ private fun DashboardPager(
542542

543543
CourseContainerTab.CONTENT -> {
544544
ContentTabScreen(
545+
viewModel = koinViewModel(
546+
parameters = { parametersOf(viewModel.courseId, viewModel.courseName) }
547+
),
545548
windowSize = windowSize,
546549
fragmentManager = fragmentManager,
547550
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
@@ -336,7 +336,8 @@ class CourseContainerViewModel(
336336
CourseContainerTab.DATES -> datesTabClickedEvent()
337337
CourseContainerTab.PROGRESS -> progressTabClickedEvent()
338338
CourseContainerTab.MORE -> moreTabClickedEvent()
339-
CourseContainerTab.OFFLINE, CourseContainerTab.CONTENT -> {}
339+
CourseContainerTab.OFFLINE -> offlineTabClickedEvent()
340+
CourseContainerTab.CONTENT -> contentTabClickedEvent()
340341
}
341342
}
342343

@@ -388,6 +389,15 @@ class CourseContainerViewModel(
388389
logCourseContainerEvent(CourseAnalyticsEvent.PROGRESS_TAB)
389390
}
390391

392+
private fun offlineTabClickedEvent() {
393+
logCourseContainerEvent(CourseAnalyticsEvent.OFFLINE_TAB)
394+
}
395+
396+
private fun contentTabClickedEvent() {
397+
logCourseContainerEvent(CourseAnalyticsEvent.CONTENT_TAB)
398+
}
399+
400+
391401
private fun logCourseContainerEvent(event: CourseAnalyticsEvent) {
392402
courseAnalytics.logScreenEvent(
393403
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)