fixed stale state after logout and replayed or lost share intents

This commit is contained in:
2026-09-24 21:43:21 +02:00
parent e4e2b1a4fb
commit 498d195138
32 changed files with 743 additions and 188 deletions
+1 -1
View File
@@ -9,7 +9,7 @@
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:launchMode="singleTask"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
@@ -1,15 +1,38 @@
package eu.mhsl.marianum.mobile.client
import android.content.Intent
import android.os.Bundle
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
class MainActivity : FlutterActivity() {
private val widgetChannel = "eu.mhsl.marianum.widget"
private val shareChannel = "eu.mhsl.marianum.share"
/// Last seen widget tap target. Cleared by Dart via `consumePendingNavigation`
/// so the same intent isn't replayed on every resume.
private var pendingTimetableTap: Boolean = false
private val shareActions = setOf(Intent.ACTION_SEND, Intent.ACTION_SEND_MULTIPLE)
/// receive_sharing_intent only emits warm shares to a live Dart listener and
/// does not buffer them. After a relaunch into an existing task the share
/// arrives via onNewIntent before Dart subscribed, so it is held here until
/// Dart reports `listenerReady`.
private var shareListenerReady = false
private var bufferedShare: Intent? = null
override fun onCreate(savedInstanceState: Bundle?) {
// Android replays the original launch intent when the activity is
// recreated from recents or after process death. A share or widget tap
// that was already handled would otherwise run again — for shares with
// temp files that are long gone.
val replayed = savedInstanceState != null ||
(intent.flags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0
if (replayed && (intent.action in shareActions || isWidgetTap(intent))) {
intent = Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER)
}
super.onCreate(savedInstanceState)
}
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
@@ -26,17 +49,35 @@ class MainActivity : FlutterActivity() {
else -> result.notImplemented()
}
}
MethodChannel(
flutterEngine.dartExecutor.binaryMessenger,
shareChannel
).setMethodCallHandler { call, result ->
when (call.method) {
"listenerReady" -> {
shareListenerReady = true
bufferedShare?.let { flutterEngine.activityControlSurface.onNewIntent(it) }
bufferedShare = null
result.success(null)
}
else -> result.notImplemented()
}
}
consumeIntentData(intent)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
if (!shareListenerReady && intent.action in shareActions) {
bufferedShare = intent
}
consumeIntentData(intent)
}
private fun isWidgetTap(intent: Intent?): Boolean =
intent?.getBooleanExtra("widget_open_timetable", false) == true
private fun consumeIntentData(intent: Intent?) {
if (intent?.getBooleanExtra("widget_open_timetable", false) == true) {
pendingTimetableTap = true
}
if (isWidgetTap(intent)) pendingTimetableTap = true
}
}