Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Advanced repeat rules #8456

Open
wants to merge 29 commits into
base: dev-calendar
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
98bef5e
Prototype event generation using ByRules
andrehgdias Nov 28, 2024
86fedd5
Implements event expansion for daily BYDAY and BYMONTH
Dec 2, 2024
6fb655c
Implements event expansion for Weekly interval
Dec 3, 2024
23ac945
Implements event expansion for Monthly interval
Dec 3, 2024
ed88973
Implements expansion for Yearly interval
Dec 9, 2024
c04c45b
Add export of advanced repeat rules
Patrik-wav Dec 10, 2024
8647d66
Implements BYMONTHDAY filtering
andrehgdias Dec 12, 2024
d4b9eaa
Filter events happening before progenitor
andrehgdias Dec 12, 2024
5475873
Implements BYSETPOS filtering
andrehgdias Dec 9, 2024
3fb2590
Fixes BYWEEKNO expansion
andrehgdias Dec 11, 2024
041938b
Implements BYYEARDAY filtering
Dec 16, 2024
2d643ae
Fixes SETPOS filtering
Dec 17, 2024
f552413
Simplifies generator with advanced rules
Dec 17, 2024
3d46221
[SDK] Implements BYMONTH expansion
Dec 18, 2024
234198d
[SDK] Implements BYWEEKNO expansion
Dec 18, 2024
3a3d089
[SDK] Implements BYYEARDAY expansion
Dec 19, 2024
43756f9
[SDK] Implements BYMONTHDAY expansion
Dec 19, 2024
8f83e7f
[SDK] Implements BYDAY expansion
Dec 20, 2024
a8d9330
[SDK] Implements tests for the complete recurrence generation flow
Jan 6, 2025
5c78df1
[SDK] Exposes EventFacade to uniffi
Jan 8, 2025
c8623fe
[Android] Integrates SDK event expansion during alarm scheduling
Jan 8, 2025
e1fe4d9
[iOS] Integrates SDK event expansion during alarm scheduling
murilopereirame Jan 13, 2025
c08d56f
Fixes BYSETPOS on Web/Desktop
Jan 14, 2025
5a7b97d
[Desktop] Integrates event expansion during alarm scheduling
Jan 14, 2025
768599d
[iOS] Adds BYSETPOS handling during alarm schedule
murilopereirame Jan 15, 2025
9073423
[Android] Fixes BYSETPOS during alarm schedule
Jan 15, 2025
ad42294
Adds info banner for unsupported rules
Jan 16, 2025
7400adf
Adds translations to Advanced Repeat Rules
murilopereirame Jan 13, 2025
ffbc61b
WIP
Feb 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app-android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ android {
buildTypes.each {
it.buildConfigField 'String', 'FILE_PROVIDER_AUTHORITY', '"' + it.manifestPlaceholders['contentProviderAuthority'] + '"'
// keep in sync with src/native/main/NativePushServiceApp.ts
it.buildConfigField 'String', "SYS_MODEL_VERSION", '"99"'
it.buildConfigField 'String', "TUTANOTA_MODEL_VERSION", '"73"'
it.buildConfigField 'String', "SYS_MODEL_VERSION", '"119"'
it.buildConfigField 'String', "TUTANOTA_MODEL_VERSION", '"80"'
it.buildConfigField 'String', 'RES_ADDRESS', '"tutanota"'
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package de.tutao.tutanota.alarms
import android.util.Log
import de.tutao.tutanota.*
import de.tutao.tutanota.push.LocalNotificationsFacade
import de.tutao.tutasdk.ByRule
import de.tutao.tutashared.AndroidNativeCryptoFacade
import de.tutao.tutashared.CryptoError
import de.tutao.tutashared.OperationType
Expand Down Expand Up @@ -185,7 +186,6 @@ class AlarmNotificationsManager(
alarmNotification: EncryptedAlarmNotification,
pushKeyResolver: PushKeyResolver,
) {

// The DELETE notification we receive from the server has only placeholder fields and no keys. We must use our saved alarm to cancel notifications.
val savedAlarmNotification = sseStorage.readAlarmNotifications().find {
it.alarmInfo.identifier == alarmNotification.alarmInfo.identifier
Expand Down Expand Up @@ -243,10 +243,12 @@ class AlarmNotificationsManager(
val endValue = repeatRule.endValue
val excludedDates = repeatRule.excludedDates
val alarmTrigger: AlarmInterval = alarmNotification.alarmInfo.trigger
val byRules: List<ByRule> = alarmNotification.repeatRule?.advancedRules ?: listOf()

AlarmModel.iterateAlarmOccurrences(
Date(),
timeZone, eventStart, eventEnd, frequency, interval, endType,
endValue, alarmTrigger, TimeZone.getDefault(), excludedDates, callback
endValue, alarmTrigger, TimeZone.getDefault(), excludedDates, byRules, callback
)
}

Expand Down
16 changes: 13 additions & 3 deletions app-android/app/src/test/java/de/tutao/tutanota/AlarmModelTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class AlarmModelTest {
val eventStart = getDate(timeZone, 2019, 4, 2, 12, 0)
iterateAlarmOccurrences(
now, timeZone, eventStart, eventStart, RepeatPeriod.WEEKLY,
1, EndType.NEVER, 0, AlarmInterval(AlarmIntervalUnit.HOUR, 1), timeZone, emptyList()
1, EndType.NEVER, 0, AlarmInterval(AlarmIntervalUnit.HOUR, 1), timeZone, emptyList(), emptyList()
) { time: Date, _: Int, _: Date? -> occurrences.add(time) }
Assert.assertArrayEquals(
listOf(
Expand All @@ -45,8 +45,18 @@ class AlarmModelTest {
val eventEnd = getAllDayDateUTC(getDate(timeZone, 2019, 4, 3, 0, 0), timeZone)
val repeatEnd = getAllDayDateUTC(getDate(timeZone, 2019, 4, 4, 0, 0), timeZone)
iterateAlarmOccurrences(
now, repeatTimeZone, eventStart, eventEnd, RepeatPeriod.DAILY,
1, EndType.UNTIL, repeatEnd.time, AlarmInterval(AlarmIntervalUnit.DAY, 1), timeZone, emptyList()
now,
repeatTimeZone,
eventStart,
eventEnd,
RepeatPeriod.DAILY,
1,
EndType.UNTIL,
repeatEnd.time,
AlarmInterval(AlarmIntervalUnit.DAY, 1),
timeZone,
emptyList(),
emptyList()
) { time: Date, _: Int, _: Date? -> occurrences.add(time) }
val expected = listOf( // Event on 2nd, alarm on 1st
getDate(timeZone, 2019, 4, 1, 0, 0), // Event on 3rd, alarm on 2d
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,15 @@ class AlarmNotificationsManagerTest {
val repeatingAlarmIdentifier = "repeatingAlarmIdentifier"
val alarmNotification = createEncryptedAlarmNotification(userId, singleAlarmIdentifier, null, null)
val repeatRule =
EncryptedRepeatRule("1", "1", "Europe/Berlin", EndType.COUNT.ordinal.toString(), "2", emptyList())
EncryptedRepeatRule(
"1",
"1",
"Europe/Berlin",
EndType.COUNT.ordinal.toString(),
"2",
emptyList(),
emptyList()
)
val repeatingAlarmNotification = createEncryptedAlarmNotification(
userId, repeatingAlarmIdentifier, null, repeatRule
)
Expand Down Expand Up @@ -126,7 +134,15 @@ class AlarmNotificationsManagerTest {
val identifier = "notTooFarR"
val startDate = Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1))
val repeatRule =
EncryptedRepeatRule(RepeatPeriod.WEEKLY.value().toString(), "1", "Europe/Berlin", "0", "0", emptyList())
EncryptedRepeatRule(
RepeatPeriod.WEEKLY.value().toString(),
"1",
"Europe/Berlin",
"0",
"0",
emptyList(),
emptyList()
)
val alarmNotification = createEncryptedAlarmNotification(userId, identifier, startDate, repeatRule)
manager.scheduleNewAlarms(listOf(alarmNotification))

Expand Down
4 changes: 2 additions & 2 deletions app-android/calendar/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ android {
"\"" + it.manifestPlaceholders["contentProviderAuthority"] + "\""
)
// keep in sync with src/native/main/NativePushServiceApp.ts
it.buildConfigField("String", "SYS_MODEL_VERSION", "\"99\"")
it.buildConfigField("String", "TUTANOTA_MODEL_VERSION", "\"73\"")
it.buildConfigField("String", "SYS_MODEL_VERSION", "\"119\"")
it.buildConfigField("String", "TUTANOTA_MODEL_VERSION", "\"80\"")
it.buildConfigField("String", "RES_ADDRESS", "\"tutanota\"")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package de.tutao.calendar.alarms
import android.util.Log
import de.tutao.calendar.*
import de.tutao.calendar.push.LocalNotificationsFacade
import de.tutao.tutasdk.ByRule
import de.tutao.tutashared.AndroidNativeCryptoFacade
import de.tutao.tutashared.CryptoError
import de.tutao.tutashared.OperationType
Expand Down Expand Up @@ -229,10 +230,12 @@ class AlarmNotificationsManager(
val endValue = repeatRule.endValue
val excludedDates = repeatRule.excludedDates
val alarmTrigger: AlarmInterval = alarmNotification.alarmInfo.trigger
val byRules: List<ByRule> = alarmNotification.repeatRule?.advancedRules ?: listOf()

AlarmModel.iterateAlarmOccurrences(
Date(),
timeZone, eventStart, eventEnd, frequency, interval, endType,
endValue, alarmTrigger, TimeZone.getDefault(), excludedDates, callback
endValue, alarmTrigger, TimeZone.getDefault(), excludedDates, byRules, callback
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.util.Log
import de.tutao.calendar.BuildConfig
import java.util.Date


Expand All @@ -17,7 +18,12 @@ class SystemAlarmFacade(private val context: Context) {
eventDate: Date,
user: String
) {
Log.d(TAG, "Scheduled notification $identifier")
if (BuildConfig.DEBUG) {
Log.d(TAG, "Scheduled notification $identifier at $alarmTime")
} else {
Log.d(TAG, "Scheduled notification $identifier")
}

val alarmManager = alarmManager
val pendingIntent = makeAlarmPendingIntent(occurrence, identifier, summary, eventDate, user)
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, alarmTime.time, pendingIntent)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,15 @@ class AlarmNotificationsManagerTest {
val repeatingAlarmIdentifier = "repeatingAlarmIdentifier"
val alarmNotification = createEncryptedAlarmNotification(userId, singleAlarmIdentifier, null, null)
val repeatRule =
EncryptedRepeatRule("1", "1", "Europe/Berlin", EndType.COUNT.ordinal.toString(), "2", emptyList())
EncryptedRepeatRule(
"1",
"1",
"Europe/Berlin",
EndType.COUNT.ordinal.toString(),
"2",
emptyList(),
emptyList()
)
val repeatingAlarmNotification = createEncryptedAlarmNotification(
userId, repeatingAlarmIdentifier, null, repeatRule
)
Expand Down Expand Up @@ -125,7 +133,15 @@ class AlarmNotificationsManagerTest {
val identifier = "notTooFarR"
val startDate = Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1))
val repeatRule =
EncryptedRepeatRule(RepeatPeriod.WEEKLY.value().toString(), "1", "Europe/Berlin", "0", "0", emptyList())
EncryptedRepeatRule(
RepeatPeriod.WEEKLY.value().toString(),
"1",
"Europe/Berlin",
"0",
"0",
emptyList(),
emptyList()
)
val alarmNotification = createEncryptedAlarmNotification(userId, identifier, startDate, repeatRule)
manager.scheduleNewAlarms(listOf(alarmNotification))

Expand Down
Loading
Loading