Skip to content

Commit f7cfb43

Browse files
feat: course home pager and pager indicator with navigation
1 parent 8de8a4d commit f7cfb43

File tree

10 files changed

+1240
-111
lines changed

10 files changed

+1240
-111
lines changed

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import org.openedx.course.presentation.container.CourseContainerViewModel
2323
import org.openedx.course.presentation.contenttab.ContentTabViewModel
2424
import org.openedx.course.presentation.dates.CourseDatesViewModel
2525
import org.openedx.course.presentation.handouts.HandoutsViewModel
26+
import org.openedx.course.presentation.home.CourseHomeViewModel
2627
import org.openedx.course.presentation.offline.CourseOfflineViewModel
2728
import org.openedx.course.presentation.outline.CourseContentAllViewModel
2829
import org.openedx.course.presentation.progress.CourseProgressViewModel
@@ -309,6 +310,26 @@ val screenModule = module {
309310
get(),
310311
)
311312
}
313+
viewModel { (courseId: String, courseTitle: String) ->
314+
CourseHomeViewModel(
315+
courseId,
316+
courseTitle,
317+
get(),
318+
get(),
319+
get(),
320+
get(),
321+
get(),
322+
get(),
323+
get(),
324+
get(),
325+
get(),
326+
get(),
327+
get(),
328+
get(),
329+
get(),
330+
get(),
331+
)
332+
}
312333
viewModel { (courseId: String) ->
313334
CourseSectionViewModel(
314335
courseId,
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package org.openedx.core.ui
2+
3+
import androidx.compose.animation.animateColorAsState
4+
import androidx.compose.animation.core.animateDpAsState
5+
import androidx.compose.animation.core.tween
6+
import androidx.compose.foundation.Canvas
7+
import androidx.compose.foundation.layout.Arrangement
8+
import androidx.compose.foundation.layout.Row
9+
import androidx.compose.foundation.layout.size
10+
import androidx.compose.material.MaterialTheme
11+
import androidx.compose.runtime.Composable
12+
import androidx.compose.runtime.getValue
13+
import androidx.compose.ui.Alignment
14+
import androidx.compose.ui.Modifier
15+
import androidx.compose.ui.geometry.CornerRadius
16+
import androidx.compose.ui.geometry.Offset
17+
import androidx.compose.ui.geometry.Size
18+
import androidx.compose.ui.graphics.Color
19+
import androidx.compose.ui.tooling.preview.Preview
20+
import androidx.compose.ui.unit.Dp
21+
import androidx.compose.ui.unit.dp
22+
import org.openedx.core.ui.theme.OpenEdXTheme
23+
import org.openedx.core.ui.theme.appColors
24+
25+
@Composable
26+
fun PageIndicator(
27+
numberOfPages: Int,
28+
modifier: Modifier = Modifier,
29+
selectedPage: Int = 0,
30+
selectedColor: Color = MaterialTheme.appColors.info,
31+
previousUnselectedColor: Color = MaterialTheme.appColors.cardViewBorder,
32+
nextUnselectedColor: Color = MaterialTheme.appColors.textFieldBorder,
33+
defaultRadius: Dp = 20.dp,
34+
selectedLength: Dp = 60.dp,
35+
space: Dp = 30.dp,
36+
animationDurationInMillis: Int = 300,
37+
) {
38+
Row(
39+
verticalAlignment = Alignment.CenterVertically,
40+
horizontalArrangement = Arrangement.spacedBy(space),
41+
modifier = modifier,
42+
) {
43+
for (i in 0 until numberOfPages) {
44+
val isSelected = i == selectedPage
45+
val unselectedColor =
46+
if (i < selectedPage) previousUnselectedColor else nextUnselectedColor
47+
PageIndicatorView(
48+
isSelected = isSelected,
49+
selectedColor = selectedColor,
50+
defaultColor = unselectedColor,
51+
defaultRadius = defaultRadius,
52+
selectedLength = selectedLength,
53+
animationDurationInMillis = animationDurationInMillis,
54+
)
55+
}
56+
}
57+
}
58+
59+
@Composable
60+
fun PageIndicatorView(
61+
isSelected: Boolean,
62+
selectedColor: Color,
63+
defaultColor: Color,
64+
defaultRadius: Dp,
65+
selectedLength: Dp,
66+
animationDurationInMillis: Int,
67+
modifier: Modifier = Modifier,
68+
) {
69+
val color: Color by animateColorAsState(
70+
targetValue = if (isSelected) {
71+
selectedColor
72+
} else {
73+
defaultColor
74+
},
75+
animationSpec = tween(
76+
durationMillis = animationDurationInMillis,
77+
),
78+
label = ""
79+
)
80+
val width: Dp by animateDpAsState(
81+
targetValue = if (isSelected) {
82+
selectedLength
83+
} else {
84+
defaultRadius
85+
},
86+
animationSpec = tween(
87+
durationMillis = animationDurationInMillis,
88+
),
89+
label = ""
90+
)
91+
92+
Canvas(
93+
modifier = modifier
94+
.size(
95+
width = width,
96+
height = defaultRadius,
97+
),
98+
) {
99+
drawRoundRect(
100+
color = color,
101+
topLeft = Offset.Zero,
102+
size = Size(
103+
width = width.toPx(),
104+
height = defaultRadius.toPx(),
105+
),
106+
cornerRadius = CornerRadius(
107+
x = defaultRadius.toPx(),
108+
y = defaultRadius.toPx(),
109+
),
110+
)
111+
}
112+
}
113+
114+
@Preview
115+
@Composable
116+
private fun PageIndicatorViewPreview() {
117+
OpenEdXTheme {
118+
PageIndicator(
119+
numberOfPages = 4,
120+
selectedPage = 2
121+
)
122+
}
123+
}

core/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@
176176
<string name="core_not_synced">Not Synced</string>
177177
<string name="core_syncing_to_calendar">Syncing to calendar…</string>
178178
<string name="core_next">Next</string>
179+
<string name="core_previous">Previous</string>
179180

180181
<string name="core_download_queue_title">Downloads</string>
181182
<string name="core_download_untitled">(Untitled)</string>

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ import org.openedx.course.presentation.contenttab.ContentTabScreen
9090
import org.openedx.course.presentation.dates.CourseDatesScreen
9191
import org.openedx.course.presentation.handouts.HandoutsScreen
9292
import org.openedx.course.presentation.handouts.HandoutsType
93+
import org.openedx.course.presentation.home.CourseHomeScreen
9394
import org.openedx.course.presentation.offline.CourseOfflineScreen
9495
import org.openedx.course.presentation.progress.CourseProgressScreen
9596
import org.openedx.course.presentation.ui.DatesShiftedSnackBar
@@ -469,7 +470,16 @@ private fun DashboardPager(
469470
) { page ->
470471
when (CourseContainerTab.entries[page]) {
471472
CourseContainerTab.HOME -> {
472-
// Home tab content will be implemented later
473+
CourseHomeScreen(
474+
windowSize = windowSize,
475+
viewModel = koinViewModel(
476+
parameters = { parametersOf(viewModel.courseId, viewModel.courseName) }
477+
),
478+
fragmentManager = fragmentManager,
479+
onResetDatesClick = {
480+
viewModel.onRefresh(CourseContainerTab.DATES)
481+
}
482+
)
473483
}
474484

475485
CourseContainerTab.DATES -> {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.openedx.course.presentation.home
2+
3+
enum class CourseHomePagerTab {
4+
COURSE_COMPLETION,
5+
VIDEOS,
6+
ASSIGNMENT,
7+
GRADES
8+
}

0 commit comments

Comments
 (0)