Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1,728 changes: 1,728 additions & 0 deletions libpebble3/schema/io.rebble.libpebblecommon.database.Database/34.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ internal const val DATABASE_FILENAME = "libpebble3.db"
AppPrefsEntryEntity::class,
AppPrefsEntrySyncEntity::class,
],
version = 33,
version = 34,
autoMigrations = [
AutoMigration(from = 10, to = 11),
AutoMigration(from = 11, to = 12),
Expand All @@ -115,6 +115,7 @@ internal const val DATABASE_FILENAME = "libpebble3.db"
AutoMigration(from = 30, to = 31),
AutoMigration(from = 31, to = 32),
AutoMigration(from = 32, to = 33),
AutoMigration(from = 33, to = 34),
],
exportSchema = true,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,18 @@ data class MillisecondInstant(val instant: Instant) {

fun Instant.asMillisecond(): MillisecondInstant = MillisecondInstant(this)

/**
* Compare this MillisecondInstant with an Instant to check if this is after the given instant.
* Useful for checking if a mute expiration has passed.
*/
fun MillisecondInstant.isAfter(other: Instant): Boolean = instant > other

/**
* Get the epoch milliseconds from a MillisecondInstant.
* Useful for comparisons when the instant property is not accessible from other modules.
*/
fun MillisecondInstant.toEpochMilliseconds(): Long = instant.toEpochMilliseconds()

class RoomTypeConverters {
@TypeConverter
fun ListUIntToString(value: List<UInt>): String = value.joinToString(",");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ interface NotificationAppRealDao : NotificationAppItemDao {
insertOrReplace(existing.copy(
muteState = muteState,
stateUpdated = Clock.System.now().asMillisecond(),
muteExpiration = null,
))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ data class NotificationAppItem(
*/
val stateUpdated: MillisecondInstant,
val lastNotified: MillisecondInstant,
/**
* Timestamp when the mute should expire (for temporary mutes like "mute for 1 hour" or "mute for 1 day").
* If null, the mute is permanent or based on schedule (Weekdays/Weekends).
*/
@ColumnInfo(defaultValue = "null")
val muteExpiration: MillisecondInstant? = null,
@ColumnInfo(defaultValue = "null")
val vibePatternName: String?,
@ColumnInfo(defaultValue = "null")
Expand Down Expand Up @@ -171,6 +177,17 @@ fun DbWrite.asNotificationAppItem(): NotificationAppItem? {
return null
}
val lastUpdated = timestamp.let { Instant.fromEpochSeconds(it.toLong()) }
// Read MuteExpiration if present
val muteExpiration = item.attributes.get(TimelineAttribute.MuteExpiration)?.let { expirationBytes ->
if (expirationBytes.size >= 4) {
val expirationSeconds = SUInt(StructMapper(), endianness = Endian.Little).apply {
fromBytes(DataBuffer(expirationBytes))
}.get().toLong()
Instant.fromEpochSeconds(expirationSeconds).asMillisecond()
} else {
null
}
}
// val lastUpdated = item.attributes.get(TimelineAttribute.LastUpdated)
// ?.getUIntAt(0, littleEndian = true)?.let { Instant.fromEpochSeconds(it.toLong()) }
// if (lastUpdated == null) {
Expand All @@ -184,6 +201,7 @@ fun DbWrite.asNotificationAppItem(): NotificationAppItem? {
name = appName,
channelGroups = emptyList(),
lastNotified = lastUpdated.asMillisecond(),
muteExpiration = muteExpiration,
vibePatternName = null,
colorName = null,
iconCode = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ enum class TimelineAttribute(val id: UByte, val maxLength: Int = -1) {
Timestamp(0x25u),
DisplayTime(0x26u),
MuteDayOfWeek(40u),
MuteExpiration(50u),
SubtitleTemplateString(0x2Fu, 150),
Icon(0x30u),
VibrationPattern(0x31u),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import androidx.lifecycle.ViewModel
import coredevices.pebble.Platform
import io.rebble.libpebblecommon.connection.NotificationApps
import io.rebble.libpebblecommon.database.dao.ChannelAndCount
import io.rebble.libpebblecommon.database.isAfter
import io.rebble.libpebblecommon.database.entity.ChannelGroup
import io.rebble.libpebblecommon.database.entity.ChannelItem
import io.rebble.libpebblecommon.database.entity.MuteState
Expand Down Expand Up @@ -231,7 +232,20 @@ private fun ChannelCard(
channelCounts: Map<String, ChannelAndCount>,
nav: NavBarNav,
) {
val appMuted = app.muteState != MuteState.Never
val expiration = app.muteExpiration
val appMuted = when {
// Check temporary mute first (takes priority)
expiration != null -> {
// Temporary mute: check if it hasn't expired yet
val now = kotlin.time.Clock.System.now()
expiration.isAfter(now)
}
app.muteState == MuteState.Never -> false
else -> {
// Permanent or schedule-based mute (Always, Weekdays, Weekends)
true
}
}
val channelMuted = channelItem.muteState != MuteState.Never
val count = channelCounts[channelItem.id]?.count
val clickable = count != null && count > 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@ import coredevices.pebble.account.BootConfig
import coredevices.pebble.account.BootConfigProvider
import coredevices.pebble.account.iconUrlFor
import io.rebble.libpebblecommon.connection.NotificationApps
import io.rebble.libpebblecommon.database.isAfter
import io.rebble.libpebblecommon.database.dao.AppWithCount
import io.rebble.libpebblecommon.database.entity.MuteState
import kotlin.time.Clock
import org.jetbrains.compose.ui.tooling.preview.Preview
import org.koin.compose.koinInject
import org.koin.compose.viewmodel.koinViewModel
Expand Down Expand Up @@ -144,7 +146,22 @@ fun NotificationAppCard(
nav.navigateTo(PebbleNavBarRoutes.NotificationAppRoute(app.packageName))
}
} else Modifier
val muted = remember(app) { app.muteState != MuteState.Never }
val muted = remember(app) {
val expiration = app.muteExpiration
when {
// Check temporary mute first (takes priority)
expiration != null -> {
// Temporary mute: check if it hasn't expired yet
val now = Clock.System.now()
expiration.isAfter(now)
}
app.muteState == MuteState.Never -> false
else -> {
// Permanent or schedule-based mute (Always, Weekdays, Weekends)
true
}
}
}
ListItem(
modifier = modifier,
leadingContent = {
Expand Down