Skip to content

Commit

Permalink
Merge branch 'release/3.1.5'
Browse files Browse the repository at this point in the history
  • Loading branch information
benoitletondor committed Jan 21, 2024
2 parents 1cfa566 + 373bcb3 commit b08b46e
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 25 deletions.
4 changes: 2 additions & 2 deletions Android/EasyBudget/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ android {
compileSdk = 34
minSdk = 21
targetSdk = 34
versionCode = 121
versionName = "3.1.4"
versionCode = 123
versionName = "3.1.5"
vectorDrawables.useSupportLibrary = true
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ class OnlineDBImpl(

override suspend fun updateRecurringExpenseAfterDate(
newRecurringExpense: RecurringExpense,
oldOccurrenceDate: LocalDate,
afterDate: LocalDate,
) {
val recurringExpenses = awaitRecurringExpensesLoadOrThrow().expenses

Expand All @@ -329,7 +329,7 @@ class OnlineDBImpl(

realm.write {
findLatest(entity)?.updateAllOccurrencesAfterDate(
oldOccurrenceDate,
afterDate,
newRecurringExpense,
)
}
Expand Down Expand Up @@ -366,7 +366,7 @@ class OnlineDBImpl(
val icalBeforeDeletion = entity.iCalRepresentation

realm.write {
findLatest(entity)?.deleteOccurrence(expense.date)
findLatest(entity)?.deleteOccurrence(expense.date, expense.associatedRecurringExpense.originalDate)
}

return {
Expand Down Expand Up @@ -417,7 +417,7 @@ class OnlineDBImpl(

override suspend fun deleteAllExpenseForRecurringExpenseBeforeDate(
recurringExpense: RecurringExpense,
beforeDate: LocalDate
beforeDate: LocalDate,
): RestoreAction {
val recurringExpenses = awaitRecurringExpensesLoadOrThrow().expenses

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,9 @@ class RecurringExpenseEntity() : RealmObject {
exceptionEvent.addExperimentalProperty(CHECKED_KEY, expense.checked.toString())
exceptionEvent.uid = events
.filterExceptions()
.first { it.dateEnd == null || !it.dateEnd.value.before(expense.date.toStartOfDayDate()) }
.first {
it.dateEnd == null || !it.dateEnd.value.before(originalOccurrenceDate.toStartOfDayDate())
}
.uid

val recurrenceId = RecurrenceId(ICalDate(originalOccurrenceDate.toStartOfDayDate(), false))
Expand All @@ -115,7 +117,7 @@ class RecurringExpenseEntity() : RealmObject {
// Cancel any previous exception
events.filterNotException()
.forEach { exception ->
if (exception.dateStart.value.time == originalOccurrenceDate.toStartOfDayDate().time) {
if (exception.recurrenceId.value.time == originalOccurrenceDate.toStartOfDayDate().time) {
exception.status.value = Status.CANCELLED
}
}
Expand All @@ -124,19 +126,27 @@ class RecurringExpenseEntity() : RealmObject {
addEvent(exceptionEvent)
}

fun deleteOccurrence(occurrenceDate: LocalDate) {
fun deleteOccurrence(occurrenceDate: LocalDate, originalOccurrenceDate: LocalDate) {
val cal = getCal()

val exceptionEvent = VEvent()
exceptionEvent.dateStart = DateStart(occurrenceDate.toStartOfDayDate(), false)
exceptionEvent.uid = cal.events
.filterExceptions()
.first { it.dateEnd == null || !it.dateEnd.value.before(occurrenceDate.toStartOfDayDate()) }
.first { it.dateEnd == null || !it.dateEnd.value.before(originalOccurrenceDate.toStartOfDayDate()) }
.uid
exceptionEvent.status = Status.cancelled()
val recurrenceId = RecurrenceId(ICalDate(occurrenceDate.toStartOfDayDate(), false))
val recurrenceId = RecurrenceId(ICalDate(originalOccurrenceDate.toStartOfDayDate(), false))
exceptionEvent.recurrenceId = recurrenceId

// Cancel any previous exception
cal.events.filterNotException()
.forEach { exception ->
if (exception.recurrenceId.value.time == originalOccurrenceDate.toStartOfDayDate().time) {
exception.status.value = Status.CANCELLED
}
}

cal.addEvent(exceptionEvent)

iCalRepresentation = cal.write()
Expand Down Expand Up @@ -171,7 +181,9 @@ class RecurringExpenseEntity() : RealmObject {
.filterExceptions()
.forEach { event ->
if (event.dateStart.value.before(date.toStartOfDayDate())) {
event.dateStart = DateStart(date.toStartOfDayDate(), false)
val iterator = event.getDateIterator(TimeZone.getDefault())
iterator.advanceTo(date.toStartOfDayDate())
event.dateStart = DateStart(iterator.next(), false)
}
}

Expand All @@ -187,18 +199,36 @@ class RecurringExpenseEntity() : RealmObject {
}

fun updateAllOccurrencesAfterDate(
oldOccurrenceDate: LocalDate,
afterDate: LocalDate,
newRecurringExpense: RecurringExpense,
) {
val cal = getCal()

// Put an end date to all existing events (and memoize the biggest existing end date to re-apply it to the new event later)
var newEventEndDate: Date? = null
cal.events
.filterExceptions()
.filter { it.dateEnd == null || it.dateEnd.value.after(oldOccurrenceDate.toStartOfDayDate()) }
.forEach { it.dateEnd = DateEnd(oldOccurrenceDate.minusDays(1).toStartOfDayDate(), false) }
.filter { it.dateEnd == null || it.dateEnd.value.after(afterDate.toStartOfDayDate()) }
.forEach {
if (it.dateEnd !== null && (newEventEndDate == null || it.dateEnd.value.after(newEventEndDate))) {
newEventEndDate = it.dateEnd.value
}

it.dateEnd = DateEnd(afterDate.minusDays(1).toStartOfDayDate(), false)
}

// Remove all exceptions after the date
cal.events
.removeAll { event ->
event.isException && !event.dateStart.value.before(afterDate.toStartOfDayDate())
}

// Create a new event starting at the date with the new properties
val exceptionEvent = VEvent()
exceptionEvent.dateStart = DateStart(newRecurringExpense.recurringDate.toStartOfDayDate(), false)
if (newEventEndDate != null) {
exceptionEvent.dateEnd = DateEnd(newEventEndDate, false)
}
exceptionEvent.summary = Summary(newRecurringExpense.title)
exceptionEvent.addExperimentalProperty(AMOUNT_KEY, newRecurringExpense.amount.getDBValue().toString())
exceptionEvent.addExperimentalProperty(CHECKED_KEY, false.toString())
Expand All @@ -213,9 +243,12 @@ class RecurringExpenseEntity() : RealmObject {
fun getFirstOccurrenceDate(): LocalDate {
val cal = getCal()

val event = cal.events.first()
val firstEventTimestamp = cal.events
.filter { !it.status.isCancelled }
.minBy { it.dateStart.value.time }
.dateStart.value.time

return localDateFromTimestamp(event.dateStart.value.time)
return localDateFromTimestamp(firstEventTimestamp)
}

fun getFirstOccurrence(): Expense {
Expand Down Expand Up @@ -250,6 +283,12 @@ class RecurringExpenseEntity() : RealmObject {
setProductId(null as String?)
}

private data class EventInRange(
val event: VEvent,
val date: Date,
val originalDate: Date,
)

private fun ICalendar.getExpenses(from: LocalDate?, to: LocalDate, recurringExpense: RecurringExpense): List<Expense> {
val startDate = from?.toStartOfDayDate()
val endDate = to.toStartOfDayDate()
Expand All @@ -264,11 +303,11 @@ class RecurringExpenseEntity() : RealmObject {
}
}

val eventsInRange = mutableListOf<Triple<VEvent, Date, Date>>()
val eventsInRange = mutableListOf<EventInRange>()

exceptions.forEach { (date, event) ->
if (!event.status.isCancelled && !event.dateStart.value.after(endDate) && (startDate == null || !event.dateStart.value.before(startDate))) {
eventsInRange.add(Triple(event, event.dateStart.value, date))
eventsInRange.add(EventInRange(event, event.dateStart.value, date))
}
}

Expand Down Expand Up @@ -296,7 +335,7 @@ class RecurringExpenseEntity() : RealmObject {
val eventException = exceptions[eventOccurrenceDate]
if (eventException == null) {
// No exception for this instance, use the original event
eventsInRange.add(Triple(recurrentEvent, eventOccurrenceDate, eventOccurrenceDate))
eventsInRange.add(EventInRange(recurrentEvent, eventOccurrenceDate, eventOccurrenceDate))
}
}
}
Expand All @@ -318,9 +357,11 @@ class RecurringExpenseEntity() : RealmObject {
}
}

private fun List<VEvent>.filterExceptions() = filter { it.recurrenceId == null }
private fun List<VEvent>.filterExceptions() = filter { !it.isException }

private fun List<VEvent>.filterNotException() = filter { it.isException }

private fun List<VEvent>.filterNotException() = filter { it.recurrenceId != null }
private val VEvent.isException get() = recurrenceId != null

companion object {
fun newFromRecurringExpense(recurringExpense: RecurringExpense, account: Account): RecurringExpenseEntity {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,6 @@ class ExpenseEditViewModel @Inject constructor(
title = description,
amount = if (isRevenue) -value else value,
date = date,
associatedRecurringExpense = editedExpense.associatedRecurringExpense?.copy(
originalDate = editedExpense.date,
)
) ?: Expense(description, if (isRevenue) -value else value, date, false)

db.persistExpense(expense)
Expand Down

0 comments on commit b08b46e

Please sign in to comment.