Skip to content

Commit cc4f47f

Browse files
feat: navigate to course outline, swipe refresh on empty state
1 parent 26eb430 commit cc4f47f

File tree

5 files changed

+70
-10
lines changed

5 files changed

+70
-10
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,9 @@ val screenModule = module {
523523
downloadHelper = get(),
524524
downloadDialogManager = get(),
525525
fileUtil = get(),
526-
analytics = get()
526+
analytics = get(),
527+
discoveryNotifier = get(),
528+
router = get()
527529
)
528530
}
529531
}

downloads/src/main/java/org/openedx/downloads/presentation/DownloadsRouter.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,10 @@ import androidx.fragment.app.FragmentManager
55
interface DownloadsRouter {
66

77
fun navigateToSettings(fm: FragmentManager)
8+
9+
fun navigateToCourseOutline(
10+
fm: FragmentManager,
11+
courseId: String,
12+
courseTitle: String,
13+
)
814
}

downloads/src/main/java/org/openedx/downloads/presentation/download/DownloadsFragment.kt

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ import androidx.compose.foundation.layout.width
2121
import androidx.compose.foundation.layout.widthIn
2222
import androidx.compose.foundation.lazy.LazyColumn
2323
import androidx.compose.foundation.lazy.items
24+
import androidx.compose.foundation.rememberScrollState
2425
import androidx.compose.foundation.shape.CircleShape
26+
import androidx.compose.foundation.verticalScroll
2527
import androidx.compose.material.Card
2628
import androidx.compose.material.CircularProgressIndicator
2729
import androidx.compose.material.Divider
@@ -128,6 +130,13 @@ class DownloadsFragment : Fragment() {
128130
viewModel.refreshData()
129131
}
130132

