feat(setup): bootstrap Android plugin and web UI
This initial commit adds a multi-part scaffold for Wechselbild, including a web UI and an Android plugin. It introduces frontend assets and a package.json-based dev setup, plus plugin scaffolding for Android with Kotlin sources and Cargo.toml for the Tauri plugin. - Adds Android wallpaper plugin with Kotlin sources and manifest - Includes web UI scaffold with index.html and package.json - Adds Tauri plugin scaffold with Cargo.toml and build config
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
package de.wechselbild.wallpaper
|
||||
|
||||
import android.app.WallpaperManager
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.util.Base64
|
||||
import app.tauri.plugin.JSArray
|
||||
import app.tauri.plugin.JSObject
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import kotlin.random.Random
|
||||
|
||||
object WallpaperStore {
|
||||
private const val PREFS = "wechselbild"
|
||||
private const val KEY_INDEX = "current_index"
|
||||
fun directory(context: Context) = File(context.filesDir, "wallpapers").apply { mkdirs() }
|
||||
fun files(context: Context) = directory(context).listFiles()?.filter { it.isFile }?.sortedBy { it.name } ?: emptyList()
|
||||
private fun prefs(context: Context) = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
|
||||
fun enabled(context: Context) = prefs(context).getBoolean("enabled", false)
|
||||
fun shuffle(context: Context) = prefs(context).getBoolean("shuffle", true)
|
||||
fun lockOnly(context: Context) = prefs(context).getBoolean("lockScreenOnly", true)
|
||||
|
||||
fun set(context: Context, name: String, value: Boolean) {
|
||||
require(name in setOf("enabled", "shuffle", "lockScreenOnly")) { "Unbekannte Einstellung" }
|
||||
prefs(context).edit().putBoolean(name, value).apply()
|
||||
}
|
||||
|
||||
fun state(context: Context): JSObject {
|
||||
val originals = files(context)
|
||||
val index = prefs(context).getInt(KEY_INDEX, 0).coerceIn(0, (originals.size - 1).coerceAtLeast(0))
|
||||
val previewFiles = if (index < 24) originals.take(24) else listOf(originals[index]) + originals.take(23)
|
||||
val previewIndex = if (index < 24) index else 0
|
||||
return JSObject().apply {
|
||||
put("imageCount", originals.size)
|
||||
put("enabled", enabled(context))
|
||||
put("shuffle", shuffle(context))
|
||||
put("lockScreenOnly", lockOnly(context))
|
||||
put("currentIndex", previewIndex)
|
||||
val previews = JSArray()
|
||||
previewFiles.forEach { previews.put(thumbnailDataUrl(it)) }
|
||||
put("imageUrls", previews)
|
||||
}
|
||||
}
|
||||
|
||||
private fun thumbnailDataUrl(file: File): String {
|
||||
val bounds = BitmapFactory.Options().apply { inJustDecodeBounds = true }
|
||||
BitmapFactory.decodeFile(file.absolutePath, bounds)
|
||||
var sample = 1
|
||||
while (bounds.outWidth / sample > 360 || bounds.outHeight / sample > 480) sample *= 2
|
||||
val bitmap = BitmapFactory.decodeFile(file.absolutePath, BitmapFactory.Options().apply { inSampleSize = sample }) ?: return ""
|
||||
return ByteArrayOutputStream().use { out ->
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 76, out)
|
||||
bitmap.recycle()
|
||||
"data:image/jpeg;base64," + Base64.encodeToString(out.toByteArray(), Base64.NO_WRAP)
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun applyNext(context: Context): Boolean {
|
||||
val images = files(context)
|
||||
if (images.isEmpty()) return false
|
||||
val preferences = prefs(context)
|
||||
val previous = preferences.getInt(KEY_INDEX, -1)
|
||||
val index = if (shuffle(context) && images.size > 1) {
|
||||
generateSequence { Random.nextInt(images.size) }.first { it != previous }
|
||||
} else (previous + 1).mod(images.size)
|
||||
val bitmap = BitmapFactory.decodeFile(images[index].absolutePath) ?: return false
|
||||
try {
|
||||
val manager = WallpaperManager.getInstance(context)
|
||||
if (android.os.Build.VERSION.SDK_INT >= 24 && lockOnly(context)) manager.setBitmap(bitmap, null, true, WallpaperManager.FLAG_LOCK)
|
||||
else manager.setBitmap(bitmap)
|
||||
preferences.edit().putInt(KEY_INDEX, index).apply()
|
||||
return true
|
||||
} finally { bitmap.recycle() }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user