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>,
|
||||
|
||||
+12
-4
@@ -1,10 +1,10 @@
|
||||
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
||||
import { ArrowLeft, Check, ChevronRight, Cloud, CloudDownload, Crop, Home, Images, Languages, Link2Off, LockKeyhole, Plus, RotateCcw, RotateCw, Save, Server, Settings, Shuffle, Smartphone, Sparkles, Trash2 } from "lucide-react";
|
||||
import { ArrowLeft, Check, ChevronRight, Cloud, CloudDownload, Crop, Download, Home, Images, Languages, Link2Off, LockKeyhole, Plus, RotateCcw, RotateCw, Save, Server, Settings, Shuffle, Smartphone, Sparkles, Trash2, Wifi } from "lucide-react";
|
||||
import { applyWallpaper, connectImmich, deleteImages, disconnectImmich, getGallery, getImageIds, getImmichAlbums, getImmichAssets, getImmichConnection, getImmichImportProgress, getState, importImmichAssets, nextWallpaper, selectImages, setImageCrop, setIntervalMinutes, setSetting, type GalleryImage, type ImmichAlbum, type ImmichAsset, type ImmichConnection, type ImmichImportProgress, type WallpaperState } from "./native";
|
||||
import { initialLanguage, languageNames, languages, translations, type Language } from "./i18n-local";
|
||||
import { immichTranslations } from "./immich-i18n";
|
||||
|
||||
const initial: WallpaperState = { imageCount: 0, enabled: false, intervalMinutes: 0, shuffle: true, lockScreenOnly: true, currentIndex: 0, currentId: null, imageIds: [], imageUrls: [] };
|
||||
const initial: WallpaperState = { imageCount: 0, enabled: false, intervalMinutes: 0, shuffle: true, lockScreenOnly: true, allowMobileData: false, prefetchImmich: true, currentIndex: 0, currentId: null, imageIds: [], imageUrls: [] };
|
||||
|
||||
function Switch({ checked, onChange, label }: { checked: boolean; onChange: (value: boolean) => void; label: string }) {
|
||||
return <button className={`switch ${checked ? "on" : ""}`} role="switch" aria-checked={checked} aria-label={label} onClick={() => onChange(!checked)}><span /></button>;
|
||||
@@ -107,13 +107,17 @@ export default function App() {
|
||||
finally { setGalleryLoading(false); }
|
||||
}
|
||||
|
||||
async function update(name: "shuffle" | "lockScreenOnly", value: boolean) {
|
||||
async function update(name: "shuffle" | "lockScreenOnly" | "allowMobileData" | "prefetchImmich", value: boolean) {
|
||||
const previous = state[name];
|
||||
setState(prev => ({ ...prev, [name]: value }));
|
||||
try {
|
||||
const saved = await setSetting(name, value);
|
||||
setState(saved);
|
||||
setNotice(t.settingSaved);
|
||||
} catch { setNotice(t.androidOnly); }
|
||||
} catch (error) {
|
||||
setState(prev => ({ ...prev, [name]: previous }));
|
||||
setNotice(String(error).replace(/^Error:\s*/, "") || t.androidOnly);
|
||||
}
|
||||
}
|
||||
|
||||
async function updateInterval(minutes: number) {
|
||||
@@ -425,6 +429,10 @@ export default function App() {
|
||||
<div className="immich-title"><span><Cloud /></span><div><h3>{it.immich}</h3><p>{it.immichIntro}</p></div></div>
|
||||
{immichConnection.configured ? <>
|
||||
<div className="immich-connected"><strong>{it.connectedAs} {immichConnection.userName}</strong><span>{immichConnection.serverUrl}</span></div>
|
||||
<SettingRow icon={<Download />} label={it.prefetchImmich} value={state.prefetchImmich} onChange={v => update("prefetchImmich", v)} />
|
||||
<p className="immich-help">{it.prefetchImmichHint}</p>
|
||||
<SettingRow icon={<Wifi />} label={it.allowMobileData} value={state.allowMobileData} onChange={v => update("allowMobileData", v)} />
|
||||
<p className="immich-help">{it.allowMobileDataHint}</p>
|
||||
<button className="immich-open" onClick={openImmich} disabled={busy}><Images /> {it.openImmich} <ChevronRight /></button>
|
||||
<button className="immich-disconnect" onClick={removeImmichConnection} disabled={busy}><Link2Off /> {it.disconnect}</button>
|
||||
</> : <>
|
||||
|
||||
@@ -22,6 +22,10 @@ export type ImmichText = {
|
||||
importSuccess: string;
|
||||
immichLoadFailed: string;
|
||||
noImmichPhotos: string;
|
||||
allowMobileData: string;
|
||||
allowMobileDataHint: string;
|
||||
prefetchImmich: string;
|
||||
prefetchImmichHint: string;
|
||||
};
|
||||
|
||||
export const immichTranslations: Record<Language, ImmichText> = {
|
||||
@@ -47,6 +51,10 @@ export const immichTranslations: Record<Language, ImmichText> = {
|
||||
importSuccess: "Immich-Bilder wurden zur Sammlung hinzugefügt",
|
||||
immichLoadFailed: "Immich-Bilder konnten nicht geladen werden",
|
||||
noImmichPhotos: "Keine Bilder gefunden",
|
||||
allowMobileData: "Auch über mobile Daten laden",
|
||||
allowMobileDataHint: "Ist das ausgeschaltet, lädt der automatische Wechsel Immich-Bilder nur über WLAN und überspringt sie sonst. Manuelles Wechseln lädt immer.",
|
||||
prefetchImmich: "Immich-Bilder immer vorladen",
|
||||
prefetchImmichHint: "Lädt neue Immich-Bilder automatisch im Hintergrund herunter, sobald WLAN verfügbar ist – nie über mobile Daten. Ausgeschaltet werden Bilder nur bei Bedarf geladen.",
|
||||
},
|
||||
en: {
|
||||
immich: "Immich", immichIntro: "Import images from your own Immich server.", serverUrl: "Server URL", apiKey: "API key",
|
||||
@@ -56,6 +64,10 @@ export const immichTranslations: Record<Language, ImmichText> = {
|
||||
httpWarning: "HTTP is unencrypted. Use HTTPS outside your home network.", allPhotos: "All photos",
|
||||
selectImmichPhotos: "Select images to import", importSelected: "Import selection", importing: "Importing images…",
|
||||
importSuccess: "Immich images imported", immichLoadFailed: "Could not load Immich images", noImmichPhotos: "No images found",
|
||||
allowMobileData: "Allow downloads over mobile data",
|
||||
allowMobileDataHint: "When off, automatic rotation only downloads Immich images over Wi-Fi and skips them otherwise. Manually changing the wallpaper always downloads.",
|
||||
prefetchImmich: "Always prefetch Immich images",
|
||||
prefetchImmichHint: "Downloads new Immich images in the background as soon as Wi-Fi is available – never over mobile data. When off, images are only downloaded when needed.",
|
||||
},
|
||||
fr: {
|
||||
immich: "Immich", immichIntro: "Importez des images depuis votre propre serveur Immich.", serverUrl: "URL du serveur", apiKey: "Clé API",
|
||||
@@ -65,6 +77,10 @@ export const immichTranslations: Record<Language, ImmichText> = {
|
||||
httpWarning: "HTTP n’est pas chiffré. Utilisez HTTPS hors de votre réseau domestique.", allPhotos: "Toutes les photos",
|
||||
selectImmichPhotos: "Sélectionnez les images à importer", importSelected: "Importer la sélection", importing: "Importation des images…",
|
||||
importSuccess: "Images Immich importées", immichLoadFailed: "Impossible de charger les images Immich", noImmichPhotos: "Aucune image trouvée",
|
||||
allowMobileData: "Autoriser les données mobiles",
|
||||
allowMobileDataHint: "Désactivé, la rotation automatique ne télécharge les images Immich que via le Wi-Fi et les ignore sinon. Un changement manuel télécharge toujours.",
|
||||
prefetchImmich: "Toujours précharger les images Immich",
|
||||
prefetchImmichHint: "Télécharge les nouvelles images Immich en arrière-plan dès que le Wi-Fi est disponible – jamais via les données mobiles. Désactivé, les images ne sont téléchargées qu’en cas de besoin.",
|
||||
},
|
||||
es: {
|
||||
immich: "Immich", immichIntro: "Importa imágenes desde tu propio servidor Immich.", serverUrl: "URL del servidor", apiKey: "Clave API",
|
||||
@@ -74,6 +90,10 @@ export const immichTranslations: Record<Language, ImmichText> = {
|
||||
httpWarning: "HTTP no está cifrado. Usa HTTPS fuera de tu red doméstica.", allPhotos: "Todas las fotos",
|
||||
selectImmichPhotos: "Selecciona imágenes para importar", importSelected: "Importar selección", importing: "Importando imágenes…",
|
||||
importSuccess: "Imágenes de Immich importadas", immichLoadFailed: "No se pudieron cargar las imágenes de Immich", noImmichPhotos: "No se encontraron imágenes",
|
||||
allowMobileData: "Permitir datos móviles",
|
||||
allowMobileDataHint: "Si está desactivado, la rotación automática solo descarga imágenes de Immich por Wi-Fi y las omite si no hay Wi-Fi. Cambiar manualmente siempre descarga.",
|
||||
prefetchImmich: "Precargar siempre las imágenes de Immich",
|
||||
prefetchImmichHint: "Descarga las nuevas imágenes de Immich en segundo plano en cuanto haya Wi-Fi disponible, nunca con datos móviles. Si está desactivado, las imágenes solo se descargan cuando se necesitan.",
|
||||
},
|
||||
it: {
|
||||
immich: "Immich", immichIntro: "Importa immagini dal tuo server Immich.", serverUrl: "URL del server", apiKey: "Chiave API",
|
||||
@@ -83,6 +103,10 @@ export const immichTranslations: Record<Language, ImmichText> = {
|
||||
httpWarning: "HTTP non è crittografato. Usa HTTPS fuori dalla rete domestica.", allPhotos: "Tutte le foto",
|
||||
selectImmichPhotos: "Seleziona le immagini da importare", importSelected: "Importa selezione", importing: "Importazione immagini…",
|
||||
importSuccess: "Immagini Immich importate", immichLoadFailed: "Impossibile caricare le immagini Immich", noImmichPhotos: "Nessuna immagine trovata",
|
||||
allowMobileData: "Consenti dati mobili",
|
||||
allowMobileDataHint: "Se disattivato, la rotazione automatica scarica le immagini Immich solo via Wi-Fi e le salta altrimenti. Il cambio manuale scarica sempre.",
|
||||
prefetchImmich: "Precarica sempre le immagini Immich",
|
||||
prefetchImmichHint: "Scarica le nuove immagini Immich in background non appena il Wi-Fi è disponibile, mai con i dati mobili. Se disattivato, le immagini vengono scaricate solo quando servono.",
|
||||
},
|
||||
nl: {
|
||||
immich: "Immich", immichIntro: "Importeer afbeeldingen van je eigen Immich-server.", serverUrl: "Server-URL", apiKey: "API-sleutel",
|
||||
@@ -92,6 +116,10 @@ export const immichTranslations: Record<Language, ImmichText> = {
|
||||
httpWarning: "HTTP is niet versleuteld. Gebruik HTTPS buiten je thuisnetwerk.", allPhotos: "Alle foto’s",
|
||||
selectImmichPhotos: "Selecteer afbeeldingen om te importeren", importSelected: "Selectie importeren", importing: "Afbeeldingen importeren…",
|
||||
importSuccess: "Immich-afbeeldingen geïmporteerd", immichLoadFailed: "Immich-afbeeldingen konden niet worden geladen", noImmichPhotos: "Geen afbeeldingen gevonden",
|
||||
allowMobileData: "Mobiele data toestaan",
|
||||
allowMobileDataHint: "Indien uit, worden Immich-afbeeldingen bij automatisch wisselen alleen via wifi gedownload en anders overgeslagen. Handmatig wisselen downloadt altijd.",
|
||||
prefetchImmich: "Immich-afbeeldingen altijd vooraf laden",
|
||||
prefetchImmichHint: "Downloadt nieuwe Immich-afbeeldingen op de achtergrond zodra wifi beschikbaar is – nooit via mobiele data. Indien uit, worden afbeeldingen alleen bij gebruik gedownload.",
|
||||
},
|
||||
pl: {
|
||||
immich: "Immich", immichIntro: "Importuj obrazy z własnego serwera Immich.", serverUrl: "Adres serwera", apiKey: "Klucz API",
|
||||
@@ -101,6 +129,10 @@ export const immichTranslations: Record<Language, ImmichText> = {
|
||||
httpWarning: "HTTP nie jest szyfrowany. Poza siecią domową używaj HTTPS.", allPhotos: "Wszystkie zdjęcia",
|
||||
selectImmichPhotos: "Wybierz obrazy do importu", importSelected: "Importuj wybrane", importing: "Importowanie obrazów…",
|
||||
importSuccess: "Zaimportowano obrazy Immich", immichLoadFailed: "Nie udało się wczytać obrazów Immich", noImmichPhotos: "Nie znaleziono obrazów",
|
||||
allowMobileData: "Zezwól na dane mobilne",
|
||||
allowMobileDataHint: "Gdy wyłączone, automatyczna zmiana pobiera obrazy Immich tylko przez Wi-Fi, w przeciwnym razie je pomija. Ręczna zmiana zawsze pobiera.",
|
||||
prefetchImmich: "Zawsze pobieraj obrazy Immich z wyprzedzeniem",
|
||||
prefetchImmichHint: "Pobiera nowe obrazy Immich w tle, gdy tylko dostępne jest Wi-Fi – nigdy przez dane mobilne. Gdy wyłączone, obrazy są pobierane tylko w razie potrzeby.",
|
||||
},
|
||||
pt: {
|
||||
immich: "Immich", immichIntro: "Importe imagens do seu próprio servidor Immich.", serverUrl: "URL do servidor", apiKey: "Chave de API",
|
||||
@@ -110,6 +142,10 @@ export const immichTranslations: Record<Language, ImmichText> = {
|
||||
httpWarning: "HTTP não é encriptado. Use HTTPS fora da sua rede doméstica.", allPhotos: "Todas as fotos",
|
||||
selectImmichPhotos: "Selecione imagens para importar", importSelected: "Importar seleção", importing: "A importar imagens…",
|
||||
importSuccess: "Imagens do Immich importadas", immichLoadFailed: "Não foi possível carregar imagens do Immich", noImmichPhotos: "Nenhuma imagem encontrada",
|
||||
allowMobileData: "Permitir dados móveis",
|
||||
allowMobileDataHint: "Quando desativado, a rotação automática só transfere imagens do Immich por Wi-Fi e ignora-as caso contrário. A troca manual transfere sempre.",
|
||||
prefetchImmich: "Pré-carregar sempre imagens do Immich",
|
||||
prefetchImmichHint: "Transfere novas imagens do Immich em segundo plano assim que o Wi-Fi estiver disponível – nunca com dados móveis. Quando desativado, as imagens só são transferidas quando necessário.",
|
||||
},
|
||||
ja: {
|
||||
immich: "Immich", immichIntro: "自分の Immich サーバーから画像を取り込みます。", serverUrl: "サーバー URL", apiKey: "API キー",
|
||||
@@ -119,6 +155,10 @@ export const immichTranslations: Record<Language, ImmichText> = {
|
||||
httpWarning: "HTTP は暗号化されません。自宅ネットワーク外では HTTPS を使用してください。", allPhotos: "すべての写真",
|
||||
selectImmichPhotos: "取り込む画像を選択", importSelected: "選択項目を取り込む", importing: "画像を取り込み中…",
|
||||
importSuccess: "Immich の画像を取り込みました", immichLoadFailed: "Immich の画像を読み込めません", noImmichPhotos: "画像が見つかりません",
|
||||
allowMobileData: "モバイルデータでのダウンロードを許可",
|
||||
allowMobileDataHint: "オフの場合、自動切り替えは Wi-Fi 接続時のみ Immich の画像をダウンロードし、それ以外はスキップします。手動での切り替えは常にダウンロードします。",
|
||||
prefetchImmich: "Immich画像を常に先読みする",
|
||||
prefetchImmichHint: "Wi-Fi が利用可能になり次第、新しい Immich 画像をバックグラウンドでダウンロードします(モバイルデータは使用しません)。オフの場合、画像は必要なときのみダウンロードされます。",
|
||||
},
|
||||
ko: {
|
||||
immich: "Immich", immichIntro: "내 Immich 서버에서 이미지를 가져옵니다.", serverUrl: "서버 URL", apiKey: "API 키",
|
||||
@@ -128,6 +168,10 @@ export const immichTranslations: Record<Language, ImmichText> = {
|
||||
httpWarning: "HTTP는 암호화되지 않습니다. 홈 네트워크 밖에서는 HTTPS를 사용하세요.", allPhotos: "모든 사진",
|
||||
selectImmichPhotos: "가져올 이미지를 선택하세요", importSelected: "선택 항목 가져오기", importing: "이미지 가져오는 중…",
|
||||
importSuccess: "Immich 이미지를 가져왔습니다", immichLoadFailed: "Immich 이미지를 불러올 수 없습니다", noImmichPhotos: "이미지를 찾을 수 없습니다",
|
||||
allowMobileData: "모바일 데이터 다운로드 허용",
|
||||
allowMobileDataHint: "꺼져 있으면 자동 변경 시 Wi-Fi에서만 Immich 이미지를 다운로드하고 그렇지 않으면 건너뜁니다. 수동 변경은 항상 다운로드합니다.",
|
||||
prefetchImmich: "Immich 이미지 항상 미리 다운로드",
|
||||
prefetchImmichHint: "Wi-Fi를 사용할 수 있게 되면 새 Immich 이미지를 백그라운드에서 다운로드합니다(모바일 데이터는 사용하지 않음). 꺼져 있으면 필요할 때만 이미지를 다운로드합니다.",
|
||||
},
|
||||
"zh-CN": {
|
||||
immich: "Immich", immichIntro: "从你自己的 Immich 服务器导入图片。", serverUrl: "服务器 URL", apiKey: "API 密钥",
|
||||
@@ -137,5 +181,9 @@ export const immichTranslations: Record<Language, ImmichText> = {
|
||||
httpWarning: "HTTP 未加密。在家庭网络之外请使用 HTTPS。", allPhotos: "所有照片",
|
||||
selectImmichPhotos: "选择要导入的图片", importSelected: "导入所选图片", importing: "正在导入图片…",
|
||||
importSuccess: "已导入 Immich 图片", immichLoadFailed: "无法加载 Immich 图片", noImmichPhotos: "未找到图片",
|
||||
allowMobileData: "允许使用移动数据下载",
|
||||
allowMobileDataHint: "关闭时,自动更换仅在 Wi-Fi 下下载 Immich 图片,否则将跳过;手动更换始终会下载。",
|
||||
prefetchImmich: "始终预下载 Immich 图片",
|
||||
prefetchImmichHint: "只要有 Wi-Fi 可用,就会在后台下载新的 Immich 图片——绝不使用移动数据。关闭时,图片仅在需要时才会下载。",
|
||||
},
|
||||
};
|
||||
|
||||
+5
-1
@@ -6,6 +6,8 @@ export type WallpaperState = {
|
||||
intervalMinutes: number;
|
||||
shuffle: boolean;
|
||||
lockScreenOnly: boolean;
|
||||
allowMobileData: boolean;
|
||||
prefetchImmich: boolean;
|
||||
currentIndex: number;
|
||||
currentId: string | null;
|
||||
imageIds: string[];
|
||||
@@ -68,6 +70,8 @@ const demoState: WallpaperState = {
|
||||
intervalMinutes: 30,
|
||||
shuffle: true,
|
||||
lockScreenOnly: true,
|
||||
allowMobileData: false,
|
||||
prefetchImmich: true,
|
||||
currentIndex: 0,
|
||||
currentId: "demo-0",
|
||||
imageIds: ["demo-0", "demo-1", "demo-2"],
|
||||
@@ -148,7 +152,7 @@ export async function setImageCrop(image: GalleryImage): Promise<GalleryImage> {
|
||||
return { ...image };
|
||||
}
|
||||
|
||||
export async function setSetting(name: "shuffle" | "lockScreenOnly", value: boolean) {
|
||||
export async function setSetting(name: "shuffle" | "lockScreenOnly" | "allowMobileData" | "prefetchImmich", value: boolean) {
|
||||
if (!inTauri()) return { ...demoState, [name]: value };
|
||||
return invoke<WallpaperState>("plugin:wallpaper|set_setting", { name, value });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user