From ac5b77cf413a035292230fbc7159694831187f4e Mon Sep 17 00:00:00 2001 From: Pratyush Singh Date: Tue, 7 May 2024 00:02:17 +0530 Subject: [PATCH] feat #1620: swipe refresh state --- gradle/libs.versions.toml | 2 + mifospay/build.gradle.kts | 3 + .../presenter/NotificationViewModel.kt | 19 +++ .../notification/ui/NotificationScreen.kt | 127 +++++++++++------- 4 files changed, 101 insertions(+), 50 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3dfde17c..53be71fd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,4 +1,5 @@ [versions] +accompanistSwiperefreshVersion = "0.27.0" appcompatVersion = "1.6.1" androidGradlePlugin = "8.3.0" compileSdk = "34" @@ -65,6 +66,7 @@ androidxBrowser = "1.8.0" playServicesCodeScanner = "16.1.0" [libraries] +accompanist-swiperefresh = { module = "com.google.accompanist:accompanist-swiperefresh", version.ref = "accompanistSwiperefreshVersion" } androidx-activity-ktx = { module = "androidx.activity:activity-ktx", version.ref = "activityVersion" } androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompatVersion" } androidx-constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "constraintlayoutVersion" } diff --git a/mifospay/build.gradle.kts b/mifospay/build.gradle.kts index 52e58611..71d0b281 100644 --- a/mifospay/build.gradle.kts +++ b/mifospay/build.gradle.kts @@ -152,6 +152,9 @@ dependencies { implementation("de.hdodenhof:circleimageview:3.1.0") implementation("com.github.yalantis:ucrop:2.2.2") + // Swipe Refresh + implementation (libs.accompanist.swiperefresh) + kspTest(libs.hilt.compiler) testImplementation(libs.junit) diff --git a/mifospay/src/main/java/org/mifospay/notification/presenter/NotificationViewModel.kt b/mifospay/src/main/java/org/mifospay/notification/presenter/NotificationViewModel.kt index 9ebd9245..ee416f37 100644 --- a/mifospay/src/main/java/org/mifospay/notification/presenter/NotificationViewModel.kt +++ b/mifospay/src/main/java/org/mifospay/notification/presenter/NotificationViewModel.kt @@ -1,10 +1,14 @@ package org.mifospay.notification.presenter import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import com.mifospay.core.model.domain.NotificationPayload import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.notification.FetchNotifications @@ -22,6 +26,21 @@ class NotificationViewModel @Inject constructor( MutableStateFlow(NotificationUiState.Loading) val notificationUiState: StateFlow = _notificationUiState + private val _isRefreshing = MutableStateFlow(false) + val isRefreshing: StateFlow get() = _isRefreshing.asStateFlow() + + fun refresh() { + viewModelScope.launch { + _isRefreshing.emit(true) + delay(1000) + _isRefreshing.emit(false) + } + } + + init { + fetchNotifications() + } + fun fetchNotifications() { mUseCaseHandler.execute(fetchNotificationsUseCase, FetchNotifications.RequestValues( diff --git a/mifospay/src/main/java/org/mifospay/notification/ui/NotificationScreen.kt b/mifospay/src/main/java/org/mifospay/notification/ui/NotificationScreen.kt index 37f295c5..8d0fdc22 100644 --- a/mifospay/src/main/java/org/mifospay/notification/ui/NotificationScreen.kt +++ b/mifospay/src/main/java/org/mifospay/notification/ui/NotificationScreen.kt @@ -23,6 +23,8 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.google.accompanist.swiperefresh.SwipeRefresh +import com.google.accompanist.swiperefresh.rememberSwipeRefreshState import com.mifospay.core.model.domain.NotificationPayload import org.mifospay.R import org.mifospay.core.designsystem.component.MfLoadingWheel @@ -36,36 +38,77 @@ import org.mifospay.notification.presenter.NotificationViewModel @Composable fun NotificationScreen(viewmodel: NotificationViewModel = hiltViewModel()) { val uiState by viewmodel.notificationUiState.collectAsStateWithLifecycle() - NotificationScreen(uiState = uiState) + val isRefreshing by viewmodel.isRefreshing.collectAsStateWithLifecycle() + NotificationScreen( + uiState = uiState, + isRefreshing = isRefreshing, + onRefresh = { + viewmodel.refresh() + viewmodel.fetchNotifications() + } + ) } @OptIn(ExperimentalMaterial3Api::class) @Composable -fun NotificationScreen(uiState: NotificationUiState) { - Column( - modifier = Modifier.fillMaxSize() +fun NotificationScreen( + uiState: NotificationUiState, + isRefreshing: Boolean, + onRefresh: () -> Unit +) { + val swipeRefreshState = rememberSwipeRefreshState(isRefreshing = isRefreshing) + SwipeRefresh( + state = swipeRefreshState, + onRefresh = onRefresh ) { - MifosTopAppBar(titleRes = R.string.notifications) - when (uiState) { - is NotificationUiState.Error -> { - EmptyContentScreen( - modifier = Modifier, - title = stringResource(id = R.string.error_oops), - subTitle = stringResource(id = R.string.unexpected_error_subtitle), - iconTint = Color.Black, - iconImageVector = Icons.Rounded.Info - ) - } + Column( + modifier = Modifier.fillMaxSize() + ) { + MifosTopAppBar(titleRes = R.string.notifications) + when (uiState) { + is NotificationUiState.Error -> { + EmptyContentScreen( + modifier = Modifier, + title = stringResource(id = R.string.error_oops), + subTitle = stringResource(id = R.string.unexpected_error_subtitle), + iconTint = Color.Black, + iconImageVector = Icons.Rounded.Info + ) + } - NotificationUiState.Loading -> { - MfLoadingWheel( - contentDesc = stringResource(R.string.loading), - backgroundColor = Color.White - ) - } + NotificationUiState.Loading -> { + MfLoadingWheel( + contentDesc = stringResource(R.string.loading), + backgroundColor = Color.White + ) + } - is NotificationUiState.Success -> { - if (uiState.notificationList.isEmpty()) { + is NotificationUiState.Success -> { + if (uiState.notificationList.isEmpty()) { + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = stringResource(id = R.string.no_notification_found), + style = styleMedium16sp + ) + } + } else { + LazyColumn { + items(uiState.notificationList) { notification -> + NotificationList( + title = notification.title.toString(), + body = notification.body.toString(), + timestamp = notification.timestamp.toString() + ) + } + } + } + } + + NotificationUiState.Empty -> { Column( modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.Center, @@ -76,29 +119,6 @@ fun NotificationScreen(uiState: NotificationUiState) { style = styleMedium16sp ) } - } else { - LazyColumn { - items(uiState.notificationList) { notification -> - NotificationList( - title = notification.title.toString(), - body = notification.body.toString(), - timestamp = notification.timestamp.toString() - ) - } - } - } - } - - NotificationUiState.Empty -> { - Column( - modifier = Modifier.fillMaxSize(), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally - ) { - Text( - text = stringResource(id = R.string.no_notification_found), - style = styleMedium16sp - ) } } } @@ -144,25 +164,32 @@ fun NotificationList(title: String, body: String, timestamp: String) { @Preview(showSystemUi = true, showBackground = true) @Composable private fun NotificationEmptyScreenPreview() { - NotificationScreen(uiState = NotificationUiState.Empty) + NotificationScreen(uiState = NotificationUiState.Empty, isRefreshing = true, onRefresh = {}) } @Preview(showSystemUi = true, showBackground = true) @Composable private fun NotificationLoadingPreview() { - NotificationScreen(uiState = NotificationUiState.Loading) + NotificationScreen(uiState = NotificationUiState.Loading, isRefreshing = true, onRefresh = {}) } @Preview(showSystemUi = true, showBackground = true) @Composable private fun NotificationSuccessPreview() { - NotificationScreen(uiState = NotificationUiState.Success(sampleNotificationList)) + NotificationScreen( + uiState = NotificationUiState.Success(sampleNotificationList), + isRefreshing = true, + onRefresh = {}) } @Preview(showSystemUi = true, showBackground = true) @Composable private fun NotificationErrorScreenPreview() { - NotificationScreen(uiState = NotificationUiState.Error("Error Occurred")) + NotificationScreen( + uiState = NotificationUiState.Error("Error Occurred"), + isRefreshing = true, + onRefresh = {} + ) } val sampleNotificationList = List(10) {