Skip to content
This repository has been archived by the owner on Nov 5, 2024. It is now read-only.

Commit

Permalink
Fix updating transactions's time (#3453)
Browse files Browse the repository at this point in the history
* Implement a proper DateTimePicker

* Fix updating date & time on transaction

* Improve the time picker UI

* Fix Detekt errors
  • Loading branch information
ILIYANGERMANOV authored Aug 31, 2024
1 parent dc89aee commit e7081e5
Show file tree
Hide file tree
Showing 14 changed files with 249 additions and 88 deletions.
6 changes: 6 additions & 0 deletions app/src/main/java/com/ivy/wallet/RootActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import com.ivy.navigation.Navigation
import com.ivy.navigation.NavigationRoot
import com.ivy.ui.R
import com.ivy.ui.time.TimeFormatter
import com.ivy.ui.time.impl.DateTimePicker
import com.ivy.wallet.ui.applocked.AppLockedScreen
import com.ivy.widget.balance.WalletBalanceWidgetReceiver
import com.ivy.widget.transaction.AddTransactionWidget
Expand Down Expand Up @@ -78,6 +79,9 @@ class RootActivity : AppCompatActivity(), RootScreen {
@Inject
lateinit var timeFormatter: TimeFormatter

@Inject
lateinit var dateTimePicker: DateTimePicker

private lateinit var createFileLauncher: ActivityResultLauncher<String>
private lateinit var onFileCreated: (fileUri: Uri) -> Unit

Expand Down Expand Up @@ -154,6 +158,8 @@ class RootActivity : AppCompatActivity(), RootScreen {
}
}
}

