Skip to content

Commit f31162d

Browse files
feat: minor ui fixes
1 parent 86351b3 commit f31162d

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
@@ -26,7 +26,6 @@ import org.openedx.course.domain.interactor.CourseInteractor
2626
import org.openedx.course.presentation.CourseAnalytics
2727
import org.openedx.course.presentation.CourseAnalyticsEvent
2828
import org.openedx.course.presentation.CourseAnalyticsKey
29-
import org.openedx.course.presentation.CourseRouter
3029
import org.openedx.foundation.extension.clearAndAddAll
3130
import org.openedx.foundation.extension.indexOfFirstFromIndex
3231
import org.openedx.foundation.presentation.BaseViewModel
@@ -41,7 +40,6 @@ class CourseUnitContainerViewModel(
4140
private val notifier: CourseNotifier,
4241
private val analytics: CourseAnalytics,
4342
private val networkConnection: NetworkConnection,
44-
private val router: CourseRouter,
4543
) : BaseViewModel() {
4644

4745
private val blocks = ArrayList<Block>()
@@ -95,6 +93,9 @@ class CourseUnitContainerViewModel(
9593
private val _currentBlock = MutableStateFlow<Block?>(null)
9694
val currentBlock = _currentBlock.asStateFlow()
9795

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

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

@@ -269,6 +271,7 @@ class CourseUnitContainerViewModel(
269271
_indexInContainer.value = currentIndex
270272
}
271273
_currentBlock.value = block
274+
_hierarchyPath.value = buildHierarchyPath(block)
272275
return block
273276
}
274277
return null
@@ -377,6 +380,10 @@ class CourseUnitContainerViewModel(
377380
currentIndex = blockIndex
378381
_indexInContainer.value = currentIndex
379382
_currentBlock.value = videoBlock
383+
_hierarchyPath.value = buildHierarchyPath(videoBlock)
384+
}
385+
viewModelScope.launch {
386+
loadVideoProgress()
380387
}
381388
}
382389

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

0 commit comments

Comments
 (0)