Skip to content

Commit 8e7952a

Browse files
committed
test: add date picker roborazzi
1 parent 0079210 commit 8e7952a

File tree

5 files changed

+101
-243
lines changed

5 files changed

+101
-243
lines changed

shared/src/androidUnitTest/kotlin/com/prof18/moneyflow/AddTransactionRoborazziTest.kt

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package com.prof18.moneyflow
22

33
import androidx.compose.runtime.mutableStateOf
44
import androidx.compose.runtime.remember
5+
import androidx.compose.ui.test.onNodeWithText
6+
import androidx.compose.ui.test.performClick
57
import androidx.test.ext.junit.runners.AndroidJUnit4
68
import com.github.takahirom.roborazzi.RobolectricDeviceQualifiers
79
import com.prof18.moneyflow.database.model.TransactionType
@@ -11,6 +13,7 @@ import org.junit.Test
1113
import org.junit.runner.RunWith
1214
import org.robolectric.annotation.Config
1315
import org.robolectric.annotation.GraphicsMode
16+
import kotlin.time.Clock
1417

1518
@RunWith(AndroidJUnit4::class)
1619
@GraphicsMode(GraphicsMode.Mode.NATIVE)
@@ -35,11 +38,9 @@ class AddTransactionRoborazziTest : RoborazziTestBase() {
3538
updateDescriptionText = {},
3639
selectedTransactionType = TransactionType.OUTCOME,
3740
updateTransactionType = {},
38-
updateYear = {},
39-
updateMonth = {},
40-
updateDay = {},
41-
saveDate = {},
41+
updateSelectedDate = {},
4242
dateLabel = "11 July 2021",
43+
selectedDateMillis = Clock.System.now().toEpochMilliseconds(),
4344
addTransactionAction = null,
4445
resetAction = {},
4546
currencyConfig = RoborazziSampleData.sampleCurrencyConfig,
@@ -49,4 +50,36 @@ class AddTransactionRoborazziTest : RoborazziTestBase() {
4950

5051
capture("add_transaction_screen")
5152
}
53+
54+
@Test
55+
fun captureAddTransactionDatePicker() {
56+
val dateLabel = "11 July 2021"
57+
58+
composeRule.setContent {
59+
MoneyFlowTheme {
60+
AddTransactionScreen(
61+
categoryState = remember { mutableStateOf(RoborazziSampleData.sampleCategory) },
62+
navigateUp = {},
63+
navigateToCategoryList = {},
64+
addTransaction = {},
65+
amountText = "10.00",
66+
updateAmountText = {},
67+
descriptionText = "Pizza 🍕",
68+
updateDescriptionText = {},
69+
selectedTransactionType = TransactionType.OUTCOME,
70+
updateTransactionType = {},
71+
updateSelectedDate = {},
72+
dateLabel = dateLabel,
73+
selectedDateMillis = Clock.System.now().toEpochMilliseconds(),
74+
addTransactionAction = null,
75+
resetAction = {},
76+
currencyConfig = RoborazziSampleData.sampleCurrencyConfig,
77+
)
78+
}
79+
}
80+
81+
composeRule.onNodeWithText(dateLabel).performClick()
82+
83+
capture("add_transaction_screen_date_picker")
84+
}
5285
}

shared/src/commonMain/kotlin/com/prof18/moneyflow/features/addtransaction/AddTransactionViewModel.kt

Lines changed: 11 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,6 @@ import kotlinx.coroutines.flow.StateFlow
1919
import kotlinx.coroutines.flow.collectLatest
2020
import kotlinx.coroutines.flow.update
2121
import kotlinx.coroutines.launch
22-
import kotlinx.datetime.LocalDate
23-
import kotlinx.datetime.TimeZone
24-
import kotlinx.datetime.atStartOfDayIn
25-
import kotlinx.datetime.toLocalDateTime
2622
import money_flow.shared.generated.resources.Res
2723
import money_flow.shared.generated.resources.amount_not_empty_error
2824
import kotlin.time.Clock
@@ -32,26 +28,22 @@ internal class AddTransactionViewModel(
3228
private val errorMapper: MoneyFlowErrorMapper,
3329
) : ViewModel() {
3430

31+
private val initialSelectedDateMillis: Long = Clock.System.now().toEpochMilliseconds()
32+
3533
private val _uiState = MutableStateFlow(
3634
AddTransactionUiState(
3735
selectedTransactionType = TransactionType.INCOME,
3836
amountText = "",
3937
descriptionText = null,
40-
dateLabel = null,
38+
dateLabel = initialSelectedDateMillis.formatDateDayMonthYear(),
4139
addTransactionAction = null,
4240
currencyConfig = null,
41+
selectedDateMillis = initialSelectedDateMillis,
4342
),
4443
)
4544
val uiState: StateFlow<AddTransactionUiState> = _uiState
4645

47-
// Private variables
48-
private var selectedDateMillis: Long = Clock.System.now().toEpochMilliseconds()
49-
private var yearNumber: Int = currentLocalDate().year
50-
private var monthNumber: Int = currentLocalDate().month.ordinal
51-
private var dayNumber: Int = currentLocalDate().day
52-
5346
init {
54-
updateDateLabel()
5547
observeCurrencyConfig()
5648
}
5749

@@ -65,27 +57,12 @@ internal class AddTransactionViewModel(
6557
}
6658
}
6759