dateTimePicker.Content()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,7 @@ import kotlinx.collections.immutable.ImmutableSet
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.persistentSetOf
import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.ZoneOffset
import java.util.UUID
import kotlin.math.roundToInt
Expand Down Expand Up @@ -126,10 +124,10 @@ fun BoxWithConstraintsScope.EditTransactionScreen(screen: EditTransactionScreen)
transactionAssociatedTags = uiState.transactionAssociatedTags,
hasChanges = uiState.hasChanges,
onSetDate = {
viewModel.onEvent(EditTransactionViewEvent.OnSetDate(it))
viewModel.onEvent(EditTransactionViewEvent.OnChangeDate)
},
onSetTime = {
viewModel.onEvent(EditTransactionViewEvent.OnSetTime(it))
viewModel.onEvent(EditTransactionViewEvent.OnChangeTime)
},
onTitleChange = {
viewModel.onEvent(EditTransactionViewEvent.OnTitleChanged(it))
Expand Down Expand Up @@ -218,8 +216,8 @@ private fun BoxWithConstraintsScope.UI(
onAccountChange: (Account) -> Unit,
onToAccountChange: (Account) -> Unit,
onDueDateChange: (LocalDateTime?) -> Unit,
onSetDate: (LocalDate) -> Unit,
onSetTime: (LocalTime) -> Unit,
onSetDate: () -> Unit,
onSetTime: () -> Unit,
onSetTransactionType: (TransactionType) -> Unit,

onCreateCategory: (CreateCategoryData) -> Unit,
Expand Down Expand Up @@ -382,24 +380,8 @@ private fun BoxWithConstraintsScope.UI(
TransactionDateTime(
dateTime = dateTime,
dueDateTime = dueDate,
onEditDate = {
ivyContext.datePicker(
initialDate = with(timeConverter) {
dateTime?.toLocalDate()
}
) { date ->
onSetDate((date))
}
},
onEditTime = {
ivyContext.timePicker(
initialTime = with(timeConverter) {
dateTime?.toLocalTime()
}
) { time ->
onSetTime(time)
}
}
onEditDate = onSetDate,
onEditTime = onSetTime,
)

if (transactionType == TransactionType.TRANSFER && customExchangeRateState.showCard) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ import com.ivy.wallet.domain.deprecated.logic.model.CreateCategoryData
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.ImmutableSet
import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime

@Immutable
data class EditTransactionViewState(
Expand Down Expand Up @@ -48,10 +46,11 @@ sealed interface EditTransactionViewEvent {
data class OnAccountChanged(val newAccount: Account) : EditTransactionViewEvent
data class OnToAccountChanged(val newAccount: Account) : EditTransactionViewEvent
data class OnDueDateChanged(val newDueDate: LocalDateTime?) : EditTransactionViewEvent
data class OnSetDateTime(val newDateTime: LocalDateTime) : EditTransactionViewEvent
data class OnSetDate(val newDate: LocalDate) : EditTransactionViewEvent
data class OnSetTime(val newTime: LocalTime) : EditTransactionViewEvent
data class OnSetTransactionType(val newTransactionType: TransactionType) : EditTransactionViewEvent
data object OnChangeDate : EditTransactionViewEvent
data object OnChangeTime : EditTransactionViewEvent
data class OnSetTransactionType(val newTransactionType: TransactionType) :
EditTransactionViewEvent

data object OnPayPlannedPayment : EditTransactionViewEvent
data object Delete : EditTransactionViewEvent
data object Duplicate : EditTransactionViewEvent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import com.ivy.legacy.datamodel.Account
import com.ivy.legacy.datamodel.temp.toDomain
import com.ivy.legacy.domain.deprecated.logic.AccountCreator
import com.ivy.legacy.utils.computationThread
import com.ivy.legacy.utils.convertUTCToLocal
import com.ivy.legacy.utils.ioThread
import com.ivy.legacy.utils.toLowerCaseLocal
import com.ivy.legacy.utils.uiThread
Expand All @@ -43,6 +42,7 @@ import com.ivy.navigation.MainScreen
import com.ivy.navigation.Navigation
import com.ivy.ui.ComposeViewModel
import com.ivy.ui.R
import com.ivy.ui.time.impl.DateTimePicker
import com.ivy.wallet.domain.action.account.AccountByIdAct
import com.ivy.wallet.domain.action.account.AccountsAct
import com.ivy.wallet.domain.action.transaction.TrnByIdAct
Expand Down Expand Up @@ -71,9 +71,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.math.BigDecimal
import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.util.UUID
import javax.inject.Inject

Expand Down Expand Up @@ -106,6 +104,7 @@ class EditTransactionViewModel @Inject constructor(
private val features: Features,
private val timeConverter: TimeConverter,
private val timeProvider: TimeProvider,
private val dateTimePicker: DateTimePicker,
) : ComposeViewModel<EditTransactionViewState, EditTransactionViewEvent>() {

private val transactionType = mutableStateOf(TransactionType.EXPENSE)
Expand Down Expand Up @@ -322,9 +321,8 @@ class EditTransactionViewModel @Inject constructor(

is EditTransactionViewEvent.OnDueDateChanged -> onDueDateChanged(event.newDueDate)
EditTransactionViewEvent.OnPayPlannedPayment -> onPayPlannedPayment()
is EditTransactionViewEvent.OnSetDateTime -> onSetDateTime(event.newDateTime)
is EditTransactionViewEvent.OnSetDate -> onSetDate(event.newDate)
is EditTransactionViewEvent.OnSetTime -> onSetTime(event.newTime)
is EditTransactionViewEvent.OnChangeDate -> handleChangeDate()
is EditTransactionViewEvent.OnChangeTime -> handleChangeTime()
is EditTransactionViewEvent.OnSetTransactionType ->
onSetTransactionType(event.newTransactionType)

Expand Down Expand Up @@ -536,45 +534,46 @@ class EditTransactionViewModel @Inject constructor(
saveIfEditMode()
}

private fun onSetDateTime(newDateTime: LocalDateTime) {
val newDateTimeUtc = with(timeConverter) { newDateTime.toUTC() }
loadedTransaction = loadedTransaction().copy(
dateTime = newDateTimeUtc
)
dateTime.value = newDateTimeUtc

saveIfEditMode()
private fun handleChangeDate() {
dateTimePicker.pickDate(
initialDate = loadedTransaction?.dateTime,
) { localDate ->
val localTime = loadedTransaction().dateTime?.let {
with(timeConverter) { it.toLocalTime() }
} ?: timeProvider.localTimeNow()
loadedTransaction = loadedTransaction().copy(
date = localDate,
)
updateDateTime(localDate.atTime(localTime))
}
}

private fun onSetDate(newDate: LocalDate) {
loadedTransaction = loadedTransaction().copy(
date = newDate
)
val localDateTime = with(timeConverter) {
(dateTime.value ?: timeProvider.utcNow()).toLocalDateTime()
}
onSetDateTime(
localDateTime
.withDayOfMonth(newDate.dayOfMonth)
.withMonth(newDate.monthValue)
.withYear(newDate.year)
)
private fun handleChangeTime() {
dateTimePicker.pickTime(
initialTime = loadedTransaction?.dateTime?.let {
with(timeConverter) {
it.toLocalDateTime()
}
}?.toLocalTime()
) { localTime ->
val localDate = loadedTransaction().dateTime?.let {
with(timeConverter) { it.toLocalDate() }
} ?: timeProvider.localDateNow()
loadedTransaction = loadedTransaction().copy(
time = localTime,
)
updateDateTime(localDate.atTime(localTime))
}
}

private fun onSetTime(newTime: LocalTime) {
private fun updateDateTime(newDateTime: LocalDateTime) {
val newDateTimeUtc = with(timeConverter) { newDateTime.toUTC() }
loadedTransaction = loadedTransaction().copy(
time = newTime.convertUTCToLocal()
)
val localDateTime = with(timeConverter) {
(dateTime.value ?: timeProvider.utcNow()).toLocalDateTime()
}
onSetDateTime(
localDateTime
.withHour(newTime.hour)
.withMinute(newTime.minute)
.withSecond(0)
.withNano(0)
dateTime = newDateTimeUtc,
)
dateTime.value = newDateTimeUtc

saveIfEditMode()
}

private fun onSetTransactionType(newTransactionType: TransactionType) {
Expand Down
2 changes: 2 additions & 0 deletions shared/base/src/main/java/com/ivy/base/time/TimeProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package com.ivy.base.time
import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.ZoneId

interface TimeProvider {
fun getZoneId(): ZoneId
fun utcNow(): Instant
fun localNow(): LocalDateTime
fun localDateNow(): LocalDate
fun localTimeNow(): LocalTime
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.ivy.base.time.TimeProvider
import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.ZoneId
import javax.inject.Inject

Expand All @@ -17,4 +18,6 @@ class DeviceTimeProvider @Inject constructor() : TimeProvider {
override fun localNow(): LocalDateTime = LocalDateTime.now()

override fun localDateNow(): LocalDate = localNow().toLocalDate()

override fun localTimeNow(): LocalTime = localNow().toLocalTime()
}
11 changes: 8 additions & 3 deletions shared/ui/core/src/main/java/com/ivy/ui/di/IvyUiBindings.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.ivy.ui.di

import com.ivy.ui.time.DeviceTimePreferences
import com.ivy.ui.time.DevicePreferences
import com.ivy.ui.time.TimeFormatter
import com.ivy.ui.time.impl.AndroidDeviceTimePreferences
import com.ivy.ui.time.impl.AndroidDateTimePicker
import com.ivy.ui.time.impl.AndroidDevicePreferences
import com.ivy.ui.time.impl.DateTimePicker
import com.ivy.ui.time.impl.IvyTimeFormatter
import dagger.Binds
import dagger.Module
Expand All @@ -16,5 +18,8 @@ interface IvyUiBindings {
fun timeFormatter(impl: IvyTimeFormatter): TimeFormatter

@Binds
fun deviceTimePreferences(impl: AndroidDeviceTimePreferences): DeviceTimePreferences
fun deviceTimePreferences(impl: AndroidDevicePreferences): DevicePreferences

@Binds
fun dateTimePicker(impl: AndroidDateTimePicker): DateTimePicker
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.ivy.ui.time

import java.util.Locale

interface DeviceTimePreferences {
interface DevicePreferences {
fun is24HourFormat(): Boolean
fun locale(): Locale
}
Loading

0 comments on commit e7081e5

Please sign in to comment.