From 81b9f148b2a4fd0475a8e91245b80ae5fe87ea1f Mon Sep 17 00:00:00 2001 From: KhooLy <73142442+KhooLy@users.noreply.github.com> Date: Wed, 5 Aug 2026 15:30:47 +0300 Subject: [PATCH] Stand up Room-on-desktop and share WatchlistManager Moves AppDatabase/WatchlistDao/WatchlistEntities into commonMain using Room 2.8.4's multiplatform pattern (@ConstructedBy/RoomDatabaseConstructor, KSP-generated actuals) with zero schema/version changes, so the Android on-device database is unaffected. Wires Room's KSP compiler for desktop and the native targets (kspDesktop, kspIosSimulatorArm64, kspTvosArm64, etc.), alongside the existing kspAndroid. Adds a desktop AppDatabase factory backed by androidx.sqlite's BundledSQLiteDriver, storing the file under ~/.fluxa/watchlist_db. Drops room-ktx from the shared source sets (it transitively pulls in kotlinx-coroutines-android, which has no native/JVM variant and broke the iOS/tvOS build) - room-runtime alone already carries Room's Flow/coroutines support since 2.4+. Replaces java.lang.System.currentTimeMillis() defaults in the entity classes with the existing portable epochMillisNow() (same one PlatformClock already uses), since java.lang.System doesn't exist on Kotlin/Native. WatchlistManager itself had zero non-Room Android surface once its two dead imports (unused Context/Room) were dropped, so it moves to jvmCommonMain unchanged - now shared with desktop. Also cleans up three stale Room schema-export directories left over from a historical `com.fluxa.app.ui.catalog.AppDatabase`/`FluxaDatabase` package rename, in both data/schemas/ and the now entirely-stale app/schemas/. --- .../10.json | 427 ------------ .../11.json | 557 --------------- .../14.json | 629 ----------------- .../15.json | 634 ------------------ .../8.json | 156 ----- .../9.json | 310 --------- .../8.json | 156 ----- .../7.json | 146 ---- .../8.json | 156 ----- .../java/com/fluxa/app/di/DatabaseModule.kt | 7 - data/build.gradle.kts | 13 +- .../8.json | 156 ----- .../7.json | 146 ---- .../8.json | 156 ----- .../com/fluxa/app/data/local/WatchlistDao.kt | 2 - .../fluxa/app/data/local/WatchlistDatabase.kt | 7 + .../fluxa/app/data/local/WatchlistEntities.kt | 29 +- .../app/data/local/DesktopAppDatabase.kt | 18 + .../kotlin/com/fluxa/app/core/StremioId.kt | 2 +- .../fluxa/app/data/local/WatchlistManager.kt | 2 - gradle/libs.versions.toml | 1 + 21 files changed, 51 insertions(+), 3659 deletions(-) delete mode 100644 app/schemas/com.fluxa.app.data.local.AppDatabase/10.json delete mode 100644 app/schemas/com.fluxa.app.data.local.AppDatabase/11.json delete mode 100644 app/schemas/com.fluxa.app.data.local.AppDatabase/14.json delete mode 100644 app/schemas/com.fluxa.app.data.local.AppDatabase/15.json delete mode 100644 app/schemas/com.fluxa.app.data.local.AppDatabase/8.json delete mode 100644 app/schemas/com.fluxa.app.data.local.AppDatabase/9.json delete mode 100644 app/schemas/com.fluxa.app.ui.catalog.AppDatabase/8.json delete mode 100644 app/schemas/com.fluxa.app.ui.catalog.FluxaDatabase/7.json delete mode 100644 app/schemas/com.fluxa.app.ui.catalog.FluxaDatabase/8.json delete mode 100644 data/schemas/com.fluxa.app.ui.catalog.AppDatabase/8.json delete mode 100644 data/schemas/com.fluxa.app.ui.catalog.FluxaDatabase/7.json delete mode 100644 data/schemas/com.fluxa.app.ui.catalog.FluxaDatabase/8.json rename data/src/{androidMain => commonMain}/kotlin/com/fluxa/app/data/local/WatchlistDao.kt (99%) rename data/src/{androidMain => commonMain}/kotlin/com/fluxa/app/data/local/WatchlistDatabase.kt (73%) rename data/src/{androidMain => commonMain}/kotlin/com/fluxa/app/data/local/WatchlistEntities.kt (87%) create mode 100644 data/src/desktopMain/kotlin/com/fluxa/app/data/local/DesktopAppDatabase.kt rename data/src/{androidMain => jvmCommonMain}/kotlin/com/fluxa/app/data/local/WatchlistManager.kt (99%) diff --git a/app/schemas/com.fluxa.app.data.local.AppDatabase/10.json b/app/schemas/com.fluxa.app.data.local.AppDatabase/10.json deleted file mode 100644 index f42aea5..0000000 --- a/app/schemas/com.fluxa.app.data.local.AppDatabase/10.json +++ /dev/null @@ -1,427 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 10, - "identityHash": "8823f3903112bf858c3952daafea46de", - "entities": [ - { - "tableName": "content_items", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `poster` TEXT, `background` TEXT, `logo` TEXT, `description` TEXT, `rating` TEXT, `releaseInfo` TEXT, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "poster", - "columnName": "poster", - "affinity": "TEXT" - }, - { - "fieldPath": "background", - "columnName": "background", - "affinity": "TEXT" - }, - { - "fieldPath": "logo", - "columnName": "logo", - "affinity": "TEXT" - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT" - }, - { - "fieldPath": "rating", - "columnName": "rating", - "affinity": "TEXT" - }, - { - "fieldPath": "releaseInfo", - "columnName": "releaseInfo", - "affinity": "TEXT" - }, - { - "fieldPath": "updatedAt", - "columnName": "updatedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - } - }, - { - "tableName": "watchlist_entries", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `addedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "addedAt", - "columnName": "addedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - } - }, - { - "tableName": "playback_progress", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `videoId` TEXT, `timeOffset` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `lastStreamIndex` INTEGER, `lastEpisodeName` TEXT, `lastStreamUrl` TEXT, `lastStreamTitle` TEXT, `continueWatchingPoster` TEXT, `continueWatchingBackground` TEXT, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "videoId", - "columnName": "videoId", - "affinity": "TEXT" - }, - { - "fieldPath": "timeOffset", - "columnName": "timeOffset", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "duration", - "columnName": "duration", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "lastStreamIndex", - "columnName": "lastStreamIndex", - "affinity": "INTEGER" - }, - { - "fieldPath": "lastEpisodeName", - "columnName": "lastEpisodeName", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamUrl", - "columnName": "lastStreamUrl", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamTitle", - "columnName": "lastStreamTitle", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingPoster", - "columnName": "continueWatchingPoster", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingBackground", - "columnName": "continueWatchingBackground", - "affinity": "TEXT" - }, - { - "fieldPath": "updatedAt", - "columnName": "updatedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - } - }, - { - "tableName": "user_feedback", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `isLiked` INTEGER, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "isLiked", - "columnName": "isLiked", - "affinity": "INTEGER" - }, - { - "fieldPath": "updatedAt", - "columnName": "updatedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - } - }, - { - "tableName": "track_preferences", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `lastAudioLanguage` TEXT, `lastSubtitleLanguage` TEXT, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lastAudioLanguage", - "columnName": "lastAudioLanguage", - "affinity": "TEXT" - }, - { - "fieldPath": "lastSubtitleLanguage", - "columnName": "lastSubtitleLanguage", - "affinity": "TEXT" - }, - { - "fieldPath": "updatedAt", - "columnName": "updatedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - } - }, - { - "tableName": "watched_episodes", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `seriesId` TEXT NOT NULL, `videoId` TEXT NOT NULL, `watchedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `seriesId`, `videoId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "seriesId", - "columnName": "seriesId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "videoId", - "columnName": "videoId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "watchedAt", - "columnName": "watchedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "seriesId", - "videoId" - ] - } - }, - { - "tableName": "external_playback_progress", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `provider` TEXT NOT NULL, `contentId` TEXT NOT NULL, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `poster` TEXT, `background` TEXT, `logo` TEXT, `description` TEXT, `rating` TEXT, `releaseInfo` TEXT, `videoId` TEXT, `timeOffset` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `lastEpisodeName` TEXT, `reason` TEXT, `continueWatchingPoster` TEXT, `continueWatchingBackground` TEXT, `syncedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `provider`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "provider", - "columnName": "provider", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "poster", - "columnName": "poster", - "affinity": "TEXT" - }, - { - "fieldPath": "background", - "columnName": "background", - "affinity": "TEXT" - }, - { - "fieldPath": "logo", - "columnName": "logo", - "affinity": "TEXT" - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT" - }, - { - "fieldPath": "rating", - "columnName": "rating", - "affinity": "TEXT" - }, - { - "fieldPath": "releaseInfo", - "columnName": "releaseInfo", - "affinity": "TEXT" - }, - { - "fieldPath": "videoId", - "columnName": "videoId", - "affinity": "TEXT" - }, - { - "fieldPath": "timeOffset", - "columnName": "timeOffset", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "duration", - "columnName": "duration", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "lastEpisodeName", - "columnName": "lastEpisodeName", - "affinity": "TEXT" - }, - { - "fieldPath": "reason", - "columnName": "reason", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingPoster", - "columnName": "continueWatchingPoster", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingBackground", - "columnName": "continueWatchingBackground", - "affinity": "TEXT" - }, - { - "fieldPath": "syncedAt", - "columnName": "syncedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "provider", - "contentId" - ] - } - } - ], - "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, '8823f3903112bf858c3952daafea46de')" - ] - } -} \ No newline at end of file diff --git a/app/schemas/com.fluxa.app.data.local.AppDatabase/11.json b/app/schemas/com.fluxa.app.data.local.AppDatabase/11.json deleted file mode 100644 index dde8b6d..0000000 --- a/app/schemas/com.fluxa.app.data.local.AppDatabase/11.json +++ /dev/null @@ -1,557 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 11, - "identityHash": "3b183a297ce202ed8a171a3c129d11fe", - "entities": [ - { - "tableName": "content_items", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `poster` TEXT, `background` TEXT, `logo` TEXT, `description` TEXT, `rating` TEXT, `releaseInfo` TEXT, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "poster", - "columnName": "poster", - "affinity": "TEXT" - }, - { - "fieldPath": "background", - "columnName": "background", - "affinity": "TEXT" - }, - { - "fieldPath": "logo", - "columnName": "logo", - "affinity": "TEXT" - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT" - }, - { - "fieldPath": "rating", - "columnName": "rating", - "affinity": "TEXT" - }, - { - "fieldPath": "releaseInfo", - "columnName": "releaseInfo", - "affinity": "TEXT" - }, - { - "fieldPath": "updatedAt", - "columnName": "updatedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - } - }, - { - "tableName": "watchlist_entries", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `addedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "addedAt", - "columnName": "addedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - }, - "indices": [ - { - "name": "index_watchlist_entries_profile_addedAt", - "unique": false, - "columnNames": [ - "profileId", - "addedAt" - ], - "orders": [ - "ASC", - "DESC" - ], - "createSql": "CREATE INDEX IF NOT EXISTS `index_watchlist_entries_profile_addedAt` ON `${TABLE_NAME}` (`profileId` ASC, `addedAt` DESC)" - } - ] - }, - { - "tableName": "playback_progress", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `videoId` TEXT, `timeOffset` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `lastStreamIndex` INTEGER, `lastEpisodeName` TEXT, `lastStreamUrl` TEXT, `lastStreamTitle` TEXT, `continueWatchingPoster` TEXT, `continueWatchingBackground` TEXT, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "videoId", - "columnName": "videoId", - "affinity": "TEXT" - }, - { - "fieldPath": "timeOffset", - "columnName": "timeOffset", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "duration", - "columnName": "duration", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "lastStreamIndex", - "columnName": "lastStreamIndex", - "affinity": "INTEGER" - }, - { - "fieldPath": "lastEpisodeName", - "columnName": "lastEpisodeName", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamUrl", - "columnName": "lastStreamUrl", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamTitle", - "columnName": "lastStreamTitle", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingPoster", - "columnName": "continueWatchingPoster", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingBackground", - "columnName": "continueWatchingBackground", - "affinity": "TEXT" - }, - { - "fieldPath": "updatedAt", - "columnName": "updatedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - }, - "indices": [ - { - "name": "index_playback_progress_profile_updatedAt", - "unique": false, - "columnNames": [ - "profileId", - "updatedAt" - ], - "orders": [ - "ASC", - "DESC" - ], - "createSql": "CREATE INDEX IF NOT EXISTS `index_playback_progress_profile_updatedAt` ON `${TABLE_NAME}` (`profileId` ASC, `updatedAt` DESC)" - } - ] - }, - { - "tableName": "user_feedback", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `isLiked` INTEGER, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "isLiked", - "columnName": "isLiked", - "affinity": "INTEGER" - }, - { - "fieldPath": "updatedAt", - "columnName": "updatedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - }, - "indices": [ - { - "name": "index_user_feedback_profile_updatedAt", - "unique": false, - "columnNames": [ - "profileId", - "updatedAt" - ], - "orders": [ - "ASC", - "DESC" - ], - "createSql": "CREATE INDEX IF NOT EXISTS `index_user_feedback_profile_updatedAt` ON `${TABLE_NAME}` (`profileId` ASC, `updatedAt` DESC)" - } - ] - }, - { - "tableName": "track_preferences", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `lastAudioLanguage` TEXT, `lastSubtitleLanguage` TEXT, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lastAudioLanguage", - "columnName": "lastAudioLanguage", - "affinity": "TEXT" - }, - { - "fieldPath": "lastSubtitleLanguage", - "columnName": "lastSubtitleLanguage", - "affinity": "TEXT" - }, - { - "fieldPath": "updatedAt", - "columnName": "updatedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - } - }, - { - "tableName": "watched_episodes", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `seriesId` TEXT NOT NULL, `videoId` TEXT NOT NULL, `watchedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `seriesId`, `videoId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "seriesId", - "columnName": "seriesId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "videoId", - "columnName": "videoId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "watchedAt", - "columnName": "watchedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "seriesId", - "videoId" - ] - }, - "indices": [ - { - "name": "index_watched_episodes_profile_series", - "unique": false, - "columnNames": [ - "profileId", - "seriesId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_watched_episodes_profile_series` ON `${TABLE_NAME}` (`profileId`, `seriesId`)" - } - ] - }, - { - "tableName": "external_playback_progress", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `provider` TEXT NOT NULL, `contentId` TEXT NOT NULL, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `poster` TEXT, `background` TEXT, `logo` TEXT, `description` TEXT, `rating` TEXT, `releaseInfo` TEXT, `videoId` TEXT, `timeOffset` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `lastEpisodeName` TEXT, `reason` TEXT, `continueWatchingPoster` TEXT, `continueWatchingBackground` TEXT, `syncedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `provider`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "provider", - "columnName": "provider", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "poster", - "columnName": "poster", - "affinity": "TEXT" - }, - { - "fieldPath": "background", - "columnName": "background", - "affinity": "TEXT" - }, - { - "fieldPath": "logo", - "columnName": "logo", - "affinity": "TEXT" - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT" - }, - { - "fieldPath": "rating", - "columnName": "rating", - "affinity": "TEXT" - }, - { - "fieldPath": "releaseInfo", - "columnName": "releaseInfo", - "affinity": "TEXT" - }, - { - "fieldPath": "videoId", - "columnName": "videoId", - "affinity": "TEXT" - }, - { - "fieldPath": "timeOffset", - "columnName": "timeOffset", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "duration", - "columnName": "duration", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "lastEpisodeName", - "columnName": "lastEpisodeName", - "affinity": "TEXT" - }, - { - "fieldPath": "reason", - "columnName": "reason", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingPoster", - "columnName": "continueWatchingPoster", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingBackground", - "columnName": "continueWatchingBackground", - "affinity": "TEXT" - }, - { - "fieldPath": "syncedAt", - "columnName": "syncedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "provider", - "contentId" - ] - }, - "indices": [ - { - "name": "index_external_playback_progress_profile_syncedAt", - "unique": false, - "columnNames": [ - "profileId", - "syncedAt" - ], - "orders": [ - "ASC", - "DESC" - ], - "createSql": "CREATE INDEX IF NOT EXISTS `index_external_playback_progress_profile_syncedAt` ON `${TABLE_NAME}` (`profileId` ASC, `syncedAt` DESC)" - } - ] - }, - { - "tableName": "external_watched_episodes", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `provider` TEXT NOT NULL, `seriesId` TEXT NOT NULL, `videoId` TEXT NOT NULL, `syncedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `provider`, `seriesId`, `videoId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "provider", - "columnName": "provider", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "seriesId", - "columnName": "seriesId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "videoId", - "columnName": "videoId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "syncedAt", - "columnName": "syncedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "provider", - "seriesId", - "videoId" - ] - }, - "indices": [ - { - "name": "index_external_watched_episodes_profile_provider_series", - "unique": false, - "columnNames": [ - "profileId", - "provider", - "seriesId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_external_watched_episodes_profile_provider_series` ON `${TABLE_NAME}` (`profileId`, `provider`, `seriesId`)" - } - ] - } - ], - "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, '3b183a297ce202ed8a171a3c129d11fe')" - ] - } -} \ No newline at end of file diff --git a/app/schemas/com.fluxa.app.data.local.AppDatabase/14.json b/app/schemas/com.fluxa.app.data.local.AppDatabase/14.json deleted file mode 100644 index c32370c..0000000 --- a/app/schemas/com.fluxa.app.data.local.AppDatabase/14.json +++ /dev/null @@ -1,629 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 14, - "identityHash": "dcb9ebb1831d22b536c21ee42710799b", - "entities": [ - { - "tableName": "content_items", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `poster` TEXT, `background` TEXT, `logo` TEXT, `description` TEXT, `rating` TEXT, `releaseInfo` TEXT, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "poster", - "columnName": "poster", - "affinity": "TEXT" - }, - { - "fieldPath": "background", - "columnName": "background", - "affinity": "TEXT" - }, - { - "fieldPath": "logo", - "columnName": "logo", - "affinity": "TEXT" - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT" - }, - { - "fieldPath": "rating", - "columnName": "rating", - "affinity": "TEXT" - }, - { - "fieldPath": "releaseInfo", - "columnName": "releaseInfo", - "affinity": "TEXT" - }, - { - "fieldPath": "updatedAt", - "columnName": "updatedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - } - }, - { - "tableName": "watchlist_entries", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `addedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "addedAt", - "columnName": "addedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - }, - "indices": [ - { - "name": "index_watchlist_entries_profile_addedAt", - "unique": false, - "columnNames": [ - "profileId", - "addedAt" - ], - "orders": [ - "ASC", - "DESC" - ], - "createSql": "CREATE INDEX IF NOT EXISTS `index_watchlist_entries_profile_addedAt` ON `${TABLE_NAME}` (`profileId` ASC, `addedAt` DESC)" - } - ] - }, - { - "tableName": "playback_progress", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `videoId` TEXT, `timeOffset` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `lastStreamIndex` INTEGER, `lastEpisodeName` TEXT, `lastStreamUrl` TEXT, `lastStreamTitle` TEXT, `continueWatchingPoster` TEXT, `continueWatchingBackground` TEXT, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "videoId", - "columnName": "videoId", - "affinity": "TEXT" - }, - { - "fieldPath": "timeOffset", - "columnName": "timeOffset", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "duration", - "columnName": "duration", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "lastStreamIndex", - "columnName": "lastStreamIndex", - "affinity": "INTEGER" - }, - { - "fieldPath": "lastEpisodeName", - "columnName": "lastEpisodeName", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamUrl", - "columnName": "lastStreamUrl", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamTitle", - "columnName": "lastStreamTitle", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingPoster", - "columnName": "continueWatchingPoster", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingBackground", - "columnName": "continueWatchingBackground", - "affinity": "TEXT" - }, - { - "fieldPath": "updatedAt", - "columnName": "updatedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - }, - "indices": [ - { - "name": "index_playback_progress_profile_updatedAt", - "unique": false, - "columnNames": [ - "profileId", - "updatedAt" - ], - "orders": [ - "ASC", - "DESC" - ], - "createSql": "CREATE INDEX IF NOT EXISTS `index_playback_progress_profile_updatedAt` ON `${TABLE_NAME}` (`profileId` ASC, `updatedAt` DESC)" - } - ] - }, - { - "tableName": "user_feedback", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `isLiked` INTEGER, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "isLiked", - "columnName": "isLiked", - "affinity": "INTEGER" - }, - { - "fieldPath": "updatedAt", - "columnName": "updatedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - }, - "indices": [ - { - "name": "index_user_feedback_profile_updatedAt", - "unique": false, - "columnNames": [ - "profileId", - "updatedAt" - ], - "orders": [ - "ASC", - "DESC" - ], - "createSql": "CREATE INDEX IF NOT EXISTS `index_user_feedback_profile_updatedAt` ON `${TABLE_NAME}` (`profileId` ASC, `updatedAt` DESC)" - } - ] - }, - { - "tableName": "track_preferences", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `lastAudioLanguage` TEXT, `lastSubtitleLanguage` TEXT, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lastAudioLanguage", - "columnName": "lastAudioLanguage", - "affinity": "TEXT" - }, - { - "fieldPath": "lastSubtitleLanguage", - "columnName": "lastSubtitleLanguage", - "affinity": "TEXT" - }, - { - "fieldPath": "updatedAt", - "columnName": "updatedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - } - }, - { - "tableName": "watched_episodes", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `seriesId` TEXT NOT NULL, `videoId` TEXT NOT NULL, `watchedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `seriesId`, `videoId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "seriesId", - "columnName": "seriesId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "videoId", - "columnName": "videoId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "watchedAt", - "columnName": "watchedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "seriesId", - "videoId" - ] - }, - "indices": [ - { - "name": "index_watched_episodes_profile_series", - "unique": false, - "columnNames": [ - "profileId", - "seriesId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_watched_episodes_profile_series` ON `${TABLE_NAME}` (`profileId`, `seriesId`)" - } - ] - }, - { - "tableName": "watched_content_durations", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `source` TEXT NOT NULL, `contentId` TEXT NOT NULL, `videoId` TEXT NOT NULL, `duration` INTEGER NOT NULL, `watchedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `source`, `contentId`, `videoId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "source", - "columnName": "source", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "videoId", - "columnName": "videoId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "duration", - "columnName": "duration", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "watchedAt", - "columnName": "watchedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "source", - "contentId", - "videoId" - ] - }, - "indices": [ - { - "name": "index_watched_content_durations_profile", - "unique": false, - "columnNames": [ - "profileId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_watched_content_durations_profile` ON `${TABLE_NAME}` (`profileId`)" - }, - { - "name": "index_watched_content_durations_profile_source", - "unique": false, - "columnNames": [ - "profileId", - "source" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_watched_content_durations_profile_source` ON `${TABLE_NAME}` (`profileId`, `source`)" - } - ] - }, - { - "tableName": "external_playback_progress", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `provider` TEXT NOT NULL, `contentId` TEXT NOT NULL, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `poster` TEXT, `background` TEXT, `logo` TEXT, `description` TEXT, `rating` TEXT, `releaseInfo` TEXT, `videoId` TEXT, `timeOffset` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `lastEpisodeName` TEXT, `reason` TEXT, `continueWatchingPoster` TEXT, `continueWatchingBackground` TEXT, `syncedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `provider`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "provider", - "columnName": "provider", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "poster", - "columnName": "poster", - "affinity": "TEXT" - }, - { - "fieldPath": "background", - "columnName": "background", - "affinity": "TEXT" - }, - { - "fieldPath": "logo", - "columnName": "logo", - "affinity": "TEXT" - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT" - }, - { - "fieldPath": "rating", - "columnName": "rating", - "affinity": "TEXT" - }, - { - "fieldPath": "releaseInfo", - "columnName": "releaseInfo", - "affinity": "TEXT" - }, - { - "fieldPath": "videoId", - "columnName": "videoId", - "affinity": "TEXT" - }, - { - "fieldPath": "timeOffset", - "columnName": "timeOffset", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "duration", - "columnName": "duration", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "lastEpisodeName", - "columnName": "lastEpisodeName", - "affinity": "TEXT" - }, - { - "fieldPath": "reason", - "columnName": "reason", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingPoster", - "columnName": "continueWatchingPoster", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingBackground", - "columnName": "continueWatchingBackground", - "affinity": "TEXT" - }, - { - "fieldPath": "syncedAt", - "columnName": "syncedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "provider", - "contentId" - ] - }, - "indices": [ - { - "name": "index_external_playback_progress_profile_syncedAt", - "unique": false, - "columnNames": [ - "profileId", - "syncedAt" - ], - "orders": [ - "ASC", - "DESC" - ], - "createSql": "CREATE INDEX IF NOT EXISTS `index_external_playback_progress_profile_syncedAt` ON `${TABLE_NAME}` (`profileId` ASC, `syncedAt` DESC)" - } - ] - }, - { - "tableName": "external_watched_episodes", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `provider` TEXT NOT NULL, `seriesId` TEXT NOT NULL, `videoId` TEXT NOT NULL, `syncedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `provider`, `seriesId`, `videoId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "provider", - "columnName": "provider", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "seriesId", - "columnName": "seriesId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "videoId", - "columnName": "videoId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "syncedAt", - "columnName": "syncedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "provider", - "seriesId", - "videoId" - ] - }, - "indices": [ - { - "name": "index_external_watched_episodes_profile_provider_series", - "unique": false, - "columnNames": [ - "profileId", - "provider", - "seriesId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_external_watched_episodes_profile_provider_series` ON `${TABLE_NAME}` (`profileId`, `provider`, `seriesId`)" - } - ] - } - ], - "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, 'dcb9ebb1831d22b536c21ee42710799b')" - ] - } -} \ No newline at end of file diff --git a/app/schemas/com.fluxa.app.data.local.AppDatabase/15.json b/app/schemas/com.fluxa.app.data.local.AppDatabase/15.json deleted file mode 100644 index a2034e7..0000000 --- a/app/schemas/com.fluxa.app.data.local.AppDatabase/15.json +++ /dev/null @@ -1,634 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 15, - "identityHash": "e9287e5a13def610a5b078a881b21a3b", - "entities": [ - { - "tableName": "content_items", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `poster` TEXT, `background` TEXT, `logo` TEXT, `description` TEXT, `rating` TEXT, `releaseInfo` TEXT, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "poster", - "columnName": "poster", - "affinity": "TEXT" - }, - { - "fieldPath": "background", - "columnName": "background", - "affinity": "TEXT" - }, - { - "fieldPath": "logo", - "columnName": "logo", - "affinity": "TEXT" - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT" - }, - { - "fieldPath": "rating", - "columnName": "rating", - "affinity": "TEXT" - }, - { - "fieldPath": "releaseInfo", - "columnName": "releaseInfo", - "affinity": "TEXT" - }, - { - "fieldPath": "updatedAt", - "columnName": "updatedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - } - }, - { - "tableName": "watchlist_entries", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `addedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "addedAt", - "columnName": "addedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - }, - "indices": [ - { - "name": "index_watchlist_entries_profile_addedAt", - "unique": false, - "columnNames": [ - "profileId", - "addedAt" - ], - "orders": [ - "ASC", - "DESC" - ], - "createSql": "CREATE INDEX IF NOT EXISTS `index_watchlist_entries_profile_addedAt` ON `${TABLE_NAME}` (`profileId` ASC, `addedAt` DESC)" - } - ] - }, - { - "tableName": "playback_progress", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `videoId` TEXT, `timeOffset` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `lastStreamIndex` INTEGER, `lastEpisodeName` TEXT, `lastStreamUrl` TEXT, `lastStreamTitle` TEXT, `lastBingeGroup` TEXT, `continueWatchingPoster` TEXT, `continueWatchingBackground` TEXT, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "videoId", - "columnName": "videoId", - "affinity": "TEXT" - }, - { - "fieldPath": "timeOffset", - "columnName": "timeOffset", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "duration", - "columnName": "duration", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "lastStreamIndex", - "columnName": "lastStreamIndex", - "affinity": "INTEGER" - }, - { - "fieldPath": "lastEpisodeName", - "columnName": "lastEpisodeName", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamUrl", - "columnName": "lastStreamUrl", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamTitle", - "columnName": "lastStreamTitle", - "affinity": "TEXT" - }, - { - "fieldPath": "lastBingeGroup", - "columnName": "lastBingeGroup", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingPoster", - "columnName": "continueWatchingPoster", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingBackground", - "columnName": "continueWatchingBackground", - "affinity": "TEXT" - }, - { - "fieldPath": "updatedAt", - "columnName": "updatedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - }, - "indices": [ - { - "name": "index_playback_progress_profile_updatedAt", - "unique": false, - "columnNames": [ - "profileId", - "updatedAt" - ], - "orders": [ - "ASC", - "DESC" - ], - "createSql": "CREATE INDEX IF NOT EXISTS `index_playback_progress_profile_updatedAt` ON `${TABLE_NAME}` (`profileId` ASC, `updatedAt` DESC)" - } - ] - }, - { - "tableName": "user_feedback", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `isLiked` INTEGER, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "isLiked", - "columnName": "isLiked", - "affinity": "INTEGER" - }, - { - "fieldPath": "updatedAt", - "columnName": "updatedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - }, - "indices": [ - { - "name": "index_user_feedback_profile_updatedAt", - "unique": false, - "columnNames": [ - "profileId", - "updatedAt" - ], - "orders": [ - "ASC", - "DESC" - ], - "createSql": "CREATE INDEX IF NOT EXISTS `index_user_feedback_profile_updatedAt` ON `${TABLE_NAME}` (`profileId` ASC, `updatedAt` DESC)" - } - ] - }, - { - "tableName": "track_preferences", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `lastAudioLanguage` TEXT, `lastSubtitleLanguage` TEXT, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lastAudioLanguage", - "columnName": "lastAudioLanguage", - "affinity": "TEXT" - }, - { - "fieldPath": "lastSubtitleLanguage", - "columnName": "lastSubtitleLanguage", - "affinity": "TEXT" - }, - { - "fieldPath": "updatedAt", - "columnName": "updatedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - } - }, - { - "tableName": "watched_episodes", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `seriesId` TEXT NOT NULL, `videoId` TEXT NOT NULL, `watchedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `seriesId`, `videoId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "seriesId", - "columnName": "seriesId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "videoId", - "columnName": "videoId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "watchedAt", - "columnName": "watchedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "seriesId", - "videoId" - ] - }, - "indices": [ - { - "name": "index_watched_episodes_profile_series", - "unique": false, - "columnNames": [ - "profileId", - "seriesId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_watched_episodes_profile_series` ON `${TABLE_NAME}` (`profileId`, `seriesId`)" - } - ] - }, - { - "tableName": "watched_content_durations", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `source` TEXT NOT NULL, `contentId` TEXT NOT NULL, `videoId` TEXT NOT NULL, `duration` INTEGER NOT NULL, `watchedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `source`, `contentId`, `videoId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "source", - "columnName": "source", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "videoId", - "columnName": "videoId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "duration", - "columnName": "duration", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "watchedAt", - "columnName": "watchedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "source", - "contentId", - "videoId" - ] - }, - "indices": [ - { - "name": "index_watched_content_durations_profile", - "unique": false, - "columnNames": [ - "profileId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_watched_content_durations_profile` ON `${TABLE_NAME}` (`profileId`)" - }, - { - "name": "index_watched_content_durations_profile_source", - "unique": false, - "columnNames": [ - "profileId", - "source" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_watched_content_durations_profile_source` ON `${TABLE_NAME}` (`profileId`, `source`)" - } - ] - }, - { - "tableName": "external_playback_progress", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `provider` TEXT NOT NULL, `contentId` TEXT NOT NULL, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `poster` TEXT, `background` TEXT, `logo` TEXT, `description` TEXT, `rating` TEXT, `releaseInfo` TEXT, `videoId` TEXT, `timeOffset` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `lastEpisodeName` TEXT, `reason` TEXT, `continueWatchingPoster` TEXT, `continueWatchingBackground` TEXT, `syncedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `provider`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "provider", - "columnName": "provider", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "poster", - "columnName": "poster", - "affinity": "TEXT" - }, - { - "fieldPath": "background", - "columnName": "background", - "affinity": "TEXT" - }, - { - "fieldPath": "logo", - "columnName": "logo", - "affinity": "TEXT" - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT" - }, - { - "fieldPath": "rating", - "columnName": "rating", - "affinity": "TEXT" - }, - { - "fieldPath": "releaseInfo", - "columnName": "releaseInfo", - "affinity": "TEXT" - }, - { - "fieldPath": "videoId", - "columnName": "videoId", - "affinity": "TEXT" - }, - { - "fieldPath": "timeOffset", - "columnName": "timeOffset", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "duration", - "columnName": "duration", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "lastEpisodeName", - "columnName": "lastEpisodeName", - "affinity": "TEXT" - }, - { - "fieldPath": "reason", - "columnName": "reason", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingPoster", - "columnName": "continueWatchingPoster", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingBackground", - "columnName": "continueWatchingBackground", - "affinity": "TEXT" - }, - { - "fieldPath": "syncedAt", - "columnName": "syncedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "provider", - "contentId" - ] - }, - "indices": [ - { - "name": "index_external_playback_progress_profile_syncedAt", - "unique": false, - "columnNames": [ - "profileId", - "syncedAt" - ], - "orders": [ - "ASC", - "DESC" - ], - "createSql": "CREATE INDEX IF NOT EXISTS `index_external_playback_progress_profile_syncedAt` ON `${TABLE_NAME}` (`profileId` ASC, `syncedAt` DESC)" - } - ] - }, - { - "tableName": "external_watched_episodes", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `provider` TEXT NOT NULL, `seriesId` TEXT NOT NULL, `videoId` TEXT NOT NULL, `syncedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `provider`, `seriesId`, `videoId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "provider", - "columnName": "provider", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "seriesId", - "columnName": "seriesId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "videoId", - "columnName": "videoId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "syncedAt", - "columnName": "syncedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "provider", - "seriesId", - "videoId" - ] - }, - "indices": [ - { - "name": "index_external_watched_episodes_profile_provider_series", - "unique": false, - "columnNames": [ - "profileId", - "provider", - "seriesId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_external_watched_episodes_profile_provider_series` ON `${TABLE_NAME}` (`profileId`, `provider`, `seriesId`)" - } - ] - } - ], - "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, 'e9287e5a13def610a5b078a881b21a3b')" - ] - } -} \ No newline at end of file diff --git a/app/schemas/com.fluxa.app.data.local.AppDatabase/8.json b/app/schemas/com.fluxa.app.data.local.AppDatabase/8.json deleted file mode 100644 index b8b48a2..0000000 --- a/app/schemas/com.fluxa.app.data.local.AppDatabase/8.json +++ /dev/null @@ -1,156 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 8, - "identityHash": "15c93c0248dd5a768eaf5168e80a22d7", - "entities": [ - { - "tableName": "watchlist", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `profileId` TEXT NOT NULL, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `poster` TEXT, `background` TEXT, `logo` TEXT, `description` TEXT, `rating` TEXT, `releaseInfo` TEXT, `addedAt` INTEGER NOT NULL, `isLiked` INTEGER, `timeOffset` INTEGER, `duration` INTEGER, `lastVideoId` TEXT, `lastStreamIndex` INTEGER, `lastEpisodeName` TEXT, `lastAudioTrackId` TEXT, `lastSubtitleTrackId` TEXT, `lastStreamUrl` TEXT, `lastStreamTitle` TEXT, `lastAudioLanguage` TEXT, `lastSubtitleLanguage` TEXT, `continueWatchingPoster` TEXT, `continueWatchingBackground` TEXT, PRIMARY KEY(`id`, `profileId`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "poster", - "columnName": "poster", - "affinity": "TEXT" - }, - { - "fieldPath": "background", - "columnName": "background", - "affinity": "TEXT" - }, - { - "fieldPath": "logo", - "columnName": "logo", - "affinity": "TEXT" - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT" - }, - { - "fieldPath": "rating", - "columnName": "rating", - "affinity": "TEXT" - }, - { - "fieldPath": "releaseInfo", - "columnName": "releaseInfo", - "affinity": "TEXT" - }, - { - "fieldPath": "addedAt", - "columnName": "addedAt", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isLiked", - "columnName": "isLiked", - "affinity": "INTEGER" - }, - { - "fieldPath": "timeOffset", - "columnName": "timeOffset", - "affinity": "INTEGER" - }, - { - "fieldPath": "duration", - "columnName": "duration", - "affinity": "INTEGER" - }, - { - "fieldPath": "lastVideoId", - "columnName": "lastVideoId", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamIndex", - "columnName": "lastStreamIndex", - "affinity": "INTEGER" - }, - { - "fieldPath": "lastEpisodeName", - "columnName": "lastEpisodeName", - "affinity": "TEXT" - }, - { - "fieldPath": "lastAudioTrackId", - "columnName": "lastAudioTrackId", - "affinity": "TEXT" - }, - { - "fieldPath": "lastSubtitleTrackId", - "columnName": "lastSubtitleTrackId", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamUrl", - "columnName": "lastStreamUrl", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamTitle", - "columnName": "lastStreamTitle", - "affinity": "TEXT" - }, - { - "fieldPath": "lastAudioLanguage", - "columnName": "lastAudioLanguage", - "affinity": "TEXT" - }, - { - "fieldPath": "lastSubtitleLanguage", - "columnName": "lastSubtitleLanguage", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingPoster", - "columnName": "continueWatchingPoster", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingBackground", - "columnName": "continueWatchingBackground", - "affinity": "TEXT" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id", - "profileId" - ] - } - } - ], - "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, '15c93c0248dd5a768eaf5168e80a22d7')" - ] - } -} \ No newline at end of file diff --git a/app/schemas/com.fluxa.app.data.local.AppDatabase/9.json b/app/schemas/com.fluxa.app.data.local.AppDatabase/9.json deleted file mode 100644 index 8f398d5..0000000 --- a/app/schemas/com.fluxa.app.data.local.AppDatabase/9.json +++ /dev/null @@ -1,310 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 9, - "identityHash": "2abcf22154237076f68a698eb41e6eee", - "entities": [ - { - "tableName": "content_items", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `poster` TEXT, `background` TEXT, `logo` TEXT, `description` TEXT, `rating` TEXT, `releaseInfo` TEXT, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "poster", - "columnName": "poster", - "affinity": "TEXT" - }, - { - "fieldPath": "background", - "columnName": "background", - "affinity": "TEXT" - }, - { - "fieldPath": "logo", - "columnName": "logo", - "affinity": "TEXT" - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT" - }, - { - "fieldPath": "rating", - "columnName": "rating", - "affinity": "TEXT" - }, - { - "fieldPath": "releaseInfo", - "columnName": "releaseInfo", - "affinity": "TEXT" - }, - { - "fieldPath": "updatedAt", - "columnName": "updatedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - } - }, - { - "tableName": "watchlist_entries", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `addedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "addedAt", - "columnName": "addedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - } - }, - { - "tableName": "playback_progress", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `videoId` TEXT, `timeOffset` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `lastStreamIndex` INTEGER, `lastEpisodeName` TEXT, `lastStreamUrl` TEXT, `lastStreamTitle` TEXT, `continueWatchingPoster` TEXT, `continueWatchingBackground` TEXT, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "videoId", - "columnName": "videoId", - "affinity": "TEXT" - }, - { - "fieldPath": "timeOffset", - "columnName": "timeOffset", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "duration", - "columnName": "duration", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "lastStreamIndex", - "columnName": "lastStreamIndex", - "affinity": "INTEGER" - }, - { - "fieldPath": "lastEpisodeName", - "columnName": "lastEpisodeName", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamUrl", - "columnName": "lastStreamUrl", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamTitle", - "columnName": "lastStreamTitle", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingPoster", - "columnName": "continueWatchingPoster", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingBackground", - "columnName": "continueWatchingBackground", - "affinity": "TEXT" - }, - { - "fieldPath": "updatedAt", - "columnName": "updatedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - } - }, - { - "tableName": "user_feedback", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `isLiked` INTEGER, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "isLiked", - "columnName": "isLiked", - "affinity": "INTEGER" - }, - { - "fieldPath": "updatedAt", - "columnName": "updatedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - } - }, - { - "tableName": "track_preferences", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `contentId` TEXT NOT NULL, `lastAudioLanguage` TEXT, `lastSubtitleLanguage` TEXT, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `contentId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "contentId", - "columnName": "contentId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lastAudioLanguage", - "columnName": "lastAudioLanguage", - "affinity": "TEXT" - }, - { - "fieldPath": "lastSubtitleLanguage", - "columnName": "lastSubtitleLanguage", - "affinity": "TEXT" - }, - { - "fieldPath": "updatedAt", - "columnName": "updatedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "contentId" - ] - } - }, - { - "tableName": "watched_episodes", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` TEXT NOT NULL, `seriesId` TEXT NOT NULL, `videoId` TEXT NOT NULL, `watchedAt` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `seriesId`, `videoId`))", - "fields": [ - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "seriesId", - "columnName": "seriesId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "videoId", - "columnName": "videoId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "watchedAt", - "columnName": "watchedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "profileId", - "seriesId", - "videoId" - ] - } - } - ], - "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, '2abcf22154237076f68a698eb41e6eee')" - ] - } -} \ No newline at end of file diff --git a/app/schemas/com.fluxa.app.ui.catalog.AppDatabase/8.json b/app/schemas/com.fluxa.app.ui.catalog.AppDatabase/8.json deleted file mode 100644 index b8b48a2..0000000 --- a/app/schemas/com.fluxa.app.ui.catalog.AppDatabase/8.json +++ /dev/null @@ -1,156 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 8, - "identityHash": "15c93c0248dd5a768eaf5168e80a22d7", - "entities": [ - { - "tableName": "watchlist", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `profileId` TEXT NOT NULL, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `poster` TEXT, `background` TEXT, `logo` TEXT, `description` TEXT, `rating` TEXT, `releaseInfo` TEXT, `addedAt` INTEGER NOT NULL, `isLiked` INTEGER, `timeOffset` INTEGER, `duration` INTEGER, `lastVideoId` TEXT, `lastStreamIndex` INTEGER, `lastEpisodeName` TEXT, `lastAudioTrackId` TEXT, `lastSubtitleTrackId` TEXT, `lastStreamUrl` TEXT, `lastStreamTitle` TEXT, `lastAudioLanguage` TEXT, `lastSubtitleLanguage` TEXT, `continueWatchingPoster` TEXT, `continueWatchingBackground` TEXT, PRIMARY KEY(`id`, `profileId`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "poster", - "columnName": "poster", - "affinity": "TEXT" - }, - { - "fieldPath": "background", - "columnName": "background", - "affinity": "TEXT" - }, - { - "fieldPath": "logo", - "columnName": "logo", - "affinity": "TEXT" - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT" - }, - { - "fieldPath": "rating", - "columnName": "rating", - "affinity": "TEXT" - }, - { - "fieldPath": "releaseInfo", - "columnName": "releaseInfo", - "affinity": "TEXT" - }, - { - "fieldPath": "addedAt", - "columnName": "addedAt", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isLiked", - "columnName": "isLiked", - "affinity": "INTEGER" - }, - { - "fieldPath": "timeOffset", - "columnName": "timeOffset", - "affinity": "INTEGER" - }, - { - "fieldPath": "duration", - "columnName": "duration", - "affinity": "INTEGER" - }, - { - "fieldPath": "lastVideoId", - "columnName": "lastVideoId", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamIndex", - "columnName": "lastStreamIndex", - "affinity": "INTEGER" - }, - { - "fieldPath": "lastEpisodeName", - "columnName": "lastEpisodeName", - "affinity": "TEXT" - }, - { - "fieldPath": "lastAudioTrackId", - "columnName": "lastAudioTrackId", - "affinity": "TEXT" - }, - { - "fieldPath": "lastSubtitleTrackId", - "columnName": "lastSubtitleTrackId", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamUrl", - "columnName": "lastStreamUrl", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamTitle", - "columnName": "lastStreamTitle", - "affinity": "TEXT" - }, - { - "fieldPath": "lastAudioLanguage", - "columnName": "lastAudioLanguage", - "affinity": "TEXT" - }, - { - "fieldPath": "lastSubtitleLanguage", - "columnName": "lastSubtitleLanguage", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingPoster", - "columnName": "continueWatchingPoster", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingBackground", - "columnName": "continueWatchingBackground", - "affinity": "TEXT" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id", - "profileId" - ] - } - } - ], - "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, '15c93c0248dd5a768eaf5168e80a22d7')" - ] - } -} \ No newline at end of file diff --git a/app/schemas/com.fluxa.app.ui.catalog.FluxaDatabase/7.json b/app/schemas/com.fluxa.app.ui.catalog.FluxaDatabase/7.json deleted file mode 100644 index 6444a8a..0000000 --- a/app/schemas/com.fluxa.app.ui.catalog.FluxaDatabase/7.json +++ /dev/null @@ -1,146 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 7, - "identityHash": "042e3197561264c60178ca25ea720e85", - "entities": [ - { - "tableName": "watchlist", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `profileId` TEXT NOT NULL, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `poster` TEXT, `background` TEXT, `logo` TEXT, `description` TEXT, `rating` TEXT, `releaseInfo` TEXT, `addedAt` INTEGER NOT NULL, `isLiked` INTEGER, `timeOffset` INTEGER, `duration` INTEGER, `lastVideoId` TEXT, `lastStreamIndex` INTEGER, `lastEpisodeName` TEXT, `lastAudioTrackId` TEXT, `lastSubtitleTrackId` TEXT, `lastStreamUrl` TEXT, `lastStreamTitle` TEXT, `lastAudioLanguage` TEXT, `lastSubtitleLanguage` TEXT, PRIMARY KEY(`id`, `profileId`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "poster", - "columnName": "poster", - "affinity": "TEXT" - }, - { - "fieldPath": "background", - "columnName": "background", - "affinity": "TEXT" - }, - { - "fieldPath": "logo", - "columnName": "logo", - "affinity": "TEXT" - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT" - }, - { - "fieldPath": "rating", - "columnName": "rating", - "affinity": "TEXT" - }, - { - "fieldPath": "releaseInfo", - "columnName": "releaseInfo", - "affinity": "TEXT" - }, - { - "fieldPath": "addedAt", - "columnName": "addedAt", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isLiked", - "columnName": "isLiked", - "affinity": "INTEGER" - }, - { - "fieldPath": "timeOffset", - "columnName": "timeOffset", - "affinity": "INTEGER" - }, - { - "fieldPath": "duration", - "columnName": "duration", - "affinity": "INTEGER" - }, - { - "fieldPath": "lastVideoId", - "columnName": "lastVideoId", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamIndex", - "columnName": "lastStreamIndex", - "affinity": "INTEGER" - }, - { - "fieldPath": "lastEpisodeName", - "columnName": "lastEpisodeName", - "affinity": "TEXT" - }, - { - "fieldPath": "lastAudioTrackId", - "columnName": "lastAudioTrackId", - "affinity": "TEXT" - }, - { - "fieldPath": "lastSubtitleTrackId", - "columnName": "lastSubtitleTrackId", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamUrl", - "columnName": "lastStreamUrl", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamTitle", - "columnName": "lastStreamTitle", - "affinity": "TEXT" - }, - { - "fieldPath": "lastAudioLanguage", - "columnName": "lastAudioLanguage", - "affinity": "TEXT" - }, - { - "fieldPath": "lastSubtitleLanguage", - "columnName": "lastSubtitleLanguage", - "affinity": "TEXT" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id", - "profileId" - ] - } - } - ], - "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, '042e3197561264c60178ca25ea720e85')" - ] - } -} \ No newline at end of file diff --git a/app/schemas/com.fluxa.app.ui.catalog.FluxaDatabase/8.json b/app/schemas/com.fluxa.app.ui.catalog.FluxaDatabase/8.json deleted file mode 100644 index b8b48a2..0000000 --- a/app/schemas/com.fluxa.app.ui.catalog.FluxaDatabase/8.json +++ /dev/null @@ -1,156 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 8, - "identityHash": "15c93c0248dd5a768eaf5168e80a22d7", - "entities": [ - { - "tableName": "watchlist", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `profileId` TEXT NOT NULL, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `poster` TEXT, `background` TEXT, `logo` TEXT, `description` TEXT, `rating` TEXT, `releaseInfo` TEXT, `addedAt` INTEGER NOT NULL, `isLiked` INTEGER, `timeOffset` INTEGER, `duration` INTEGER, `lastVideoId` TEXT, `lastStreamIndex` INTEGER, `lastEpisodeName` TEXT, `lastAudioTrackId` TEXT, `lastSubtitleTrackId` TEXT, `lastStreamUrl` TEXT, `lastStreamTitle` TEXT, `lastAudioLanguage` TEXT, `lastSubtitleLanguage` TEXT, `continueWatchingPoster` TEXT, `continueWatchingBackground` TEXT, PRIMARY KEY(`id`, `profileId`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "poster", - "columnName": "poster", - "affinity": "TEXT" - }, - { - "fieldPath": "background", - "columnName": "background", - "affinity": "TEXT" - }, - { - "fieldPath": "logo", - "columnName": "logo", - "affinity": "TEXT" - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT" - }, - { - "fieldPath": "rating", - "columnName": "rating", - "affinity": "TEXT" - }, - { - "fieldPath": "releaseInfo", - "columnName": "releaseInfo", - "affinity": "TEXT" - }, - { - "fieldPath": "addedAt", - "columnName": "addedAt", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isLiked", - "columnName": "isLiked", - "affinity": "INTEGER" - }, - { - "fieldPath": "timeOffset", - "columnName": "timeOffset", - "affinity": "INTEGER" - }, - { - "fieldPath": "duration", - "columnName": "duration", - "affinity": "INTEGER" - }, - { - "fieldPath": "lastVideoId", - "columnName": "lastVideoId", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamIndex", - "columnName": "lastStreamIndex", - "affinity": "INTEGER" - }, - { - "fieldPath": "lastEpisodeName", - "columnName": "lastEpisodeName", - "affinity": "TEXT" - }, - { - "fieldPath": "lastAudioTrackId", - "columnName": "lastAudioTrackId", - "affinity": "TEXT" - }, - { - "fieldPath": "lastSubtitleTrackId", - "columnName": "lastSubtitleTrackId", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamUrl", - "columnName": "lastStreamUrl", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamTitle", - "columnName": "lastStreamTitle", - "affinity": "TEXT" - }, - { - "fieldPath": "lastAudioLanguage", - "columnName": "lastAudioLanguage", - "affinity": "TEXT" - }, - { - "fieldPath": "lastSubtitleLanguage", - "columnName": "lastSubtitleLanguage", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingPoster", - "columnName": "continueWatchingPoster", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingBackground", - "columnName": "continueWatchingBackground", - "affinity": "TEXT" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id", - "profileId" - ] - } - } - ], - "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, '15c93c0248dd5a768eaf5168e80a22d7')" - ] - } -} \ No newline at end of file diff --git a/app/src/main/java/com/fluxa/app/di/DatabaseModule.kt b/app/src/main/java/com/fluxa/app/di/DatabaseModule.kt index 5495989..0240b8a 100644 --- a/app/src/main/java/com/fluxa/app/di/DatabaseModule.kt +++ b/app/src/main/java/com/fluxa/app/di/DatabaseModule.kt @@ -4,7 +4,6 @@ import android.content.Context import androidx.room.Room import com.fluxa.app.data.local.AppDatabase import com.fluxa.app.data.local.WatchlistDao -import com.fluxa.app.data.local.WatchlistManager import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -31,10 +30,4 @@ object DatabaseModule { fun provideWatchlistDao(database: AppDatabase): WatchlistDao { return database.watchlistDao() } - - @Provides - @Singleton - fun provideWatchlistManager(dao: WatchlistDao): WatchlistManager { - return WatchlistManager(dao) - } } diff --git a/data/build.gradle.kts b/data/build.gradle.kts index cd501ce..5b15806 100644 --- a/data/build.gradle.kts +++ b/data/build.gradle.kts @@ -72,7 +72,7 @@ val generateFluxaCoreUniFfiBindings by tasks.registering(Exec::class) { outputs.dir(uniffiKotlinOutDir) } -tasks.matching { it.name == "preBuild" || it.name == "compileKotlinDesktop" }.configureEach { +tasks.matching { it.name == "preBuild" || it.name == "compileKotlinDesktop" || it.name == "kspKotlinDesktop" }.configureEach { dependsOn(generateFluxaCoreUniFfiBindings) } @@ -96,6 +96,7 @@ kotlin { implementation(project(":core")) implementation(libs.kotlinx.serialization.json) implementation(libs.kotlinx.coroutines.core) + implementation(libs.androidx.room.runtime) } } commonTest.dependencies { @@ -123,13 +124,14 @@ kotlin { implementation(libs.bundles.coroutines) implementation(libs.androidx.work.runtime) implementation(libs.androidx.hilt.work) - implementation(libs.androidx.room.runtime) - implementation(libs.androidx.room.ktx) implementation(libs.okhttp.doh) } } val desktopMain by getting { dependsOn(jvmCommonMain) + dependencies { + implementation(libs.androidx.sqlite.bundled) + } } val nativeMain by creating { dependsOn(commonMain.get()) } val appleMain by creating { dependsOn(nativeMain) } @@ -145,4 +147,9 @@ kotlin { dependencies { add("kspAndroid", libs.androidx.hilt.compiler) add("kspAndroid", libs.androidx.room.compiler) + add("kspDesktop", libs.androidx.room.compiler) + add("kspIosSimulatorArm64", libs.androidx.room.compiler) + add("kspIosArm64", libs.androidx.room.compiler) + add("kspTvosArm64", libs.androidx.room.compiler) + add("kspTvosSimulatorArm64", libs.androidx.room.compiler) } diff --git a/data/schemas/com.fluxa.app.ui.catalog.AppDatabase/8.json b/data/schemas/com.fluxa.app.ui.catalog.AppDatabase/8.json deleted file mode 100644 index b8b48a2..0000000 --- a/data/schemas/com.fluxa.app.ui.catalog.AppDatabase/8.json +++ /dev/null @@ -1,156 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 8, - "identityHash": "15c93c0248dd5a768eaf5168e80a22d7", - "entities": [ - { - "tableName": "watchlist", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `profileId` TEXT NOT NULL, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `poster` TEXT, `background` TEXT, `logo` TEXT, `description` TEXT, `rating` TEXT, `releaseInfo` TEXT, `addedAt` INTEGER NOT NULL, `isLiked` INTEGER, `timeOffset` INTEGER, `duration` INTEGER, `lastVideoId` TEXT, `lastStreamIndex` INTEGER, `lastEpisodeName` TEXT, `lastAudioTrackId` TEXT, `lastSubtitleTrackId` TEXT, `lastStreamUrl` TEXT, `lastStreamTitle` TEXT, `lastAudioLanguage` TEXT, `lastSubtitleLanguage` TEXT, `continueWatchingPoster` TEXT, `continueWatchingBackground` TEXT, PRIMARY KEY(`id`, `profileId`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "poster", - "columnName": "poster", - "affinity": "TEXT" - }, - { - "fieldPath": "background", - "columnName": "background", - "affinity": "TEXT" - }, - { - "fieldPath": "logo", - "columnName": "logo", - "affinity": "TEXT" - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT" - }, - { - "fieldPath": "rating", - "columnName": "rating", - "affinity": "TEXT" - }, - { - "fieldPath": "releaseInfo", - "columnName": "releaseInfo", - "affinity": "TEXT" - }, - { - "fieldPath": "addedAt", - "columnName": "addedAt", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isLiked", - "columnName": "isLiked", - "affinity": "INTEGER" - }, - { - "fieldPath": "timeOffset", - "columnName": "timeOffset", - "affinity": "INTEGER" - }, - { - "fieldPath": "duration", - "columnName": "duration", - "affinity": "INTEGER" - }, - { - "fieldPath": "lastVideoId", - "columnName": "lastVideoId", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamIndex", - "columnName": "lastStreamIndex", - "affinity": "INTEGER" - }, - { - "fieldPath": "lastEpisodeName", - "columnName": "lastEpisodeName", - "affinity": "TEXT" - }, - { - "fieldPath": "lastAudioTrackId", - "columnName": "lastAudioTrackId", - "affinity": "TEXT" - }, - { - "fieldPath": "lastSubtitleTrackId", - "columnName": "lastSubtitleTrackId", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamUrl", - "columnName": "lastStreamUrl", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamTitle", - "columnName": "lastStreamTitle", - "affinity": "TEXT" - }, - { - "fieldPath": "lastAudioLanguage", - "columnName": "lastAudioLanguage", - "affinity": "TEXT" - }, - { - "fieldPath": "lastSubtitleLanguage", - "columnName": "lastSubtitleLanguage", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingPoster", - "columnName": "continueWatchingPoster", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingBackground", - "columnName": "continueWatchingBackground", - "affinity": "TEXT" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id", - "profileId" - ] - } - } - ], - "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, '15c93c0248dd5a768eaf5168e80a22d7')" - ] - } -} \ No newline at end of file diff --git a/data/schemas/com.fluxa.app.ui.catalog.FluxaDatabase/7.json b/data/schemas/com.fluxa.app.ui.catalog.FluxaDatabase/7.json deleted file mode 100644 index 6444a8a..0000000 --- a/data/schemas/com.fluxa.app.ui.catalog.FluxaDatabase/7.json +++ /dev/null @@ -1,146 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 7, - "identityHash": "042e3197561264c60178ca25ea720e85", - "entities": [ - { - "tableName": "watchlist", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `profileId` TEXT NOT NULL, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `poster` TEXT, `background` TEXT, `logo` TEXT, `description` TEXT, `rating` TEXT, `releaseInfo` TEXT, `addedAt` INTEGER NOT NULL, `isLiked` INTEGER, `timeOffset` INTEGER, `duration` INTEGER, `lastVideoId` TEXT, `lastStreamIndex` INTEGER, `lastEpisodeName` TEXT, `lastAudioTrackId` TEXT, `lastSubtitleTrackId` TEXT, `lastStreamUrl` TEXT, `lastStreamTitle` TEXT, `lastAudioLanguage` TEXT, `lastSubtitleLanguage` TEXT, PRIMARY KEY(`id`, `profileId`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "poster", - "columnName": "poster", - "affinity": "TEXT" - }, - { - "fieldPath": "background", - "columnName": "background", - "affinity": "TEXT" - }, - { - "fieldPath": "logo", - "columnName": "logo", - "affinity": "TEXT" - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT" - }, - { - "fieldPath": "rating", - "columnName": "rating", - "affinity": "TEXT" - }, - { - "fieldPath": "releaseInfo", - "columnName": "releaseInfo", - "affinity": "TEXT" - }, - { - "fieldPath": "addedAt", - "columnName": "addedAt", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isLiked", - "columnName": "isLiked", - "affinity": "INTEGER" - }, - { - "fieldPath": "timeOffset", - "columnName": "timeOffset", - "affinity": "INTEGER" - }, - { - "fieldPath": "duration", - "columnName": "duration", - "affinity": "INTEGER" - }, - { - "fieldPath": "lastVideoId", - "columnName": "lastVideoId", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamIndex", - "columnName": "lastStreamIndex", - "affinity": "INTEGER" - }, - { - "fieldPath": "lastEpisodeName", - "columnName": "lastEpisodeName", - "affinity": "TEXT" - }, - { - "fieldPath": "lastAudioTrackId", - "columnName": "lastAudioTrackId", - "affinity": "TEXT" - }, - { - "fieldPath": "lastSubtitleTrackId", - "columnName": "lastSubtitleTrackId", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamUrl", - "columnName": "lastStreamUrl", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamTitle", - "columnName": "lastStreamTitle", - "affinity": "TEXT" - }, - { - "fieldPath": "lastAudioLanguage", - "columnName": "lastAudioLanguage", - "affinity": "TEXT" - }, - { - "fieldPath": "lastSubtitleLanguage", - "columnName": "lastSubtitleLanguage", - "affinity": "TEXT" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id", - "profileId" - ] - } - } - ], - "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, '042e3197561264c60178ca25ea720e85')" - ] - } -} \ No newline at end of file diff --git a/data/schemas/com.fluxa.app.ui.catalog.FluxaDatabase/8.json b/data/schemas/com.fluxa.app.ui.catalog.FluxaDatabase/8.json deleted file mode 100644 index b8b48a2..0000000 --- a/data/schemas/com.fluxa.app.ui.catalog.FluxaDatabase/8.json +++ /dev/null @@ -1,156 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 8, - "identityHash": "15c93c0248dd5a768eaf5168e80a22d7", - "entities": [ - { - "tableName": "watchlist", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `profileId` TEXT NOT NULL, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `poster` TEXT, `background` TEXT, `logo` TEXT, `description` TEXT, `rating` TEXT, `releaseInfo` TEXT, `addedAt` INTEGER NOT NULL, `isLiked` INTEGER, `timeOffset` INTEGER, `duration` INTEGER, `lastVideoId` TEXT, `lastStreamIndex` INTEGER, `lastEpisodeName` TEXT, `lastAudioTrackId` TEXT, `lastSubtitleTrackId` TEXT, `lastStreamUrl` TEXT, `lastStreamTitle` TEXT, `lastAudioLanguage` TEXT, `lastSubtitleLanguage` TEXT, `continueWatchingPoster` TEXT, `continueWatchingBackground` TEXT, PRIMARY KEY(`id`, `profileId`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "profileId", - "columnName": "profileId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "poster", - "columnName": "poster", - "affinity": "TEXT" - }, - { - "fieldPath": "background", - "columnName": "background", - "affinity": "TEXT" - }, - { - "fieldPath": "logo", - "columnName": "logo", - "affinity": "TEXT" - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT" - }, - { - "fieldPath": "rating", - "columnName": "rating", - "affinity": "TEXT" - }, - { - "fieldPath": "releaseInfo", - "columnName": "releaseInfo", - "affinity": "TEXT" - }, - { - "fieldPath": "addedAt", - "columnName": "addedAt", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isLiked", - "columnName": "isLiked", - "affinity": "INTEGER" - }, - { - "fieldPath": "timeOffset", - "columnName": "timeOffset", - "affinity": "INTEGER" - }, - { - "fieldPath": "duration", - "columnName": "duration", - "affinity": "INTEGER" - }, - { - "fieldPath": "lastVideoId", - "columnName": "lastVideoId", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamIndex", - "columnName": "lastStreamIndex", - "affinity": "INTEGER" - }, - { - "fieldPath": "lastEpisodeName", - "columnName": "lastEpisodeName", - "affinity": "TEXT" - }, - { - "fieldPath": "lastAudioTrackId", - "columnName": "lastAudioTrackId", - "affinity": "TEXT" - }, - { - "fieldPath": "lastSubtitleTrackId", - "columnName": "lastSubtitleTrackId", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamUrl", - "columnName": "lastStreamUrl", - "affinity": "TEXT" - }, - { - "fieldPath": "lastStreamTitle", - "columnName": "lastStreamTitle", - "affinity": "TEXT" - }, - { - "fieldPath": "lastAudioLanguage", - "columnName": "lastAudioLanguage", - "affinity": "TEXT" - }, - { - "fieldPath": "lastSubtitleLanguage", - "columnName": "lastSubtitleLanguage", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingPoster", - "columnName": "continueWatchingPoster", - "affinity": "TEXT" - }, - { - "fieldPath": "continueWatchingBackground", - "columnName": "continueWatchingBackground", - "affinity": "TEXT" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id", - "profileId" - ] - } - } - ], - "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, '15c93c0248dd5a768eaf5168e80a22d7')" - ] - } -} \ No newline at end of file diff --git a/data/src/androidMain/kotlin/com/fluxa/app/data/local/WatchlistDao.kt b/data/src/commonMain/kotlin/com/fluxa/app/data/local/WatchlistDao.kt similarity index 99% rename from data/src/androidMain/kotlin/com/fluxa/app/data/local/WatchlistDao.kt rename to data/src/commonMain/kotlin/com/fluxa/app/data/local/WatchlistDao.kt index af46fae..b7e6b86 100644 --- a/data/src/androidMain/kotlin/com/fluxa/app/data/local/WatchlistDao.kt +++ b/data/src/commonMain/kotlin/com/fluxa/app/data/local/WatchlistDao.kt @@ -9,8 +9,6 @@ import androidx.room.OnConflictStrategy import androidx.room.PrimaryKey import androidx.room.Query import androidx.room.RoomDatabase -import androidx.room.migration.Migration -import androidx.sqlite.db.SupportSQLiteDatabase import kotlinx.coroutines.flow.Flow @Dao diff --git a/data/src/androidMain/kotlin/com/fluxa/app/data/local/WatchlistDatabase.kt b/data/src/commonMain/kotlin/com/fluxa/app/data/local/WatchlistDatabase.kt similarity index 73% rename from data/src/androidMain/kotlin/com/fluxa/app/data/local/WatchlistDatabase.kt rename to data/src/commonMain/kotlin/com/fluxa/app/data/local/WatchlistDatabase.kt index 756ffe3..5906fb1 100644 --- a/data/src/androidMain/kotlin/com/fluxa/app/data/local/WatchlistDatabase.kt +++ b/data/src/commonMain/kotlin/com/fluxa/app/data/local/WatchlistDatabase.kt @@ -1,7 +1,9 @@ package com.fluxa.app.data.local +import androidx.room.ConstructedBy import androidx.room.Database import androidx.room.RoomDatabase +import androidx.room.RoomDatabaseConstructor @Database( entities = [ @@ -20,6 +22,11 @@ import androidx.room.RoomDatabase version = 17, exportSchema = true ) +@ConstructedBy(AppDatabaseConstructor::class) abstract class AppDatabase : RoomDatabase() { abstract fun watchlistDao(): WatchlistDao } + +expect object AppDatabaseConstructor : RoomDatabaseConstructor { + override fun initialize(): AppDatabase +} diff --git a/data/src/androidMain/kotlin/com/fluxa/app/data/local/WatchlistEntities.kt b/data/src/commonMain/kotlin/com/fluxa/app/data/local/WatchlistEntities.kt similarity index 87% rename from data/src/androidMain/kotlin/com/fluxa/app/data/local/WatchlistEntities.kt rename to data/src/commonMain/kotlin/com/fluxa/app/data/local/WatchlistEntities.kt index e14fe2c..25386b6 100644 --- a/data/src/androidMain/kotlin/com/fluxa/app/data/local/WatchlistEntities.kt +++ b/data/src/commonMain/kotlin/com/fluxa/app/data/local/WatchlistEntities.kt @@ -9,8 +9,7 @@ import androidx.room.OnConflictStrategy import androidx.room.PrimaryKey import androidx.room.Query import androidx.room.RoomDatabase -import androidx.room.migration.Migration -import androidx.sqlite.db.SupportSQLiteDatabase +import com.fluxa.app.common.epochMillisNow import kotlinx.coroutines.flow.Flow @Entity(tableName = "content_items", primaryKeys = ["profileId", "contentId"]) @@ -25,7 +24,7 @@ data class ContentItemEntity( val description: String?, val rating: String?, val releaseInfo: String?, - val updatedAt: Long = System.currentTimeMillis() + val updatedAt: Long = epochMillisNow() ) @Entity( @@ -36,8 +35,8 @@ data class ContentItemEntity( data class WatchlistEntryEntity( val profileId: String, val contentId: String, - val addedAt: Long = System.currentTimeMillis(), - val updatedAt: Long = System.currentTimeMillis() + val addedAt: Long = epochMillisNow(), + val updatedAt: Long = epochMillisNow() ) @Entity( @@ -47,7 +46,7 @@ data class WatchlistEntryEntity( data class WatchlistRemovalEntity( val profileId: String, val contentId: String, - val removedAt: Long = System.currentTimeMillis() + val removedAt: Long = epochMillisNow() ) @Entity( @@ -68,7 +67,7 @@ data class PlaybackProgressEntity( val lastBingeGroup: String? = null, val continueWatchingPoster: String?, val continueWatchingBackground: String?, - val updatedAt: Long = System.currentTimeMillis() + val updatedAt: Long = epochMillisNow() ) @Entity( @@ -80,7 +79,7 @@ data class UserFeedbackEntity( val profileId: String, val contentId: String, val isLiked: Boolean?, - val updatedAt: Long = System.currentTimeMillis() + val updatedAt: Long = epochMillisNow() ) @Entity(tableName = "track_preferences", primaryKeys = ["profileId", "contentId"]) @@ -89,7 +88,7 @@ data class TrackPreferenceEntity( val contentId: String, val lastAudioLanguage: String?, val lastSubtitleLanguage: String?, - val updatedAt: Long = System.currentTimeMillis() + val updatedAt: Long = epochMillisNow() ) @Entity( @@ -101,8 +100,8 @@ data class WatchedEpisodeEntity( val profileId: String, val seriesId: String, val videoId: String, - val watchedAt: Long = System.currentTimeMillis(), - val updatedAt: Long = System.currentTimeMillis() + val watchedAt: Long = epochMillisNow(), + val updatedAt: Long = epochMillisNow() ) @Entity( @@ -113,7 +112,7 @@ data class WatchedEpisodeRemovalEntity( val profileId: String, val seriesId: String, val videoId: String, - val removedAt: Long = System.currentTimeMillis() + val removedAt: Long = epochMillisNow() ) @Entity( @@ -130,7 +129,7 @@ data class WatchedContentDurationEntity( val contentId: String, val videoId: String, val duration: Long, - val watchedAt: Long = System.currentTimeMillis() + val watchedAt: Long = epochMillisNow() ) @Entity( @@ -158,7 +157,7 @@ data class ExternalPlaybackProgressEntity( val reason: String?, val continueWatchingPoster: String?, val continueWatchingBackground: String?, - val syncedAt: Long = System.currentTimeMillis() + val syncedAt: Long = epochMillisNow() ) @Entity( @@ -171,7 +170,7 @@ data class ExternalWatchedEpisodeEntity( val provider: String, val seriesId: String, val videoId: String, - val syncedAt: Long = System.currentTimeMillis() + val syncedAt: Long = epochMillisNow() ) data class ContentStateRow( diff --git a/data/src/desktopMain/kotlin/com/fluxa/app/data/local/DesktopAppDatabase.kt b/data/src/desktopMain/kotlin/com/fluxa/app/data/local/DesktopAppDatabase.kt new file mode 100644 index 0000000..5899cbc --- /dev/null +++ b/data/src/desktopMain/kotlin/com/fluxa/app/data/local/DesktopAppDatabase.kt @@ -0,0 +1,18 @@ +package com.fluxa.app.data.local + +import androidx.room.Room +import androidx.sqlite.driver.bundled.BundledSQLiteDriver +import kotlinx.coroutines.Dispatchers +import java.io.File + +fun buildDesktopAppDatabase(databaseFile: File): AppDatabase { + databaseFile.parentFile?.mkdirs() + return Room.databaseBuilder( + name = databaseFile.absolutePath, + factory = { AppDatabaseConstructor.initialize() } + ) + .setDriver(BundledSQLiteDriver()) + .setQueryCoroutineContext(Dispatchers.IO) + .fallbackToDestructiveMigration(false) + .build() +} diff --git a/data/src/jvmCommonMain/kotlin/com/fluxa/app/core/StremioId.kt b/data/src/jvmCommonMain/kotlin/com/fluxa/app/core/StremioId.kt index d7fba11..1790597 100644 --- a/data/src/jvmCommonMain/kotlin/com/fluxa/app/core/StremioId.kt +++ b/data/src/jvmCommonMain/kotlin/com/fluxa/app/core/StremioId.kt @@ -2,7 +2,7 @@ package com.fluxa.app.core import com.fluxa.app.core.rust.FluxaCoreNative -internal object StremioId { +object StremioId { fun imdbId(id: String?): String? = id?.let(FluxaCoreNative::contentImdbId) fun baseContentId(id: String): String = FluxaCoreNative.contentBaseId(id) diff --git a/data/src/androidMain/kotlin/com/fluxa/app/data/local/WatchlistManager.kt b/data/src/jvmCommonMain/kotlin/com/fluxa/app/data/local/WatchlistManager.kt similarity index 99% rename from data/src/androidMain/kotlin/com/fluxa/app/data/local/WatchlistManager.kt rename to data/src/jvmCommonMain/kotlin/com/fluxa/app/data/local/WatchlistManager.kt index 75ee670..da81452 100644 --- a/data/src/androidMain/kotlin/com/fluxa/app/data/local/WatchlistManager.kt +++ b/data/src/jvmCommonMain/kotlin/com/fluxa/app/data/local/WatchlistManager.kt @@ -1,7 +1,5 @@ package com.fluxa.app.data.local -import android.content.Context -import androidx.room.Room import com.fluxa.app.data.remote.Meta import com.fluxa.app.data.remote.Video import com.fluxa.app.ui.catalog.isUpNextContinueItem diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 17f4587..fb93abd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -72,6 +72,7 @@ androidx-browser = { group = "androidx.browser", na androidx-room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" } androidx-room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" } androidx-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" } +androidx-sqlite-bundled = { group = "androidx.sqlite", name = "sqlite-bundled", version = "2.6.2" } # Compose (versions managed by BOM — no version.ref here) androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }