Skip to content

Commit b86868a

Browse files
committed
Prohibit identical currencies
1 parent d370d54 commit b86868a

File tree

10 files changed

+280
-43
lines changed

10 files changed

+280
-43
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package dev.arkbuilders.rate.core.presentation.ui
2+
3+
import androidx.compose.foundation.background
4+
import androidx.compose.foundation.layout.Box
5+
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.fillMaxWidth
7+
import androidx.compose.foundation.layout.padding
8+
import androidx.compose.foundation.layout.size
9+
import androidx.compose.foundation.shape.RoundedCornerShape
10+
import androidx.compose.material3.Icon
11+
import androidx.compose.material3.IconButton
12+
import androidx.compose.material3.Text
13+
import androidx.compose.runtime.Composable
14+
import androidx.compose.ui.Alignment
15+
import androidx.compose.ui.Modifier
16+
import androidx.compose.ui.graphics.Color
17+
import androidx.compose.ui.res.painterResource
18+
import androidx.compose.ui.text.font.FontWeight
19+
import androidx.compose.ui.tooling.preview.Preview
20+
import androidx.compose.ui.unit.dp
21+
import androidx.compose.ui.unit.sp
22+
import androidx.compose.ui.window.Dialog
23+
import dev.arkbuilders.rate.core.presentation.R
24+
import dev.arkbuilders.rate.core.presentation.theme.ArkColor
25+
26+
@Composable
27+
fun InfoDialog(
28+
title: String,
29+
desc: String,
30+
onDismiss: () -> Unit,
31+
) {
32+
Dialog(onDismissRequest = { onDismiss() }) {
33+
Content(title, desc, onDismiss)
34+
}
35+
}
36+
37+
@Preview(showBackground = true)
38+
@Composable
39+
private fun Content(
40+
title: String = "Currency Already Selected",
41+
desc: String =
42+
"Please choose a different currency to complete the pairing. " +
43+
"Identical currencies cannot be paired together.",
44+
onDismiss: () -> Unit = {},
45+
) {
46+
Column(
47+
modifier =
48+
Modifier
49+
.fillMaxWidth()
50+
.background(Color.White, RoundedCornerShape(12.dp)),
51+
) {
52+
Box(modifier = Modifier.fillMaxWidth()) {
53+
Icon(
54+
modifier =
55+
Modifier
56+
.padding(top = 20.dp, start = 16.dp)
57+
.align(Alignment.TopStart),
58+
painter = painterResource(id = R.drawable.ic_info_bg),
59+
contentDescription = "",
60+
tint = Color.Unspecified,
61+
)
62+
IconButton(
63+
modifier =
64+
Modifier
65+
.size(44.dp)
66+
.padding(top = 12.dp, end = 12.dp)
67+
.align(Alignment.TopEnd),
68+
onClick = { onDismiss() },
69+
) {
70+
Icon(
71+
modifier = Modifier.size(12.dp),
72+
painter = painterResource(id = R.drawable.ic_close),
73+
contentDescription = "",
74+
tint = ArkColor.FGQuinary,
75+
)
76+
}
77+
}
78+
Text(
79+
modifier = Modifier.padding(top = 12.dp, start = 16.dp, end = 16.dp),
80+
text = title,
81+
fontWeight = FontWeight.SemiBold,
82+
fontSize = 18.sp,
83+
color = ArkColor.TextPrimary,
84+
)
85+
Text(
86+
modifier = Modifier.padding(top = 4.dp, start = 16.dp, end = 16.dp, bottom = 36.dp),
87+
text = desc,
88+
fontSize = 18.sp,
89+
color = ArkColor.TextTertiary,
90+
)
91+
}
92+
}

core/presentation/src/main/res/values/strings.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@
6464
<string name="settings_latest_rates_refresh">Latest rates refresh</string>
6565
<string name="settings_latest_alerts_check">Latest alerts check</string>
6666

67+
<string name="search_currency_already_selected">Currency already selected</string>
68+
<string name="search_currency_already_selected_desc">Please choose a different currency. Identical currencies cannot be used together.</string>
69+
6770
<string name="group_create_group">Create Group</string>
6871
<string name="group_please_enter_a_name_for_this_group">Please enter a name for this group.</string>
6972
<string name="group_name">Group name</string>

