diff --git a/apps/flipcash/app/build.gradle.kts b/apps/flipcash/app/build.gradle.kts index 6a8823528..eb69774cc 100644 --- a/apps/flipcash/app/build.gradle.kts +++ b/apps/flipcash/app/build.gradle.kts @@ -148,8 +148,8 @@ dependencies { implementation(project(":apps:flipcash:shared:router")) implementation(project(":apps:flipcash:shared:session")) implementation(project(":apps:flipcash:shared:google-play-billing")) - implementation(project(":apps:flipcash:shared:currency-selection:core")) - implementation(project(":apps:flipcash:shared:currency-selection:ui")) + implementation(project(":apps:flipcash:shared:region-selection:core")) + implementation(project(":apps:flipcash:shared:region-selection:ui")) implementation(project(":apps:flipcash:shared:contacts")) implementation(project(":apps:flipcash:shared:notifications")) implementation(project(":apps:flipcash:shared:onramp:coinbase")) diff --git a/apps/flipcash/shared/currency-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/components/RegionList.kt b/apps/flipcash/shared/currency-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/components/RegionList.kt deleted file mode 100644 index 216e7f76d..000000000 --- a/apps/flipcash/shared/currency-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/components/RegionList.kt +++ /dev/null @@ -1,194 +0,0 @@ -package com.flipcash.app.currency.internal.components - -import androidx.compose.animation.core.animateDpAsState -import androidx.compose.animation.core.tween -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.navigationBars -import androidx.compose.foundation.layout.windowInsetsPadding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.lazy.rememberLazyListState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp -import com.flipcash.app.currency.internal.CurrencyListItem -import com.getcode.opencode.model.financial.Currency -import com.getcode.theme.CodeTheme -import com.getcode.ui.core.verticalScrollStateGradient -import com.getcode.ui.theme.CodeCircularProgressIndicator -import com.getcode.ui.utils.sheetResignmentBehavior - -@Composable -internal fun RegionList( - items: List, - isLoading: Boolean, - selected: Currency?, - modifier: Modifier = Modifier, - onRemoved: (Currency) -> Unit, - onSelected: (Currency) -> Unit, -) { - val groups by remember(items) { - derivedStateOf { - if (items.isEmpty()) return@derivedStateOf emptyList() to emptyList() - val index = items.indexOfLast { it is CurrencyListItem.TitleItem } - if (index == 0) { - // no recents - emptyList() to items - } else { - // recents - items.subList(0, index) to items.subList( - index, - items.lastIndex - ) - } - } - } - - val (recents, other) = groups - - var recentItems by remember(recents) { - mutableStateOf(recents) - } - - var otherItems by remember(other) { - mutableStateOf(other) - } - - val listState = rememberLazyListState() - - LazyColumn( - modifier = modifier - .fillMaxWidth() - .background(CodeTheme.colors.background) - .verticalScrollStateGradient( - scrollState = listState, - color = CodeTheme.colors.background, - ).sheetResignmentBehavior(listState), - state = listState, - ) { - if (isLoading) { - item { - Box(Modifier.fillParentMaxSize()) { - CodeCircularProgressIndicator( - Modifier.align( - Alignment.TopCenter - ) - ) - } - } - } - - items(recentItems) { listItem -> - val currencyCode = when (listItem) { - is CurrencyListItem.RegionCurrencyItem -> listItem.currency.code - else -> "" - } - - Box( - modifier = Modifier - .fillMaxWidth() - .height(if (listItem !is CurrencyListItem.TitleItem) 70.dp else 60.dp) - ) { - - when (listItem) { - is CurrencyListItem.TitleItem -> { - GroupHeader( - modifier = Modifier.align(Alignment.BottomStart), - text = listItem.text - ) - } - - is CurrencyListItem.RegionCurrencyItem -> { - ListRowItem( - item = listItem, - isSelected = selected?.code.orEmpty() == currencyCode, - onRemoved = { - recentItems = if (recentItems.count() == 2) { - emptyList() - } else { - recentItems.minus(listItem) - } - val title = otherItems[0] - val filtered = - otherItems.filterIsInstance() + listItem - - otherItems = listOf(title) + filtered.sortedBy { it.currency.name } - - onRemoved(listItem.currency) - - }, - ) { - onSelected(listItem.currency) - } - } - } - } - } - - items(otherItems) { listItem -> - val currencyCode = when (listItem) { - is CurrencyListItem.RegionCurrencyItem -> listItem.currency.code - else -> "" - } - - Box( - modifier = Modifier - .fillMaxWidth() - .height(if (listItem !is CurrencyListItem.TitleItem) 70.dp else 60.dp) - ) { - - when (listItem) { - is CurrencyListItem.TitleItem -> { - GroupHeader( - modifier = Modifier.align(Alignment.BottomStart), - text = listItem.text - ) - } - - is CurrencyListItem.RegionCurrencyItem -> { - var isSwipedAway by remember(listItem) { - mutableStateOf(false) - } - - val animatedHeight by animateDpAsState( - targetValue = if (!isSwipedAway) 70.dp else 0.dp, - label = "height animation", - animationSpec = tween(300), - finishedListener = { - if (it == 0.dp) { - onRemoved(listItem.currency) - } - } - ) - ListRowItem( - modifier = Modifier.height(animatedHeight), - item = listItem, - isSelected = selected?.code.orEmpty() == currencyCode, - onRemoved = { - isSwipedAway = true - onRemoved(listItem.currency) - }, - ) { - onSelected(listItem.currency) - } - } - } - } - } - - item { - Spacer(Modifier.windowInsetsPadding(WindowInsets.navigationBars)) - } - } -} \ No newline at end of file diff --git a/apps/flipcash/shared/google-play-billing/build.gradle.kts b/apps/flipcash/shared/google-play-billing/build.gradle.kts index b3fe0d005..dff618034 100644 --- a/apps/flipcash/shared/google-play-billing/build.gradle.kts +++ b/apps/flipcash/shared/google-play-billing/build.gradle.kts @@ -13,6 +13,6 @@ dependencies { api(libs.google.play.billing.ktx) implementation(project(":apps:flipcash:shared:analytics")) - implementation(project(":apps:flipcash:shared:currency-selection:core")) + implementation(project(":apps:flipcash:shared:region-selection:core")) implementation(project(":libs:datetime")) } diff --git a/apps/flipcash/shared/currency-selection/core/.gitignore b/apps/flipcash/shared/region-selection/core/.gitignore similarity index 100% rename from apps/flipcash/shared/currency-selection/core/.gitignore rename to apps/flipcash/shared/region-selection/core/.gitignore diff --git a/apps/flipcash/shared/currency-selection/core/build.gradle.kts b/apps/flipcash/shared/region-selection/core/build.gradle.kts similarity index 100% rename from apps/flipcash/shared/currency-selection/core/build.gradle.kts rename to apps/flipcash/shared/region-selection/core/build.gradle.kts diff --git a/apps/flipcash/shared/currency-selection/core/src/main/kotlin/com/flipcash/app/currency/PreferredCurrencyController.kt b/apps/flipcash/shared/region-selection/core/src/main/kotlin/com/flipcash/app/currency/PreferredCurrencyController.kt similarity index 100% rename from apps/flipcash/shared/currency-selection/core/src/main/kotlin/com/flipcash/app/currency/PreferredCurrencyController.kt rename to apps/flipcash/shared/region-selection/core/src/main/kotlin/com/flipcash/app/currency/PreferredCurrencyController.kt diff --git a/apps/flipcash/shared/currency-selection/ui/.gitignore b/apps/flipcash/shared/region-selection/ui/.gitignore similarity index 100% rename from apps/flipcash/shared/currency-selection/ui/.gitignore rename to apps/flipcash/shared/region-selection/ui/.gitignore diff --git a/apps/flipcash/shared/currency-selection/ui/build.gradle.kts b/apps/flipcash/shared/region-selection/ui/build.gradle.kts similarity index 76% rename from apps/flipcash/shared/currency-selection/ui/build.gradle.kts rename to apps/flipcash/shared/region-selection/ui/build.gradle.kts index e5345ff32..96b378a8a 100644 --- a/apps/flipcash/shared/currency-selection/ui/build.gradle.kts +++ b/apps/flipcash/shared/region-selection/ui/build.gradle.kts @@ -9,6 +9,6 @@ android { dependencies { implementation(libs.androidx.datastore) - implementation(project(":apps:flipcash:shared:currency-selection:core")) + implementation(project(":apps:flipcash:shared:region-selection:core")) implementation(project(":libs:datetime")) } diff --git a/apps/flipcash/shared/currency-selection/ui/src/main/kotlin/com/flipcash/app/currency/RegionSelectionScreen.kt b/apps/flipcash/shared/region-selection/ui/src/main/kotlin/com/flipcash/app/currency/RegionSelectionScreen.kt similarity index 80% rename from apps/flipcash/shared/currency-selection/ui/src/main/kotlin/com/flipcash/app/currency/RegionSelectionScreen.kt rename to apps/flipcash/shared/region-selection/ui/src/main/kotlin/com/flipcash/app/currency/RegionSelectionScreen.kt index f7232af0a..d7950f68c 100644 --- a/apps/flipcash/shared/currency-selection/ui/src/main/kotlin/com/flipcash/app/currency/RegionSelectionScreen.kt +++ b/apps/flipcash/shared/region-selection/ui/src/main/kotlin/com/flipcash/app/currency/RegionSelectionScreen.kt @@ -7,8 +7,8 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.hilt.navigation.compose.hiltViewModel -import com.flipcash.app.currency.internal.CurrencyViewModel -import com.flipcash.app.currency.internal.RegionSelectionModalContent +import com.flipcash.app.currency.internal.RegionSelectionViewModel +import com.flipcash.app.currency.internal.RegionSelectionScreen import com.flipcash.core.R import com.getcode.navigation.core.LocalCodeNavigator import com.getcode.ui.components.AppBarWithTitle @@ -30,7 +30,7 @@ fun RegionSelectionScreen() { } ) - val viewModel = hiltViewModel() - RegionSelectionModalContent(viewModel) + val viewModel = hiltViewModel() + RegionSelectionScreen(viewModel) } } diff --git a/apps/flipcash/shared/currency-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/CurrencyListItem.kt b/apps/flipcash/shared/region-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/RegionListItem.kt similarity index 54% rename from apps/flipcash/shared/currency-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/CurrencyListItem.kt rename to apps/flipcash/shared/region-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/RegionListItem.kt index d6b2d8263..ac80aec43 100644 --- a/apps/flipcash/shared/currency-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/CurrencyListItem.kt +++ b/apps/flipcash/shared/region-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/RegionListItem.kt @@ -2,7 +2,7 @@ package com.flipcash.app.currency.internal import com.getcode.opencode.model.financial.Currency -sealed interface CurrencyListItem { - data class TitleItem(val text: String) : CurrencyListItem - data class RegionCurrencyItem(val currency: Currency, val isRecent: Boolean) : CurrencyListItem +sealed interface RegionListItem { + data class TitleItem(val text: String) : RegionListItem + data class RegionCurrencyItem(val currency: Currency, val isRecent: Boolean) : RegionListItem } \ No newline at end of file diff --git a/apps/flipcash/shared/currency-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/RegionSelectionModalContent.kt b/apps/flipcash/shared/region-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/RegionSelectionScreen.kt similarity index 87% rename from apps/flipcash/shared/currency-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/RegionSelectionModalContent.kt rename to apps/flipcash/shared/region-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/RegionSelectionScreen.kt index c3a60287c..c655bd366 100644 --- a/apps/flipcash/shared/currency-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/RegionSelectionModalContent.kt +++ b/apps/flipcash/shared/region-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/RegionSelectionScreen.kt @@ -26,7 +26,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @Composable -internal fun RegionSelectionModalContent(viewModel: CurrencyViewModel) { +internal fun RegionSelectionScreen(viewModel: RegionSelectionViewModel) { val navigator = LocalCodeNavigator.current val state by viewModel.stateFlow.collectAsStateWithLifecycle() val keyboard = rememberKeyboardController() @@ -35,7 +35,7 @@ internal fun RegionSelectionModalContent(viewModel: CurrencyViewModel) { LaunchedEffect(viewModel) { viewModel.eventFlow - .filterIsInstance() + .filterIsInstance() .onEach { if (keyboard.visible) { keyboard.hide() @@ -65,13 +65,12 @@ internal fun RegionSelectionModalContent(viewModel: CurrencyViewModel) { RegionList( modifier = Modifier.weight(1f), items = state.listItems, - isLoading = state.loading, selected = state.selectedCurrency, onRemoved = { currency -> - viewModel.dispatchEvent(CurrencyViewModel.Event.OnRecentCurrencyRemoved(currency)) + viewModel.dispatchEvent(RegionSelectionViewModel.Event.OnRecentCurrencyRemoved(currency)) }, onSelected = { currency -> - viewModel.dispatchEvent(CurrencyViewModel.Event.OnCurrencySelected(currency)) + viewModel.dispatchEvent(RegionSelectionViewModel.Event.OnCurrencySelected(currency)) } ) } diff --git a/apps/flipcash/shared/currency-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/CurrencyViewModel.kt b/apps/flipcash/shared/region-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/RegionSelectionViewModel.kt similarity index 67% rename from apps/flipcash/shared/currency-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/CurrencyViewModel.kt rename to apps/flipcash/shared/region-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/RegionSelectionViewModel.kt index 4ff1d3c40..60551f81d 100644 --- a/apps/flipcash/shared/currency-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/CurrencyViewModel.kt +++ b/apps/flipcash/shared/region-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/RegionSelectionViewModel.kt @@ -15,68 +15,51 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterIsInstance -import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.onEach import javax.inject.Inject @HiltViewModel -class CurrencyViewModel @Inject constructor( +class RegionSelectionViewModel @Inject constructor( exchange: Exchange, preferredCurrencyController: PreferredCurrencyController, private val resources: ResourceHelper, dispatchers: DispatcherProvider, -) : BaseViewModel( +) : BaseViewModel( initialState = State(), updateStateForEvent = updateStateForEvent, defaultDispatcher = dispatchers.Default, ) { data class State( - val loading: Boolean = false, - val listItems: List = emptyList(), - val currencies: List = emptyList(), - val recents: List? = null, + val listItems: List = emptyList(), val wasLocalRemovedFromRecents: Boolean = false, val searchState: TextFieldState = TextFieldState(), val selectedCurrency: Currency? = null, ) sealed interface Event { - data class OnLoadingChanged(val loading: Boolean) : Event - data class OnItemsPopulated(val currencies: List) : Event - data class OnCurrenciesUpdated(val currencies: List): Event - data class OnRecentCurrenciesUpdated(val recents: List) : Event + data class OnItemsPopulated(val items: List) : Event data class OnCurrencySelected(val currency: Currency, val fromUser: Boolean = true) : Event data object OnSelectedCurrencyChanged: Event data object RemovedLocalFromRecents : Event - data class OnRecentCurrencyRemoved(val currency: Currency) : Event } + private val searchState = stateFlow.value.searchState + init { + // Observe preferred currency selection for initial state combine( exchange.observeRates().distinctUntilChanged().map { exchange.getCurrenciesWithRates() }, preferredCurrencyController.observePreferredCurrency().distinctUntilChanged(), ) { currenciesWithRates, preferredCurrency -> - dispatchEvent(Event.OnCurrenciesUpdated(currenciesWithRates)) val preferredWithRate = currenciesWithRates.find { it.code == preferredCurrency } if (preferredWithRate != null) { dispatchEvent(Event.OnCurrencySelected(preferredWithRate, false)) } }.launchIn(viewModelScope) - preferredCurrencyController - .observeRecentCurrencies() - .distinctUntilChanged() - .map { recents -> - val currencies = exchange.getCurrenciesWithRates() - recents.mapNotNull { currencies.find { c -> c.code == it } } - } - .onEach { dispatchEvent(Event.OnRecentCurrenciesUpdated(it)) } - .launchIn(viewModelScope) - eventFlow .filterIsInstance() .filter { it.fromUser } @@ -89,23 +72,23 @@ class CurrencyViewModel @Inject constructor( eventFlow .filterIsInstance() .map { it.currency } - .map { selected -> - preferredCurrencyController.removeFromRecents(selected) - }.launchIn(viewModelScope) + .onEach { preferredCurrencyController.removeFromRecents(it) } + .launchIn(viewModelScope) + // Single combine from source flows directly to list items combine( - stateFlow.map { it.currencies }, - stateFlow.map { it.recents }, - stateFlow.map { it.searchState }.flatMapLatest { snapshotFlow { it.text } } - ) { currencies, recents, search -> + exchange.observeRates().distinctUntilChanged().map { exchange.getCurrenciesWithRates() }, + preferredCurrencyController.observeRecentCurrencies().distinctUntilChanged(), + snapshotFlow { searchState.text }, + ) { currencies, recentCodes, search -> + val recents = recentCodes.mapNotNull { code -> currencies.find { it.code == code } } generateListItems( currencies = currencies, - recents = recents.orEmpty(), - searchString = search.toString() + recents = recents, + searchString = search.toString(), ) }.onEach { items -> dispatchEvent(Event.OnItemsPopulated(items)) - dispatchEvent(Event.OnLoadingChanged(false)) }.launchIn(viewModelScope) } @@ -113,7 +96,7 @@ class CurrencyViewModel @Inject constructor( currencies: List, recents: List, searchString: String - ): List = buildList { + ): List = buildList { val sortedCurrencies = currencies.sortedBy { it.name } val sortedRecents = recents.sortedBy { it.name } val isSearch = searchString.isNotBlank() @@ -124,15 +107,15 @@ class CurrencyViewModel @Inject constructor( sortedRecents.isNotEmpty() -> R.string.title_recentRegions else -> R.string.title_otherRegions } - add(CurrencyListItem.TitleItem(resources.getString(titleRes))) + add(RegionListItem.TitleItem(resources.getString(titleRes))) // Add recent currencies (only if not searching) if (!isSearch && recents.isNotEmpty()) { sortedRecents.forEach { currency -> - add(CurrencyListItem.RegionCurrencyItem(currency, isRecent = true)) + add(RegionListItem.RegionCurrencyItem(currency, isRecent = true)) } // Add "Other Currencies" title if there are recent currencies - add(CurrencyListItem.TitleItem(resources.getString(R.string.title_otherRegions))) + add(RegionListItem.TitleItem(resources.getString(R.string.title_otherRegions))) } sortedCurrencies @@ -143,7 +126,7 @@ class CurrencyViewModel @Inject constructor( } .forEach { currency -> if (isSearch || !recents.contains(currency)) { - add(CurrencyListItem.RegionCurrencyItem(currency, isRecent = false)) + add(RegionListItem.RegionCurrencyItem(currency, isRecent = false)) } } } @@ -151,13 +134,10 @@ class CurrencyViewModel @Inject constructor( internal companion object { val updateStateForEvent: (Event) -> ((State) -> State) = { event -> when (event) { - is Event.OnItemsPopulated -> { state -> state.copy(listItems = event.currencies) } - is Event.OnLoadingChanged -> { state -> state.copy(loading = event.loading) } - is Event.OnCurrenciesUpdated -> { state -> state.copy(currencies = event.currencies) } - is Event.OnRecentCurrenciesUpdated -> { state -> state.copy(recents = event.recents) } - is Event.OnRecentCurrencyRemoved -> { state -> state } + is Event.OnItemsPopulated -> { state -> state.copy(listItems = event.items) } is Event.OnSelectedCurrencyChanged -> { state -> state } is Event.RemovedLocalFromRecents -> { state -> state.copy(wasLocalRemovedFromRecents = true) } + is Event.OnRecentCurrencyRemoved -> { state -> state } is Event.OnCurrencySelected -> { state -> if (event.fromUser) { state diff --git a/apps/flipcash/shared/currency-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/components/GroupHeader.kt b/apps/flipcash/shared/region-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/components/GroupHeader.kt similarity index 90% rename from apps/flipcash/shared/currency-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/components/GroupHeader.kt rename to apps/flipcash/shared/region-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/components/GroupHeader.kt index 42bf824d8..2fb42d93f 100644 --- a/apps/flipcash/shared/currency-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/components/GroupHeader.kt +++ b/apps/flipcash/shared/region-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/components/GroupHeader.kt @@ -5,8 +5,8 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.material.Divider -import androidx.compose.material.Text +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp @@ -30,7 +30,7 @@ internal fun GroupHeader( text = text ) } - Divider( + HorizontalDivider( color = CodeTheme.colors.dividerVariant, modifier = Modifier .fillMaxWidth() diff --git a/apps/flipcash/shared/currency-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/components/ListRowItem.kt b/apps/flipcash/shared/region-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/components/ListRowItem.kt similarity index 97% rename from apps/flipcash/shared/currency-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/components/ListRowItem.kt rename to apps/flipcash/shared/region-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/components/ListRowItem.kt index e365851c0..29244c053 100644 --- a/apps/flipcash/shared/currency-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/components/ListRowItem.kt +++ b/apps/flipcash/shared/region-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/components/ListRowItem.kt @@ -20,7 +20,7 @@ import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.clip import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp -import com.flipcash.app.currency.internal.CurrencyListItem +import com.flipcash.app.currency.internal.RegionListItem import com.flipcash.features.currency.R import com.getcode.theme.CodeTheme import com.getcode.ui.components.SwipeActionRow @@ -28,7 +28,7 @@ import com.getcode.ui.core.rememberedClickable @Composable internal fun ListRowItem( - item: CurrencyListItem.RegionCurrencyItem, + item: RegionListItem.RegionCurrencyItem, isSelected: Boolean, modifier: Modifier = Modifier, onRemoved: () -> Unit, diff --git a/apps/flipcash/shared/region-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/components/RegionList.kt b/apps/flipcash/shared/region-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/components/RegionList.kt new file mode 100644 index 000000000..a82fc354a --- /dev/null +++ b/apps/flipcash/shared/region-selection/ui/src/main/kotlin/com/flipcash/app/currency/internal/components/RegionList.kt @@ -0,0 +1,106 @@ +package com.flipcash.app.currency.internal.components + +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.togetherWith +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.navigationBars +import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.flipcash.app.currency.internal.RegionListItem +import com.getcode.opencode.model.financial.Currency +import com.getcode.theme.CodeTheme +import com.getcode.ui.core.verticalScrollStateGradient +import com.getcode.ui.utils.sheetResignmentBehavior + +@Composable +internal fun RegionList( + items: List, + selected: Currency?, + modifier: Modifier = Modifier, + onRemoved: (Currency) -> Unit, + onSelected: (Currency) -> Unit, +) { + val listState = rememberLazyListState() + + AnimatedContent( + targetState = items.isEmpty(), + modifier = modifier.fillMaxWidth(), + transitionSpec = { fadeIn() togetherWith fadeOut() }, + label = "region-list", + ) { isEmpty -> + if (isEmpty) { + Box(Modifier.fillMaxSize()) + } else { + LazyColumn( + modifier = Modifier + .fillMaxWidth() + .background(CodeTheme.colors.background) + .verticalScrollStateGradient( + scrollState = listState, + color = CodeTheme.colors.background, + ) + .sheetResignmentBehavior(listState), + state = listState, + ) { + items( + items, + key = { item -> + when (item) { + is RegionListItem.RegionCurrencyItem -> item.currency.code + is RegionListItem.TitleItem -> item.text + } + }, + ) { listItem -> + val currencyCode = when (listItem) { + is RegionListItem.RegionCurrencyItem -> listItem.currency.code + else -> "" + } + + Box( + modifier = Modifier + .animateItem() + .fillMaxWidth() + .height(if (listItem !is RegionListItem.TitleItem) 70.dp else 60.dp) + ) { + when (listItem) { + is RegionListItem.TitleItem -> { + GroupHeader( + modifier = Modifier.align(Alignment.BottomStart), + text = listItem.text + ) + } + + is RegionListItem.RegionCurrencyItem -> { + ListRowItem( + item = listItem, + isSelected = selected?.code.orEmpty() == currencyCode, + onRemoved = { onRemoved(listItem.currency) }, + ) { + onSelected(listItem.currency) + } + } + } + } + } + + item { + Spacer(Modifier.windowInsetsPadding(WindowInsets.navigationBars)) + } + } + } + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 2db9bbabb..952432485 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -55,8 +55,8 @@ include( ":apps:flipcash:shared:onramp:deeplinks", ":apps:flipcash:shared:appupdates", ":apps:flipcash:shared:google-play-billing", - ":apps:flipcash:shared:currency-selection:core", - ":apps:flipcash:shared:currency-selection:ui", + ":apps:flipcash:shared:region-selection:core", + ":apps:flipcash:shared:region-selection:ui", ":apps:flipcash:shared:featureflags", ":apps:flipcash:shared:ksp", ":apps:flipcash:shared:menu",