Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Use UiState pattern to load TransferDetailsScreen #189

Merged
merged 7 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import com.infomaniak.swisstransfer.ui.images.icons.QrCode
import com.infomaniak.swisstransfer.ui.images.icons.Share
import com.infomaniak.swisstransfer.ui.previewparameter.TransferUiListPreviewParameter
import com.infomaniak.swisstransfer.ui.screen.main.components.SmallWindowTopAppBarScaffold
import com.infomaniak.swisstransfer.ui.screen.main.transferdetails.TransferDetailsViewModel.TransferDetailsUiState.*
import com.infomaniak.swisstransfer.ui.screen.main.transferdetails.components.PasswordBottomSheet
import com.infomaniak.swisstransfer.ui.screen.main.transferdetails.components.QrCodeBottomSheet
import com.infomaniak.swisstransfer.ui.screen.main.transferdetails.components.TransferInfo
Expand All @@ -63,19 +64,20 @@ fun TransferDetailsScreen(
navigateBack: (() -> Unit)?,
transferDetailsViewModel: TransferDetailsViewModel = hiltViewModel<TransferDetailsViewModel>(),
) {
val transfer by transferDetailsViewModel.transfer.collectAsStateWithLifecycle()
val isLoading by remember { derivedStateOf { transfer == null } }
val uiState by transferDetailsViewModel.uiState.collectAsStateWithLifecycle()

LaunchedEffect(transferUuid) {
transferDetailsViewModel.loadTransfer(transferUuid)
}

if (!isLoading) {
if (uiState is Delete) {
navigateBack?.invoke()
} else if (uiState is Success) {
TransferDetailsScreen(
transferUrl = transferDetailsViewModel.getTransferUrl(transferUuid),
direction = direction,
navigateBack = navigateBack,
getTransfer = { transfer },
getTransfer = { (uiState as Success).transfer },
getCheckedFiles = { transferDetailsViewModel.checkedFiles },
clearCheckedFiles = { transferDetailsViewModel.checkedFiles.clear() },
setFileCheckStatus = { fileUid, isChecked ->
Expand All @@ -90,14 +92,13 @@ private fun TransferDetailsScreen(
transferUrl: String,
direction: TransferDirection,
navigateBack: (() -> Unit)?,
getTransfer: () -> TransferUi?,
getTransfer: () -> TransferUi,
getCheckedFiles: () -> SnapshotStateMap<String, Boolean>,
clearCheckedFiles: () -> Unit,
setFileCheckStatus: (String, Boolean) -> Unit,
) {

val context = LocalContext.current
val transfer = getTransfer() ?: return
val transferRecipients: List<String> = emptyList() // TODO: Use real data
val transferPassword = "toto42" // TODO: Use real data

Expand All @@ -108,7 +109,7 @@ private fun TransferDetailsScreen(
SmallWindowTopAppBarScaffold(
smallWindowTopAppBar = {
SwissTransferTopAppBar(
title = transfer.createdDateTimestamp.toDateFromSeconds().format(FORMAT_DATE_FULL),
title = getTransfer().createdDateTimestamp.toDateFromSeconds().format(FORMAT_DATE_FULL),
navigationMenu = TopAppBarButton.backButton(navigateBack ?: {}),
TopAppBarButton.downloadButton { /* TODO */ },
)
Expand All @@ -117,7 +118,7 @@ private fun TransferDetailsScreen(
) {
Column {

FilesList(transfer, transferRecipients, isMultiselectOn, getCheckedFiles, setFileCheckStatus)
FilesList(getTransfer, transferRecipients, isMultiselectOn, getCheckedFiles, setFileCheckStatus)

BottomBar(
direction = direction,
Expand Down Expand Up @@ -156,33 +157,33 @@ private fun TransferDetailsScreen(

@Composable
private fun ColumnScope.FilesList(
transfer: TransferUi,
getTransfer: () -> TransferUi,
transferRecipients: List<String>,
isMultiselectOn: Boolean,
getCheckedFiles: () -> SnapshotStateMap<String, Boolean>,
setFileCheckStatus: (String, Boolean) -> Unit,
) {

val shouldDisplayRecipients = transferRecipients.isNotEmpty()
val shouldDisplayMessage = transfer.message != null
val shouldDisplayMessage = getTransfer().message != null

FileItemList(
modifier = Modifier
.weight(1.0f)
.padding(horizontal = Margin.Medium),
files = transfer.files,
files = getTransfer().files,
isRemoveButtonVisible = false,
isCheckboxVisible = { isMultiselectOn },
isUidChecked = { fileUid -> getCheckedFiles()[fileUid] ?: false },
setUidCheckStatus = { fileUid, isChecked -> setFileCheckStatus(fileUid, isChecked) },
header = {
Column {
Spacer(Modifier.height(Margin.Large))
TransferInfo(transfer)
TransferInfo(getTransfer)
Spacer(Modifier.height(Margin.Large))
if (shouldDisplayRecipients) TransferRecipients(transferRecipients)
if (shouldDisplayRecipients && shouldDisplayMessage) Spacer(Modifier.height(Margin.Mini))
if (shouldDisplayMessage) TransferMessage(transfer.message!!)
if (shouldDisplayMessage) TransferMessage(getTransfer().message!!)
if (shouldDisplayRecipients || shouldDisplayMessage) Spacer(Modifier.height(Margin.Large))
TransferContentHeader()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,17 @@
*/
package com.infomaniak.swisstransfer.ui.screen.main.transferdetails

import androidx.compose.runtime.Immutable
import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.snapshots.SnapshotStateMap
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.infomaniak.multiplatform_swisstransfer.SharedApiUrlCreator
import com.infomaniak.multiplatform_swisstransfer.common.interfaces.ui.TransferUi
import com.infomaniak.multiplatform_swisstransfer.managers.TransferManager
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import javax.inject.Inject

Expand All @@ -41,9 +40,15 @@ class TransferDetailsViewModel @Inject constructor(
private val _transferUuidFlow = MutableSharedFlow<String>(1)

@OptIn(ExperimentalCoroutinesApi::class)
val transfer = _transferUuidFlow
val uiState = _transferUuidFlow
.flatMapLatest { transferManager.getTransferFlow(it) }
.stateIn(viewModelScope, SharingStarted.Eagerly, null)
.map { transfer ->
when (transfer) {
null -> TransferDetailsUiState.Delete
else -> TransferDetailsUiState.Success(transfer)
}
}
.stateIn(viewModelScope, SharingStarted.Eagerly, TransferDetailsUiState.Loading)

val checkedFiles: SnapshotStateMap<String, Boolean> = mutableStateMapOf()

Expand All @@ -54,4 +59,16 @@ class TransferDetailsViewModel @Inject constructor(
}

fun getTransferUrl(transferUuid: String): String = sharedApiUrlCreator.shareTransferUrl(transferUuid)

sealed class TransferDetailsUiState {

@Immutable
data class Success(val transfer: TransferUi) : TransferDetailsUiState()

@Immutable
data object Loading : TransferDetailsUiState()

@Immutable
data object Delete : TransferDetailsUiState()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,13 @@ import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme
import com.infomaniak.swisstransfer.ui.utils.PreviewLightAndDark

@Composable
fun TransferInfo(transfer: TransferUi) {
fun TransferInfo(getTransfer: () -> TransferUi) {

val filesCount = transfer.files.count()
val downloadedCount by remember { derivedStateOf { transfer.downloadLimit - transfer.downloadLeft } }
val filesCount by remember { derivedStateOf { getTransfer().files.count() } }
val downloadedCount by remember { derivedStateOf { getTransfer().downloadLimit - getTransfer().downloadLeft } }
val expiresInDays by remember { derivedStateOf { getTransfer().expiresInDays } }
val downloadLimit by remember { derivedStateOf { getTransfer().downloadLimit } }
val sizeUploaded by remember { derivedStateOf { getTransfer().sizeUploaded } }

Row(verticalAlignment = Alignment.CenterVertically) {
Icon(
Expand All @@ -62,7 +65,7 @@ fun TransferInfo(transfer: TransferUi) {
Spacer(Modifier.width(Margin.Mini))
TextDotText(
firstText = { pluralStringResource(R.plurals.filesCount, filesCount, filesCount) },
secondText = { Formatter.formatShortFileSize(LocalContext.current, transfer.sizeUploaded) },
secondText = { Formatter.formatShortFileSize(LocalContext.current, sizeUploaded) },
color = SwissTransferTheme.colors.primaryTextColor,
)
}
Expand All @@ -71,14 +74,14 @@ fun TransferInfo(transfer: TransferUi) {

IconText(
icon = AppIcons.Clock,
text = stringResource(R.string.expiresIn, transfer.expiresInDays),
text = stringResource(R.string.expiresIn, expiresInDays),
)

HorizontalDivider(modifier = Modifier.padding(vertical = Margin.Medium))

IconText(
icon = AppIcons.ArrowDownFile,
text = stringResource(R.string.downloadedTransferLabel, downloadedCount, transfer.downloadLimit),
text = stringResource(R.string.downloadedTransferLabel, downloadedCount, downloadLimit),
)
}

Expand Down Expand Up @@ -106,7 +109,7 @@ private fun Preview(@PreviewParameter(TransferUiListPreviewParameter::class) tra
SwissTransferTheme {
Surface {
Column {
TransferInfo(transfers.first())
TransferInfo { transfers.first() }
}
}
}
Expand Down