feat(widget): Android forecast widgets (Solar/Price/CO₂/Feed-in) - #264
Draft
webalexeu wants to merge 7 commits into
Draft
feat(widget): Android forecast widgets (Solar/Price/CO₂/Feed-in)#264webalexeu wants to merge 7 commits into
webalexeu wants to merge 7 commits into
Conversation
Adds loadpoint and forecast home-screen widgets built with Jetpack Glance: a widget configuration activity for picking server + loadpoint, real chart rendering for forecast data, per-instance widget config with immediate refresh on server change, and widget package name derived from app config so fork builds can coexist with the official app install. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
lint was failing on 3 @typescript-eslint/no-explicit-any errors in withAndroidWidget.ts; typed the receiver/activity manifest nodes against AndroidConfig.Manifest instead. Also brings the README status section up to date - it still described the pipeline-spike state (one widget, no config Activity, no instant refresh) even though all 5 widgets, per-instance config, and instant refresh are implemented.
Ports LoadpointVM's full status/metric logic (heating, finished/ waitForVehicle, kWh fallback), status dot + color coding, a canvas-rendered progress bar (Glance has no fractional-width modifier), chip-style mode buttons, a two-column forecast header, a chart Y-axis + step-vs-area modes + per-type color (previously always a flat green line), bold/colored footer stats, and day/night theming throughout - all mirrored from LoadpointViews.swift / Views.swift / Theme.swift. Both widget config Activities now fetch real data for the tapped choice and show an actual preview of the widget (plain Views reusing the same chart/ progress-bar bitmaps, since a live Glance render would need pulling in the full Compose UI stack) before committing via a new "Use this" button, instead of committing immediately on tap with no preview. Verified with expo prebuild + local assembleDebug/assembleRelease builds.
The Android widgets and their config Activities had hardcoded English text. Extend build-widget-strings.mts (already generating the iOS .xcstrings catalog from evcc's + this app's Weblate translations) to also emit Android string resources under targets/android-widget/res/values(-b+<locale>)/, and have withAndroidWidget.ts merge them into the prebuilt project's values/strings.xml (which already has app_name etc.) instead of overwriting it. Replaced every hardcoded string in the widget/config-Activity Kotlin with R.string.* lookups. The config Activities' picker/live-preview flow has no iOS equivalent, so those strings are new additions to this app's own i18n (en.json source + de.json, matching this repo's i18n conventions) rather than reuses of existing evcc/app keys. Also generalized the config plugin's package-rewrite from a single `package` line replace to a whole-file regex, since the widget Kotlin now needs `import io.evcc.android.R` to resolve correctly for the LOCAL-ONLY dev fork build too (io.evcc.android.dev). Verified with expo prebuild + local assembleDebug (confirmed the manifest merge keeps app_name, and R resolves for the fork package).
Adds the last open follow-up from the parity work: a second widget size,
mirroring LoadpointCard's HStack { left; modeSelector } on iOS. Declares
SizeMode.Responsive(setOf(SMALL_SIZE, WIDE_SIZE)) and reads LocalSize to
branch layout - compact keeps the inline mode-chip row (deliberately kept
interactive, unlike iOS's compact size which drops to a plain-text mode
label), wide adds a vertical mode-selector column alongside. No manifest
change needed since the widget was already resizable; this just makes the
wider size render differently once a user resizes it.
Forecast widgets have no iOS size-variant precedent, so they stay single-size.
Verified with expo prebuild + local assembleDebug.
pairs with evcc-io/evcc#32490 and mirrors targets/widget/Loadpoint.swift's handling from evcc-io#246, which this branch picked up via a rebase onto main. Detects smart-mode servers via loadpoints[].alwaysCharge, switching the selector to off/smart/now (with device-class labels for continuous heat pumps and switchable devices) while old servers keep off/pv/minpv/now unchanged. A read-only "∞" marks the Smart chip when Always charge is on/once, no toggle in the widget yet, matching iOS. Also fixes a bug the rebase's auto-merge introduced: the frozen pv/minpv legacy-label loop wrote straight into `strings`, a variable that in this branch is now built later from an intermediate `translations` map (added here to share resolved strings between the iOS and Android generators) - it was referencing `strings` before its declaration.
Addresses evcc-io#255#issuecomment-5317470240 (Maschga's PR review): - LoadpointWidget gets a reload button in the title row (res/drawable/ic_reload.xml tinted via Glance's ColorFilter.tint(), wired to a new ReloadAction), mirroring iOS's ReloadIntent. - Both widget families are now tappable end-to-end, deep-linking to the right app screen (evcc://loadpoint?server=&lp=, evcc://forecast?server=, evcc://server when unconfigured) via a shared deepLinkAction() helper - mirrors widgetURL in LoadpointViews.swift/Views.swift, including the same query param semantics the app's own router (AppContext.tsx) expects. - loadpoint_widget_info.xml's resize bounds are now pinned to SizeMode.Responsive's two declared breakpoints (180-340dp wide, height locked at 110dp, resizeMode="horizontal" only) instead of open-ended horizontal|vertical; forecast_widget_info.xml drops resizeMode entirely since those widgets have no size-variant layout. Closes the gap where a launcher could hand the widget a real container bigger than any size Glance was told to lay content out for, leaving unfillable blank space - the likely cause of the "strange spacing" in Maschga's screenshot, pending on-device confirmation. The mode-button highlight bug and widget-reconfigure check from the same review are held for a live-device pass.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #255 (split out per naltatis's review: #255 (comment))
#255 now covers the Android Loadpoint widget only. This branch is a snapshot of #255 from just before that split - it still has the from-scratch Solar/Price/CO₂/Feed-in forecast widgets, kept here for whenever the charting approach is settled (Android has no first-party charting API comparable to iOS's Swift Charts; the current implementation hand-rolls each chart to a Canvas bitmap in
ChartRenderer.ktrather than relying on a library).ForecastWidget.kt/ChartRenderer.kt- the four forecast widgets, Y-axis + step/step-area/area chart modes, per-type colorForecastWidgetConfigActivity.kt- server picker + live preview, Solar's "adjust to real production" toggleApiClient.kt/SharedStore.kt/Theme.kt/WidgetConfig.ktwith the Loadpoint widget in feat: Android home-screen widgets (Jetpack Glance) #255TODO
ChartRenderer.kt(already working) vs. a library (e.g. Vico'scompose-glancemodule, currently pre-release) - before this is ready for review