Fix various issues regarding Notification Profile scheduling.

- Timezone conversion when detecting scheduled profile
- Not automatically enabling a scheduled profile on creation regardless
  of when other profiles were enabled/disabled
This commit is contained in:
Cody Henthorne 2021-12-08 17:28:36 -05:00
parent 372b0d9f2b
commit a8a104242a
11 changed files with 126 additions and 104 deletions

View file

@ -1,10 +1,10 @@
package org.thoughtcrime.securesms.components.settings.app.notifications.manual
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile
import java.util.Calendar
import java.time.LocalDateTime
data class NotificationProfileSelectionState(
val notificationProfiles: List<NotificationProfile> = listOf(),
val expandedId: Long = -1L,
val timeSlotB: Calendar
val timeSlotB: LocalDateTime
)

View file

@ -9,8 +9,10 @@ import io.reactivex.rxjava3.kotlin.plusAssign
import io.reactivex.rxjava3.kotlin.subscribeBy
import org.thoughtcrime.securesms.components.settings.app.notifications.profiles.NotificationProfilesRepository
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile
import org.thoughtcrime.securesms.util.isBetween
import org.thoughtcrime.securesms.util.livedata.Store
import java.util.Calendar
import org.thoughtcrime.securesms.util.toMillis
import java.time.LocalDateTime
import java.util.concurrent.TimeUnit
class NotificationProfileSelectionViewModel(private val repository: NotificationProfilesRepository) : ViewModel() {
@ -53,29 +55,24 @@ class NotificationProfileSelectionViewModel(private val repository: Notification
.subscribe()
}
fun enableUntil(profile: NotificationProfile, calendar: Calendar) {
disposables += repository.manuallyEnableProfileForDuration(profile.id, calendar.timeInMillis)
fun enableUntil(profile: NotificationProfile, enableUntil: LocalDateTime) {
disposables += repository.manuallyEnableProfileForDuration(profile.id, enableUntil.toMillis())
.subscribe()
}
companion object {
private fun getTimeSlotB(): Calendar {
val now = Calendar.getInstance()
val sixPm = Calendar.getInstance()
val eightAm = Calendar.getInstance()
@Suppress("CascadeIf")
private fun getTimeSlotB(): LocalDateTime {
val now = LocalDateTime.now()
val sixPm = now.withHour(18).withMinute(0).withSecond(0)
val eightAm = now.withHour(8).withMinute(0).withSecond(0)
sixPm.set(Calendar.HOUR_OF_DAY, 18)
sixPm.set(Calendar.MINUTE, 0)
sixPm.set(Calendar.SECOND, 0)
eightAm.set(Calendar.HOUR_OF_DAY, 8)
eightAm.set(Calendar.MINUTE, 0)
eightAm.set(Calendar.SECOND, 0)
return if (now.before(sixPm) && (now.after(eightAm) || now == eightAm)) {
return if (now.isBetween(eightAm, sixPm)) {
sixPm
} else {
} else if (now.isBefore(eightAm)) {
eightAm
} else {
eightAm.plusDays(1)
}
}
}

View file

@ -9,12 +9,12 @@ import org.thoughtcrime.securesms.components.emoji.EmojiImageView
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.PreferenceModel
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile
import org.thoughtcrime.securesms.util.DateUtils
import org.thoughtcrime.securesms.util.MappingAdapter
import org.thoughtcrime.securesms.util.MappingViewHolder
import org.thoughtcrime.securesms.util.formatHours
import org.thoughtcrime.securesms.util.visible
import java.util.Calendar
import java.util.Locale
import java.time.LocalDateTime
import java.time.LocalTime
/**
* Notification Profile selection preference.
@ -34,10 +34,10 @@ object NotificationProfileSelection {
override val summary: DSLSettingsText,
val notificationProfile: NotificationProfile,
val isExpanded: Boolean,
val timeSlotB: Calendar,
val timeSlotB: LocalDateTime,
val onRowClick: (NotificationProfile) -> Unit,
val onTimeSlotAClick: (NotificationProfile) -> Unit,
val onTimeSlotBClick: (NotificationProfile, Calendar) -> Unit,
val onTimeSlotBClick: (NotificationProfile, LocalDateTime) -> Unit,
val onViewSettingsClick: (NotificationProfile) -> Unit,
val onToggleClick: (NotificationProfile) -> Unit
) : PreferenceModel<Entry>() {
@ -87,7 +87,7 @@ object NotificationProfileSelection {
expansion.visible = model.isExpanded
timeSlotB.text = context.getString(
R.string.NotificationProfileSelection__until_s,
DateUtils.getTimeString(context, Locale.getDefault(), model.timeSlotB.timeInMillis)
LocalTime.from(model.timeSlotB).formatHours()
)
if (TOGGLE_EXPANSION in payload || UPDATE_TIMESLOT in payload) {
@ -107,7 +107,7 @@ object NotificationProfileSelection {
timeSlotB.text = context.getString(
R.string.NotificationProfileSelection__until_s,
DateUtils.getTimeString(context, Locale.getDefault(), model.timeSlotB.timeInMillis)
LocalTime.from(model.timeSlotB).formatHours()
)
itemView.isSelected = model.isOn

View file

@ -35,7 +35,7 @@ import java.time.format.DateTimeFormatter
*/
class EditNotificationProfileScheduleFragment : LoggingFragment(R.layout.fragment_edit_notification_profile_schedule) {
private val viewModel: EditNotificationProfileScheduleViewModel by viewModels(factoryProducer = { EditNotificationProfileScheduleViewModel.Factory(profileId) })
private val viewModel: EditNotificationProfileScheduleViewModel by viewModels(factoryProducer = { EditNotificationProfileScheduleViewModel.Factory(profileId, createMode) })
private val lifecycleDisposable = LifecycleDisposable()
private val profileId: Long by lazy { EditNotificationProfileScheduleFragmentArgs.fromBundle(requireArguments()).profileId }

View file

@ -17,7 +17,8 @@ import java.time.DayOfWeek
* from the database and into the [scheduleSubject] allowing the safe use of !! with [schedule].
*/
class EditNotificationProfileScheduleViewModel(
profileId: Long,
private val profileId: Long,
private val createMode: Boolean,
private val repository: NotificationProfilesRepository
) : ViewModel() {
@ -72,14 +73,23 @@ class EditNotificationProfileScheduleViewModel(
} else if (createMode && !schedule.enabled) {
Single.just(SaveScheduleResult.Success)
} else {
repository.updateSchedule(schedule).toSingle { SaveScheduleResult.Success }
repository.updateSchedule(schedule)
.toSingleDefault(SaveScheduleResult.Success)
.flatMap { r ->
if (createMode && schedule.enabled && schedule.coversTime(System.currentTimeMillis())) {
repository.manuallyToggleProfile(profileId, schedule)
.toSingleDefault(r)
} else {
Single.just(r)
}
}
}
return result.observeOn(AndroidSchedulers.mainThread())
}
class Factory(private val profileId: Long) : ViewModelProvider.Factory {
class Factory(private val profileId: Long, private val createMode: Boolean) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return modelClass.cast(EditNotificationProfileScheduleViewModel(profileId, NotificationProfilesRepository()))!!
return modelClass.cast(EditNotificationProfileScheduleViewModel(profileId, createMode, NotificationProfilesRepository()))!!
}
}

View file

@ -96,19 +96,23 @@ class NotificationProfilesRepository {
}
fun manuallyToggleProfile(profile: NotificationProfile, now: Long = System.currentTimeMillis()): Completable {
return manuallyToggleProfile(profile.id, profile.schedule, now)
}
fun manuallyToggleProfile(profileId: Long, schedule: NotificationProfileSchedule, now: Long = System.currentTimeMillis()): Completable {
return Completable.fromAction {
val profiles = database.getProfiles()
val activeProfile = NotificationProfiles.getActiveProfile(profiles, now)
if (profile.id == activeProfile?.id) {
if (profileId == activeProfile?.id) {
SignalStore.notificationProfileValues().manuallyEnabledProfile = 0
SignalStore.notificationProfileValues().manuallyEnabledUntil = 0
SignalStore.notificationProfileValues().manuallyDisabledAt = now
SignalStore.notificationProfileValues().lastProfilePopup = 0
SignalStore.notificationProfileValues().lastProfilePopupTime = 0
} else {
val inScheduledWindow = profile.schedule.isCurrentlyActive(now)
SignalStore.notificationProfileValues().manuallyEnabledProfile = if (inScheduledWindow) 0 else profile.id
val inScheduledWindow = schedule.isCurrentlyActive(now)
SignalStore.notificationProfileValues().manuallyEnabledProfile = if (inScheduledWindow) 0 else profileId
SignalStore.notificationProfileValues().manuallyEnabledUntil = if (inScheduledWindow) 0 else Long.MAX_VALUE
SignalStore.notificationProfileValues().manuallyDisabledAt = if (inScheduledWindow) 0 else now
}

View file

@ -8,6 +8,7 @@ import org.thoughtcrime.securesms.util.formatHours
import org.thoughtcrime.securesms.util.toLocalDateTime
import org.thoughtcrime.securesms.util.toLocalTime
import org.thoughtcrime.securesms.util.toMillis
import org.thoughtcrime.securesms.util.toOffset
import java.time.LocalDateTime
import java.time.ZoneId
@ -26,7 +27,7 @@ object NotificationProfiles {
val manualProfile: NotificationProfile? = profiles.firstOrNull { it.id == storeValues.manuallyEnabledProfile }
val scheduledProfile: NotificationProfile? = profiles.sortedDescending().filter { it.schedule.isCurrentlyActive(now, zoneId) }.firstOrNull { profile ->
profile.schedule.startDateTime(localNow).toMillis() > storeValues.manuallyDisabledAt
profile.schedule.startDateTime(localNow).toMillis(zoneId.toOffset()) > storeValues.manuallyDisabledAt
}
if (manualProfile == null || scheduledProfile == null) {

View file

@ -3,17 +3,25 @@ package org.thoughtcrime.securesms.util
import java.time.Instant
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.OffsetDateTime
import java.time.ZoneId
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
import java.util.concurrent.TimeUnit
/**
* Given a [ZoneId] return the time offset as a [ZoneOffset].
*/
fun ZoneId.toOffset(): ZoneOffset {
return OffsetDateTime.now(this).offset
}
/**
* Convert [LocalDateTime] to be same as [System.currentTimeMillis]
*/
fun LocalDateTime.toMillis(): Long {
return TimeUnit.SECONDS.toMillis(toEpochSecond(ZoneOffset.UTC))
fun LocalDateTime.toMillis(zoneOffset: ZoneOffset = ZoneId.systemDefault().toOffset()): Long {
return TimeUnit.SECONDS.toMillis(toEpochSecond(zoneOffset))
}
/**

View file

@ -411,7 +411,7 @@
</plurals>
<!-- Show in conversation list overflow menu to open selection bottom sheet -->
<string name="ConversationListFragment__notification_profile">Notification Profile</string>
<string name="ConversationListFragment__notification_profile">Notification profile</string>
<!-- Tooltip shown after you have created your first notification profile -->
<string name="ConversationListFragment__turn_your_notification_profile_on_or_off_here">Turn your notification profile on or off here.</string>
<!-- Message shown in top toast to indicate the named profile is on -->

View file

@ -7,6 +7,7 @@ import org.junit.Test
import org.thoughtcrime.securesms.util.toMillis
import java.time.DayOfWeek
import java.time.LocalDateTime
import java.time.ZoneOffset
import java.util.TimeZone
class NotificationProfileScheduleTest {
@ -37,105 +38,105 @@ class NotificationProfileScheduleTest {
fun `when time is within enabled schedule 9am to 5pm then return true`() {
val schedule = NotificationProfileSchedule(id = 1L, enabled = true, start = 900, end = 1700, daysEnabled = setOf(DayOfWeek.SUNDAY))
assertTrue(schedule.isCurrentlyActive(sunday9am.toMillis()))
assertTrue(schedule.isCurrentlyActive(sunday9am.plusHours(1).toMillis()))
assertTrue(schedule.isCurrentlyActive(sunday9am.toMillis(ZoneOffset.UTC)))
assertTrue(schedule.isCurrentlyActive(sunday9am.plusHours(1).toMillis(ZoneOffset.UTC)))
}
@Test
fun `when time is outside enabled schedule 9am to 5pm then return false`() {
val schedule = NotificationProfileSchedule(id = 1L, enabled = true, start = 900, end = 1700, daysEnabled = setOf(DayOfWeek.SUNDAY))
assertFalse(schedule.isCurrentlyActive(sunday1am.toMillis()))
assertFalse(schedule.isCurrentlyActive(sunday10pm.toMillis()))
assertFalse(schedule.isCurrentlyActive(monday1am.toMillis()))
assertFalse(schedule.isCurrentlyActive(monday9am.toMillis()))
assertFalse(schedule.isCurrentlyActive(monday10pm.toMillis()))
assertFalse(schedule.isCurrentlyActive(tuesday9am.toMillis()))
assertFalse(schedule.isCurrentlyActive(sunday1am.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(sunday10pm.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(monday1am.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(monday9am.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(monday10pm.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(tuesday9am.toMillis(ZoneOffset.UTC)))
}
@Test
fun `when time is inside enabled with day wrapping schedule 10pm to 2am then return true`() {
val schedule = NotificationProfileSchedule(id = 1L, enabled = true, start = 2100, end = 200, daysEnabled = setOf(DayOfWeek.MONDAY))
assertTrue(schedule.isCurrentlyActive(monday10pm.toMillis()))
assertTrue(schedule.isCurrentlyActive(tuesday1am.toMillis()))
assertTrue(schedule.isCurrentlyActive(monday10pm.toMillis(ZoneOffset.UTC)))
assertTrue(schedule.isCurrentlyActive(tuesday1am.toMillis(ZoneOffset.UTC)))
}
@Test
fun `when time is outside enabled with day wrapping schedule 10pm to 2am then return false`() {
val schedule = NotificationProfileSchedule(id = 1L, enabled = true, start = 2100, end = 200, daysEnabled = setOf(DayOfWeek.MONDAY))
assertFalse(schedule.isCurrentlyActive(sunday1am.toMillis()))
assertFalse(schedule.isCurrentlyActive(sunday10pm.toMillis()))
assertFalse(schedule.isCurrentlyActive(monday1am.toMillis()))
assertFalse(schedule.isCurrentlyActive(monday9am.toMillis()))
assertFalse(schedule.isCurrentlyActive(tuesday9am.toMillis()))
assertFalse(schedule.isCurrentlyActive(tuesday10pm.toMillis()))
assertFalse(schedule.isCurrentlyActive(sunday1am.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(sunday10pm.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(monday1am.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(monday9am.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(tuesday9am.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(tuesday10pm.toMillis(ZoneOffset.UTC)))
}
@Test
fun `when time is inside enabled schedule 12am to 10am then return false`() {
val schedule = NotificationProfileSchedule(id = 1L, enabled = true, start = 0, end = 1000, daysEnabled = setOf(DayOfWeek.SUNDAY))
assertTrue(schedule.isCurrentlyActive(sunday0am.toMillis()))
assertTrue(schedule.isCurrentlyActive(sunday1am.toMillis()))
assertTrue(schedule.isCurrentlyActive(sunday9am.toMillis()))
assertTrue(schedule.isCurrentlyActive(sunday0am.toMillis(ZoneOffset.UTC)))
assertTrue(schedule.isCurrentlyActive(sunday1am.toMillis(ZoneOffset.UTC)))
assertTrue(schedule.isCurrentlyActive(sunday9am.toMillis(ZoneOffset.UTC)))
}
@Test
fun `when time is inside enabled schedule 12am to 12am then return false`() {
val schedule = NotificationProfileSchedule(id = 1L, enabled = true, start = 0, end = 2400, daysEnabled = setOf(DayOfWeek.SUNDAY))
assertTrue(schedule.isCurrentlyActive(sunday0am.toMillis()))
assertTrue(schedule.isCurrentlyActive(sunday1am.toMillis()))
assertTrue(schedule.isCurrentlyActive(sunday9am.toMillis()))
assertTrue(schedule.isCurrentlyActive(sunday10pm.toMillis()))
assertTrue(schedule.isCurrentlyActive(sunday0am.toMillis(ZoneOffset.UTC)))
assertTrue(schedule.isCurrentlyActive(sunday1am.toMillis(ZoneOffset.UTC)))
assertTrue(schedule.isCurrentlyActive(sunday9am.toMillis(ZoneOffset.UTC)))
assertTrue(schedule.isCurrentlyActive(sunday10pm.toMillis(ZoneOffset.UTC)))
}
@Test
fun `when time is outside enabled schedule 12am to 12am then return false`() {
val schedule = NotificationProfileSchedule(id = 1L, enabled = true, start = 0, end = 2400, daysEnabled = setOf(DayOfWeek.SUNDAY))
assertFalse(schedule.isCurrentlyActive(monday0am.toMillis()))
assertFalse(schedule.isCurrentlyActive(monday1am.toMillis()))
assertFalse(schedule.isCurrentlyActive(monday9am.toMillis()))
assertFalse(schedule.isCurrentlyActive(monday10pm.toMillis()))
assertFalse(schedule.isCurrentlyActive(tuesday1am.toMillis()))
assertFalse(schedule.isCurrentlyActive(tuesday9am.toMillis()))
assertFalse(schedule.isCurrentlyActive(tuesday10pm.toMillis()))
assertFalse(schedule.isCurrentlyActive(monday0am.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(monday1am.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(monday9am.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(monday10pm.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(tuesday1am.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(tuesday9am.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(tuesday10pm.toMillis(ZoneOffset.UTC)))
}
@Test
fun `when enabled schedule 12am to 12am for all days then return true`() {
val schedule = NotificationProfileSchedule(id = 1L, enabled = true, start = 0, end = 2400, daysEnabled = DayOfWeek.values().toSet())
assertTrue(schedule.isCurrentlyActive(sunday0am.toMillis()))
assertTrue(schedule.isCurrentlyActive(sunday1am.toMillis()))
assertTrue(schedule.isCurrentlyActive(sunday9am.toMillis()))
assertTrue(schedule.isCurrentlyActive(sunday10pm.toMillis()))
assertTrue(schedule.isCurrentlyActive(monday0am.toMillis()))
assertTrue(schedule.isCurrentlyActive(monday1am.toMillis()))
assertTrue(schedule.isCurrentlyActive(monday9am.toMillis()))
assertTrue(schedule.isCurrentlyActive(monday10pm.toMillis()))
assertTrue(schedule.isCurrentlyActive(tuesday1am.toMillis()))
assertTrue(schedule.isCurrentlyActive(tuesday9am.toMillis()))
assertTrue(schedule.isCurrentlyActive(tuesday10pm.toMillis()))
assertTrue(schedule.isCurrentlyActive(sunday0am.toMillis(ZoneOffset.UTC)))
assertTrue(schedule.isCurrentlyActive(sunday1am.toMillis(ZoneOffset.UTC)))
assertTrue(schedule.isCurrentlyActive(sunday9am.toMillis(ZoneOffset.UTC)))
assertTrue(schedule.isCurrentlyActive(sunday10pm.toMillis(ZoneOffset.UTC)))
assertTrue(schedule.isCurrentlyActive(monday0am.toMillis(ZoneOffset.UTC)))
assertTrue(schedule.isCurrentlyActive(monday1am.toMillis(ZoneOffset.UTC)))
assertTrue(schedule.isCurrentlyActive(monday9am.toMillis(ZoneOffset.UTC)))
assertTrue(schedule.isCurrentlyActive(monday10pm.toMillis(ZoneOffset.UTC)))
assertTrue(schedule.isCurrentlyActive(tuesday1am.toMillis(ZoneOffset.UTC)))
assertTrue(schedule.isCurrentlyActive(tuesday9am.toMillis(ZoneOffset.UTC)))
assertTrue(schedule.isCurrentlyActive(tuesday10pm.toMillis(ZoneOffset.UTC)))
}
@Test
fun `when disabled schedule 12am to 12am for all days then return false`() {
val schedule = NotificationProfileSchedule(id = 1L, enabled = false, start = 0, end = 2400, daysEnabled = DayOfWeek.values().toSet())
assertFalse(schedule.isCurrentlyActive(sunday0am.toMillis()))
assertFalse(schedule.isCurrentlyActive(sunday1am.toMillis()))
assertFalse(schedule.isCurrentlyActive(sunday9am.toMillis()))
assertFalse(schedule.isCurrentlyActive(sunday10pm.toMillis()))
assertFalse(schedule.isCurrentlyActive(monday0am.toMillis()))
assertFalse(schedule.isCurrentlyActive(monday1am.toMillis()))
assertFalse(schedule.isCurrentlyActive(monday9am.toMillis()))
assertFalse(schedule.isCurrentlyActive(monday10pm.toMillis()))
assertFalse(schedule.isCurrentlyActive(tuesday1am.toMillis()))
assertFalse(schedule.isCurrentlyActive(tuesday9am.toMillis()))
assertFalse(schedule.isCurrentlyActive(tuesday10pm.toMillis()))
assertFalse(schedule.isCurrentlyActive(sunday0am.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(sunday1am.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(sunday9am.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(sunday10pm.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(monday0am.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(monday1am.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(monday9am.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(monday10pm.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(tuesday1am.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(tuesday9am.toMillis(ZoneOffset.UTC)))
assertFalse(schedule.isCurrentlyActive(tuesday10pm.toMillis(ZoneOffset.UTC)))
}
}

View file

@ -15,6 +15,7 @@ import org.thoughtcrime.securesms.util.toMillis
import java.time.DayOfWeek
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.ZoneOffset
@RunWith(RobolectricTestRunner::class)
@Config(manifest = Config.NONE, application = Application::class)
@ -69,30 +70,30 @@ class NotificationProfilesTest {
fun `when first is scheduled and second is not manually enabled and now is within schedule return first`() {
val schedule = NotificationProfileSchedule(id = 3L, true, start = 700, daysEnabled = setOf(DayOfWeek.SUNDAY))
val profiles = listOf(first.copy(schedule = schedule), second)
assertThat("active profile is first", NotificationProfiles.getActiveProfile(profiles, sunday9am.toMillis(), utc), `is`(profiles[0]))
assertThat("active profile is first", NotificationProfiles.getActiveProfile(profiles, sunday9am.toMillis(ZoneOffset.UTC), utc), `is`(profiles[0]))
}
@Test
fun `when first is scheduled and second is manually enabled forever within first's schedule then return second`() {
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_PROFILE, second.id)
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, Long.MAX_VALUE)
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis())
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis(ZoneOffset.UTC))
val schedule = NotificationProfileSchedule(id = 3L, true, start = 700, daysEnabled = setOf(DayOfWeek.SUNDAY))
val profiles = listOf(first.copy(schedule = schedule), second)
assertThat("active profile is first", NotificationProfiles.getActiveProfile(profiles, sunday9am.toMillis(), utc), `is`(profiles[1]))
assertThat("active profile is first", NotificationProfiles.getActiveProfile(profiles, sunday9am.toMillis(ZoneOffset.UTC), utc), `is`(profiles[1]))
}
@Test
fun `when first is scheduled and second is manually enabled forever before first's schedule start then return first`() {
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_PROFILE, second.id)
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, Long.MAX_VALUE)
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis())
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis(ZoneOffset.UTC))
val schedule = NotificationProfileSchedule(id = 3L, true, start = 900, daysEnabled = setOf(DayOfWeek.SUNDAY))
val profiles = listOf(first.copy(schedule = schedule), second)
assertThat("active profile is first", NotificationProfiles.getActiveProfile(profiles, sunday930am.toMillis(), utc), `is`(profiles[0]))
assertThat("active profile is first", NotificationProfiles.getActiveProfile(profiles, sunday930am.toMillis(ZoneOffset.UTC), utc), `is`(profiles[0]))
}
@Test
@ -101,41 +102,41 @@ class NotificationProfilesTest {
val secondSchedule = NotificationProfileSchedule(id = 4L, true, start = 800, daysEnabled = setOf(DayOfWeek.SUNDAY))
val profiles = listOf(first.copy(schedule = firstSchedule), second.copy(schedule = secondSchedule))
assertThat("active profile is second", NotificationProfiles.getActiveProfile(profiles, sunday9am.toMillis(), utc), `is`(profiles[1]))
assertThat("active profile is second", NotificationProfiles.getActiveProfile(profiles, sunday9am.toMillis(ZoneOffset.UTC), utc), `is`(profiles[1]))
}
@Test
fun `when first and second have overlapping schedules and first is created before second and first is manually enabled within overlapping schedule then return first`() {
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_PROFILE, first.id)
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, Long.MAX_VALUE)
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis())
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis(ZoneOffset.UTC))
val firstSchedule = NotificationProfileSchedule(id = 3L, true, start = 700, daysEnabled = setOf(DayOfWeek.SUNDAY))
val secondSchedule = NotificationProfileSchedule(id = 4L, true, start = 700, daysEnabled = setOf(DayOfWeek.SUNDAY))
val profiles = listOf(first.copy(schedule = firstSchedule), second.copy(schedule = secondSchedule))
assertThat("active profile is first", NotificationProfiles.getActiveProfile(profiles, sunday9am.toMillis(), utc), `is`(profiles[0]))
assertThat("active profile is first", NotificationProfiles.getActiveProfile(profiles, sunday9am.toMillis(ZoneOffset.UTC), utc), `is`(profiles[0]))
}
@Test
fun `when profile is manually enabled for set time after schedule end and now is after schedule end but before manual then return profile`() {
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_PROFILE, first.id)
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, sunday930am.toMillis())
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis())
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, sunday930am.toMillis(ZoneOffset.UTC))
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis(ZoneOffset.UTC))
val schedule = NotificationProfileSchedule(id = 3L, true, start = 700, end = 845, daysEnabled = setOf(DayOfWeek.SUNDAY))
val profiles = listOf(first.copy(schedule = schedule))
assertThat("active profile is first", NotificationProfiles.getActiveProfile(profiles, sunday9am.toMillis(), utc), `is`(profiles[0]))
assertThat("active profile is first", NotificationProfiles.getActiveProfile(profiles, sunday9am.toMillis(ZoneOffset.UTC), utc), `is`(profiles[0]))
}
@Test
fun `when profile is manually enabled for set time before schedule end and now is after manual but before schedule end then return null`() {
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_PROFILE, first.id)
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, sunday9am.toMillis())
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis())
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, sunday9am.toMillis(ZoneOffset.UTC))
signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis(ZoneOffset.UTC))
val schedule = NotificationProfileSchedule(id = 3L, true, start = 700, end = 1000, daysEnabled = setOf(DayOfWeek.SUNDAY))
val profiles = listOf(first.copy(schedule = schedule))
assertThat("active profile is null", NotificationProfiles.getActiveProfile(profiles, sunday930am.toMillis(), utc), nullValue())
assertThat("active profile is null", NotificationProfiles.getActiveProfile(profiles, sunday930am.toMillis(ZoneOffset.UTC), utc), nullValue())
}
}