133+
is DownloadsViewActions.OpenCourse -> {
134+
viewModel.navigateToCourseOutline(
135+
fm = requireActivity().supportFragmentManager,
136+
courseId = action.courseId
137+
)
138+
}
139+
131140
is DownloadsViewActions.DownloadCourse -> {
132141
viewModel.downloadCourse(
133142
requireActivity().supportFragmentManager,
@@ -211,7 +220,11 @@ private fun DownloadsScreen(
211220
CircularProgressIndicator(color = MaterialTheme.appColors.primary)
212221
}
213222
} else if (uiState.downloadCoursePreviews.isEmpty()) {
214-
EmptyState()
223+
EmptyState(
224+
modifier = Modifier
225+
.fillMaxSize()
226+
.verticalScroll(rememberScrollState())
227+
)
215228
} else {
216229
Box(
217230
modifier = Modifier
@@ -236,6 +249,9 @@ private fun DownloadsScreen(
236249
downloadModels = downloadModels,
237250
downloadedState = downloadState,
238251
apiHostUrl = apiHostUrl,
252+
onCourseClick = {
253+
onAction(DownloadsViewActions.OpenCourse(item.id))
254+
},
239255
onDownloadClick = {
240256
onAction(DownloadsViewActions.DownloadCourse(item.id))
241257
},
@@ -278,13 +294,15 @@ private fun DownloadsScreen(
278294
)
279295
}
280296

297+
@OptIn(ExperimentalMaterialApi::class)
281298
@Composable
282299
private fun CourseItem(
283300
modifier: Modifier = Modifier,
284301
downloadCoursePreview: DownloadCoursePreview,
285302
downloadModels: List<DownloadModel>,
286303
downloadedState: DownloadedState,
287304
apiHostUrl: String,
305+
onCourseClick: () -> Unit,
288306
onDownloadClick: () -> Unit,
289307
onRemoveClick: () -> Unit,
290308
onCancelClick: () -> Unit
@@ -306,6 +324,7 @@ private fun CourseItem(
306324
backgroundColor = MaterialTheme.appColors.background,
307325
shape = MaterialTheme.appShapes.courseImageShape,
308326
elevation = 4.dp,
327+
onClick = onCourseClick
309328
) {
310329
Box {
311330
Column(
@@ -507,7 +526,7 @@ private fun EmptyState(
507526
modifier: Modifier = Modifier
508527
) {
509528
Box(
510-
modifier = modifier.fillMaxSize(),
529+
modifier = modifier,
511530
contentAlignment = Alignment.Center
512531
) {
513532
Column(
@@ -566,6 +585,7 @@ private fun CourseItemPreview() {
566585
downloadModels = emptyList(),
567586
apiHostUrl = "",
568587
downloadedState = DownloadedState.NOT_DOWNLOADED,
588+
onCourseClick = {},
569589
onDownloadClick = {},
570590
onCancelClick = {},
571591
onRemoveClick = {},

downloads/src/main/java/org/openedx/downloads/presentation/download/DownloadsViewModel.kt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ import org.openedx.core.presentation.DownloadsAnalyticsKey
3535
import org.openedx.core.presentation.dialog.downloaddialog.DownloadDialogItem
3636
import org.openedx.core.presentation.dialog.downloaddialog.DownloadDialogManager
3737
import org.openedx.core.system.connection.NetworkConnection
38+
import org.openedx.core.system.notifier.CourseDashboardUpdate
39+
import org.openedx.core.system.notifier.DiscoveryNotifier
3840
import org.openedx.downloads.domain.interactor.DownloadInteractor
3941
import org.openedx.downloads.presentation.DownloadsRouter
4042
import org.openedx.foundation.extension.isInternetError
@@ -51,6 +53,8 @@ class DownloadsViewModel(
5153
private val fileUtil: FileUtil,
5254
private val config: Config,
5355
private val analytics: DownloadsAnalytics,
56+
private val discoveryNotifier: DiscoveryNotifier,
57+
private val router: DownloadsRouter,
5458
preferencesManager: CorePreferences,
5559
coreAnalytics: CoreAnalytics,
5660
downloadDao: DownloadDao,
@@ -83,6 +87,14 @@ class DownloadsViewModel(
8387
init {
8488
fetchDownloads(false)
8589

90+
viewModelScope.launch {
91+
discoveryNotifier.notifier.collect {
92+
if (it is CourseDashboardUpdate) {
93+
fetchDownloads(true)
94+
}
95+
}
96+
}
97+
8698
viewModelScope.launch {
8799
downloadingModelsFlow.collect { downloadModels ->
88100
_uiState.update { state ->
@@ -322,6 +334,19 @@ class DownloadsViewModel(
322334
)
323335
}
324336

337+
fun navigateToCourseOutline(
338+
fm: FragmentManager,
339+
courseId: String
340+
) {
341+
val coursePreview =
342+
_uiState.value.downloadCoursePreviews.find { it.id == courseId } ?: return
343+
router.navigateToCourseOutline(
344+
fm = fm,
345+
courseId = coursePreview.id,
346+
courseTitle = coursePreview.name,
347+
)
348+
}
349+
325350
fun logEvent(event: DownloadsAnalyticsEvent) {
326351
analytics.logEvent(
327352
event = event.eventName,
@@ -335,6 +360,7 @@ class DownloadsViewModel(
335360
interface DownloadsViewActions {
336361
object OpenSettings : DownloadsViewActions
337362
object SwipeRefresh : DownloadsViewActions
363+
data class OpenCourse(val courseId: String) : DownloadsViewActions
338364
data class DownloadCourse(val courseId: String) : DownloadsViewActions
339365
data class CancelDownloading(val courseId: String) : DownloadsViewActions
340366
data class RemoveDownloads(val courseId: String) : DownloadsViewActions

downloads/src/test/java/org/openedx/downloads/DownloadsViewModelTest.kt

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,8 @@ import kotlinx.coroutines.flow.flow
1414
import kotlinx.coroutines.flow.flowOf
1515
import kotlinx.coroutines.test.StandardTestDispatcher
1616
import kotlinx.coroutines.test.advanceUntilIdle
17-
import kotlinx.coroutines.test.resetMain
1817
import kotlinx.coroutines.test.runTest
1918
import kotlinx.coroutines.test.setMain
20-
import org.junit.After
2119
import org.junit.Assert.assertEquals
2220
import org.junit.Assert.assertFalse
2321
import org.junit.Before
@@ -45,6 +43,7 @@ import org.openedx.core.presentation.CoreAnalytics
4543
import org.openedx.core.presentation.DownloadsAnalytics
4644
import org.openedx.core.presentation.dialog.downloaddialog.DownloadDialogManager
4745
import org.openedx.core.system.connection.NetworkConnection
46+
import org.openedx.core.system.notifier.DiscoveryNotifier
4847
import org.openedx.downloads.domain.interactor.DownloadInteractor
4948
import org.openedx.downloads.presentation.DownloadsRouter
5049
import org.openedx.downloads.presentation.download.DownloadsViewModel
@@ -75,6 +74,8 @@ class DownloadsViewModelTest {
7574
private val downloadDao = mockk<DownloadDao>(relaxed = true)
7675
private val workerController = mockk<DownloadWorkerController>(relaxed = true)
7776
private val downloadHelper = mockk<DownloadHelper>(relaxed = true)
77+
private val router = mockk<DownloadsRouter>(relaxed = true)
78+
private val discoveryNotifier = mockk<DiscoveryNotifier>(relaxed = true)
7879

7980
private val noInternet = "No connection"
8081
private val unknownError = "Unknown error"
@@ -207,11 +208,6 @@ class DownloadsViewModelTest {
207208
)
208209
}
209210

210-
@After
211-
fun tearDown() {
212-
Dispatchers.resetMain()
213-
}
214-
215211
@Test
216212
fun `onSettingsClick should navigate to settings`() = runTest {
217213
val viewModel = DownloadsViewModel(
@@ -223,6 +219,8 @@ class DownloadsViewModelTest {
223219
fileUtil,
224220
config,
225221
analytics,
222+
discoveryNotifier,
223+
router,
226224
preferencesManager,
227225
coreAnalytics,
228226
downloadDao,
@@ -247,6 +245,8 @@ class DownloadsViewModelTest {
247245
fileUtil,
248246
config,
249247
analytics,
248+
discoveryNotifier,
249+
router,
250250
preferencesManager,
251251
coreAnalytics,
252252
downloadDao,
@@ -280,6 +280,8 @@ class DownloadsViewModelTest {
280280
fileUtil,
281281
config,
282282
analytics,
283+
discoveryNotifier,
284+
router,
283285
preferencesManager,
284286
coreAnalytics,
285287
downloadDao,
@@ -316,6 +318,8 @@ class DownloadsViewModelTest {
316318
fileUtil,
317319
config,
318320
analytics,
321+
discoveryNotifier,
322+
router,
319323
preferencesManager,
320324
coreAnalytics,
321325
downloadDao,
@@ -353,6 +357,8 @@ class DownloadsViewModelTest {
353357
fileUtil,
354358
config,
355359
analytics,
360+
discoveryNotifier,
361+
router,
356362
preferencesManager,
357363
coreAnalytics,
358364
downloadDao,

0 commit comments

Comments
 (0)