From 7485b6eea8edd22a5122e55c7859f11d7f9fb22d Mon Sep 17 00:00:00 2001 From: rainxchzed Date: Sat, 28 Mar 2026 16:29:10 +0500 Subject: [PATCH 1/2] locale: add translations for "Tweaks" feature across multiple languages - Add localized strings for `bottom_nav_profile_tweaks` and `tweaks_title`. - Provide translations for Bengali, Hindi, Italian, Spanish, Arabic, French, Polish, Russian, Japanese, Korean, Turkish, and Chinese (Simplified). --- .../src/commonMain/composeResources/values-ar/strings-ar.xml | 3 +++ .../src/commonMain/composeResources/values-bn/strings-bn.xml | 3 +++ .../src/commonMain/composeResources/values-es/strings-es.xml | 3 +++ .../src/commonMain/composeResources/values-fr/strings-fr.xml | 3 +++ .../src/commonMain/composeResources/values-hi/strings-hi.xml | 3 +++ .../src/commonMain/composeResources/values-it/strings-it.xml | 3 +++ .../src/commonMain/composeResources/values-ja/strings-ja.xml | 3 +++ .../src/commonMain/composeResources/values-ko/strings-ko.xml | 3 +++ .../src/commonMain/composeResources/values-pl/strings-pl.xml | 3 +++ .../src/commonMain/composeResources/values-ru/strings-ru.xml | 3 +++ .../src/commonMain/composeResources/values-tr/strings-tr.xml | 3 +++ .../composeResources/values-zh-rCN/strings-zh-rCN.xml | 3 +++ 12 files changed, 36 insertions(+) diff --git a/core/presentation/src/commonMain/composeResources/values-ar/strings-ar.xml b/core/presentation/src/commonMain/composeResources/values-ar/strings-ar.xml index 9ad3705a..bde53b73 100644 --- a/core/presentation/src/commonMain/composeResources/values-ar/strings-ar.xml +++ b/core/presentation/src/commonMain/composeResources/values-ar/strings-ar.xml @@ -618,4 +618,7 @@ عمليات البحث الأخيرة مسح الكل إزالة + + تعديلات + تعديلات diff --git a/core/presentation/src/commonMain/composeResources/values-bn/strings-bn.xml b/core/presentation/src/commonMain/composeResources/values-bn/strings-bn.xml index 234f1826..a2cc73d5 100644 --- a/core/presentation/src/commonMain/composeResources/values-bn/strings-bn.xml +++ b/core/presentation/src/commonMain/composeResources/values-bn/strings-bn.xml @@ -617,4 +617,7 @@ সাম্প্রতিক অনুসন্ধান সব মুছুন সরান + + টুইকস + টুইকস diff --git a/core/presentation/src/commonMain/composeResources/values-es/strings-es.xml b/core/presentation/src/commonMain/composeResources/values-es/strings-es.xml index 910a2b25..9b16c575 100644 --- a/core/presentation/src/commonMain/composeResources/values-es/strings-es.xml +++ b/core/presentation/src/commonMain/composeResources/values-es/strings-es.xml @@ -578,4 +578,7 @@ Búsquedas recientes Borrar todo Eliminar + + Ajustes + Ajustes \ No newline at end of file diff --git a/core/presentation/src/commonMain/composeResources/values-fr/strings-fr.xml b/core/presentation/src/commonMain/composeResources/values-fr/strings-fr.xml index c37053d8..df656133 100644 --- a/core/presentation/src/commonMain/composeResources/values-fr/strings-fr.xml +++ b/core/presentation/src/commonMain/composeResources/values-fr/strings-fr.xml @@ -579,4 +579,7 @@ Recherches récentes Tout effacer Supprimer + + Réglages + Réglages \ No newline at end of file diff --git a/core/presentation/src/commonMain/composeResources/values-hi/strings-hi.xml b/core/presentation/src/commonMain/composeResources/values-hi/strings-hi.xml index 6fb6202b..eb28845d 100644 --- a/core/presentation/src/commonMain/composeResources/values-hi/strings-hi.xml +++ b/core/presentation/src/commonMain/composeResources/values-hi/strings-hi.xml @@ -616,4 +616,7 @@ हाल की खोजें सभी साफ करें हटाएँ + + ट्वीक्स + ट्वीक्स diff --git a/core/presentation/src/commonMain/composeResources/values-it/strings-it.xml b/core/presentation/src/commonMain/composeResources/values-it/strings-it.xml index 1591c55f..f999430e 100644 --- a/core/presentation/src/commonMain/composeResources/values-it/strings-it.xml +++ b/core/presentation/src/commonMain/composeResources/values-it/strings-it.xml @@ -617,4 +617,7 @@ Ricerche recenti Cancella tutto Rimuovi + + Modifiche + Modifiche \ No newline at end of file diff --git a/core/presentation/src/commonMain/composeResources/values-ja/strings-ja.xml b/core/presentation/src/commonMain/composeResources/values-ja/strings-ja.xml index 13f3c69d..e1e109db 100644 --- a/core/presentation/src/commonMain/composeResources/values-ja/strings-ja.xml +++ b/core/presentation/src/commonMain/composeResources/values-ja/strings-ja.xml @@ -580,4 +580,7 @@ 最近の検索 すべてクリア 削除 + + 調整 + 調整 \ No newline at end of file diff --git a/core/presentation/src/commonMain/composeResources/values-ko/strings-ko.xml b/core/presentation/src/commonMain/composeResources/values-ko/strings-ko.xml index 6d81402b..36a1c48a 100644 --- a/core/presentation/src/commonMain/composeResources/values-ko/strings-ko.xml +++ b/core/presentation/src/commonMain/composeResources/values-ko/strings-ko.xml @@ -615,4 +615,7 @@ 최근 검색 모두 지우기 삭제 + + 조정 + 조정 \ No newline at end of file diff --git a/core/presentation/src/commonMain/composeResources/values-pl/strings-pl.xml b/core/presentation/src/commonMain/composeResources/values-pl/strings-pl.xml index 804124d1..c8d3a25a 100644 --- a/core/presentation/src/commonMain/composeResources/values-pl/strings-pl.xml +++ b/core/presentation/src/commonMain/composeResources/values-pl/strings-pl.xml @@ -581,4 +581,7 @@ Ostatnie wyszukiwania Wyczyść wszystko Usuń + + Ustawienia + Ustawienia \ No newline at end of file diff --git a/core/presentation/src/commonMain/composeResources/values-ru/strings-ru.xml b/core/presentation/src/commonMain/composeResources/values-ru/strings-ru.xml index 233021e1..37f4cbbe 100644 --- a/core/presentation/src/commonMain/composeResources/values-ru/strings-ru.xml +++ b/core/presentation/src/commonMain/composeResources/values-ru/strings-ru.xml @@ -581,4 +581,7 @@ Недавние поиски Очистить всё Удалить + + Настройки + Настройки \ No newline at end of file diff --git a/core/presentation/src/commonMain/composeResources/values-tr/strings-tr.xml b/core/presentation/src/commonMain/composeResources/values-tr/strings-tr.xml index da2134e7..cc6f4168 100644 --- a/core/presentation/src/commonMain/composeResources/values-tr/strings-tr.xml +++ b/core/presentation/src/commonMain/composeResources/values-tr/strings-tr.xml @@ -615,4 +615,7 @@ Son aramalar Tümünü temizle Kaldır + + İnce Ayarlar + İnce Ayarlar diff --git a/core/presentation/src/commonMain/composeResources/values-zh-rCN/strings-zh-rCN.xml b/core/presentation/src/commonMain/composeResources/values-zh-rCN/strings-zh-rCN.xml index 705e0ba9..2987fd8c 100644 --- a/core/presentation/src/commonMain/composeResources/values-zh-rCN/strings-zh-rCN.xml +++ b/core/presentation/src/commonMain/composeResources/values-zh-rCN/strings-zh-rCN.xml @@ -581,4 +581,7 @@ 最近搜索 清除全部 移除 + + 调整 + 调整 \ No newline at end of file From 3163f60b4d25cf9915342918f8f787601249cc07 Mon Sep 17 00:00:00 2001 From: rainxchzed Date: Sat, 28 Mar 2026 16:57:47 +0500 Subject: [PATCH 2/2] feat: implement per-app pre-release update settings - Add `includePreReleases` column to `installed_apps` table in database version 8. - Implement database migration `MIGRATION_7_8` to support the new schema change. - Update `InstalledApp` domain and UI models to include the pre-release preference. - Add a "Pre-releases" toggle switch to the app details UI in the apps list. - Implement `OnTogglePreReleases` action in `AppsViewModel` to update settings and trigger immediate update checks. - Refactor `AppsRepository` and `InstalledAppsRepository` to pass the `includePreReleases` flag when fetching the latest releases from GitHub. - Add localized strings for "Pre-releases" in Arabic, Turkish, Bengali, Hindi, Italian, Spanish, French, Polish, Russian, Japanese, Korean, and Chinese (Simplified). - Remove unnecessary `TweaksRepository` dependency from `InstalledAppsRepositoryImpl` and `SharedModule`. --- .../baselineProfiles/0/composeApp-release.dm | Bin 11370 -> 11283 bytes .../baselineProfiles/1/composeApp-release.dm | Bin 11340 -> 11276 bytes .../8.json | 592 ++++++++++++++++++ .../core/data/local/db/initDatabase.kt | 2 + .../data/local/db/migrations/MIGRATION_7_8.kt | 13 + .../zed/rainxch/core/data/di/SharedModule.kt | 1 - .../rainxch/core/data/local/db/AppDatabase.kt | 2 +- .../core/data/local/db/dao/InstalledAppDao.kt | 3 + .../local/db/entities/InstalledAppEntity.kt | 1 + .../core/data/mappers/InstalledAppsMappers.kt | 2 + .../repository/InstalledAppsRepositoryImpl.kt | 13 +- .../rainxch/core/domain/model/InstalledApp.kt | 1 + .../repository/InstalledAppsRepository.kt | 5 + .../composeResources/values-ar/strings-ar.xml | 1 + .../composeResources/values-bn/strings-bn.xml | 1 + .../composeResources/values-es/strings-es.xml | 1 + .../composeResources/values-fr/strings-fr.xml | 1 + .../composeResources/values-hi/strings-hi.xml | 1 + .../composeResources/values-it/strings-it.xml | 1 + .../composeResources/values-ja/strings-ja.xml | 1 + .../composeResources/values-ko/strings-ko.xml | 1 + .../composeResources/values-pl/strings-pl.xml | 1 + .../composeResources/values-ru/strings-ru.xml | 1 + .../composeResources/values-tr/strings-tr.xml | 1 + .../values-zh-rCN/strings-zh-rCN.xml | 1 + .../composeResources/values/strings.xml | 3 + .../data/repository/AppsRepositoryImpl.kt | 5 +- .../apps/domain/repository/AppsRepository.kt | 1 + .../rainxch/apps/presentation/AppsAction.kt | 3 + .../zed/rainxch/apps/presentation/AppsRoot.kt | 26 +- .../apps/presentation/AppsViewModel.kt | 16 + .../mappers/InstalledAppMapper.kt | 2 + .../apps/presentation/model/InstalledAppUi.kt | 1 + 33 files changed, 695 insertions(+), 9 deletions(-) create mode 100644 core/data/schemas/zed.rainxch.core.data.local.db.AppDatabase/8.json create mode 100644 core/data/src/androidMain/kotlin/zed/rainxch/core/data/local/db/migrations/MIGRATION_7_8.kt diff --git a/composeApp/release/baselineProfiles/0/composeApp-release.dm b/composeApp/release/baselineProfiles/0/composeApp-release.dm index d8abd1c20b6802f842b43845e3d45c9575ab6fd3..838e163fbe7717dbd1cad78a359d5b4a201541ca 100644 GIT binary patch literal 11283 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 literal 11370 zcmZ{~cTf{R*Z&Km1f>K8L202VNS6+wL3<2{Yd#@7g8$hl@h=MfPk!%Tbo}RH_wn#{>G1xqJ%#^rcV;}i z;Y&Qcdw8$xewTW^#>0c(;o%YEnc0~*J6kyOm|Gya)*`SF03O~XB_1Bh|6Sn!PX&R0 zpsQ?8Ax(a8*&cB)9Y9VJqD~$vOBC!)6=XWHZ!$Y~vqfLkHVBCPqDAKyK*`<+DBD58(9md636%JGiB3cR&Q3rv1$XJU@OK3ck^ z^hqCBsTduEwg+v1CFO!fYbfRo9=k$TliV*}skF6n4IXIgg3jHFD~YH-@tP*-7ga2o z{9y_e@8{oD2`?uBM32HOvW-Can-5QOtGcQ9h{vW^NtS|Zk3B6Sy5pLy23sWh*%yq` zjkImDU05=_^4}pTVVitYwJ3!?PFxJu2^5I&(e@1rH`rw5ChMT#NbsyvRpa!gU67*h z7eMJ(UEX9V6?|EPKK=C`hNai0+g)LQv}hd6NSE>&nWU6E&i{ub%icj_Q21b;nY=C* z>TvfUHKr7nWHdwlBmLzN4AG$(Q2*q;{l45Yf%0A|D+Ms2Ih4wbN7s^gsPZ_YrC-DL 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 Bme~LR literal 11340 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 diff --git a/core/data/schemas/zed.rainxch.core.data.local.db.AppDatabase/8.json b/core/data/schemas/zed.rainxch.core.data.local.db.AppDatabase/8.json new file mode 100644 index 00000000..b744ae8f --- /dev/null +++ b/core/data/schemas/zed.rainxch.core.data.local.db.AppDatabase/8.json @@ -0,0 +1,592 @@ +{ + "formatVersion": 1, + "database": { + "version": 8, + "identityHash": "3eb2e531af655730018ea2743e2b8ca0", + "entities": [ + { + "tableName": "installed_apps", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`packageName` TEXT NOT NULL, `repoId` INTEGER NOT NULL, `repoName` TEXT NOT NULL, `repoOwner` TEXT NOT NULL, `repoOwnerAvatarUrl` TEXT NOT NULL, `repoDescription` TEXT, `primaryLanguage` TEXT, `repoUrl` TEXT NOT NULL, `installedVersion` TEXT NOT NULL, `installedAssetName` TEXT, `installedAssetUrl` TEXT, `latestVersion` TEXT, `latestAssetName` TEXT, `latestAssetUrl` TEXT, `latestAssetSize` INTEGER, `appName` TEXT NOT NULL, `installSource` TEXT NOT NULL, `signingFingerprint` TEXT, `installedAt` INTEGER NOT NULL, `lastCheckedAt` INTEGER NOT NULL, `lastUpdatedAt` INTEGER NOT NULL, `isUpdateAvailable` INTEGER NOT NULL, `updateCheckEnabled` INTEGER NOT NULL, `releaseNotes` TEXT, `systemArchitecture` TEXT NOT NULL, `fileExtension` TEXT NOT NULL, `isPendingInstall` INTEGER NOT NULL, `installedVersionName` TEXT, `installedVersionCode` INTEGER NOT NULL, `latestVersionName` TEXT, `latestVersionCode` INTEGER, `includePreReleases` INTEGER NOT NULL, PRIMARY KEY(`packageName`))", + "fields": [ + { + "fieldPath": "packageName", + "columnName": "packageName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "repoId", + "columnName": "repoId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "repoName", + "columnName": "repoName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "repoOwner", + "columnName": "repoOwner", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "repoOwnerAvatarUrl", + "columnName": "repoOwnerAvatarUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "repoDescription", + "columnName": "repoDescription", + "affinity": "TEXT" + }, + { + "fieldPath": "primaryLanguage", + "columnName": "primaryLanguage", + "affinity": "TEXT" + }, + { + "fieldPath": "repoUrl", + "columnName": "repoUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "installedVersion", + "columnName": "installedVersion", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "installedAssetName", + "columnName": "installedAssetName", + "affinity": "TEXT" + }, + { + "fieldPath": "installedAssetUrl", + "columnName": "installedAssetUrl", + "affinity": "TEXT" + }, + { + "fieldPath": "latestVersion", + "columnName": "latestVersion", + "affinity": "TEXT" + }, + { + "fieldPath": "latestAssetName", + "columnName": "latestAssetName", + "affinity": "TEXT" + }, + { + "fieldPath": "latestAssetUrl", + "columnName": "latestAssetUrl", + "affinity": "TEXT" + }, + { + "fieldPath": "latestAssetSize", + "columnName": "latestAssetSize", + "affinity": "INTEGER" + }, + { + "fieldPath": "appName", + "columnName": "appName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "installSource", + "columnName": "installSource", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "signingFingerprint", + "columnName": "signingFingerprint", + "affinity": "TEXT" + }, + { + "fieldPath": "installedAt", + "columnName": "installedAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastCheckedAt", + "columnName": "lastCheckedAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastUpdatedAt", + "columnName": "lastUpdatedAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isUpdateAvailable", + "columnName": "isUpdateAvailable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "updateCheckEnabled", + "columnName": "updateCheckEnabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "releaseNotes", + "columnName": "releaseNotes", + "affinity": "TEXT" + }, + { + "fieldPath": "systemArchitecture", + "columnName": "systemArchitecture", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "fileExtension", + "columnName": "fileExtension", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isPendingInstall", + "columnName": "isPendingInstall", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "installedVersionName", + "columnName": "installedVersionName", + "affinity": "TEXT" + }, + { + "fieldPath": "installedVersionCode", + "columnName": "installedVersionCode", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "latestVersionName", + "columnName": "latestVersionName", + "affinity": "TEXT" + }, + { + "fieldPath": "latestVersionCode", + "columnName": "latestVersionCode", + "affinity": "INTEGER" + }, + { + "fieldPath": "includePreReleases", + "columnName": "includePreReleases", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "packageName" + ] + } + }, + { + "tableName": "favorite_repos", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`repoId` INTEGER NOT NULL, `repoName` TEXT NOT NULL, `repoOwner` TEXT NOT NULL, `repoOwnerAvatarUrl` TEXT NOT NULL, `repoDescription` TEXT, `primaryLanguage` TEXT, `repoUrl` TEXT NOT NULL, `isInstalled` INTEGER NOT NULL, `installedPackageName` TEXT, `latestVersion` TEXT, `latestReleaseUrl` TEXT, `addedAt` INTEGER NOT NULL, `lastSyncedAt` INTEGER NOT NULL, PRIMARY KEY(`repoId`))", + "fields": [ + { + "fieldPath": "repoId", + "columnName": "repoId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "repoName", + "columnName": "repoName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "repoOwner", + "columnName": "repoOwner", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "repoOwnerAvatarUrl", + "columnName": "repoOwnerAvatarUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "repoDescription", + "columnName": "repoDescription", + "affinity": "TEXT" + }, + { + "fieldPath": "primaryLanguage", + "columnName": "primaryLanguage", + "affinity": "TEXT" + }, + { + "fieldPath": "repoUrl", + "columnName": "repoUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isInstalled", + "columnName": "isInstalled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "installedPackageName", + "columnName": "installedPackageName", + "affinity": "TEXT" + }, + { + "fieldPath": "latestVersion", + "columnName": "latestVersion", + "affinity": "TEXT" + }, + { + "fieldPath": "latestReleaseUrl", + "columnName": "latestReleaseUrl", + "affinity": "TEXT" + }, + { + "fieldPath": "addedAt", + "columnName": "addedAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastSyncedAt", + "columnName": "lastSyncedAt", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "repoId" + ] + } + }, + { + "tableName": "update_history", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `packageName` TEXT NOT NULL, `appName` TEXT NOT NULL, `repoOwner` TEXT NOT NULL, `repoName` TEXT NOT NULL, `fromVersion` TEXT NOT NULL, `toVersion` TEXT NOT NULL, `updatedAt` INTEGER NOT NULL, `updateSource` TEXT NOT NULL, `success` INTEGER NOT NULL, `errorMessage` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "packageName", + "columnName": "packageName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "appName", + "columnName": "appName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "repoOwner", + "columnName": "repoOwner", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "repoName", + "columnName": "repoName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "fromVersion", + "columnName": "fromVersion", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "toVersion", + "columnName": "toVersion", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "updateSource", + "columnName": "updateSource", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "success", + "columnName": "success", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "errorMessage", + "columnName": "errorMessage", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "starred_repos", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`repoId` INTEGER NOT NULL, `repoName` TEXT NOT NULL, `repoOwner` TEXT NOT NULL, `repoOwnerAvatarUrl` TEXT NOT NULL, `repoDescription` TEXT, `primaryLanguage` TEXT, `repoUrl` TEXT NOT NULL, `stargazersCount` INTEGER NOT NULL, `forksCount` INTEGER NOT NULL, `openIssuesCount` INTEGER NOT NULL, `isInstalled` INTEGER NOT NULL, `installedPackageName` TEXT, `latestVersion` TEXT, `latestReleaseUrl` TEXT, `starredAt` INTEGER, `addedAt` INTEGER NOT NULL, `lastSyncedAt` INTEGER NOT NULL, PRIMARY KEY(`repoId`))", + "fields": [ + { + "fieldPath": "repoId", + "columnName": "repoId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "repoName", + "columnName": "repoName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "repoOwner", + "columnName": "repoOwner", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "repoOwnerAvatarUrl", + "columnName": "repoOwnerAvatarUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "repoDescription", + "columnName": "repoDescription", + "affinity": "TEXT" + }, + { + "fieldPath": "primaryLanguage", + "columnName": "primaryLanguage", + "affinity": "TEXT" + }, + { + "fieldPath": "repoUrl", + "columnName": "repoUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "stargazersCount", + "columnName": "stargazersCount", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "forksCount", + "columnName": "forksCount", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "openIssuesCount", + "columnName": "openIssuesCount", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isInstalled", + "columnName": "isInstalled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "installedPackageName", + "columnName": "installedPackageName", + "affinity": "TEXT" + }, + { + "fieldPath": "latestVersion", + "columnName": "latestVersion", + "affinity": "TEXT" + }, + { + "fieldPath": "latestReleaseUrl", + "columnName": "latestReleaseUrl", + "affinity": "TEXT" + }, + { + "fieldPath": "starredAt", + "columnName": "starredAt", + "affinity": "INTEGER" + }, + { + "fieldPath": "addedAt", + "columnName": "addedAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastSyncedAt", + "columnName": "lastSyncedAt", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "repoId" + ] + } + }, + { + "tableName": "cache_entries", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `jsonData` TEXT NOT NULL, `cachedAt` INTEGER NOT NULL, `expiresAt` INTEGER NOT NULL, PRIMARY KEY(`key`))", + "fields": [ + { + "fieldPath": "key", + "columnName": "key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "jsonData", + "columnName": "jsonData", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "cachedAt", + "columnName": "cachedAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "expiresAt", + "columnName": "expiresAt", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "key" + ] + } + }, + { + "tableName": "seen_repos", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`repoId` INTEGER NOT NULL, `repoName` TEXT NOT NULL, `repoOwner` TEXT NOT NULL, `repoOwnerAvatarUrl` TEXT NOT NULL, `repoDescription` TEXT, `primaryLanguage` TEXT, `repoUrl` TEXT NOT NULL, `seenAt` INTEGER NOT NULL, PRIMARY KEY(`repoId`))", + "fields": [ + { + "fieldPath": "repoId", + "columnName": "repoId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "repoName", + "columnName": "repoName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "repoOwner", + "columnName": "repoOwner", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "repoOwnerAvatarUrl", + "columnName": "repoOwnerAvatarUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "repoDescription", + "columnName": "repoDescription", + "affinity": "TEXT" + }, + { + "fieldPath": "primaryLanguage", + "columnName": "primaryLanguage", + "affinity": "TEXT" + }, + { + "fieldPath": "repoUrl", + "columnName": "repoUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "seenAt", + "columnName": "seenAt", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "repoId" + ] + } + }, + { + "tableName": "search_history", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`query` TEXT NOT NULL, `searchedAt` INTEGER NOT NULL, PRIMARY KEY(`query`))", + "fields": [ + { + "fieldPath": "query", + "columnName": "query", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "searchedAt", + "columnName": "searchedAt", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "query" + ] + } + } + ], + "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, '3eb2e531af655730018ea2743e2b8ca0')" + ] + } +} \ No newline at end of file diff --git a/core/data/src/androidMain/kotlin/zed/rainxch/core/data/local/db/initDatabase.kt b/core/data/src/androidMain/kotlin/zed/rainxch/core/data/local/db/initDatabase.kt index d21090d9..75a5d28e 100644 --- a/core/data/src/androidMain/kotlin/zed/rainxch/core/data/local/db/initDatabase.kt +++ b/core/data/src/androidMain/kotlin/zed/rainxch/core/data/local/db/initDatabase.kt @@ -8,6 +8,7 @@ import zed.rainxch.core.data.local.db.migrations.MIGRATION_2_3 import zed.rainxch.core.data.local.db.migrations.MIGRATION_3_4 import zed.rainxch.core.data.local.db.migrations.MIGRATION_4_5 import zed.rainxch.core.data.local.db.migrations.MIGRATION_5_6 +import zed.rainxch.core.data.local.db.migrations.MIGRATION_7_8 fun initDatabase(context: Context): AppDatabase { val appContext = context.applicationContext @@ -23,5 +24,6 @@ fun initDatabase(context: Context): AppDatabase { MIGRATION_3_4, MIGRATION_4_5, MIGRATION_5_6, + MIGRATION_7_8, ).build() } diff --git a/core/data/src/androidMain/kotlin/zed/rainxch/core/data/local/db/migrations/MIGRATION_7_8.kt b/core/data/src/androidMain/kotlin/zed/rainxch/core/data/local/db/migrations/MIGRATION_7_8.kt new file mode 100644 index 00000000..d1f7a49f --- /dev/null +++ b/core/data/src/androidMain/kotlin/zed/rainxch/core/data/local/db/migrations/MIGRATION_7_8.kt @@ -0,0 +1,13 @@ +package zed.rainxch.core.data.local.db.migrations + +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase + +val MIGRATION_7_8 = + object : Migration(7, 8) { + override fun migrate(db: SupportSQLiteDatabase) { + db.execSQL( + "ALTER TABLE installed_apps ADD COLUMN includePreReleases INTEGER NOT NULL DEFAULT 0", + ) + } + } diff --git a/core/data/src/commonMain/kotlin/zed/rainxch/core/data/di/SharedModule.kt b/core/data/src/commonMain/kotlin/zed/rainxch/core/data/di/SharedModule.kt index 6b9269c1..f42f1f10 100644 --- a/core/data/src/commonMain/kotlin/zed/rainxch/core/data/di/SharedModule.kt +++ b/core/data/src/commonMain/kotlin/zed/rainxch/core/data/di/SharedModule.kt @@ -81,7 +81,6 @@ val coreModule = historyDao = get(), installer = get(), httpClient = get(), - tweaksRepository = get(), ) } diff --git a/core/data/src/commonMain/kotlin/zed/rainxch/core/data/local/db/AppDatabase.kt b/core/data/src/commonMain/kotlin/zed/rainxch/core/data/local/db/AppDatabase.kt index eb98ce46..b08cef57 100644 --- a/core/data/src/commonMain/kotlin/zed/rainxch/core/data/local/db/AppDatabase.kt +++ b/core/data/src/commonMain/kotlin/zed/rainxch/core/data/local/db/AppDatabase.kt @@ -27,7 +27,7 @@ import zed.rainxch.core.data.local.db.entities.UpdateHistoryEntity SeenRepoEntity::class, SearchHistoryEntity::class, ], - version = 7, + version = 8, exportSchema = true, ) abstract class AppDatabase : RoomDatabase() { diff --git a/core/data/src/commonMain/kotlin/zed/rainxch/core/data/local/db/dao/InstalledAppDao.kt b/core/data/src/commonMain/kotlin/zed/rainxch/core/data/local/db/dao/InstalledAppDao.kt index 4561bf9e..4ac3ed7b 100644 --- a/core/data/src/commonMain/kotlin/zed/rainxch/core/data/local/db/dao/InstalledAppDao.kt +++ b/core/data/src/commonMain/kotlin/zed/rainxch/core/data/local/db/dao/InstalledAppDao.kt @@ -69,6 +69,9 @@ interface InstalledAppDao { latestVersionCode: Long?, ) + @Query("UPDATE installed_apps SET includePreReleases = :enabled WHERE packageName = :packageName") + suspend fun updateIncludePreReleases(packageName: String, enabled: Boolean) + @Query("UPDATE installed_apps SET lastCheckedAt = :timestamp WHERE packageName = :packageName") suspend fun updateLastChecked( packageName: String, diff --git a/core/data/src/commonMain/kotlin/zed/rainxch/core/data/local/db/entities/InstalledAppEntity.kt b/core/data/src/commonMain/kotlin/zed/rainxch/core/data/local/db/entities/InstalledAppEntity.kt index 12dff89d..b632626d 100644 --- a/core/data/src/commonMain/kotlin/zed/rainxch/core/data/local/db/entities/InstalledAppEntity.kt +++ b/core/data/src/commonMain/kotlin/zed/rainxch/core/data/local/db/entities/InstalledAppEntity.kt @@ -37,4 +37,5 @@ data class InstalledAppEntity( val installedVersionCode: Long = 0L, val latestVersionName: String? = null, val latestVersionCode: Long? = null, + val includePreReleases: Boolean = false, ) diff --git a/core/data/src/commonMain/kotlin/zed/rainxch/core/data/mappers/InstalledAppsMappers.kt b/core/data/src/commonMain/kotlin/zed/rainxch/core/data/mappers/InstalledAppsMappers.kt index 7515f26c..3dc1aed4 100644 --- a/core/data/src/commonMain/kotlin/zed/rainxch/core/data/mappers/InstalledAppsMappers.kt +++ b/core/data/src/commonMain/kotlin/zed/rainxch/core/data/mappers/InstalledAppsMappers.kt @@ -36,6 +36,7 @@ fun InstalledApp.toEntity(): InstalledAppEntity = latestVersionName = latestVersionName, latestVersionCode = latestVersionCode, signingFingerprint = signingFingerprint, + includePreReleases = includePreReleases, ) fun InstalledAppEntity.toDomain(): InstalledApp = @@ -71,4 +72,5 @@ fun InstalledAppEntity.toDomain(): InstalledApp = latestVersionName = latestVersionName, latestVersionCode = latestVersionCode, signingFingerprint = signingFingerprint, + includePreReleases = includePreReleases, ) diff --git a/core/data/src/commonMain/kotlin/zed/rainxch/core/data/repository/InstalledAppsRepositoryImpl.kt b/core/data/src/commonMain/kotlin/zed/rainxch/core/data/repository/InstalledAppsRepositoryImpl.kt index 926b9fac..e761858a 100644 --- a/core/data/src/commonMain/kotlin/zed/rainxch/core/data/repository/InstalledAppsRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/zed/rainxch/core/data/repository/InstalledAppsRepositoryImpl.kt @@ -23,7 +23,6 @@ import zed.rainxch.core.domain.model.GithubRelease import zed.rainxch.core.domain.model.InstallSource import zed.rainxch.core.domain.model.InstalledApp import zed.rainxch.core.domain.repository.InstalledAppsRepository -import zed.rainxch.core.domain.repository.TweaksRepository import zed.rainxch.core.domain.system.Installer class InstalledAppsRepositoryImpl( @@ -32,7 +31,6 @@ class InstalledAppsRepositoryImpl( private val historyDao: UpdateHistoryDao, private val installer: Installer, private val httpClient: HttpClient, - private val tweaksRepository: TweaksRepository, ) : InstalledAppsRepository { override suspend fun executeInTransaction(block: suspend () -> R): R = database.useWriterConnection { transactor -> @@ -76,10 +74,9 @@ class InstalledAppsRepositoryImpl( private suspend fun fetchLatestPublishedRelease( owner: String, repo: String, + includePreReleases: Boolean, ): GithubRelease? { return try { - val includePreReleases = tweaksRepository.getIncludePreReleases().first() - val releases = httpClient .executeRequest> { @@ -112,6 +109,7 @@ class InstalledAppsRepositoryImpl( fetchLatestPublishedRelease( owner = app.repoOwner, repo = app.repoName, + includePreReleases = app.includePreReleases, ) if (latestRelease != null) { @@ -241,6 +239,13 @@ class InstalledAppsRepositoryImpl( installedAppsDao.updateApp(app.copy(isPendingInstall = isPending)) } + override suspend fun setIncludePreReleases( + packageName: String, + enabled: Boolean, + ) { + installedAppsDao.updateIncludePreReleases(packageName, enabled) + } + private fun normalizeVersion(version: String): String = version.removePrefix("v").removePrefix("V").trim() /** diff --git a/core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/model/InstalledApp.kt b/core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/model/InstalledApp.kt index 11a3d447..468c00bf 100644 --- a/core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/model/InstalledApp.kt +++ b/core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/model/InstalledApp.kt @@ -32,4 +32,5 @@ data class InstalledApp( val installedVersionCode: Long = 0L, val latestVersionName: String? = null, val latestVersionCode: Long? = null, + val includePreReleases: Boolean = false, ) diff --git a/core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/repository/InstalledAppsRepository.kt b/core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/repository/InstalledAppsRepository.kt index 5255261e..85b9ebff 100644 --- a/core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/repository/InstalledAppsRepository.kt +++ b/core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/repository/InstalledAppsRepository.kt @@ -44,5 +44,10 @@ interface InstalledAppsRepository { isPending: Boolean, ) + suspend fun setIncludePreReleases( + packageName: String, + enabled: Boolean, + ) + suspend fun executeInTransaction(block: suspend () -> R): R } diff --git a/core/presentation/src/commonMain/composeResources/values-ar/strings-ar.xml b/core/presentation/src/commonMain/composeResources/values-ar/strings-ar.xml index bde53b73..25a6a86b 100644 --- a/core/presentation/src/commonMain/composeResources/values-ar/strings-ar.xml +++ b/core/presentation/src/commonMain/composeResources/values-ar/strings-ar.xml @@ -621,4 +621,5 @@ تعديلات تعديلات + إصدارات تجريبية diff --git a/core/presentation/src/commonMain/composeResources/values-bn/strings-bn.xml b/core/presentation/src/commonMain/composeResources/values-bn/strings-bn.xml index a2cc73d5..e63aba91 100644 --- a/core/presentation/src/commonMain/composeResources/values-bn/strings-bn.xml +++ b/core/presentation/src/commonMain/composeResources/values-bn/strings-bn.xml @@ -620,4 +620,5 @@ টুইকস টুইকস + প্রি-রিলিজ diff --git a/core/presentation/src/commonMain/composeResources/values-es/strings-es.xml b/core/presentation/src/commonMain/composeResources/values-es/strings-es.xml index 9b16c575..97d923c4 100644 --- a/core/presentation/src/commonMain/composeResources/values-es/strings-es.xml +++ b/core/presentation/src/commonMain/composeResources/values-es/strings-es.xml @@ -581,4 +581,5 @@ Ajustes Ajustes + Pre-lanzamientos \ No newline at end of file diff --git a/core/presentation/src/commonMain/composeResources/values-fr/strings-fr.xml b/core/presentation/src/commonMain/composeResources/values-fr/strings-fr.xml index df656133..40e160ab 100644 --- a/core/presentation/src/commonMain/composeResources/values-fr/strings-fr.xml +++ b/core/presentation/src/commonMain/composeResources/values-fr/strings-fr.xml @@ -582,4 +582,5 @@ Réglages Réglages + Pré-versions \ No newline at end of file diff --git a/core/presentation/src/commonMain/composeResources/values-hi/strings-hi.xml b/core/presentation/src/commonMain/composeResources/values-hi/strings-hi.xml index eb28845d..2d43d2eb 100644 --- a/core/presentation/src/commonMain/composeResources/values-hi/strings-hi.xml +++ b/core/presentation/src/commonMain/composeResources/values-hi/strings-hi.xml @@ -619,4 +619,5 @@ ट्वीक्स ट्वीक्स + प्री-रिलीज़ diff --git a/core/presentation/src/commonMain/composeResources/values-it/strings-it.xml b/core/presentation/src/commonMain/composeResources/values-it/strings-it.xml index f999430e..b9fda143 100644 --- a/core/presentation/src/commonMain/composeResources/values-it/strings-it.xml +++ b/core/presentation/src/commonMain/composeResources/values-it/strings-it.xml @@ -620,4 +620,5 @@ Modifiche Modifiche + Pre-release \ No newline at end of file diff --git a/core/presentation/src/commonMain/composeResources/values-ja/strings-ja.xml b/core/presentation/src/commonMain/composeResources/values-ja/strings-ja.xml index e1e109db..fba0121a 100644 --- a/core/presentation/src/commonMain/composeResources/values-ja/strings-ja.xml +++ b/core/presentation/src/commonMain/composeResources/values-ja/strings-ja.xml @@ -583,4 +583,5 @@ 調整 調整 + プレリリース \ No newline at end of file diff --git a/core/presentation/src/commonMain/composeResources/values-ko/strings-ko.xml b/core/presentation/src/commonMain/composeResources/values-ko/strings-ko.xml index 36a1c48a..4d2ea25e 100644 --- a/core/presentation/src/commonMain/composeResources/values-ko/strings-ko.xml +++ b/core/presentation/src/commonMain/composeResources/values-ko/strings-ko.xml @@ -618,4 +618,5 @@ 조정 조정 + 프리릴리스 \ No newline at end of file diff --git a/core/presentation/src/commonMain/composeResources/values-pl/strings-pl.xml b/core/presentation/src/commonMain/composeResources/values-pl/strings-pl.xml index c8d3a25a..66e6145f 100644 --- a/core/presentation/src/commonMain/composeResources/values-pl/strings-pl.xml +++ b/core/presentation/src/commonMain/composeResources/values-pl/strings-pl.xml @@ -584,4 +584,5 @@ Ustawienia Ustawienia + Wersje wstępne \ No newline at end of file diff --git a/core/presentation/src/commonMain/composeResources/values-ru/strings-ru.xml b/core/presentation/src/commonMain/composeResources/values-ru/strings-ru.xml index 37f4cbbe..38686233 100644 --- a/core/presentation/src/commonMain/composeResources/values-ru/strings-ru.xml +++ b/core/presentation/src/commonMain/composeResources/values-ru/strings-ru.xml @@ -584,4 +584,5 @@ Настройки Настройки + Пре-релизы \ No newline at end of file diff --git a/core/presentation/src/commonMain/composeResources/values-tr/strings-tr.xml b/core/presentation/src/commonMain/composeResources/values-tr/strings-tr.xml index cc6f4168..c8a54ee8 100644 --- a/core/presentation/src/commonMain/composeResources/values-tr/strings-tr.xml +++ b/core/presentation/src/commonMain/composeResources/values-tr/strings-tr.xml @@ -618,4 +618,5 @@ İnce Ayarlar İnce Ayarlar + Ön sürümler diff --git a/core/presentation/src/commonMain/composeResources/values-zh-rCN/strings-zh-rCN.xml b/core/presentation/src/commonMain/composeResources/values-zh-rCN/strings-zh-rCN.xml index 2987fd8c..a8331e2f 100644 --- a/core/presentation/src/commonMain/composeResources/values-zh-rCN/strings-zh-rCN.xml +++ b/core/presentation/src/commonMain/composeResources/values-zh-rCN/strings-zh-rCN.xml @@ -584,4 +584,5 @@ 调整 调整 + 预发布版本 \ No newline at end of file diff --git a/core/presentation/src/commonMain/composeResources/values/strings.xml b/core/presentation/src/commonMain/composeResources/values/strings.xml index 444e8ace..e2e9d02a 100644 --- a/core/presentation/src/commonMain/composeResources/values/strings.xml +++ b/core/presentation/src/commonMain/composeResources/values/strings.xml @@ -623,4 +623,7 @@ Remove Tweaks + + + Pre-releases \ No newline at end of file diff --git a/feature/apps/data/src/commonMain/kotlin/zed/rainxch/apps/data/repository/AppsRepositoryImpl.kt b/feature/apps/data/src/commonMain/kotlin/zed/rainxch/apps/data/repository/AppsRepositoryImpl.kt index 17358454..f5dca9a5 100644 --- a/feature/apps/data/src/commonMain/kotlin/zed/rainxch/apps/data/repository/AppsRepositoryImpl.kt +++ b/feature/apps/data/src/commonMain/kotlin/zed/rainxch/apps/data/repository/AppsRepositoryImpl.kt @@ -62,10 +62,9 @@ class AppsRepositoryImpl( override suspend fun getLatestRelease( owner: String, repo: String, + includePreReleases: Boolean, ): GithubRelease? = try { - val includePreReleases = tweaksRepository.getIncludePreReleases().first() - val releases = httpClient .executeRequest> { @@ -154,6 +153,7 @@ class AppsRepositoryImpl( repoInfo: GithubRepoInfo, ) { val now = Clock.System.now().toEpochMilliseconds() + val globalPreRelease = tweaksRepository.getIncludePreReleases().first() val installedApp = InstalledApp( @@ -186,6 +186,7 @@ class AppsRepositoryImpl( installedVersionName = deviceApp.versionName, installedVersionCode = deviceApp.versionCode, signingFingerprint = deviceApp.signingFingerprint, + includePreReleases = globalPreRelease, ) appsRepository.saveInstalledApp(installedApp) diff --git a/feature/apps/domain/src/commonMain/kotlin/zed/rainxch/apps/domain/repository/AppsRepository.kt b/feature/apps/domain/src/commonMain/kotlin/zed/rainxch/apps/domain/repository/AppsRepository.kt index 8397a60d..609a6200 100644 --- a/feature/apps/domain/src/commonMain/kotlin/zed/rainxch/apps/domain/repository/AppsRepository.kt +++ b/feature/apps/domain/src/commonMain/kotlin/zed/rainxch/apps/domain/repository/AppsRepository.kt @@ -18,6 +18,7 @@ interface AppsRepository { suspend fun getLatestRelease( owner: String, repo: String, + includePreReleases: Boolean = false, ): GithubRelease? suspend fun getDeviceApps(): List diff --git a/feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsAction.kt b/feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsAction.kt index eba51c18..dad9df66 100644 --- a/feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsAction.kt +++ b/feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsAction.kt @@ -55,6 +55,9 @@ sealed interface AppsAction { data class OnLinkAssetSelected(val asset: GithubAssetUi) : AppsAction data object OnBackToEnterUrl : AppsAction + // Per-app pre-release toggle + data class OnTogglePreReleases(val packageName: String, val enabled: Boolean) : AppsAction + // Export/Import data object OnExportApps : AppsAction data object OnImportApps : AppsAction diff --git a/feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsRoot.kt b/feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsRoot.kt index c86c40f4..b6bf621c 100644 --- a/feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsRoot.kt +++ b/feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsRoot.kt @@ -50,6 +50,7 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TextField @@ -108,6 +109,7 @@ import zed.rainxch.githubstore.core.presentation.res.last_checked_minutes_ago import zed.rainxch.githubstore.core.presentation.res.no_apps_found import zed.rainxch.githubstore.core.presentation.res.open import zed.rainxch.githubstore.core.presentation.res.pending_install +import zed.rainxch.githubstore.core.presentation.res.pre_release_badge import zed.rainxch.githubstore.core.presentation.res.search_your_apps import zed.rainxch.githubstore.core.presentation.res.uninstall import zed.rainxch.githubstore.core.presentation.res.update @@ -448,6 +450,9 @@ fun AppsScreen( onCancelClick = { onAction(AppsAction.OnCancelUpdate(appItem.installedApp.packageName)) }, onUninstallClick = { onAction(AppsAction.OnUninstallApp(appItem.installedApp)) }, onRepoClick = { onAction(AppsAction.OnNavigateToRepo(appItem.installedApp.repoId)) }, + onTogglePreReleases = { enabled -> + onAction(AppsAction.OnTogglePreReleases(appItem.installedApp.packageName, enabled)) + }, modifier = Modifier .then( @@ -538,6 +543,7 @@ fun AppItemCard( onCancelClick: () -> Unit, onUninstallClick: () -> Unit, onRepoClick: () -> Unit, + onTogglePreReleases: (Boolean) -> Unit, modifier: Modifier = Modifier, ) { val app = appItem.installedApp @@ -625,7 +631,25 @@ fun AppItemCard( ) } - Spacer(Modifier.height(12.dp)) + Spacer(Modifier.height(8.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = stringResource(Res.string.pre_release_badge), + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + Switch( + checked = app.includePreReleases, + onCheckedChange = onTogglePreReleases, + ) + } + + Spacer(Modifier.height(4.dp)) when (val state = appItem.updateState) { is UpdateState.Downloading -> { diff --git a/feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsViewModel.kt b/feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsViewModel.kt index d1755141..55cfcc8e 100644 --- a/feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsViewModel.kt +++ b/feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsViewModel.kt @@ -302,6 +302,10 @@ class AppsViewModel( } } + is AppsAction.OnTogglePreReleases -> { + togglePreReleases(action.packageName, action.enabled) + } + AppsAction.OnExportApps -> { exportApps() } @@ -346,6 +350,17 @@ class AppsViewModel( .toImmutableList() } + private fun togglePreReleases(packageName: String, enabled: Boolean) { + viewModelScope.launch { + try { + installedAppsRepository.setIncludePreReleases(packageName, enabled) + installedAppsRepository.checkForUpdates(packageName) + } catch (e: Exception) { + logger.error("Failed to toggle pre-releases for $packageName: ${e.message}") + } + } + } + private fun uninstallApp(app: InstalledAppUi) { viewModelScope.launch { try { @@ -410,6 +425,7 @@ class AppsViewModel( appsRepository.getLatestRelease( owner = app.repoOwner, repo = app.repoName, + includePreReleases = app.includePreReleases, ) } catch (e: Exception) { logger.error("Failed to fetch latest release: ${e.message}") diff --git a/feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/mappers/InstalledAppMapper.kt b/feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/mappers/InstalledAppMapper.kt index de6d0164..8e326a98 100644 --- a/feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/mappers/InstalledAppMapper.kt +++ b/feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/mappers/InstalledAppMapper.kt @@ -36,6 +36,7 @@ fun InstalledApp.toUi(): InstalledAppUi = packageName = packageName, appName = appName, signingFingerprint = signingFingerprint, + includePreReleases = includePreReleases, ) fun InstalledAppUi.toDomain(): InstalledApp = @@ -71,4 +72,5 @@ fun InstalledAppUi.toDomain(): InstalledApp = packageName = packageName, appName = appName, signingFingerprint = signingFingerprint, + includePreReleases = includePreReleases, ) diff --git a/feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/model/InstalledAppUi.kt b/feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/model/InstalledAppUi.kt index a6232639..64aacec8 100644 --- a/feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/model/InstalledAppUi.kt +++ b/feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/model/InstalledAppUi.kt @@ -34,4 +34,5 @@ data class InstalledAppUi( val installedVersionCode: Long = 0L, val latestVersionName: String? = null, val latestVersionCode: Long? = null, + val includePreReleases: Boolean = false, )