package com.soulstream.transfernotice import android.Manifest import android.app.Activity import android.content.pm.PackageManager import android.os.Build import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import app.tauri.annotation.Command import app.tauri.annotation.InvokeArg import app.tauri.annotation.TauriPlugin import app.tauri.plugin.Invoke import app.tauri.plugin.JSObject import app.tauri.plugin.Plugin /** What the notice says — the Rust `TransferNotice`, camelCase. */ @InvokeArg class NoticeArgs { /** how many files are still in flight; zero means take the notice down */ var count: Int = 0 var title: String? = null var line: String? = null var percent: Int = 0 /** nobody has stated a size yet, so the bar has no end to walk towards */ var indeterminate: Boolean = false } /** * The bridge between the WebView and the service that owns the notice. * `update` mirrors what Save is fetching (and starts the service the first * time); `clear` takes the notice down. Its buttons come back as the plugin * event `action` with `{ action }` — "cancel" or "open". */ @TauriPlugin class TransferNoticePlugin(private val activity: Activity) : Plugin(activity) { private var askedForNotifications = false init { TransferHub.onAction = { action -> val payload = JSObject() payload.put("action", action) trigger("action", payload) } /* the channel exists from app start, so a user can silence the downloads on their own before the first one ever runs */ TransferHub.ensureChannel(activity.applicationContext) } @Command fun update(invoke: Invoke) { val args = invoke.parseArgs(NoticeArgs::class.java) ensureNotificationPermission() TransferHub.update(activity.applicationContext, args) invoke.resolve() } @Command fun clear(invoke: Invoke) { TransferHub.clear(activity.applicationContext) invoke.resolve() } /** Android 13+: the notice is a notification and needs the permission; * asked once, the first time something is fetched. Its own request code * — 4711 is the media card's, and two requests that share one would * answer each other. The service runs either way; without the * permission it simply has nothing to show. */ private fun ensureNotificationPermission() { if (Build.VERSION.SDK_INT < 33 || askedForNotifications) return askedForNotifications = true if (ContextCompat.checkSelfPermission(activity, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED ) return ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.POST_NOTIFICATIONS), 4712) } }