feat(immich): add prefetch and mobile data controls
Adds Immich image prefetch and a mobile data option to the UI. Android now ships ImmichPrefetchWorker to fetch originals in the background. Frontend and desktop code are updated to expose and persist new settings. Translations cover the new labels and hints in multiple languages. - Introduce ImmichPrefetchWorker for background prefetch - Add allowMobileData and prefetchImmich UI controls - Wire changes to desktop state and translations
This commit is contained in:
@@ -11,5 +11,6 @@ class BootReceiver : BroadcastReceiver() {
|
||||
WallpaperStore.screenOnEnabled(context) -> runCatching { ScreenOnRotationService.start(context) }
|
||||
WallpaperStore.timedEnabled(context) -> WallpaperScheduler.scheduleNext(context)
|
||||
}
|
||||
if (ImmichClient.configured(context) && WallpaperStore.prefetchImmich(context)) ImmichPrefetchWorker.enqueue(context)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,6 +119,11 @@ object ImmichClient {
|
||||
|
||||
fun connection(context: Context) = connectionObject(context)
|
||||
|
||||
fun configured(context: Context): Boolean {
|
||||
val preferences = prefs(context)
|
||||
return preferences.getString(KEY_SERVER_URL, "").orEmpty().isNotBlank() && !decryptApiKey(context).isNullOrBlank()
|
||||
}
|
||||
|
||||
fun connect(context: Context, serverUrl: String, apiKey: String): JSObject {
|
||||
val normalized = normalizeServerUrl(serverUrl)
|
||||
require(apiKey.isNotBlank()) { "Bitte gib deinen Immich API-Key ein." }
|
||||
@@ -314,10 +319,10 @@ object ImmichClient {
|
||||
return bounds.outWidth > 0 && bounds.outHeight > 0
|
||||
}
|
||||
|
||||
fun automaticDownloadsAllowed(context: Context): Boolean {
|
||||
fun automaticDownloadsAllowed(context: Context, allowMetered: Boolean): Boolean {
|
||||
val connectivity = context.getSystemService(ConnectivityManager::class.java)
|
||||
@Suppress("DEPRECATION")
|
||||
return connectivity.activeNetworkInfo?.isConnected == true && !connectivity.isActiveNetworkMetered
|
||||
return connectivity.activeNetworkInfo?.isConnected == true && (allowMetered || !connectivity.isActiveNetworkMetered)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package de.wechselbild.wallpaper
|
||||
|
||||
import android.content.Context
|
||||
import androidx.work.Constraints
|
||||
import androidx.work.ExistingPeriodicWorkPolicy
|
||||
import androidx.work.NetworkType
|
||||
import androidx.work.PeriodicWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class ImmichPrefetchWorker(context: Context, parameters: WorkerParameters) : Worker(context, parameters) {
|
||||
override fun doWork(): Result {
|
||||
WallpaperStore.prefetchImmichOriginals(applicationContext)
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val WORK_NAME = "immich-wifi-prefetch"
|
||||
|
||||
fun enqueue(context: Context) {
|
||||
val constraints = Constraints.Builder()
|
||||
.setRequiredNetworkType(NetworkType.UNMETERED)
|
||||
.setRequiresBatteryNotLow(true)
|
||||
.build()
|
||||
val request = PeriodicWorkRequestBuilder<ImmichPrefetchWorker>(6, TimeUnit.HOURS)
|
||||
.setConstraints(constraints)
|
||||
.build()
|
||||
WorkManager.getInstance(context).enqueueUniquePeriodicWork(WORK_NAME, ExistingPeriodicWorkPolicy.KEEP, request)
|
||||
}
|
||||
|
||||
fun cancel(context: Context) {
|
||||
WorkManager.getInstance(context).cancelUniqueWork(WORK_NAME)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,11 +170,14 @@ class WallpaperPlugin(private val activity: Activity) : Plugin(activity) {
|
||||
@Command fun connectImmich(invoke: Invoke) = io.execute {
|
||||
try {
|
||||
val args = invoke.parseArgs(ImmichConnectArgs::class.java)
|
||||
invoke.resolve(ImmichClient.connect(activity, args.serverUrl, args.apiKey))
|
||||
val result = ImmichClient.connect(activity, args.serverUrl, args.apiKey)
|
||||
if (WallpaperStore.prefetchImmich(activity)) ImmichPrefetchWorker.enqueue(activity)
|
||||
invoke.resolve(result)
|
||||
} catch (error: Exception) { invoke.reject(error.message ?: "Immich-Verbindung fehlgeschlagen") }
|
||||
}
|
||||
|
||||
@Command fun disconnectImmich(invoke: Invoke) = io.execute {
|
||||
ImmichPrefetchWorker.cancel(activity)
|
||||
invoke.resolve(ImmichClient.disconnect(activity))
|
||||
}
|
||||
|
||||
|
||||
@@ -102,10 +102,16 @@ object WallpaperStore {
|
||||
fun screenOnEnabled(context: Context) = intervalMinutes(context) == -1
|
||||
fun shuffle(context: Context) = prefs(context).getBoolean("shuffle", true)
|
||||
fun lockOnly(context: Context) = prefs(context).getBoolean("lockScreenOnly", true)
|
||||
fun allowMobileData(context: Context) = prefs(context).getBoolean("allowMobileData", false)
|
||||
fun prefetchImmich(context: Context) = prefs(context).getBoolean("prefetchImmich", true)
|
||||
|
||||
fun set(context: Context, name: String, value: Boolean) {
|
||||
require(name in setOf("shuffle", "lockScreenOnly")) { "Unbekannte Einstellung" }
|
||||
require(name in setOf("shuffle", "lockScreenOnly", "allowMobileData", "prefetchImmich")) { "Unbekannte Einstellung" }
|
||||
prefs(context).edit().putBoolean(name, value).apply()
|
||||
if (name == "prefetchImmich") {
|
||||
if (value && ImmichClient.configured(context)) ImmichPrefetchWorker.enqueue(context)
|
||||
else if (!value) ImmichPrefetchWorker.cancel(context)
|
||||
}
|
||||
}
|
||||
|
||||
fun setInterval(context: Context, minutes: Int) {
|
||||
@@ -125,6 +131,8 @@ object WallpaperStore {
|
||||
put("intervalMinutes", intervalMinutes(context))
|
||||
put("shuffle", shuffle(context))
|
||||
put("lockScreenOnly", lockOnly(context))
|
||||
put("allowMobileData", allowMobileData(context))
|
||||
put("prefetchImmich", prefetchImmich(context))
|
||||
put("currentIndex", previewIndex)
|
||||
put("currentId", items.getOrNull(index)?.id ?: JSONObject.NULL)
|
||||
val ids = JSArray()
|
||||
@@ -152,6 +160,16 @@ object WallpaperStore {
|
||||
@Synchronized
|
||||
fun imageIds(context: Context) = entries(context).map { it.id }
|
||||
|
||||
fun prefetchImmichOriginals(context: Context) {
|
||||
val unavailableServers = mutableSetOf<String>()
|
||||
entries(context).filterIsInstance<Entry.Immich>().forEach { entry ->
|
||||
if (entry.serverUrl in unavailableServers) return@forEach
|
||||
if (ImmichClient.cachedOriginal(context, entry.serverUrl, entry.assetId, allowNetwork = true) == null) {
|
||||
unavailableServers.add(entry.serverUrl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun cropKey(id: String) = CROP_PREFIX + id
|
||||
private fun crop(context: Context, entry: Entry): CropSettings {
|
||||
val raw = prefs(context).getString(cropKey(entry.id), null) ?: return CropSettings()
|
||||
@@ -401,7 +419,7 @@ object WallpaperStore {
|
||||
val sourceFile = when (entry) {
|
||||
is Entry.Local -> entry.file
|
||||
is Entry.Immich -> {
|
||||
val allowNetwork = entry.serverUrl !in unavailableServers && (!automatic || ImmichClient.automaticDownloadsAllowed(context))
|
||||
val allowNetwork = entry.serverUrl !in unavailableServers && (!automatic || ImmichClient.automaticDownloadsAllowed(context, allowMobileData(context)))
|
||||
val source = ImmichClient.cachedOriginal(context, entry.serverUrl, entry.assetId, allowNetwork)
|
||||
if (source == null) {
|
||||
if (allowNetwork) unavailableServers.add(entry.serverUrl)
|
||||
|
||||
@@ -21,6 +21,8 @@ impl<R: Runtime> Wallpaper<R> {
|
||||
interval_minutes: 30,
|
||||
shuffle: true,
|
||||
lock_screen_only: true,
|
||||
allow_mobile_data: false,
|
||||
prefetch_immich: true,
|
||||
current_index: 0,
|
||||
current_id: Some("demo-0".into()),
|
||||
image_ids: vec!["demo-0".into(), "demo-1".into(), "demo-2".into()],
|
||||
@@ -89,6 +91,8 @@ impl<R: Runtime> Wallpaper<R> {
|
||||
"enabled" => state.enabled = payload.value,
|
||||
"shuffle" => state.shuffle = payload.value,
|
||||
"lockScreenOnly" => state.lock_screen_only = payload.value,
|
||||
"allowMobileData" => state.allow_mobile_data = payload.value,
|
||||
"prefetchImmich" => state.prefetch_immich = payload.value,
|
||||
_ => {}
|
||||
};
|
||||
Ok(state)
|
||||
|
||||
@@ -8,6 +8,8 @@ pub struct WallpaperState {
|
||||
pub interval_minutes: i32,
|
||||
pub shuffle: bool,
|
||||
pub lock_screen_only: bool,
|
||||
pub allow_mobile_data: bool,
|
||||
pub prefetch_immich: bool,
|
||||
pub current_index: usize,
|
||||
pub current_id: Option<String>,
|
||||
pub image_ids: Vec<String>,
|
||||
|
||||
Reference in New Issue
Block a user