feature/pairalert/src/main/java/dev/arkbuilders/rate/feature/pairalert/presentation/add/AddPairAlertScreen.kt

Lines changed: 55 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,22 @@ fun AddPairAlertScreen(
111111
)
112112
AppSharedFlow.ShowAddedSnackbarPairAlert.flow.emit(visuals)
113113
}
114+
115+
is AddPairAlertScreenEffect.NavigateSearchBase ->
116+
navigator.navigate(
117+
SearchCurrencyScreenDestination(
118+
appSharedFlowKeyString = AppSharedFlowKey.AddPairAlertBase.name,
119+
prohibitedCodes = effect.prohibitedCodes.toTypedArray(),
120+
),
121+
)
122+
123+
is AddPairAlertScreenEffect.NavigateSearchTarget ->
124+
navigator.navigate(
125+
SearchCurrencyScreenDestination(
126+
appSharedFlowKeyString = AppSharedFlowKey.AddPairAlertTarget.name,
127+
prohibitedCodes = effect.prohibitedCodes.toTypedArray(),
128+
),
129+
)
114130
}
115131
}
116132

@@ -127,24 +143,40 @@ fun AddPairAlertScreen(
127143
},
128144
) {
129145
Box(modifier = Modifier.padding(it)) {
130-
Content(state, navigator, viewModel)
146+
Content(
147+
state = state,
148+
navigateSearchBase = viewModel::onNavigateSearchBase,
149+
navigateSearchTarget = viewModel::onNavigateSearchTarget,
150+
onGroupSelect = viewModel::onGroupSelect,
151+
onPriceOrPercentChanged = viewModel::onPriceOrPercentChanged,
152+
onOneTimeChanged = viewModel::onOneTimeChanged,
153+
onPriceOrPercentInputChanged = viewModel::onPriceOrPercentInputChanged,
154+
onIncreaseToggle = viewModel::onIncreaseToggle,
155+
onSaveClick = viewModel::onSaveClick,
156+
)
131157
}
132158
}
133159
}
134160

