Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ class TimerService : Service(), KoinComponent {

private val cs by lazy { stateRepository.colorScheme }

private lateinit var notificationStyle: NotificationCompat.ProgressStyle
private var notificationStyle = NotificationCompat.ProgressStyle()

override fun onBind(intent: Intent?): IBinder? {
return null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ class HistoryAppWidget : GlanceAppWidget(), KoinComponent {
val history = listOf(
Stat(
date = LocalDate.of(2026, 3, 12),
deviceId = "0",
focusTimeQ1 = 1617943 + 7200000,
focusTimeQ2 = 5704591,
focusTimeQ3 = 556490,
Expand All @@ -214,6 +215,7 @@ class HistoryAppWidget : GlanceAppWidget(), KoinComponent {
),
Stat(
date = LocalDate.of(2026, 3, 13),
deviceId = "0",
focusTimeQ1 = 1128282 + 7200000,
focusTimeQ2 = 4590524,
focusTimeQ3 = 7747202,
Expand All @@ -222,6 +224,7 @@ class HistoryAppWidget : GlanceAppWidget(), KoinComponent {
),
Stat(
date = LocalDate.of(2026, 3, 14),
deviceId = "0",
focusTimeQ1 = 1418079 + 7200000,
focusTimeQ2 = 8141785,
focusTimeQ3 = 5208864,
Expand All @@ -230,6 +233,7 @@ class HistoryAppWidget : GlanceAppWidget(), KoinComponent {
),
Stat(
date = LocalDate.of(2026, 3, 15),
deviceId = "0",
focusTimeQ1 = 38960 + 7200000,
focusTimeQ2 = 9544172,
focusTimeQ3 = 2216626,
Expand All @@ -238,6 +242,7 @@ class HistoryAppWidget : GlanceAppWidget(), KoinComponent {
),
Stat(
date = LocalDate.of(2026, 3, 16),
deviceId = "0",
focusTimeQ1 = 948108 + 7200000,
focusTimeQ2 = 7715257,
focusTimeQ3 = 648629,
Expand All @@ -246,6 +251,7 @@ class HistoryAppWidget : GlanceAppWidget(), KoinComponent {
),
Stat(
date = LocalDate.of(2026, 3, 17),
deviceId = "0",
focusTimeQ1 = 1673932 + 7200000,
focusTimeQ2 = 7368028,
focusTimeQ3 = 6028910,
Expand All @@ -254,6 +260,7 @@ class HistoryAppWidget : GlanceAppWidget(), KoinComponent {
),
Stat(
date = LocalDate.of(2026, 3, 18),
deviceId = "0",
focusTimeQ1 = 435688 + 7200000,
focusTimeQ2 = 9487983,
focusTimeQ3 = 248276,
Expand All @@ -262,6 +269,7 @@ class HistoryAppWidget : GlanceAppWidget(), KoinComponent {
),
Stat(
date = LocalDate.of(2026, 3, 19),
deviceId = "0",
focusTimeQ1 = 1579291 + 7200000,
focusTimeQ2 = 3743344,
focusTimeQ3 = 3383617,
Expand All @@ -270,6 +278,7 @@ class HistoryAppWidget : GlanceAppWidget(), KoinComponent {
),
Stat(
date = LocalDate.of(2026, 3, 20),
deviceId = "0",
focusTimeQ1 = 522247 + 7200000,
focusTimeQ2 = 7156785,
focusTimeQ3 = 5190730,
Expand All @@ -278,6 +287,7 @@ class HistoryAppWidget : GlanceAppWidget(), KoinComponent {
),
Stat(
date = LocalDate.of(2026, 3, 21),
deviceId = "0",
focusTimeQ1 = 310048 + 7200000,
focusTimeQ2 = 5901959,
focusTimeQ3 = 441673,
Expand All @@ -286,6 +296,7 @@ class HistoryAppWidget : GlanceAppWidget(), KoinComponent {
),
Stat(
date = LocalDate.of(2026, 3, 22),
deviceId = "0",
focusTimeQ1 = 1200000 + 7200000,
focusTimeQ2 = 4000000,
focusTimeQ3 = 3000000,
Expand All @@ -294,6 +305,7 @@ class HistoryAppWidget : GlanceAppWidget(), KoinComponent {
),
Stat(
date = LocalDate.of(2026, 3, 23),
deviceId = "0",
focusTimeQ1 = 500000 + 7200000,
focusTimeQ2 = 8000000,
focusTimeQ3 = 1000000,
Expand All @@ -302,6 +314,7 @@ class HistoryAppWidget : GlanceAppWidget(), KoinComponent {
),
Stat(
date = LocalDate.of(2026, 3, 24),
deviceId = "0",
focusTimeQ1 = 2000000 + 7200000,
focusTimeQ2 = 2000000,
focusTimeQ3 = 2000000,
Expand All @@ -310,6 +323,7 @@ class HistoryAppWidget : GlanceAppWidget(), KoinComponent {
),
Stat(
date = LocalDate.of(2026, 3, 25),
deviceId = "0",
focusTimeQ1 = 0 + 7200000,
focusTimeQ2 = 10000000,
focusTimeQ3 = 0,
Expand All @@ -318,6 +332,7 @@ class HistoryAppWidget : GlanceAppWidget(), KoinComponent {
),
Stat(
date = LocalDate.of(2026, 3, 26),
deviceId = "0",
focusTimeQ1 = 3000000 + 7200000,
focusTimeQ2 = 3000000,
focusTimeQ3 = 3000000,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class TodayAppWidget : GlanceAppWidget(), KoinComponent {
) {
val statRepository: StatRepository = get()
val stat = statRepository.getTodayStat().first()
?: Stat(LocalDate.now(), 0, 0, 0, 0, 0)
?: Stat(LocalDate.now(), "0", 0, 0, 0, 0, 0)

provideContent {
key(LocalSize.current) {
Expand Down Expand Up @@ -205,6 +205,7 @@ class TodayAppWidget : GlanceAppWidget(), KoinComponent {
Content(
Stat(
date = LocalDate.of(2026, 3, 12),
deviceId = "0",
focusTimeQ1 = 1617943,
focusTimeQ2 = 5704591,
focusTimeQ3 = 556490,
Expand Down
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ junit = "4.13.2"
junitVersion = "1.3.0"
kotlin = "2.3.20"
kotlinxCoroutines = "1.10.2"
kotlinxSerializationJson = "1.11.0"
ksp = "2.3.6"
lifecycleRuntime = "2.10.0"
materialKolor = "4.1.1"
Expand Down Expand Up @@ -64,6 +65,7 @@ filekit-core = { module = "io.github.vinceglb:filekit-core", version.ref = "file
filekit-dialogs-compose = { module = "io.github.vinceglb:filekit-dialogs-compose", version.ref = "filekitDialogsCompose" }
jlayer-player = { module = "dev.mccue:jlayer-player", version.ref = "jlayerPlayer" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
material-kolor = { module = "com.materialkolor:material-kolor", version.ref = "materialKolor" }
revenuecat-purchases = { module = "com.revenuecat.purchases:purchases", version.ref = "revenuecat" }
revenuecat-purchases-ui = { module = "com.revenuecat.purchases:purchases-ui", version.ref = "revenuecat" }
Expand Down
1 change: 1 addition & 0 deletions shared/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ kotlin {
implementation(libs.koin.compose.viewmodel)

implementation(libs.androidx.room.runtime)
implementation(libs.kotlinx.serialization.json)

implementation(libs.vico.compose.m3)
implementation(libs.material.kolor)
Expand Down
146 changes: 146 additions & 0 deletions shared/schemas/org.nsh07.pomodoro.data.AppDatabase/3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
{
"formatVersion": 1,
"database": {
"version": 3,
"identityHash": "710379259efe0b7d0cd521b4698fc0c5",
"entities": [
{
"tableName": "int_preference",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `value` INTEGER NOT NULL, PRIMARY KEY(`key`))",
"fields": [
{
"fieldPath": "key",
"columnName": "key",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "value",
"columnName": "value",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"key"
]
}
},
{
"tableName": "boolean_preference",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `value` INTEGER NOT NULL, PRIMARY KEY(`key`))",
"fields": [
{
"fieldPath": "key",
"columnName": "key",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "value",
"columnName": "value",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"key"
]
}
},
{
"tableName": "string_preference",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `value` TEXT NOT NULL, PRIMARY KEY(`key`))",
"fields": [
{
"fieldPath": "key",
"columnName": "key",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "value",
"columnName": "value",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"key"
]
}
},
{
"tableName": "stat",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`date` TEXT NOT NULL, `deviceId` TEXT NOT NULL, `updatedAt` INTEGER NOT NULL, `focusTimeQ1` INTEGER NOT NULL, `focusTimeQ2` INTEGER NOT NULL, `focusTimeQ3` INTEGER NOT NULL, `focusTimeQ4` INTEGER NOT NULL, `breakTime` INTEGER NOT NULL, PRIMARY KEY(`date`, `deviceId`))",
"fields": [
{
"fieldPath": "date",
"columnName": "date",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "deviceId",
"columnName": "deviceId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "updatedAt",
"columnName": "updatedAt",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "focusTimeQ1",
"columnName": "focusTimeQ1",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "focusTimeQ2",
"columnName": "focusTimeQ2",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "focusTimeQ3",
"columnName": "focusTimeQ3",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "focusTimeQ4",
"columnName": "focusTimeQ4",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "breakTime",
"columnName": "breakTime",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"date",
"deviceId"
]
}
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '710379259efe0b7d0cd521b4698fc0c5')"
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,14 @@ import android.content.Intent
import android.provider.DocumentsContract
import androidx.core.net.toUri
import androidx.room.RoomRawQuery
import io.github.vinceglb.filekit.FileKit
import io.github.vinceglb.filekit.PlatformFile
import io.github.vinceglb.filekit.cacheDir
import io.github.vinceglb.filekit.path
import io.github.vinceglb.filekit.writeString
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
import org.nsh07.pomodoro.BuildKonfig
import java.io.File
import java.io.FileInputStream
Expand All @@ -34,9 +38,13 @@ import kotlin.time.Clock

class AndroidBackupRestoreManager(
private val database: AppDatabase,
private val statDao: StatDao,
private val systemDao: SystemDao,
private val context: Context
private val context: Context,
deviceIdStore: DeviceIdStore
) : BackupRestoreManager {
val deviceId = deviceIdStore.deviceId

override suspend fun performBackup(directory: PlatformFile) {
withContext(Dispatchers.IO) {
systemDao.checkpoint(RoomRawQuery("PRAGMA wal_checkpoint(full)"))
Expand Down Expand Up @@ -86,6 +94,37 @@ class AndroidBackupRestoreManager(
}
}

override suspend fun exportSyncFile(): PlatformFile {
val stats = statDao.getAllRows()

val payload = SyncPayload(
schemaVersion = DB_SCHEMA_VERSION,
exportedAt = System.currentTimeMillis(),
deviceId = deviceId.value,
stats = stats
)

val outputFile =
PlatformFile(FileKit.cacheDir, "tomato-backup-${Clock.System.now()}.tomatoSync")

withContext(Dispatchers.IO) {
val content = Json.encodeToString(payload)
outputFile.writeString(content)
}

return outputFile
}

override suspend fun importSyncFile(file: PlatformFile?) {
if (file == null) return
withContext(Dispatchers.IO) {
val bytes = File(file.path).readBytes()
val content = bytes.decodeToString()
val payload = Json.decodeFromString<SyncPayload>(content)
statDao.insertStatsIfNewer(payload.stats)
}
}

override fun restartApp() {
val packageManager = context.packageManager
val intent = packageManager.getLaunchIntentForPackage(context.packageName)
Expand Down
Loading
Loading