diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-08-06 09:30:36 +0000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-08-06 09:30:36 +0000 |
| commit | ab76bcae1324aadb6d163e565f5994d0db10ca61 (patch) | |
| tree | b086ec7650a8185f1437598741114f49b3be5568 | |
| parent | f479211f0885776c379c598dac738ac08ea72548 (diff) | |
Widget: wrap the web dashboard in a WebView (DashboardActivity)
First cut per the 2026-08-06 feasibility check (verdict: easy, no
architecture blockers): a plain WebView pointed at the configured
server URL, cookie jar enabled for the existing session-cookie login
(internal/auth/middleware.go's RequireAuth) -- no separate auth bridge
needed, the widget's own bearer token is a completely different scheme
and doesn't need to touch this at all. External links (e.g. a calendar
event's source URL) escape to the user's real browser instead of
getting stuck in the WebView.
No deep-linking to specific tabs, no native-rendered chrome -- this is
the minimal first step to validate the wrapped experience is worth
building further, not the final shape.
| -rw-r--r-- | android/app/src/main/AndroidManifest.xml | 6 | ||||
| -rw-r--r-- | android/app/src/main/java/org/terst/doot/widget/ui/DashboardActivity.kt | 76 |
2 files changed, 82 insertions, 0 deletions
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index ca96e71..c2200ba 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -33,6 +33,12 @@ android:exported="false" android:windowSoftInputMode="adjustResize" /> + <!-- Full dashboard, wrapped in a WebView (see DashboardActivity's doc comment) --> + <activity + android:name=".ui.DashboardActivity" + android:exported="false" + android:label="Doot" /> + <!-- Settings activity (also the widget config screen) --> <activity android:name=".ui.SettingsActivity" diff --git a/android/app/src/main/java/org/terst/doot/widget/ui/DashboardActivity.kt b/android/app/src/main/java/org/terst/doot/widget/ui/DashboardActivity.kt new file mode 100644 index 0000000..f5ae744 --- /dev/null +++ b/android/app/src/main/java/org/terst/doot/widget/ui/DashboardActivity.kt @@ -0,0 +1,76 @@ +package org.terst.doot.widget.ui + +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.view.KeyEvent +import android.webkit.CookieManager +import android.webkit.WebView +import android.webkit.WebViewClient +import androidx.activity.ComponentActivity +import androidx.core.net.toUri +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.launch +import androidx.lifecycle.lifecycleScope +import org.terst.doot.widget.data.Keys +import org.terst.doot.widget.data.dataStore + +/** + * Wraps the existing web dashboard in a plain WebView -- the same session-cookie + * login flow a browser would use (see internal/auth/middleware.go's RequireAuth), + * no separate auth bridge needed since the widget's own bearer token is a + * completely different scheme. First cut per the 2026-08-06 feasibility check: + * one Activity, no deep-linking to specific tabs, no native-rendered chrome -- + * just prove the wrapped experience is worth building further before investing + * in anything past this. + */ +class DashboardActivity : ComponentActivity() { + + private lateinit var webView: WebView + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + webView = WebView(this).apply { + settings.javaScriptEnabled = true + settings.domStorageEnabled = true + settings.setSupportZoom(false) + webViewClient = object : WebViewClient() { + override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean { + val uri = url.toUri() + val sameHost = uri.host == null || uri.host == serverHost + if (sameHost) return false + // External links (e.g. a calendar event's source URL) open in the + // user's actual browser/app instead of getting stuck in this WebView. + startActivity(Intent(Intent.ACTION_VIEW, uri)) + return true + } + } + } + setContentView(webView) + + CookieManager.getInstance().setAcceptCookie(true) + CookieManager.getInstance().setAcceptThirdPartyCookies(webView, true) + + lifecycleScope.launch { + val prefs = dataStore.data.first() + val url = prefs[Keys.SERVER_URL]?.trimEnd('/') + if (url.isNullOrBlank()) { + finish() + return@launch + } + serverHost = url.toUri().host + webView.loadUrl(url) + } + } + + private var serverHost: String? = null + + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { + if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) { + webView.goBack() + return true + } + return super.onKeyDown(keyCode, event) + } +} |
