Skip to content

Commit 5faf071

Browse files
feat: minor ui fixes
1 parent 8e64251 commit 5faf071

File tree

4 files changed

+95
-18
lines changed

4 files changed

+95
-18
lines changed

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,6 @@ val screenModule = module {
352352
get(),
353353
get(),
354354
get(),
355-
get(),
356355
)
357356
}
358357
viewModel { (courseId: String) ->

course/src/main/java/org/openedx/course/presentation/ui/CourseUI.kt

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,9 @@ fun CourseVideoSection(
673673
0f
674674
}
675675
CourseVideoItem(
676+
modifier = Modifier
677+
.width(192.dp)
678+
.height(108.dp),
676679
modifier = Modifier
677680
.width(videoCardWidth)
678681
.height(108.dp)
@@ -700,22 +703,22 @@ fun CourseVideoItem(
700703
titleStyle: TextStyle = MaterialTheme.appTypography.bodySmall,
701704
contentModifier: Modifier = Modifier.padding(8.dp),
702705
progressModifier: Modifier = Modifier.height(4.dp),
703-
playButtonSize: Dp = 32.dp
706+
playButtonSize: Dp = 32.dp,
707+
borderColor: Color? = null
704708
) {
709+
val borderColor = borderColor ?: if (videoBlock.isCompleted()) {
710+
MaterialTheme.appColors.successGreen
711+
} else {
712+
Color.Transparent
713+
}
705714
Box(
706715
modifier = modifier
707716
.clip(MaterialTheme.appShapes.videoPreviewShape)
708-
.let {
709-
if (videoBlock.isCompleted()) {
710-
it.border(
711-
width = 3.dp,
712-
color = MaterialTheme.appColors.successGreen,
713-
shape = MaterialTheme.appShapes.videoPreviewShape
714-
)
715-
} else {
716-
it
717-
}
718-
}
717+
.border(
718+
width = 3.dp,
719+
color = borderColor,
720+
shape = MaterialTheme.appShapes.videoPreviewShape
721+
)
719722
.clickable { onClick() }
720723
) {
721724
AsyncImage(

course/src/main/java/org/openedx/course/presentation/unit/container/CourseUnitContainerFragment.kt

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,26 @@ import androidx.compose.foundation.layout.Arrangement
1010
import androidx.compose.foundation.layout.Column
1111
import androidx.compose.foundation.layout.PaddingValues
1212
import androidx.compose.foundation.layout.Spacer
13+
import androidx.compose.foundation.layout.fillMaxWidth
1314
import androidx.compose.foundation.layout.height
15+
import androidx.compose.foundation.layout.padding
1416
import androidx.compose.foundation.layout.width
1517
import androidx.compose.foundation.lazy.LazyRow
1618
import androidx.compose.foundation.lazy.items
19+
import androidx.compose.foundation.lazy.rememberLazyListState
1720
import androidx.compose.material.Divider
1821
import androidx.compose.material.MaterialTheme
22+
import androidx.compose.material.Text
1923
import androidx.compose.runtime.Composable
24+
import androidx.compose.runtime.LaunchedEffect
2025
import androidx.compose.runtime.collectAsState
2126
import androidx.compose.runtime.getValue
2227
import androidx.compose.runtime.livedata.observeAsState
2328
import androidx.compose.runtime.mutableStateOf
2429
import androidx.compose.runtime.saveable.rememberSaveable
2530
import androidx.compose.runtime.setValue
2631
import androidx.compose.ui.Modifier
32+
import androidx.compose.ui.text.style.TextOverflow
2733
import androidx.compose.ui.unit.dp
2834
import androidx.constraintlayout.widget.ConstraintLayout
2935
import androidx.core.os.bundleOf
@@ -341,6 +347,10 @@ class CourseUnitContainerFragment : Fragment(R.layout.fragment_course_unit_conta
341347
)
342348
Spacer(modifier = Modifier.height(8.dp))
343349
Divider()
350+
if (viewModel.mode == CourseViewMode.VIDEOS) {
351+
Spacer(modifier = Modifier.height(16.dp))
352+
HierarchyPathText()
353+
}
344354
Spacer(modifier = Modifier.height(8.dp))
345355
}
346356
}
@@ -500,7 +510,7 @@ class CourseUnitContainerFragment : Fragment(R.layout.fragment_course_unit_conta
500510
hasPrevBlock = hasPrevBlock,
501511
nextButtonText = nextButtonText,
502512
hasNextBlock = hasNextBlock,
503-
isVerticalNavigation = !viewModel.isCourseUnitProgressEnabled,
513+
isVerticalNavigation = !viewModel.isCourseUnitProgressEnabled || viewModel.mode != CourseViewMode.VIDEOS,
504514
onPrevClick = {
505515
handlePrevClick { next, hasPrev, hasNext ->
506516
nextButtonText = next
@@ -527,34 +537,67 @@ class CourseUnitContainerFragment : Fragment(R.layout.fragment_course_unit_conta
527537
val videoPreview by viewModel.videoPreview.collectAsState()
528538
val videoProgress by viewModel.videoProgress.collectAsState()
529539
val currentBlock by viewModel.currentBlock.collectAsState()
540+
val rowState = rememberLazyListState()
541+
542+
LaunchedEffect(currentBlock) {
543+
rowState.animateScrollToItem(videoBlocks.indexOf(currentBlock))
544+
}
530545

531546
if (videoBlocks.isNotEmpty()) {
532547
LazyRow(
548+
state = rowState,
533549
horizontalArrangement = Arrangement.spacedBy(8.dp),
534550
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp)
535551
) {
536552
items(videoBlocks) { block ->
537-
val playButtonSize = if (block.id == currentBlock?.id) {
553+
val isSelectedBlock = block.id == currentBlock?.id
554+
val playButtonSize = if (isSelectedBlock) {
538555
0.dp
539556
} else {
540557
14.dp
541558
}
559+
val borderColor = if (isSelectedBlock) {
560+
MaterialTheme.appColors.primary
561+
} else {
562+
null
563+
}
542564
CourseVideoItem(
543565
modifier = Modifier
544566
.width(112.dp)
545567
.height(63.dp),
546568
videoBlock = block,
547569
preview = videoPreview[block.id],
548570
progress = videoProgress[block.id] ?: 0f,
549-
onClick = { onVideoClick(block) },
571+
onClick = {
572+
onVideoClick(block)
573+
},
550574
style = MaterialTheme.appTypography.labelSmall,
551575
playButtonSize = playButtonSize,
576+
borderColor = borderColor
552577
)
553578
}
554579
}
555580
}
556581
}
557582

583+
@Composable
584+
private fun HierarchyPathText() {
585+
val hierarchyPath by viewModel.hierarchyPath.collectAsState()
586+
587+
if (hierarchyPath.isNotEmpty()) {
588+
Text(
589+
overflow = TextOverflow.Ellipsis,
590+
modifier = Modifier
591+
.fillMaxWidth()
592+
.padding(horizontal = 24.dp),
593+
text = hierarchyPath,
594+
style = MaterialTheme.appTypography.bodySmall,
595+
color = MaterialTheme.appColors.textDark,
596+
maxLines = 2,
597+
)
598+
}
599+
}
600+
558601
companion object {
559602

560603
private const val ARG_COURSE_ID = "courseId"

course/src/main/java/org/openedx/course/presentation/unit/container/CourseUnitContainerViewModel.kt

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import org.openedx.course.domain.interactor.CourseInteractor
2727
import org.openedx.course.presentation.CourseAnalytics
2828
import org.openedx.course.presentation.CourseAnalyticsEvent
2929
import org.openedx.course.presentation.CourseAnalyticsKey
30-
import org.openedx.course.presentation.CourseRouter
3130
import org.openedx.foundation.extension.clearAndAddAll
3231
import org.openedx.foundation.extension.indexOfFirstFromIndex
3332
import org.openedx.foundation.presentation.BaseViewModel
@@ -42,7 +41,6 @@ class CourseUnitContainerViewModel(
4241
private val notifier: CourseNotifier,
4342
private val analytics: CourseAnalytics,
4443
private val networkConnection: NetworkConnection,
45-
private val router: CourseRouter,
4644
) : BaseViewModel() {
4745

4846
private val blocks = ArrayList<Block>()
@@ -96,6 +94,9 @@ class CourseUnitContainerViewModel(
9694
private val _currentBlock = MutableStateFlow<Block?>(null)
9795
val currentBlock = _currentBlock.asStateFlow()
9896

97+
private val _hierarchyPath = MutableStateFlow<String>("")
98+
val hierarchyPath = _hierarchyPath.asStateFlow()
99+
99100
var nextButtonText = ""
100101
var hasNextBlock = false
101102

@@ -252,6 +253,7 @@ class CourseUnitContainerViewModel(
252253
fun getCurrentBlock(): Block {
253254
val block = _descendantsBlocks.value.getOrNull(currentIndex) ?: blocks[currentVerticalIndex]
254255
_currentBlock.value = block
256+
_hierarchyPath.value = buildHierarchyPath(block)
255257
return block
256258
}
257259

@@ -270,6 +272,7 @@ class CourseUnitContainerViewModel(
270272
_indexInContainer.value = currentIndex
271273
}
272274
_currentBlock.value = block
275+
_hierarchyPath.value = buildHierarchyPath(block)
273276
return block
274277
}
275278
return null
@@ -378,6 +381,10 @@ class CourseUnitContainerViewModel(
378381
currentIndex = blockIndex
379382
_indexInContainer.value = currentIndex
380383
_currentBlock.value = videoBlock
384+
_hierarchyPath.value = buildHierarchyPath(videoBlock)
385+
}
386+
viewModelScope.launch {
387+
loadVideoProgress()
381388
}
382389
}
383390

@@ -416,4 +423,29 @@ class CourseUnitContainerViewModel(
416423
}
417424
_videoPreview.value = videoPreview
418425
}
426+
427+
private fun buildHierarchyPath(block: Block): String {
428+
val pathComponents = mutableListOf<String>()
429+
430+
// Find the current block (Unit)
431+
pathComponents.add(block.displayName)
432+
433+
// Find the parent Vertical block (but don't add it to path)
434+
val verticalBlock = findParentBlock(block.id)
435+
verticalBlock?.let { vertical ->
436+
// Find the parent Sequential block (Subsection)
437+
val sequentialBlock = findParentBlock(vertical.id)
438+
sequentialBlock?.let { sequential ->
439+
pathComponents.add(0, sequential.displayName)
440+
441+
// Find the parent Chapter block (Section)
442+
val chapterBlock = findParentBlock(sequential.id)
443+
chapterBlock?.let { chapter ->
444+
pathComponents.add(0, chapter.displayName)
445+
}
446+
}
447+
}
448+
449+
return pathComponents.joinToString(" > ")
450+
}
419451
}

0 commit comments

Comments
 (0)