68-
fun setYearNumber(yearNumber: Int) {
69-
this.yearNumber = yearNumber
70-
}
71-
72-
fun setMonthNumber(monthNumber: Int) {
73-
this.monthNumber = monthNumber - 1
74-
}
75-
76-
fun setDayNumber(dayNumber: Int) {
77-
this.dayNumber = dayNumber
78-
}
79-
80-
fun saveDate() {
81-
val localDate = LocalDate(yearNumber, monthNumber + 1, dayNumber)
82-
selectedDateMillis = localDate.atStartOfDayIn(TimeZone.currentSystemDefault()).toEpochMilliseconds()
83-
updateDateLabel()
84-
}
85-
86-
private fun updateDateLabel() {
60+
fun updateSelectedDate(selectedDateMillis: Long) {
8761
_uiState.update { state ->
88-
state.copy(dateLabel = selectedDateMillis.formatDateDayMonthYear())
62+
state.copy(
63+
dateLabel = selectedDateMillis.formatDateDayMonthYear(),
64+
selectedDateMillis = selectedDateMillis,
65+
)
8966
}
9067
}
9168

@@ -106,7 +83,7 @@ internal class AddTransactionViewModel(
10683
val result = try {
10784
moneyRepository.insertTransaction(
10885
TransactionToSave(
109-
dateMillis = selectedDateMillis,
86+
dateMillis = uiState.value.selectedDateMillis,
11087
amountCents = amountCents,
11188
description = uiState.value.descriptionText,
11289
categoryId = categoryId,
@@ -152,9 +129,6 @@ internal class AddTransactionViewModel(
152129
state.copy(selectedTransactionType = transactionType)
153130
}
154131
}
155-
156-
private fun currentLocalDate(): LocalDate =
157-
Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()).date
158132
}
159133

160134
internal data class AddTransactionUiState(
@@ -164,4 +138,5 @@ internal data class AddTransactionUiState(
164138
val dateLabel: String?,
165139
val addTransactionAction: AddTransactionAction?,
166140
val currencyConfig: CurrencyConfig?,
141+
val selectedDateMillis: Long,
167142
)

shared/src/commonMain/kotlin/com/prof18/moneyflow/navigation/MoneyFlowNavHost.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -249,11 +249,9 @@ private fun EntryProviderScope<AppRoute>.screens(
249249
updateDescriptionText = viewModel::updateDescriptionText,
250250
selectedTransactionType = uiState.selectedTransactionType,
251251
updateTransactionType = viewModel::updateTransactionType,
252-
updateYear = viewModel::setYearNumber,
253-
updateMonth = viewModel::setMonthNumber,
254-
updateDay = viewModel::setDayNumber,
255-
saveDate = viewModel::saveDate,
252+
updateSelectedDate = viewModel::updateSelectedDate,
256253
dateLabel = uiState.dateLabel,
254+
selectedDateMillis = uiState.selectedDateMillis,
257255
addTransactionAction = uiState.addTransactionAction,
258256
resetAction = viewModel::resetAction,
259257
currencyConfig = uiState.currencyConfig,

shared/src/commonMain/kotlin/com/prof18/moneyflow/presentation/addtransaction/AddTransactionScreen.kt

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,19 @@ package com.prof18.moneyflow.presentation.addtransaction
33
import androidx.compose.foundation.layout.Column
44
import androidx.compose.foundation.layout.fillMaxWidth
55
import androidx.compose.foundation.layout.padding
6+
import androidx.compose.material3.DatePicker
7+
import androidx.compose.material3.DatePickerDefaults
8+
import androidx.compose.material3.DatePickerDialog
9+
import androidx.compose.material3.ExperimentalMaterial3Api
610
import androidx.compose.material3.Icon
711
import androidx.compose.material3.MaterialTheme
812
import androidx.compose.material3.Scaffold
913
import androidx.compose.material3.SnackbarHost
1014
import androidx.compose.material3.SnackbarHostState
1115
import androidx.compose.material3.Surface
16+
import androidx.compose.material3.Text
17+
import androidx.compose.material3.TextButton
18+
import androidx.compose.material3.rememberDatePickerState
1219
import androidx.compose.runtime.Composable
1320
import androidx.compose.runtime.LaunchedEffect
1421
import androidx.compose.runtime.State
@@ -20,7 +27,6 @@ import androidx.compose.ui.text.input.KeyboardType
2027
import androidx.compose.ui.tooling.preview.Preview
2128
import com.prof18.moneyflow.database.model.TransactionType
2229
import com.prof18.moneyflow.domain.entities.CurrencyConfig
23-
import com.prof18.moneyflow.presentation.addtransaction.components.DatePickerDialog
2430
import com.prof18.moneyflow.presentation.addtransaction.components.IconTextClickableRow
2531
import com.prof18.moneyflow.presentation.addtransaction.components.MFTextInput
2632
import com.prof18.moneyflow.presentation.addtransaction.components.TransactionTypeTabBar
@@ -32,6 +38,8 @@ import com.prof18.moneyflow.ui.style.Margins
3238
import com.prof18.moneyflow.ui.style.MoneyFlowTheme
3339
import money_flow.shared.generated.resources.Res
3440
import money_flow.shared.generated.resources.add_transaction_screen
41+
import money_flow.shared.generated.resources.cancel
42+
import money_flow.shared.generated.resources.confirm
3543
import money_flow.shared.generated.resources.description
3644
import money_flow.shared.generated.resources.ic_calendar
3745
import money_flow.shared.generated.resources.ic_edit
@@ -42,9 +50,11 @@ import money_flow.shared.generated.resources.select_category
4250
import money_flow.shared.generated.resources.today
4351
import org.jetbrains.compose.resources.painterResource
4452
import org.jetbrains.compose.resources.stringResource
53+
import kotlin.time.Clock
4554

4655
@Composable
4756
@Suppress("LongMethod", "LongParameterList") // TODO: reduce method length
57+
@OptIn(ExperimentalMaterial3Api::class)
4858
internal fun AddTransactionScreen(
4959
categoryState: State<CategoryUIData?>,
5060
navigateUp: () -> Unit,
@@ -56,16 +66,19 @@ internal fun AddTransactionScreen(
5666
updateDescriptionText: (String?) -> Unit,
5767
selectedTransactionType: TransactionType,
5868
updateTransactionType: (TransactionType) -> Unit,
59-
updateYear: (Int) -> Unit,
60-
updateMonth: (Int) -> Unit,
61-
updateDay: (Int) -> Unit,
62-
saveDate: () -> Unit,
69+
updateSelectedDate: (Long) -> Unit,
6370
dateLabel: String?,
71+
selectedDateMillis: Long,
6472
addTransactionAction: AddTransactionAction?,
6573
resetAction: () -> Unit,
6674
currencyConfig: CurrencyConfig?,
6775
) {
6876
val (showDatePickerDialog, setShowedDatePickerDialog) = remember { mutableStateOf(false) }
77+
val datePickerState = rememberDatePickerState(initialSelectedDateMillis = selectedDateMillis)
78+
79+
LaunchedEffect(selectedDateMillis) {
80+
datePickerState.selectedDateMillis = selectedDateMillis
81+
}
6982

7083
val snackbarHostState = remember { SnackbarHostState() }
7184
addTransactionAction?.let {
@@ -111,14 +124,37 @@ internal fun AddTransactionScreen(
111124
},
112125
content = { innerPadding ->
113126
Column(modifier = Modifier.padding(innerPadding)) {
114-
DatePickerDialog(
115-
showDatePickerDialog,
116-
setShowedDatePickerDialog,
117-
onYearSelected = { updateYear(it) },
118-
onMonthSelected = { updateMonth(it) },
119-
onDaySelected = { updateDay(it) },
120-
onSave = { saveDate() },
121-
)
127+
if (showDatePickerDialog) {
128+
DatePickerDialog(
129+
onDismissRequest = { setShowedDatePickerDialog(false) },
130+
confirmButton = {
131+
TextButton(
132+
enabled = datePickerState.selectedDateMillis != null,
133+
onClick = {
134+
datePickerState.selectedDateMillis?.let { selectedDate ->
135+
updateSelectedDate(selectedDate)
136+
}
137+
setShowedDatePickerDialog(false)
138+
},
139+
) {
140+
Text(text = stringResource(Res.string.confirm))
141+
}
142+
},
143+
dismissButton = {
144+
TextButton(onClick = { setShowedDatePickerDialog(false) }) {
145+
Text(text = stringResource(Res.string.cancel))
146+
}
147+
},
148+
) {
149+
DatePicker(
150+
state = datePickerState,
151+
showModeToggle = false,
152+
colors = DatePickerDefaults.colors(
153+
containerColor = MaterialTheme.colorScheme.surface,
154+
),
155+
)
156+
}
157+
}
122158

123159
TransactionTypeTabBar(
124160
transactionType = selectedTransactionType,
@@ -225,11 +261,9 @@ private fun AddTransactionScreenPreview() {
225261
updateDescriptionText = {},
226262
selectedTransactionType = TransactionType.OUTCOME,
227263
updateTransactionType = {},
228-
updateYear = {},
229-
updateMonth = {},
230-
updateDay = {},
231-
saveDate = {},
264+
updateSelectedDate = {},
232265
dateLabel = "11 July 2021",
266+
selectedDateMillis = Clock.System.now().toEpochMilliseconds(),
233267
addTransactionAction = null,
234268
resetAction = {},
235269
currencyConfig = CurrencyConfig(

0 commit comments

Comments
 (0)