Add Supa account and search changes

This commit is contained in:
Fabian Freund
2026-05-22 18:10:22 +02:00
parent 3a19865b2e
commit 51289f1266
374 changed files with 54061 additions and 5013 deletions
@@ -32,10 +32,11 @@ import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.PluginRegistry
import eu.weblibre.simple_intent_receiver.pigeons.IntentHost
import eu.weblibre.simple_intent_receiver.pigeons.Intent as PigeonIntent
import eu.weblibre.simple_intent_receiver.pigeons.IntentGatekeeperHostApi
class SimpleIntentReceiverPlugin: FlutterPlugin, ActivityAware, PluginRegistry.NewIntentListener {
class SimpleIntentReceiverPlugin: FlutterPlugin, ActivityAware, PluginRegistry.NewIntentListener, IntentHost {
companion object {
// Stable names that must match the notification replay path and shared-prefs schema.
private const val PREFS_NAME = "weblibre_intent_gatekeeper"
@@ -53,10 +54,28 @@ class SimpleIntentReceiverPlugin: FlutterPlugin, ActivityAware, PluginRegistry.N
private var activity: Activity? = null
private var binaryMessenger: io.flutter.plugin.common.BinaryMessenger? = null
/**
* Caches the launch intent so Dart can retrieve it after setUp().
* On cold start, onAttachedToActivity fires before Dart registers its
* Pigeon handler, so the initial sendIntent message is lost. This field
* lets Dart call getInitialIntent() to recover it.
*
* On Android configuration change (rotation, theme switch) the activity
* is recreated and onAttachedToActivity fires again with the same
* launching intent. The `lastHandledIntent` guard below prevents
* re-caching that identical intent. If a NEW deep link arrives via the
* launcher between two Dart-side reads of getInitialIntent(),
* pendingInitialIntent is overwritten — only the latest intent is
* delivered. This is intentional: dropping the stale one keeps the
* "initial" intent meaning "what should the app open into right now".
*/
private var pendingInitialIntent: PigeonIntent? = null
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
context = flutterPluginBinding.applicationContext
intentReceiver = IntentReceiver(flutterPluginBinding.binaryMessenger)
binaryMessenger = flutterPluginBinding.binaryMessenger
IntentHost.setUp(flutterPluginBinding.binaryMessenger, this)
IntentGatekeeperHostApi.setUp(
flutterPluginBinding.binaryMessenger,
IntentGatekeeperHostApiImpl(flutterPluginBinding.applicationContext),
@@ -65,10 +84,19 @@ class SimpleIntentReceiverPlugin: FlutterPlugin, ActivityAware, PluginRegistry.N
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
intentReceiver = null
binaryMessenger?.let { IntentGatekeeperHostApi.setUp(it, null) }
binaryMessenger?.let {
IntentHost.setUp(it, null)
IntentGatekeeperHostApi.setUp(it, null)
}
binaryMessenger = null
}
override fun getInitialIntent(): PigeonIntent? {
val intent = pendingInitialIntent
pendingInitialIntent = null
return intent
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
activity = binding.activity
binding.addOnNewIntentListener(this)
@@ -76,7 +104,10 @@ class SimpleIntentReceiverPlugin: FlutterPlugin, ActivityAware, PluginRegistry.N
binding.activity.intent?.let { intent ->
val uri = intent.toUri(0)
if (lastHandledIntent != uri) {
handleIntent(intent)
// Cache the launch intent for Dart to retrieve via getInitialIntent().
// Don't send via Pigeon here — the Dart handler isn't registered yet
// during cold start so the message would be lost.
pendingInitialIntent = prepareIntentForDelivery(intent)
lastHandledIntent = uri
}
}
@@ -100,8 +131,7 @@ class SimpleIntentReceiverPlugin: FlutterPlugin, ActivityAware, PluginRegistry.N
return handleIntent(intent)
}
private fun handleIntent(intent: Intent): Boolean {
// Grant URI permissions for content URIs
private fun grantUriPermissions(intent: Intent) {
intent.data?.let { uri ->
if (uri.scheme == "content") {
try {
@@ -116,7 +146,6 @@ class SimpleIntentReceiverPlugin: FlutterPlugin, ActivityAware, PluginRegistry.N
}
}
// Handle SEND action with STREAM extra
intent.getStringExtra(Intent.EXTRA_STREAM)?.let { streamUri ->
try {
val uri = Uri.parse(streamUri)
@@ -131,15 +160,23 @@ class SimpleIntentReceiverPlugin: FlutterPlugin, ActivityAware, PluginRegistry.N
Log.w("SimpleIntentReceiver", "Could not grant URI permission for stream: $streamUri", e)
}
}
}
private fun handleIntent(intent: Intent): Boolean {
val pigeonIntent = prepareIntentForDelivery(intent)
intentReceiver?.sendIntent(pigeonIntent)
return true
}
private fun prepareIntentForDelivery(intent: Intent): PigeonIntent {
grantUriPermissions(intent)
if (intent.flags and Intent.FLAG_ACTIVITY_NEW_TASK != 0) {
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
}
val notificationApproval = consumeNotificationApproval(intent)
val pigeonIntent = convertToPigeonIntent(intent, notificationApproval)
intentReceiver?.sendIntent(pigeonIntent)
return true
return convertToPigeonIntent(intent, notificationApproval)
}
private fun resolveCallerPackage(intent: Intent, notificationApproval: NotificationApproval?): String? {
@@ -270,6 +270,43 @@ private open class IntentPigeonCodec : StandardMessageCodec() {
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
interface IntentHost {
/**
* Returns the launch intent that started the activity, if any.
* This allows Dart to retrieve an intent that arrived before
* IntentEvents.setUp() was called (cold-start deep links).
* Returns null if no launch intent is pending.
*/
fun getInitialIntent(): Intent?
companion object {
/** The codec used by IntentHost. */
val codec: MessageCodec<Any?> by lazy {
IntentPigeonCodec()
}
/** Sets up an instance of `IntentHost` to handle messages through the `binaryMessenger`. */
@JvmOverloads
fun setUp(binaryMessenger: BinaryMessenger, api: IntentHost?, messageChannelSuffix: String = "") {
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.simple_intent_receiver.IntentHost.getInitialIntent$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
val wrapped: List<Any?> = try {
listOf(api.getInitialIntent())
} catch (exception: Throwable) {
IntentPigeonUtils.wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
}
}
}
/** Generated class from Pigeon that represents Flutter messages that can be called from Kotlin. */
class IntentEvents(private val binaryMessenger: BinaryMessenger, private val messageChannelSuffix: String = "") {
companion object {