135161
@Composable
136162
private fun Content(
137163
state: AddPairAlertScreenState,
138-
navigator: DestinationsNavigator,
139-
viewModel: AddPairAlertViewModel,
164+
navigateSearchBase: () -> Unit,
165+
navigateSearchTarget: () -> Unit,
166+
onGroupSelect: (String) -> Unit,
167+
onPriceOrPercentChanged: (Boolean) -> Unit,
168+
onOneTimeChanged: (Boolean) -> Unit,
169+
onPriceOrPercentInputChanged: (String) -> Unit,
170+
onIncreaseToggle: () -> Unit,
171+
onSaveClick: () -> Unit,
140172
) {
141173
var showNewGroupDialog by remember { mutableStateOf(false) }
142174
var showGroupsPopup by remember { mutableStateOf(false) }
143175
var addGroupBtnWidth by remember { mutableStateOf(0) }
144176

145177
if (showNewGroupDialog) {
146178
GroupCreateDialog(onDismiss = { showNewGroupDialog = false }) {
147-
viewModel.onGroupSelect(it)
179+
onGroupSelect(it)
148180
}
149181
}
150182

@@ -155,12 +187,18 @@ private fun Content(
155187
.weight(1f)
156188
.verticalScroll(rememberScrollState()),
157189
) {
158-
PriceOrPercent(state, viewModel::onPriceOrPercentChanged)
159-
EditCondition(state, viewModel, navigator)
190+
PriceOrPercent(state, onPriceOrPercentChanged)
191+
EditCondition(
192+
state = state,
193+
navigateSearchBase = navigateSearchBase,
194+
navigateSearchTarget = navigateSearchTarget,
195+
onPriceOrPercentInputChanged = onPriceOrPercentInputChanged,
196+
onIncreaseToggle = onIncreaseToggle,
197+
)
160198
OneTimeOrRecurrent(
161199
state.priceOrPercent.isLeft(),
162200
state.oneTimeNotRecurrent,
163-
viewModel::onOneTimeChanged,
201+
onOneTimeChanged,
164202
)
165203
DropDownWithIcon(
166204
modifier =
@@ -192,7 +230,7 @@ private fun Content(
192230
GroupSelectPopup(
193231
groups = state.availableGroups,
194232
widthPx = addGroupBtnWidth,
195-
onGroupSelect = { viewModel.onGroupSelect(it) },
233+
onGroupSelect = onGroupSelect,
196234
onNewGroupClick = { showNewGroupDialog = true },
197235
onDismiss = { showGroupsPopup = false },
198236
)
@@ -207,7 +245,7 @@ private fun Content(
207245
Modifier
208246
.fillMaxWidth()
209247
.padding(16.dp),
210-
onClick = { viewModel.onSaveClick() },
248+
onClick = onSaveClick,
211249
enabled = state.finishEnabled,
212250
) {
213251
Text(
@@ -344,8 +382,10 @@ private fun DropDownBtn(
344382
@Composable
345383
private fun EditCondition(
346384
state: AddPairAlertScreenState,
347-
viewModel: AddPairAlertViewModel,
348-
navigator: DestinationsNavigator,
385+
navigateSearchBase: () -> Unit,
386+
navigateSearchTarget: () -> Unit,
387+
onPriceOrPercentInputChanged: (String) -> Unit,
388+
onIncreaseToggle: () -> Unit,
349389
) {
350390
val ctx = LocalContext.current
351391
Column(
@@ -368,9 +408,7 @@ private fun EditCondition(
368408
modifier = Modifier.padding(start = 8.dp),
369409
title = state.targetCode,
370410
) {
371-
navigator.navigate(
372-
SearchCurrencyScreenDestination(AppSharedFlowKey.AddPairAlertTarget.name),
373-
)
411+
navigateSearchTarget()
374412
}
375413
Text(
376414
modifier = Modifier.padding(start = 8.dp),
@@ -385,7 +423,7 @@ private fun EditCondition(
385423
if (state.oneTimeNotRecurrent && state.priceOrPercent.isLeft())
386424
this
387425
else
388-
clickable { viewModel.onIncreaseToggle() }
426+
clickable { onIncreaseToggle() }
389427
},
390428
verticalAlignment = Alignment.CenterVertically,
391429
) {
@@ -448,7 +486,7 @@ private fun EditCondition(
448486
ifLeft = { it },
449487
ifRight = { it },
450488
),
451-
onValueChange = { viewModel.onPriceOrPercentInputChanged(it) },
489+
onValueChange = { onPriceOrPercentInputChanged(it) },
452490
)
453491
if (state.priceOrPercent.isLeft()) {
454492
Text(
@@ -488,9 +526,7 @@ private fun EditCondition(
488526
modifier = Modifier.padding(start = 16.dp),
489527
title = state.baseCode,
490528
) {
491-
navigator.navigate(
492-
SearchCurrencyScreenDestination(AppSharedFlowKey.AddPairAlertBase.name),
493-
)
529+
navigateSearchBase()
494530
}
495531
}
496532
}

feature/pairalert/src/main/java/dev/arkbuilders/rate/feature/pairalert/presentation/add/AddPairAlertViewModel.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@ sealed class AddPairAlertScreenEffect {
4747
data object NavigateBack : AddPairAlertScreenEffect()
4848

4949
class NotifyPairAdded(val pair: PairAlert) : AddPairAlertScreenEffect()
50+
51+
data class NavigateSearchTarget(
52+
val prohibitedCodes: List<CurrencyCode>,
53+
) : AddPairAlertScreenEffect()
54+
55+
data class NavigateSearchBase(
56+
val prohibitedCodes: List<CurrencyCode>,
57+
) : AddPairAlertScreenEffect()
5058
}
5159

5260
class AddPairAlertViewModel(
@@ -346,6 +354,18 @@ class AddPairAlertViewModel(
346354
reduce { state.copy(finishEnabled = enabled) }
347355
}
348356

357+
fun onNavigateSearchBase() =
358+
intent {
359+
val prohibitedCodes = listOf(state.targetCode)
360+
postSideEffect(AddPairAlertScreenEffect.NavigateSearchBase(prohibitedCodes))
361+
}
362+
363+
fun onNavigateSearchTarget() =
364+
intent {
365+
val prohibitedCodes = listOf(state.baseCode)
366+
postSideEffect(AddPairAlertScreenEffect.NavigateSearchTarget(prohibitedCodes))
367+
}
368+
349369
companion object {
350370
private val INITIAL_ONE_TIME_SCALE = BigDecimal.valueOf(1.1)
351371
private val INITIAL_RECURRENT_SCALE = BigDecimal.valueOf(10)

feature/portfolio/src/main/java/dev/arkbuilders/rate/feature/portfolio/presentation/add/AddAssetScreen.kt

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,23 @@ fun AddAssetScreen(navigator: DestinationsNavigator) {
100100
),
101101
)
102102
}
103+
104+
is AddAssetSideEffect.NavigateSearchAdd ->
105+
navigator.navigate(
106+
SearchCurrencyScreenDestination(
107+
appSharedFlowKeyString = AppSharedFlowKey.AddAsset.toString(),
108+
prohibitedCodes = effect.prohibitedCodes.toTypedArray(),
109+
),
110+
)
111+
112+
is AddAssetSideEffect.NavigateSearchSet ->
113+
navigator.navigate(
114+
SearchCurrencyScreenDestination(
115+
appSharedFlowKeyString = AppSharedFlowKey.SetAssetCode.name,
116+
pos = effect.index,
117+
prohibitedCodes = effect.prohibitedCodes.toTypedArray(),
118+
),
119+
)
103120
}
104121
}
105122

@@ -115,18 +132,10 @@ fun AddAssetScreen(navigator: DestinationsNavigator) {
115132
Content(
116133
state = state,
117134
onAssetValueChanged = viewModel::onAssetValueChange,
118-
onNewCurrencyClick = {
119-
navigator.navigate(
120-
SearchCurrencyScreenDestination(AppSharedFlowKey.AddAsset.toString()),
121-
)
122-
},
135+
onNewCurrencyClick = viewModel::onAddCode,
123136
onAssetRemove = viewModel::onAssetRemove,
124137
onGroupSelect = viewModel::onGroupSelect,
125-
onCodeChange = {
126-
navigator.navigate(
127-
SearchCurrencyScreenDestination(AppSharedFlowKey.SetAssetCode.name, it),
128-
)
129-
},
138+
onCodeChange = viewModel::onSetCode,
130139
onAddAsset = viewModel::onAddAsset,
131140
)
132141
}

feature/portfolio/src/main/java/dev/arkbuilders/rate/feature/portfolio/presentation/add/AddAssetViewModel.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import androidx.lifecycle.ViewModelProvider
55
import androidx.lifecycle.viewModelScope
66
import dev.arkbuilders.rate.core.domain.CurrUtils
77
import dev.arkbuilders.rate.core.domain.model.AmountStr
8+
import dev.arkbuilders.rate.core.domain.model.CurrencyCode
89
import dev.arkbuilders.rate.core.domain.repo.AnalyticsManager
910
import dev.arkbuilders.rate.core.domain.repo.CodeUseStatRepo
1011
import dev.arkbuilders.rate.core.domain.repo.CurrencyRepo
@@ -37,6 +38,11 @@ sealed class AddAssetSideEffect {
3738
AddAssetSideEffect()
3839

3940
data object NavigateBack : AddAssetSideEffect()
41+
42+
data class NavigateSearchAdd(val prohibitedCodes: List<CurrencyCode>) : AddAssetSideEffect()
43+
44+
data class NavigateSearchSet(val index: Int, val prohibitedCodes: List<CurrencyCode>) :
45+
AddAssetSideEffect()
4046
}
4147

4248
class AddAssetViewModel(
@@ -139,6 +145,19 @@ class AddAssetViewModel(
139145
postSideEffect(AddAssetSideEffect.NotifyAssetAdded(currencies))
140146
postSideEffect(AddAssetSideEffect.NavigateBack)
141147
}
148+
149+
fun onSetCode(index: Int) =
150+
intent {
151+
val prohibitedCodes = state.currencies.map { it.code }.toMutableList()
152+
prohibitedCodes.removeAt(index)
153+
postSideEffect(AddAssetSideEffect.NavigateSearchSet(index, prohibitedCodes))
154+
}
155+
156+
fun onAddCode() =
157+
intent {
158+
val prohibitedCodes = state.currencies.map { it.code }
159+
postSideEffect(AddAssetSideEffect.NavigateSearchAdd(prohibitedCodes))
160+
}
142161
}
143162

144163
@PortfolioScope

0 commit comments

Comments
 (0)