diff --git a/composeApp/src/androidMain/AndroidManifest.xml b/composeApp/src/androidMain/AndroidManifest.xml
index 8d9d16a03..44f6b584f 100644
--- a/composeApp/src/androidMain/AndroidManifest.xml
+++ b/composeApp/src/androidMain/AndroidManifest.xml
@@ -17,6 +17,16 @@
+
+
diff --git a/core/data/src/androidMain/kotlin/zed/rainxch/core/data/di/PlatformModule.android.kt b/core/data/src/androidMain/kotlin/zed/rainxch/core/data/di/PlatformModule.android.kt
index f07bc14d9..523da47a6 100644
--- a/core/data/src/androidMain/kotlin/zed/rainxch/core/data/di/PlatformModule.android.kt
+++ b/core/data/src/androidMain/kotlin/zed/rainxch/core/data/di/PlatformModule.android.kt
@@ -110,6 +110,10 @@ actual val corePlatformModule =
AndroidFileLocationsProvider(context = get())
}
+ single {
+ zed.rainxch.core.data.services.AndroidAggressiveOemDetector(context = androidContext())
+ }
+
single {
AndroidPendingInstallNotifier(context = androidContext())
}
diff --git a/core/data/src/androidMain/kotlin/zed/rainxch/core/data/services/AndroidAggressiveOemDetector.kt b/core/data/src/androidMain/kotlin/zed/rainxch/core/data/services/AndroidAggressiveOemDetector.kt
new file mode 100644
index 000000000..12abb1359
--- /dev/null
+++ b/core/data/src/androidMain/kotlin/zed/rainxch/core/data/services/AndroidAggressiveOemDetector.kt
@@ -0,0 +1,79 @@
+package zed.rainxch.core.data.services
+
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.os.Build
+import android.os.PowerManager
+import android.provider.Settings
+import co.touchlab.kermit.Logger
+import zed.rainxch.core.domain.system.AggressiveOemDetector
+
+class AndroidAggressiveOemDetector(
+ private val context: Context,
+) : AggressiveOemDetector {
+ override fun isAggressiveOem(): Boolean {
+ val brand = (Build.BRAND ?: "").lowercase()
+ val manufacturer = (Build.MANUFACTURER ?: "").lowercase()
+ return AGGRESSIVE_OEMS.any { it in brand || it in manufacturer }
+ }
+
+ override fun isBatteryOptimizationIgnored(): Boolean {
+ val pm = context.getSystemService(Context.POWER_SERVICE) as? PowerManager ?: return false
+ return pm.isIgnoringBatteryOptimizations(context.packageName)
+ }
+
+ override fun openBatteryOptimizationSettings(): Boolean =
+ // The targeted intent (`ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS`)
+ // bypasses Play Store policy on standalone APKs and lands the user
+ // directly on the system whitelist toggle — but it's gated by the
+ // `REQUEST_IGNORE_BATTERY_OPTIMIZATIONS` permission, which Play
+ // restricts. Fall back to the per-app battery-optimization screen
+ // if the targeted action throws on a packaged build.
+ runCatching {
+ val intent =
+ Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).apply {
+ data = Uri.parse("package:${context.packageName}")
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ }
+ context.startActivity(intent)
+ true
+ }.getOrElse {
+ Logger.w(it) {
+ "AggressiveOemDetector: targeted battery-optimization intent failed; opening generic screen"
+ }
+ runCatching {
+ val fallback =
+ Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS).apply {
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ }
+ context.startActivity(fallback)
+ true
+ }.getOrElse { fallbackError ->
+ Logger.w(fallbackError) {
+ "AggressiveOemDetector: fallback battery-optimization screen also failed"
+ }
+ false
+ }
+ }
+
+ private companion object {
+ // Substring matches against `Build.BRAND` / `Build.MANUFACTURER` —
+ // covers vendor sub-brands (BBK group: Oppo, OnePlus, Realme,
+ // vivo, iQOO; Xiaomi: Redmi, Poco; Huawei: Honor).
+ private val AGGRESSIVE_OEMS =
+ listOf(
+ "oppo",
+ "oneplus",
+ "realme",
+ "xiaomi",
+ "redmi",
+ "poco",
+ "vivo",
+ "iqoo",
+ "huawei",
+ "honor",
+ "meizu",
+ )
+ }
+}
diff --git a/core/data/src/androidMain/kotlin/zed/rainxch/core/data/services/UpdateScheduler.kt b/core/data/src/androidMain/kotlin/zed/rainxch/core/data/services/UpdateScheduler.kt
index e4f97dc6e..9978f6ae6 100644
--- a/core/data/src/androidMain/kotlin/zed/rainxch/core/data/services/UpdateScheduler.kt
+++ b/core/data/src/androidMain/kotlin/zed/rainxch/core/data/services/UpdateScheduler.kt
@@ -7,6 +7,7 @@ import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.ExistingWorkPolicy
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequestBuilder
+import androidx.work.OutOfQuotaPolicy
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import co.touchlab.kermit.Logger
@@ -49,6 +50,12 @@ object UpdateScheduler {
OneTimeWorkRequestBuilder()
.setConstraints(constraints)
.setInitialDelay(1, TimeUnit.MINUTES)
+ // Aggressive-OEM ROMs (Oppo / OnePlus / Realme / Xiaomi)
+ // throttle generic background work hard. Expedited tier
+ // gets more headroom; fall back to non-expedited when
+ // the system has no expedited budget left so the work
+ // still runs eventually rather than failing outright.
+ .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
.build()
WorkManager
@@ -108,7 +115,15 @@ object UpdateScheduler {
BackoffPolicy.EXPONENTIAL,
15,
TimeUnit.MINUTES,
- ).build()
+ )
+ // Intentionally NOT expedited: AutoUpdateWorker downloads
+ // multiple APKs and installs them sequentially, which can
+ // easily exceed the 10-minute expedited time limit and
+ // get the worker terminated mid-install. The worker
+ // already promotes itself to a foreground service via
+ // setForeground, which gives it the headroom it needs
+ // without the expedited time cap.
+ .build()
WorkManager
.getInstance(context)
diff --git a/core/data/src/commonMain/kotlin/zed/rainxch/core/data/repository/TweaksRepositoryImpl.kt b/core/data/src/commonMain/kotlin/zed/rainxch/core/data/repository/TweaksRepositoryImpl.kt
index 90fcb68cf..5938a2c57 100644
--- a/core/data/src/commonMain/kotlin/zed/rainxch/core/data/repository/TweaksRepositoryImpl.kt
+++ b/core/data/src/commonMain/kotlin/zed/rainxch/core/data/repository/TweaksRepositoryImpl.kt
@@ -341,6 +341,17 @@ class TweaksRepositoryImpl(
}
}
+ override fun getBatteryOptimizationPromptDismissed(): Flow =
+ preferences.data.map { prefs ->
+ prefs[BATTERY_OPT_PROMPT_DISMISSED_KEY] ?: false
+ }
+
+ override suspend fun setBatteryOptimizationPromptDismissed(dismissed: Boolean) {
+ preferences.edit { prefs ->
+ prefs[BATTERY_OPT_PROMPT_DISMISSED_KEY] = dismissed
+ }
+ }
+
override fun getLastSeenWhatsNewVersionCode(): Flow =
preferences.data.map { prefs ->
prefs[LAST_SEEN_WHATS_NEW_VERSION_CODE_KEY]
@@ -434,6 +445,7 @@ class TweaksRepositoryImpl(
private val EXTERNAL_MATCH_SEARCH_ENABLED_KEY = booleanPreferencesKey("external_match_search_enabled")
private val EXTERNAL_IMPORT_BANNER_DISMISSED_AT_KEY = intPreferencesKey("external_import_banner_dismissed_at")
private val APK_INSPECT_COACHMARK_SHOWN_KEY = booleanPreferencesKey("apk_inspect_coachmark_shown")
+ private val BATTERY_OPT_PROMPT_DISMISSED_KEY = booleanPreferencesKey("battery_opt_prompt_dismissed")
private val LAST_SEEN_WHATS_NEW_VERSION_CODE_KEY = intPreferencesKey("last_seen_whats_new_version_code")
private val ANNOUNCEMENTS_DISMISSED_IDS_KEY = stringSetPreferencesKey("announcements_dismissed_ids")
private val ANNOUNCEMENTS_ACKNOWLEDGED_IDS_KEY = stringSetPreferencesKey("announcements_acknowledged_ids")
diff --git a/core/data/src/jvmMain/kotlin/zed/rainxch/core/data/di/PlatformModule.jvm.kt b/core/data/src/jvmMain/kotlin/zed/rainxch/core/data/di/PlatformModule.jvm.kt
index c8deba5b7..34f7f11dc 100644
--- a/core/data/src/jvmMain/kotlin/zed/rainxch/core/data/di/PlatformModule.jvm.kt
+++ b/core/data/src/jvmMain/kotlin/zed/rainxch/core/data/di/PlatformModule.jvm.kt
@@ -62,6 +62,10 @@ actual val corePlatformModule = module {
)
}
+ single {
+ zed.rainxch.core.data.services.DesktopAggressiveOemDetector()
+ }
+
single {
DesktopPackageMonitor()
}
diff --git a/core/data/src/jvmMain/kotlin/zed/rainxch/core/data/services/DesktopAggressiveOemDetector.kt b/core/data/src/jvmMain/kotlin/zed/rainxch/core/data/services/DesktopAggressiveOemDetector.kt
new file mode 100644
index 000000000..b850cc5b6
--- /dev/null
+++ b/core/data/src/jvmMain/kotlin/zed/rainxch/core/data/services/DesktopAggressiveOemDetector.kt
@@ -0,0 +1,11 @@
+package zed.rainxch.core.data.services
+
+import zed.rainxch.core.domain.system.AggressiveOemDetector
+
+class DesktopAggressiveOemDetector : AggressiveOemDetector {
+ override fun isAggressiveOem(): Boolean = false
+
+ override fun isBatteryOptimizationIgnored(): Boolean = true
+
+ override fun openBatteryOptimizationSettings(): Boolean = false
+}
diff --git a/core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/repository/TweaksRepository.kt b/core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/repository/TweaksRepository.kt
index 32343a46d..a8a989eb2 100644
--- a/core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/repository/TweaksRepository.kt
+++ b/core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/repository/TweaksRepository.kt
@@ -113,6 +113,17 @@ interface TweaksRepository {
suspend fun setApkInspectCoachmarkShown(shown: Boolean)
+ /**
+ * One-shot watermark for the battery-optimization prompt on
+ * aggressive-OEM ROMs (Oppo / OnePlus / Realme / Xiaomi / vivo /
+ * Honor). `false` until the user has either granted the exemption
+ * or explicitly dismissed the prompt; flips to `true` afterwards
+ * and is never re-shown.
+ */
+ fun getBatteryOptimizationPromptDismissed(): Flow
+
+ suspend fun setBatteryOptimizationPromptDismissed(dismissed: Boolean)
+
fun getLastSeenWhatsNewVersionCode(): Flow
suspend fun setLastSeenWhatsNewVersionCode(versionCode: Int)
diff --git a/core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/system/AggressiveOemDetector.kt b/core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/system/AggressiveOemDetector.kt
new file mode 100644
index 000000000..ba09a11b1
--- /dev/null
+++ b/core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/system/AggressiveOemDetector.kt
@@ -0,0 +1,9 @@
+package zed.rainxch.core.domain.system
+
+interface AggressiveOemDetector {
+ fun isAggressiveOem(): Boolean
+
+ fun isBatteryOptimizationIgnored(): Boolean
+
+ fun openBatteryOptimizationSettings(): Boolean
+}
diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/17.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/17.json
index 651f57f26..76d8bcb0b 100644
--- a/core/presentation/src/commonMain/composeResources/files/whatsnew/17.json
+++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/17.json
@@ -17,6 +17,12 @@
"Better version detection — releases that share a numeric version but ship distinct build artifacts are no longer falsely flagged as 'already installed'.",
"Updating multiple apps in a row now works reliably — installs serialize so each one shows the correct APK in the system dialog. Apps screen versions also stay in sync after every install."
]
+ },
+ {
+ "type": "IMPROVED",
+ "bullets": [
+ "More reliable background updates on Oppo, OnePlus, Realme, Xiaomi, vivo, and Honor — Tweaks now offers a one-tap battery-optimization shortcut and update workers run with expedited priority."
+ ]
}
]
}
diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/ar/17.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/ar/17.json
index 36d530fee..3961a4e9f 100644
--- a/core/presentation/src/commonMain/composeResources/files/whatsnew/ar/17.json
+++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/ar/17.json
@@ -17,6 +17,12 @@
"اكتشاف أدق للإصدارات — لم يعد المتجر يعتبر الإصدارات التي تحمل نفس الأرقام لكن بيانات بناء مختلفة 'مثبَّتة بالفعل'.",
"تحديث عدة تطبيقات بالتتابع أصبح موثوقاً — التثبيتات تنتظر بعضها فلا يظهر مربع حوار النظام تطبيقاً سابقاً، كما تتحدث الإصدارات في شاشة التطبيقات بشكل صحيح بعد كل تثبيت."
]
+ },
+ {
+ "type": "IMPROVED",
+ "bullets": [
+ "تحديثات خلفية أكثر موثوقية على Oppo و OnePlus و Realme و Xiaomi و vivo و Honor — توفّر الإعدادات الآن اختصاراً بنقرة واحدة لاستثناء البطارية، وتعمل مهام التحديث بأولوية مُعجَّلة."
+ ]
}
]
}
diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/bn/17.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/bn/17.json
index fad157b50..6a30ef6ff 100644
--- a/core/presentation/src/commonMain/composeResources/files/whatsnew/bn/17.json
+++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/bn/17.json
@@ -17,6 +17,12 @@
"আরও সঠিক সংস্করণ শনাক্তকরণ — একই সংখ্যা থাকলেও আলাদা বিল্ডের রিলিজগুলো এখন ভুল করে 'ইতিমধ্যে ইনস্টল করা' হিসেবে দেখানো হয় না।",
"একসাথে কয়েকটি অ্যাপ আপডেট এখন নির্ভরযোগ্য — ইনস্টলগুলো ক্রমান্বয়ে চলে, তাই সিস্টেম ডায়ালগ আগের APK দেখায় না। প্রতিটি ইনস্টলের পর অ্যাপস স্ক্রিনে সংস্করণও সঠিকভাবে আপডেট হয়।"
]
+ },
+ {
+ "type": "IMPROVED",
+ "bullets": [
+ "Oppo, OnePlus, Realme, Xiaomi, vivo এবং Honor-এ আরও নির্ভরযোগ্য ব্যাকগ্রাউন্ড আপডেট — সেটিংস এখন এক-ট্যাপে ব্যাটারি অপটিমাইজেশনের শর্টকাট দেয় এবং আপডেট ওয়ার্কারগুলো ত্বরান্বিত অগ্রাধিকারে চলে।"
+ ]
}
]
}
diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/es/17.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/es/17.json
index c3bf4cf5f..7feb45c7b 100644
--- a/core/presentation/src/commonMain/composeResources/files/whatsnew/es/17.json
+++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/es/17.json
@@ -17,6 +17,12 @@
"Mejor detección de versiones — las releases que comparten número pero llevan metadatos de build distintos ya no se marcan por error como 'ya instaladas'.",
"Actualizar varias apps seguidas ahora funciona bien — las instalaciones se serializan para que cada diálogo del sistema muestre el APK correcto. Las versiones en la pantalla de apps también se mantienen al día tras cada instalación."
]
+ },
+ {
+ "type": "IMPROVED",
+ "bullets": [
+ "Actualizaciones en segundo plano más fiables en Oppo, OnePlus, Realme, Xiaomi, vivo y Honor — Ajustes ofrece ahora un acceso directo a la exclusión de optimización de batería, y las comprobaciones de actualización se ejecutan con prioridad acelerada."
+ ]
}
]
}
diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/fr/17.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/fr/17.json
index fcf9e6473..f51432b6c 100644
--- a/core/presentation/src/commonMain/composeResources/files/whatsnew/fr/17.json
+++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/fr/17.json
@@ -17,6 +17,12 @@
"Meilleure détection de version — les releases qui partagent le même numéro mais portent des métadonnées de build différentes ne sont plus signalées à tort comme 'déjà installées'.",
"Mettre à jour plusieurs applis à la suite fonctionne maintenant correctement — les installations se sérialisent pour que chaque boîte de dialogue système affiche le bon APK. Les versions dans l'écran des applis restent aussi à jour après chaque installation."
]
+ },
+ {
+ "type": "IMPROVED",
+ "bullets": [
+ "Mises à jour en arrière-plan plus fiables sur Oppo, OnePlus, Realme, Xiaomi, vivo et Honor — Réglages propose désormais un raccourci d'un seul geste pour l'exclusion de l'optimisation de la batterie, et les vérifications de mise à jour s'exécutent en priorité accélérée."
+ ]
}
]
}
diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/hi/17.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/hi/17.json
index 2a510ba68..ecfa62e20 100644
--- a/core/presentation/src/commonMain/composeResources/files/whatsnew/hi/17.json
+++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/hi/17.json
@@ -17,6 +17,12 @@
"बेहतर वर्शन डिटेक्शन — एक ही नंबर वाले लेकिन अलग बिल्ड मेटाडेटा वाले रिलीज़ अब गलती से 'पहले से इंस्टॉल' नहीं दिखाए जाते।",
"एक के बाद एक कई ऐप अपडेट करना अब विश्वसनीय है — इंस्टॉल अब क्रम में चलते हैं, इसलिए सिस्टम डायलॉग पिछला APK नहीं दिखाता। हर इंस्टॉल के बाद ऐप्स स्क्रीन में संस्करण भी सही दिखता है।"
]
+ },
+ {
+ "type": "IMPROVED",
+ "bullets": [
+ "Oppo, OnePlus, Realme, Xiaomi, vivo और Honor पर अधिक विश्वसनीय बैकग्राउंड अपडेट — सेटिंग्स अब बैटरी ऑप्टिमाइज़ेशन के लिए एक-टैप शॉर्टकट देती है, और अपडेट जॉब्स त्वरित प्राथमिकता के साथ चलते हैं।"
+ ]
}
]
}
diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/it/17.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/it/17.json
index ff107b9db..edfdf6204 100644
--- a/core/presentation/src/commonMain/composeResources/files/whatsnew/it/17.json
+++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/it/17.json
@@ -17,6 +17,12 @@
"Riconoscimento versioni più preciso — le release con lo stesso numero ma metadati di build diversi non vengono più erroneamente segnalate come 'già installate'.",
"Aggiornare più app di fila ora funziona in modo affidabile — le installazioni vengono serializzate, così ogni finestra di sistema mostra l'APK giusto. Anche le versioni nella schermata App restano aggiornate dopo ogni installazione."
]
+ },
+ {
+ "type": "IMPROVED",
+ "bullets": [
+ "Aggiornamenti in background più affidabili su Oppo, OnePlus, Realme, Xiaomi, vivo e Honor — le Impostazioni offrono ora una scorciatoia in un tocco per l'esenzione dall'ottimizzazione della batteria, e i job di aggiornamento girano con priorità accelerata."
+ ]
}
]
}
diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/ja/17.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/ja/17.json
index 7b5b6eca7..6d9242d88 100644
--- a/core/presentation/src/commonMain/composeResources/files/whatsnew/ja/17.json
+++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/ja/17.json
@@ -17,6 +17,12 @@
"バージョン検出を改善 — 同じバージョン番号でもビルドメタデータが異なるリリースを、誤って『インストール済み』と判定しなくなりました。",
"複数のアプリを連続更新する操作が安定しました — インストールが順番に実行されるため、システムダイアログに前のAPKが表示されることがなくなりました。インストールごとにアプリ画面のバージョンも正しく更新されます。"
]
+ },
+ {
+ "type": "IMPROVED",
+ "bullets": [
+ "Oppo / OnePlus / Realme / Xiaomi / vivo / Honor でバックグラウンド更新がより確実に — 設定にバッテリー最適化除外へのワンタップショートカットが追加され、更新ワーカーが優先実行されるようになりました。"
+ ]
}
]
}
diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/ko/17.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/ko/17.json
index ad6976e71..c3c186aec 100644
--- a/core/presentation/src/commonMain/composeResources/files/whatsnew/ko/17.json
+++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/ko/17.json
@@ -17,6 +17,12 @@
"버전 인식 개선 — 같은 버전 번호여도 빌드 메타데이터가 다른 릴리스를 더 이상 잘못 '이미 설치됨'으로 표시하지 않아요.",
"여러 앱을 연속으로 업데이트해도 안정적으로 동작해요 — 설치가 순차적으로 진행되어 시스템 대화상자에 이전 APK가 표시되지 않아요. 매번 설치 후 앱 화면의 버전도 바르게 갱신돼요."
]
+ },
+ {
+ "type": "IMPROVED",
+ "bullets": [
+ "Oppo, OnePlus, Realme, Xiaomi, vivo, Honor에서 백그라운드 업데이트가 더 안정적이에요 — 설정에 배터리 최적화 제외 바로가기가 추가됐고 업데이트 워커가 우선 실행돼요."
+ ]
}
]
}
diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/pl/17.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/pl/17.json
index 2f89371ec..5c42d7223 100644
--- a/core/presentation/src/commonMain/composeResources/files/whatsnew/pl/17.json
+++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/pl/17.json
@@ -17,6 +17,12 @@
"Lepsze wykrywanie wersji — wydania o tym samym numerze, ale z różnymi metadanymi build, nie są już błędnie oznaczane jako 'już zainstalowane'.",
"Aktualizowanie wielu aplikacji po kolei działa teraz niezawodnie — instalacje są szeregowane, więc okno dialogowe systemu nie pokazuje już poprzedniego APK. Wersje na ekranie aplikacji również są aktualizowane po każdej instalacji."
]
+ },
+ {
+ "type": "IMPROVED",
+ "bullets": [
+ "Bardziej niezawodne aktualizacje w tle na Oppo, OnePlus, Realme, Xiaomi, vivo i Honor — Ustawienia oferują teraz skrót do wyłączenia optymalizacji baterii w jednym kliknięciu, a zadania aktualizacji działają z przyspieszonym priorytetem."
+ ]
}
]
}
diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/ru/17.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/ru/17.json
index b7f4a881a..ebfd11811 100644
--- a/core/presentation/src/commonMain/composeResources/files/whatsnew/ru/17.json
+++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/ru/17.json
@@ -17,6 +17,12 @@
"Точнее определение версий — релизы с одинаковым номером, но разными метаданными сборки больше не помечаются ошибочно как 'уже установленные'.",
"Последовательное обновление нескольких приложений теперь стабильно — установки идут по очереди, поэтому в системном диалоге не показывается предыдущий APK. После каждой установки версия на экране приложений тоже обновляется корректно."
]
+ },
+ {
+ "type": "IMPROVED",
+ "bullets": [
+ "Надёжнее обновления в фоне на Oppo, OnePlus, Realme, Xiaomi, vivo и Honor — в настройках появился ярлык в один тап для исключения из оптимизации батареи, а воркеры обновлений работают с ускоренным приоритетом."
+ ]
}
]
}
diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/tr/17.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/tr/17.json
index c3fc4201b..a97511a4e 100644
--- a/core/presentation/src/commonMain/composeResources/files/whatsnew/tr/17.json
+++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/tr/17.json
@@ -17,6 +17,12 @@
"Daha iyi sürüm algılama — aynı numarayı paylaşan ancak farklı build meta verisi taşıyan sürümler artık yanlışlıkla 'zaten yüklü' olarak işaretlenmiyor.",
"Birkaç uygulamayı arka arkaya güncellemek artık güvenilir — yüklemeler sıralı çalıştığı için sistem diyaloğu önceki APK'yi göstermiyor. Her yüklemenin ardından Uygulamalar ekranındaki sürümler de doğru biçimde güncelleniyor."
]
+ },
+ {
+ "type": "IMPROVED",
+ "bullets": [
+ "Oppo, OnePlus, Realme, Xiaomi, vivo ve Honor'da arka plan güncellemeleri daha güvenilir — Ayarlar artık pil optimizasyonundan tek dokunuşla muafiyet kısayolu sunuyor ve güncelleme görevleri öncelikli (expedited) çalışıyor."
+ ]
}
]
}
diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/zh-CN/17.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/zh-CN/17.json
index e38d56e03..e2524e1f8 100644
--- a/core/presentation/src/commonMain/composeResources/files/whatsnew/zh-CN/17.json
+++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/zh-CN/17.json
@@ -17,6 +17,12 @@
"更准确的版本识别 — 数字版本相同但构建元数据不同的发布,不再被误判为'已安装相同版本'。",
"连续更新多个应用现在更可靠了 — 安装会依次进行,系统弹窗不再显示上一个 APK;每次安装后,应用界面的版本也会正确更新。"
]
+ },
+ {
+ "type": "IMPROVED",
+ "bullets": [
+ "Oppo / OnePlus / Realme / 小米 / vivo / Honor 上的后台更新更稳定 — 设置中新增电池优化白名单一键入口,更新任务以加急优先级运行。"
+ ]
}
]
}
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 43414994e..5560c3c06 100644
--- a/core/presentation/src/commonMain/composeResources/values-ar/strings-ar.xml
+++ b/core/presentation/src/commonMain/composeResources/values-ar/strings-ar.xml
@@ -572,6 +572,11 @@
١٢ ساعة
٢٤ ساعة
+ السماح بالتحديثات في الخلفية
+ جهازك يوقف المهام الخلفية بقوة. أضف GitHub Store إلى قائمة الاستثناء من تحسين البطارية حتى تعمل عمليات فحص التحديثات والتثبيت الصامت بشكل موثوق.
+ فتح الإعدادات
+ ربما لاحقاً
+
إضافة عبر رابط
ربط التطبيق بالمستودع
اختر تطبيقاً مثبتاً لربطه بمستودع GitHub
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 d3191cf7f..79b916877 100644
--- a/core/presentation/src/commonMain/composeResources/values-bn/strings-bn.xml
+++ b/core/presentation/src/commonMain/composeResources/values-bn/strings-bn.xml
@@ -571,6 +571,11 @@
১২ঘ
২৪ঘ
+ ব্যাকগ্রাউন্ড আপডেট অনুমতি দিন
+ আপনার ডিভাইস ব্যাকগ্রাউন্ড টাস্কগুলো আক্রমণাত্মকভাবে বন্ধ করে। GitHub Store-কে ব্যাটারি অপটিমাইজেশন থেকে হোয়াইটলিস্ট করুন যাতে নির্ধারিত আপডেট চেক এবং সাইলেন্ট ইনস্টল নির্ভরযোগ্যভাবে চলে।
+ সেটিংস খুলুন
+ পরে
+
লিঙ্ক দিয়ে যোগ করুন
অ্যাপ রিপোজিটরিতে লিঙ্ক করুন
GitHub রিপোজিটরিতে লিঙ্ক করতে একটি ইনস্টল করা অ্যাপ বেছে নিন
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 51c4e6dd5..97cbe06ed 100644
--- a/core/presentation/src/commonMain/composeResources/values-es/strings-es.xml
+++ b/core/presentation/src/commonMain/composeResources/values-es/strings-es.xml
@@ -532,6 +532,11 @@
12h
24h
+ Permitir actualizaciones en segundo plano
+ Tu dispositivo cierra agresivamente las tareas en segundo plano. Excluye GitHub Store de la optimización de batería para que las comprobaciones programadas y las instalaciones silenciosas funcionen de forma fiable.
+ Abrir ajustes
+ Más tarde
+
Añadir por enlace
Vincular app al repositorio
Elige una app instalada para vincularla a un repositorio de GitHub
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 351454034..1a120b645 100644
--- a/core/presentation/src/commonMain/composeResources/values-fr/strings-fr.xml
+++ b/core/presentation/src/commonMain/composeResources/values-fr/strings-fr.xml
@@ -533,6 +533,11 @@
12h
24h
+ Autoriser les mises à jour en arrière-plan
+ Votre appareil interrompt agressivement les tâches d\'arrière-plan. Excluez GitHub Store de l\'optimisation de la batterie pour que les vérifications planifiées et les installations silencieuses fonctionnent de manière fiable.
+ Ouvrir les paramètres
+ Plus tard
+
Ajouter par lien
Lier l'app au dépôt
Choisissez une app installée à lier à un dépôt GitHub
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 053687266..6130664d8 100644
--- a/core/presentation/src/commonMain/composeResources/values-hi/strings-hi.xml
+++ b/core/presentation/src/commonMain/composeResources/values-hi/strings-hi.xml
@@ -570,6 +570,11 @@
12घ
24घ
+ बैकग्राउंड अपडेट की अनुमति दें
+ आपका डिवाइस बैकग्राउंड कार्य आक्रामक रूप से बंद कर देता है। GitHub Store को बैटरी ऑप्टिमाइज़ेशन से व्हाइटलिस्ट करें ताकि निर्धारित अपडेट चेक और साइलेंट इंस्टॉल विश्वसनीय रूप से चलें।
+ सेटिंग्स खोलें
+ बाद में
+
लिंक से जोड़ें
ऐप को रिपॉजिटरी से लिंक करें
GitHub रिपॉजिटरी से लिंक करने के लिए एक इंस्टॉल किया हुआ ऐप चुनें
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 a454eefcf..b27c5cbf3 100644
--- a/core/presentation/src/commonMain/composeResources/values-it/strings-it.xml
+++ b/core/presentation/src/commonMain/composeResources/values-it/strings-it.xml
@@ -571,6 +571,11 @@
12h
24h
+ Consenti aggiornamenti in background
+ Il tuo dispositivo chiude in modo aggressivo le attività in background. Esenta GitHub Store dall\'ottimizzazione della batteria affinché i controlli pianificati e le installazioni silenziose funzionino in modo affidabile.
+ Apri impostazioni
+ Più tardi
+
Aggiungi tramite link
Collega app al repository
Scegli un'app installata da collegare a un repository GitHub
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 764bc4c89..12d02699d 100644
--- a/core/presentation/src/commonMain/composeResources/values-ja/strings-ja.xml
+++ b/core/presentation/src/commonMain/composeResources/values-ja/strings-ja.xml
@@ -534,6 +534,11 @@
12時間
24時間
+ バックグラウンド更新を許可
+ このデバイスはバックグラウンドタスクを積極的に終了します。バッテリー最適化からGitHub Storeを除外して、定期的な更新チェックとサイレントインストールが確実に動作するようにしましょう。
+ 設定を開く
+ 後で
+
リンクで追加
アプリをリポジトリにリンク
GitHubリポジトリにリンクするインストール済みアプリを選択
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 0d7f1ef67..4feaea090 100644
--- a/core/presentation/src/commonMain/composeResources/values-ko/strings-ko.xml
+++ b/core/presentation/src/commonMain/composeResources/values-ko/strings-ko.xml
@@ -569,6 +569,11 @@
12시간
24시간
+ 백그라운드 업데이트 허용
+ 이 기기는 백그라운드 작업을 적극적으로 종료해요. 배터리 최적화에서 GitHub Store를 화이트리스트에 추가하면 예약된 업데이트 확인과 사일런트 설치가 안정적으로 동작해요.
+ 설정 열기
+ 나중에
+
링크로 추가
앱을 저장소에 연결
GitHub 저장소에 연결할 설치된 앱을 선택하세요
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 f114557de..d4739e1ff 100644
--- a/core/presentation/src/commonMain/composeResources/values-pl/strings-pl.xml
+++ b/core/presentation/src/commonMain/composeResources/values-pl/strings-pl.xml
@@ -535,6 +535,11 @@
12g
24g
+ Zezwól na aktualizacje w tle
+ Twoje urządzenie agresywnie zamyka zadania w tle. Wyłącz optymalizację baterii dla GitHub Store, aby zaplanowane sprawdzenia aktualizacji i ciche instalacje działały niezawodnie.
+ Otwórz ustawienia
+ Później
+
Dodaj przez link
Połącz aplikację z repozytorium
Wybierz zainstalowaną aplikację, aby połączyć ją z repozytorium GitHub
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 a2eec0b1f..3be0b2098 100644
--- a/core/presentation/src/commonMain/composeResources/values-ru/strings-ru.xml
+++ b/core/presentation/src/commonMain/composeResources/values-ru/strings-ru.xml
@@ -535,6 +535,11 @@
12ч
24ч
+ Разрешить обновления в фоне
+ Ваше устройство агрессивно завершает фоновые задачи. Исключите GitHub Store из оптимизации батареи, чтобы запланированные проверки обновлений и тихая установка работали надёжно.
+ Открыть настройки
+ Позже
+
Добавить по ссылке
Привязать приложение к репозиторию
Выберите установленное приложение для привязки к репозиторию GitHub
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 75affb997..c12637d2b 100644
--- a/core/presentation/src/commonMain/composeResources/values-tr/strings-tr.xml
+++ b/core/presentation/src/commonMain/composeResources/values-tr/strings-tr.xml
@@ -569,6 +569,11 @@
12s
24s
+ Arka planda güncellemelere izin ver
+ Cihazın arka plan görevlerini agresif şekilde kapatıyor. GitHub Store\'u pil optimizasyonundan hariç tut ki zamanlanmış güncelleme kontrolleri ve sessiz kurulumlar güvenilir biçimde çalışsın.
+ Ayarları aç
+ Sonra
+
Bağlantıyla ekle
Uygulamayı depoya bağla
GitHub deposuna bağlamak için yüklü bir uygulama seçin
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 85b5d28ba..ff3c25175 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
@@ -535,6 +535,11 @@
12小时
24小时
+ 允许后台更新
+ 你的设备会积极结束后台任务。把 GitHub Store 加入电池优化白名单,定时更新检查和静默安装才能稳定运行。
+ 打开设置
+ 稍后
+
通过链接添加
将应用链接到仓库
选择一个已安装的应用以链接到GitHub仓库
diff --git a/core/presentation/src/commonMain/composeResources/values/strings.xml b/core/presentation/src/commonMain/composeResources/values/strings.xml
index fccf878e2..f5bb0ce99 100644
--- a/core/presentation/src/commonMain/composeResources/values/strings.xml
+++ b/core/presentation/src/commonMain/composeResources/values/strings.xml
@@ -665,6 +665,11 @@
12h
24h
+ Allow background updates
+ Your device aggressively kills background tasks. Whitelist GitHub Store from battery optimization so scheduled update checks and silent installs can run reliably.
+ Open settings
+ Maybe later
+
Add by link
Link app to repository
Pick an installed app to link with a GitHub repository
diff --git a/feature/tweaks/presentation/build.gradle.kts b/feature/tweaks/presentation/build.gradle.kts
index c0e08c444..cf0e9acf9 100644
--- a/feature/tweaks/presentation/build.gradle.kts
+++ b/feature/tweaks/presentation/build.gradle.kts
@@ -15,6 +15,7 @@ kotlin {
implementation(libs.androidx.compose.ui.tooling.preview)
implementation(libs.jetbrains.compose.components.resources)
+ implementation(libs.touchlab.kermit)
api(libs.ktor.client.core)
diff --git a/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksAction.kt b/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksAction.kt
index 75b70438b..66fd66fae 100644
--- a/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksAction.kt
+++ b/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksAction.kt
@@ -156,4 +156,16 @@ sealed interface TweaksAction {
data class OnAppLanguageSelected(
val tag: String?,
) : TweaksAction
+
+ data object OnOpenBatteryOptimizationSettings : TweaksAction
+
+ data object OnDismissBatteryOptimizationCard : TweaksAction
+
+ /**
+ * Re-evaluates whether the battery-optimization card should still
+ * show. Fired on Tweaks resume so the card disappears immediately
+ * after the user grants the exemption from the system Settings
+ * screen.
+ */
+ data object OnReevaluateBatteryOptimizationCard : TweaksAction
}
diff --git a/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksRoot.kt b/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksRoot.kt
index 8c85b59ce..e6c70d200 100644
--- a/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksRoot.kt
+++ b/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksRoot.kt
@@ -57,6 +57,9 @@ fun TweaksRoot(
androidx.lifecycle.LifecycleEventObserver { _, event ->
if (event == androidx.lifecycle.Lifecycle.Event.ON_RESUME) {
viewModel.onAction(TweaksAction.OnRefreshCacheSize)
+ // Re-eval after returning from system battery-optimization
+ // settings so the card disappears immediately on grant.
+ viewModel.onAction(TweaksAction.OnReevaluateBatteryOptimizationCard)
}
}
lifecycleOwner.lifecycle.addObserver(observer)
diff --git a/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksState.kt b/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksState.kt
index 6376e1e1f..b6b68f7e6 100644
--- a/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksState.kt
+++ b/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksState.kt
@@ -57,6 +57,13 @@ data class TweaksState(
*/
val selectedAppLanguage: String? = null,
val isFeedbackSheetVisible: Boolean = false,
+ /**
+ * True only on aggressive-OEM Android devices (Oppo, OnePlus, Realme,
+ * Xiaomi, vivo, Honor) that have NOT yet whitelisted the app from
+ * battery optimization AND the user has not dismissed the prompt.
+ * Drives the "Allow background updates" card in the Updates section.
+ */
+ val showBatteryOptimizationCard: Boolean = false,
) {
/** Effective provider to render as "selected" in the UI — draft
* overrides persisted when a pending selection is in flight. */
diff --git a/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksViewModel.kt b/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksViewModel.kt
index 28cbf1dec..31e1576f9 100644
--- a/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksViewModel.kt
+++ b/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksViewModel.kt
@@ -8,7 +8,10 @@ import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.catch
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.withTimeoutOrNull
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
@@ -27,6 +30,7 @@ import zed.rainxch.core.domain.repository.ProxyRepository
import zed.rainxch.core.domain.repository.SeenReposRepository
import zed.rainxch.core.domain.repository.TelemetryRepository
import zed.rainxch.core.domain.repository.TweaksRepository
+import zed.rainxch.core.domain.system.AggressiveOemDetector
import zed.rainxch.core.domain.system.InstallerStatusProvider
import zed.rainxch.core.domain.system.UpdateScheduleManager
import zed.rainxch.tweaks.presentation.model.ProxyScopeFormState
@@ -54,7 +58,12 @@ class TweaksViewModel(
private val deviceIdentityRepository: DeviceIdentityRepository,
private val telemetryRepository: TelemetryRepository,
private val logger: GitHubStoreLogger,
+ private val aggressiveOemDetector: AggressiveOemDetector,
) : ViewModel() {
+ private companion object {
+ private const val BATTERY_OPT_PREF_READ_TIMEOUT_MS: Long = 1_000
+ }
+
private var hasLoadedInitialData = false
private var cacheSizeJob: Job? = null
@@ -84,6 +93,11 @@ class TweaksViewModel(
hasLoadedInitialData = true
}
refreshCacheSize()
+ // Re-evaluate on every Tweaks (re-)entry: the user may
+ // have whitelisted the app from system Settings since
+ // the last evaluation, in which case the card should
+ // disappear without requiring an explicit dismiss.
+ evaluateBatteryOptimizationCard()
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000L),
@@ -426,6 +440,27 @@ class TweaksViewModel(
}
}
+ private fun evaluateBatteryOptimizationCard() {
+ viewModelScope.launch {
+ val dismissed =
+ runCatching {
+ withTimeoutOrNull(BATTERY_OPT_PREF_READ_TIMEOUT_MS) {
+ tweaksRepository.getBatteryOptimizationPromptDismissed().firstOrNull()
+ }
+ }.onFailure { error ->
+ logger.error(
+ "TweaksViewModel: failed to read battery-opt dismissed flag",
+ error,
+ )
+ }.getOrNull() ?: false
+ val show =
+ aggressiveOemDetector.isAggressiveOem() &&
+ !aggressiveOemDetector.isBatteryOptimizationIgnored() &&
+ !dismissed
+ _state.update { it.copy(showBatteryOptimizationCard = show) }
+ }
+ }
+
private fun loadAppLanguage() {
viewModelScope.launch {
tweaksRepository.getAppLanguage().collect { tag ->
@@ -886,6 +921,31 @@ class TweaksViewModel(
}
}
}
+
+ TweaksAction.OnOpenBatteryOptimizationSettings -> {
+ val launched = aggressiveOemDetector.openBatteryOptimizationSettings()
+ if (!launched) {
+ logger.warn("TweaksViewModel: failed to launch battery optimization settings")
+ }
+ }
+
+ TweaksAction.OnDismissBatteryOptimizationCard -> {
+ viewModelScope.launch {
+ runCatching {
+ tweaksRepository.setBatteryOptimizationPromptDismissed(true)
+ }.onFailure {
+ logger.error(
+ "TweaksViewModel: failed to persist battery-opt dismiss",
+ it,
+ )
+ }
+ _state.update { it.copy(showBatteryOptimizationCard = false) }
+ }
+ }
+
+ TweaksAction.OnReevaluateBatteryOptimizationCard -> {
+ evaluateBatteryOptimizationCard()
+ }
}
}
diff --git a/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/components/sections/Installation.kt b/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/components/sections/Installation.kt
index b804e9cf1..895e729ec 100644
--- a/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/components/sections/Installation.kt
+++ b/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/components/sections/Installation.kt
@@ -293,6 +293,18 @@ fun LazyListScope.updatesSection(
Spacer(Modifier.height(8.dp))
+ if (state.showBatteryOptimizationCard) {
+ BatteryOptimizationCard(
+ onOpenSettings = {
+ onAction(TweaksAction.OnOpenBatteryOptimizationSettings)
+ },
+ onDismiss = {
+ onAction(TweaksAction.OnDismissBatteryOptimizationCard)
+ },
+ )
+ Spacer(Modifier.height(12.dp))
+ }
+
BackgroundUpdateCheckToggleCard(
enabled = state.updateCheckEnabled,
onToggle = { enabled ->
@@ -827,3 +839,43 @@ private fun HintText(text: String) {
modifier = Modifier.padding(start = 8.dp, top = 4.dp)
)
}
+
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
+@Composable
+private fun BatteryOptimizationCard(
+ onOpenSettings: () -> Unit,
+ onDismiss: () -> Unit,
+) {
+ ExpressiveCard {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(16.dp),
+ verticalArrangement = Arrangement.spacedBy(8.dp),
+ ) {
+ Text(
+ text = stringResource(Res.string.battery_optimization_card_title),
+ style = MaterialTheme.typography.titleMedium,
+ fontWeight = FontWeight.SemiBold,
+ color = MaterialTheme.colorScheme.onSurface,
+ )
+ Text(
+ text = stringResource(Res.string.battery_optimization_card_description),
+ style = MaterialTheme.typography.bodySmall,
+ color = MaterialTheme.colorScheme.onSurfaceVariant,
+ )
+
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.End),
+ ) {
+ androidx.compose.material3.TextButton(onClick = onDismiss) {
+ Text(stringResource(Res.string.battery_optimization_card_dismiss))
+ }
+ FilledTonalButton(onClick = onOpenSettings) {
+ Text(stringResource(Res.string.battery_optimization_card_open))
+ }
+ }
+ }
+ }
+}