Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export default ({ config }: ConfigContext) =>
},
plugins: [
"@bacons/apple-targets",
["./scripts/androidWidget/withAndroidWidget.ts"],
["./scripts/fdroid/configureFdroid.ts"],
[
"./scripts/detox/configureDetox.ts",
Expand Down
14 changes: 14 additions & 0 deletions i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,20 @@
"server": "Server",
"loadpoint": "Ladepunkt"
},
"androidConfig": {
"chooseServer": "Server auswählen",
"chooseLoadpoint": "Ladepunkt auswählen",
"noServers": "Keine Server — füge zuerst einen in der App hinzu",
"noLoadpoints": "Keine Ladepunkte erreichbar",
"loading": "Lädt…",
"loadingPreview": "Vorschau wird geladen…",
"previewError": "Vorschau konnte nicht geladen werden",
"useThisLoadpoint": "Diesen Ladepunkt verwenden",
"useThis": "Diesen verwenden",
"adjustQuestion": "An reale Erzeugung anpassen?",
"yesRecommended": "Ja (empfohlen)",
"no": "Nein"
},
"loadpoint": {
"name": "Ladepunkt",
"description": "Ladepunkt-Status und Lademodus."
Expand Down
14 changes: 14 additions & 0 deletions i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,20 @@
"server": "Server",
"loadpoint": "Loadpoint"
},
"androidConfig": {
"chooseServer": "Choose server",
"chooseLoadpoint": "Choose loadpoint",
"noServers": "No servers — add one in the app first",
"noLoadpoints": "No loadpoints reachable",
"loading": "Loading…",
"loadingPreview": "Loading preview…",
"previewError": "Couldn't load a preview",
"useThisLoadpoint": "Use this loadpoint",
"useThis": "Use this",
"adjustQuestion": "Adjust to real production?",
"yesRecommended": "Yes (recommended)",
"no": "No"
},
"loadpoint": {
"name": "Loadpoint",
"description": "Loadpoint status and charge mode."
Expand Down
18 changes: 18 additions & 0 deletions modules/evcc-widget/android/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
plugins {
id 'com.android.library'
id 'expo-module-gradle-plugin'
}

group = 'expo.modules.evccwidget'
version = '0.1.0'

android {
namespace "expo.modules.evccwidget"
defaultConfig {
versionCode 1
versionName "0.1.0"
}
lintOptions {
abortOnError false
}
}
2 changes: 2 additions & 0 deletions modules/evcc-widget/android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<manifest>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package expo.modules.evccwidget

import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.content.Intent
import expo.modules.kotlin.modules.Module
import expo.modules.kotlin.modules.ModuleDefinition

class EvccWidgetModule : Module() {
// Glance widget receivers injected by scripts/androidWidget/withAndroidWidget.ts.
// Names are stable; the package is resolved at runtime so dev/prod app ids both work.
private val receivers = listOf(
"EvccLoadpointWidgetReceiver",
"EvccSolarWidgetReceiver",
"EvccPriceWidgetReceiver",
"EvccCo2WidgetReceiver",
"EvccFeedinWidgetReceiver",
)

override fun definition() = ModuleDefinition {
Name("EvccWidget")

// Force an immediate redraw of the home-screen widgets. Sends each receiver a
// targeted APPWIDGET_UPDATE broadcast; GlanceAppWidgetReceiver re-runs
// provideGlance on receipt, so the widgets re-read the synced server list.
Function("refresh") {
val context = appContext.reactContext?.applicationContext ?: return@Function Unit
val manager = AppWidgetManager.getInstance(context)
val pkg = context.packageName

for (name in receivers) {
val cn = ComponentName(pkg, "$pkg.widget.$name")
val ids = try {
manager.getAppWidgetIds(cn)
} catch (e: Exception) {
continue // provider not present (e.g. widget type never placed)
}
if (ids.isNotEmpty()) {
val intent = Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE).apply {
component = cn
putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
}
context.sendBroadcast(intent)
}
}
}
}
}
6 changes: 6 additions & 0 deletions modules/evcc-widget/expo-module.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"platforms": ["android"],
"android": {
"modules": ["expo.modules.evccwidget.EvccWidgetModule"]
}
}
7 changes: 7 additions & 0 deletions modules/evcc-widget/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "evcc-widget",
"version": "0.1.0",
"description": "Native Android widget refresh module for evcc",
"license": "MIT",
"platforms": ["android"]
}
9 changes: 9 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"@types/react": "~19.2.10",
"axios": "^1.16.0",
"base-64": "^1.0.0",
"evcc-widget": "file:./modules/evcc-widget",
"expo": "^57.0.0",
"expo-build-properties": "~57.0.7",
"expo-camera": "~57.0.3",
Expand Down
Loading
Loading