diff --git a/Cable/Loads/LoadsView.swift b/Cable/Loads/LoadsView.swift
index 0581f77..354cf26 100644
--- a/Cable/Loads/LoadsView.swift
+++ b/Cable/Loads/LoadsView.swift
@@ -19,7 +19,7 @@ struct LoadsView: View {
@State private var showingSystemEditor = false
@State private var hasPresentedSystemEditorOnAppear = false
@State private var hasOpenedLoadOnAppear = false
- @State private var showingComponentLibrary = false
+ @State private var activeLibrary: ComponentLibraryType?
@State private var showingSystemBOM = false
@State private var selectedComponentTab: ComponentTab
@State private var batteryDraft: BatteryConfiguration?
@@ -86,23 +86,7 @@ struct LoadsView: View {
.accessibilityIdentifier("components-tab")
}
- Group {
- if savedBatteries.isEmpty {
- OnboardingInfoView(
- configuration: .battery(),
- onPrimaryAction: { startBatteryConfiguration() }
- )
- } else {
- BatteriesView(
- system: system,
- batteries: savedBatteries,
- editMode: $editMode,
- onEdit: { editBattery($0) },
- onDelete: deleteBatteries
- )
- .environment(\.editMode, $editMode)
- }
- }
+ batteriesTab
.tag(ComponentTab.batteries)
.tabItem {
Label(
@@ -117,14 +101,7 @@ struct LoadsView: View {
}
.environment(\.editMode, $editMode)
- ChargersView(
- system: system,
- chargers: savedChargers,
- editMode: $editMode,
- onAdd: { startChargerConfiguration() },
- onEdit: { editCharger($0) },
- onDelete: deleteChargers
- )
+ chargersTab
.tag(ComponentTab.chargers)
.tabItem {
Label(
@@ -272,9 +249,9 @@ struct LoadsView: View {
exportDiagramImage()
}
}
- .sheet(isPresented: $showingComponentLibrary) {
- ComponentLibraryView { item in
- addComponent(item)
+ .sheet(item: $activeLibrary) { type in
+ ComponentLibraryView(libraryType: type) { item in
+ handleLibrarySelection(item, for: type)
}
}
.sheet(isPresented: $showingSystemBOM) {
@@ -439,9 +416,9 @@ struct LoadsView: View {
}
}
- private var libraryButton: some View {
+ private func libraryButton(type: ComponentLibraryType) -> some View {
Button {
- openComponentLibrary(source: "library-button")
+ openComponentLibrary(source: "library-button", type: type)
} label: {
Group {
if #available(iOS 26.0, *) {
@@ -490,6 +467,53 @@ struct LoadsView: View {
.background(Color(.systemGroupedBackground))
}
+ private var batteriesTab: some View {
+ Group {
+ if savedBatteries.isEmpty {
+ OnboardingInfoView(
+ configuration: .battery(),
+ onPrimaryAction: { startBatteryConfiguration() },
+ onSecondaryAction: { openComponentLibrary(source: "batteries-onboarding", type: .battery) }
+ )
+ } else {
+ BatteriesView(
+ system: system,
+ batteries: savedBatteries,
+ editMode: $editMode,
+ onEdit: { editBattery($0) },
+ onDelete: deleteBatteries
+ )
+ .environment(\.editMode, $editMode)
+ }
+ }
+ .overlay(alignment: .bottomTrailing) {
+ if !savedBatteries.isEmpty {
+ libraryButton(type: .battery)
+ .padding(.trailing, 24)
+ .padding(.bottom, 24)
+ }
+ }
+ }
+
+ private var chargersTab: some View {
+ ChargersView(
+ system: system,
+ chargers: savedChargers,
+ editMode: $editMode,
+ onAdd: { startChargerConfiguration() },
+ onEdit: { editCharger($0) },
+ onDelete: deleteChargers,
+ onBrowseLibrary: { openComponentLibrary(source: "chargers-onboarding", type: .charger) }
+ )
+ .overlay(alignment: .bottomTrailing) {
+ if !savedChargers.isEmpty {
+ libraryButton(type: .charger)
+ .padding(.trailing, 24)
+ .padding(.bottom, 24)
+ }
+ }
+ }
+
@ViewBuilder
private var loadsListWithHeader: some View {
Group {
@@ -507,7 +531,7 @@ struct LoadsView: View {
}
}
.overlay(alignment: .bottomTrailing) {
- libraryButton
+ libraryButton(type: .load)
.padding(.trailing, 24)
.padding(.bottom, 24)
}
@@ -802,15 +826,63 @@ struct LoadsView: View {
showingSystemEditor = true
}
- private func openComponentLibrary(source: String) {
+ private func openComponentLibrary(source: String, type: ComponentLibraryType = .load) {
AnalyticsTracker.log(
"Component Library Opened",
properties: [
"source": source,
+ "type": type.rawValue,
"system": system.name
]
)
- showingComponentLibrary = true
+ activeLibrary = type
+ }
+
+ private func handleLibrarySelection(_ item: ComponentLibraryItem, for type: ComponentLibraryType) {
+ switch type {
+ case .load:
+ addComponent(item)
+ case .battery:
+ addBatteryFromLibrary(item)
+ case .charger:
+ addChargerFromLibrary(item)
+ }
+ }
+
+ private func addBatteryFromLibrary(_ item: ComponentLibraryItem) {
+ AnalyticsTracker.log(
+ "Library Battery Added",
+ properties: [
+ "id": item.id,
+ "name": item.localizedName,
+ "system": system.name
+ ]
+ )
+ batteryDraft = SystemComponentsPersistence.makeBatteryDraft(
+ from: item,
+ for: system,
+ existingLoads: savedLoads,
+ existingBatteries: savedBatteries,
+ existingChargers: savedChargers
+ )
+ }
+
+ private func addChargerFromLibrary(_ item: ComponentLibraryItem) {
+ AnalyticsTracker.log(
+ "Library Charger Added",
+ properties: [
+ "id": item.id,
+ "name": item.localizedName,
+ "system": system.name
+ ]
+ )
+ chargerDraft = SystemComponentsPersistence.makeChargerDraft(
+ from: item,
+ for: system,
+ existingLoads: savedLoads,
+ existingBatteries: savedBatteries,
+ existingChargers: savedChargers
+ )
}
private func openBillOfMaterials() {
diff --git a/android/app/src/main/java/app/voltplan/cable/pdf/PdfShare.kt b/android/app/src/main/java/app/voltplan/cable/pdf/PdfShare.kt
index 619e11c..cf19d40 100644
--- a/android/app/src/main/java/app/voltplan/cable/pdf/PdfShare.kt
+++ b/android/app/src/main/java/app/voltplan/cable/pdf/PdfShare.kt
@@ -75,10 +75,12 @@ object PdfShare {
return file
}
- fun share(context: Context, file: File) {
+ fun share(context: Context, file: File) = shareFile(context, file, "application/pdf")
+
+ fun shareFile(context: Context, file: File, mimeType: String) {
val uri = FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", file)
val intent = Intent(Intent.ACTION_SEND).apply {
- type = "application/pdf"
+ type = mimeType
putExtra(Intent.EXTRA_STREAM, uri)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
diff --git a/android/app/src/main/java/app/voltplan/cable/pdf/SystemDiagram.kt b/android/app/src/main/java/app/voltplan/cable/pdf/SystemDiagram.kt
new file mode 100644
index 0000000..3b90b28
--- /dev/null
+++ b/android/app/src/main/java/app/voltplan/cable/pdf/SystemDiagram.kt
@@ -0,0 +1,133 @@
+package app.voltplan.cable.pdf
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.Canvas
+import android.graphics.Color
+import app.voltplan.cable.R
+import app.voltplan.cable.analytics.Analytics
+import app.voltplan.cable.data.model.effectivePowerWatts
+import app.voltplan.cable.data.model.energyWattHours
+import app.voltplan.cable.data.model.sourceType
+import app.voltplan.cable.data.UnitSystem
+import app.voltplan.cable.ui.system.DetailState
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.json.JsonObject
+import kotlinx.serialization.json.add
+import kotlinx.serialization.json.buildJsonArray
+import kotlinx.serialization.json.buildJsonObject
+import kotlinx.serialization.json.put
+import okhttp3.MediaType.Companion.toMediaType
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.RequestBody.Companion.toRequestBody
+import java.io.File
+import java.util.concurrent.TimeUnit
+
+/**
+ * Fetches the system wiring diagram PNG from the VoltPlan diagram API — the same endpoint and
+ * payload the iOS app uses (`SystemOverviewPDFExporter.fetchDiagramImage`). Used both for the
+ * standalone "Wiring Diagram" image export and the diagram page embedded in the overview PDF.
+ */
+object SystemDiagram {
+ private const val ENDPOINT = "https://voltplan.app/api/diagram/generate"
+ private val JSON_MEDIA = "application/json; charset=utf-8".toMediaType()
+ private val client = OkHttpClient.Builder()
+ .callTimeout(15, TimeUnit.SECONDS)
+ .build()
+
+ /** Fetches the diagram as a [Bitmap], or null on any network/decoding failure. */
+ suspend fun fetch(state: DetailState, unit: UnitSystem): Bitmap? = withContext(Dispatchers.IO) {
+ val payload = buildPayload(state, unit)
+ val request = Request.Builder()
+ .url(ENDPOINT)
+ .addHeader("Content-Type", "application/json")
+ .addHeader("Accept", "image/png")
+ .post(Json.encodeToString(JsonObject.serializer(), payload).toRequestBody(JSON_MEDIA))
+ .build()
+
+ runCatching {
+ client.newCall(request).execute().use { response ->
+ if (!response.isSuccessful) return@use null
+ response.body?.bytes()?.let { BitmapFactory.decodeByteArray(it, 0, it.size) }
+ }
+ }.getOrNull()
+ }
+
+ /** Fetches the diagram, flattens it onto a white background, and opens the Android share sheet. */
+ suspend fun exportAndShare(
+ context: Context,
+ state: DetailState,
+ unit: UnitSystem,
+ onError: () -> Unit,
+ ) {
+ val bitmap = fetch(state, unit)
+ if (bitmap == null) {
+ withContext(Dispatchers.Main) { onError() }
+ return
+ }
+ val file = withContext(Dispatchers.IO) {
+ val opaque = flattenOnWhite(bitmap)
+ val name = state.system?.name?.takeIf { it.isNotBlank() } ?: "System"
+ val dir = File(context.cacheDir, "exports").apply { mkdirs() }
+ val out = File(dir, "${name.replace(Regex("[^A-Za-z0-9-_]"), "_")}-Diagram.png")
+ out.outputStream().use { opaque.compress(Bitmap.CompressFormat.PNG, 100, it) }
+ out
+ }
+ withContext(Dispatchers.Main) {
+ Analytics.log("Diagram Image Shared", mapOf("system" to (state.system?.name ?: "")))
+ PdfShare.shareFile(context, file, "image/png")
+ }
+ }
+
+ private fun flattenOnWhite(source: Bitmap): Bitmap {
+ val result = Bitmap.createBitmap(source.width, source.height, Bitmap.Config.ARGB_8888)
+ Canvas(result).apply {
+ drawColor(Color.WHITE)
+ drawBitmap(source, 0f, 0f, null)
+ }
+ return result
+ }
+
+ private fun buildPayload(state: DetailState, unit: UnitSystem): JsonObject = buildJsonObject {
+ put("systemName", state.system?.name ?: "System")
+ put("source", "cable")
+ put("unitSystem", if (unit == UnitSystem.METRIC) "metric" else "imperial")
+ put("loads", buildJsonArray {
+ state.loads.forEach { load ->
+ add(buildJsonObject {
+ put("name", load.name)
+ put("power", load.power)
+ put("voltage", load.voltage)
+ put("current", load.current)
+ load.remoteIconURLString?.let { put("iconUrl", it) }
+ })
+ }
+ })
+ put("batteries", buildJsonArray {
+ state.batteries.forEach { battery ->
+ add(buildJsonObject {
+ put("name", battery.name)
+ put("voltage", battery.nominalVoltage)
+ put("capacityAh", battery.capacityAmpHours)
+ put("energyWh", battery.energyWattHours)
+ })
+ }
+ })
+ put("chargers", buildJsonArray {
+ state.chargers.forEach { charger ->
+ add(buildJsonObject {
+ put("name", charger.name)
+ put("inputVoltage", charger.inputVoltage)
+ put("outputVoltage", charger.outputVoltage)
+ put("power", charger.effectivePowerWatts)
+ put("sourceType", charger.sourceType.rawValue)
+ charger.remoteIconURLString?.let { put("iconUrl", it) }
+ })
+ }
+ })
+ }
+}
diff --git a/android/app/src/main/java/app/voltplan/cable/pdf/SystemOverviewPdf.kt b/android/app/src/main/java/app/voltplan/cable/pdf/SystemOverviewPdf.kt
index ffd6aa5..d2d0a5e 100644
--- a/android/app/src/main/java/app/voltplan/cable/pdf/SystemOverviewPdf.kt
+++ b/android/app/src/main/java/app/voltplan/cable/pdf/SystemOverviewPdf.kt
@@ -1,7 +1,11 @@
package app.voltplan.cable.pdf
import android.content.Context
+import android.graphics.Bitmap
import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Rect
+import android.graphics.RectF
import android.graphics.pdf.PdfDocument
import app.voltplan.cable.R
import app.voltplan.cable.calc.ElectricalCalculations
@@ -23,6 +27,8 @@ private val ACCENT = Color.rgb(115, 87, 219)
/** Renders a full system overview PDF and opens the Android share sheet. */
object SystemOverviewPdf {
suspend fun exportAndShare(context: Context, state: DetailState, unit: UnitSystem) {
+ // Fetch the wiring diagram first (falls back to no diagram page if unavailable).
+ val diagram = SystemDiagram.fetch(state, unit)
val file = withContext(Dispatchers.IO) {
val doc = PdfDocument()
val w = PdfWriter(doc)
@@ -42,6 +48,9 @@ object SystemOverviewPdf {
summaryLine(w, context.getString(R.string.overview_pdf_summary_batterycapacity), "${Fmt.number(m.totalCapacity)} Ah")
summaryLine(w, context.getString(R.string.overview_pdf_summary_chargerpower), "${Fmt.number(m.totalChargerPower)} W")
+ // Full-page wiring diagram, followed by a fresh page for the entity tables.
+ diagram?.let { drawDiagramPage(w, it); w.beginPage() }
+
if (state.loads.isNotEmpty()) {
w.gap(12f); w.text(context.getString(R.string.overview_pdf_loads_section), 18f, ACCENT, bold = true); w.divider()
state.loads.forEach { load ->
@@ -89,4 +98,23 @@ object SystemOverviewPdf {
private fun summaryLine(w: PdfWriter, label: String, value: String) {
w.text("$label: $value", 12f, Color.DKGRAY)
}
+
+ /** Draws the diagram bitmap on its own page, scaled to fit the margins while keeping aspect ratio. */
+ private fun drawDiagramPage(w: PdfWriter, diagram: Bitmap) {
+ w.beginPage()
+ val availableWidth = PAGE_W - MARGIN * 2
+ val availableHeight = PAGE_H - MARGIN * 2 - 30 // leave room for footer
+ val imageAspect = diagram.width.toFloat() / diagram.height.toFloat()
+ val rectAspect = availableWidth / availableHeight
+
+ val dest = if (imageAspect > rectAspect) {
+ val drawHeight = availableWidth / imageAspect
+ RectF(MARGIN, MARGIN + (availableHeight - drawHeight) / 2f, MARGIN + availableWidth, MARGIN + (availableHeight - drawHeight) / 2f + drawHeight)
+ } else {
+ val drawWidth = availableHeight * imageAspect
+ RectF(MARGIN + (availableWidth - drawWidth) / 2f, MARGIN, MARGIN + (availableWidth - drawWidth) / 2f + drawWidth, MARGIN + availableHeight)
+ }
+ val src = Rect(0, 0, diagram.width, diagram.height)
+ w.canvas.drawBitmap(diagram, src, dest, Paint().apply { isFilterBitmap = true })
+ }
}
diff --git a/android/app/src/main/java/app/voltplan/cable/ui/system/SystemDetailScreen.kt b/android/app/src/main/java/app/voltplan/cable/ui/system/SystemDetailScreen.kt
index 4b3f0b3..c0ea4c0 100644
--- a/android/app/src/main/java/app/voltplan/cable/ui/system/SystemDetailScreen.kt
+++ b/android/app/src/main/java/app/voltplan/cable/ui/system/SystemDetailScreen.kt
@@ -13,11 +13,13 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
+import androidx.compose.material.icons.filled.BatteryFull
+import androidx.compose.material.icons.filled.Bolt as BoltFilled
+import androidx.compose.material.icons.filled.Dashboard
+import androidx.compose.material.icons.filled.Layers
import androidx.compose.material.icons.outlined.Add
-import androidx.compose.material.icons.outlined.BatteryFull
import androidx.compose.material.icons.outlined.Bolt
-import androidx.compose.material.icons.outlined.Dashboard
-import androidx.compose.material.icons.outlined.Layers
+import androidx.compose.material.icons.outlined.IosShare
import androidx.compose.material.icons.outlined.PictureAsPdf
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@@ -39,6 +41,7 @@ import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import app.voltplan.cable.CableApplication
import app.voltplan.cable.R
+import app.voltplan.cable.library.ComponentLibraryType
import app.voltplan.cable.ui.LocalUnitSettings
import app.voltplan.cable.ui.batteries.BatteriesTab
import app.voltplan.cable.ui.chargers.ChargersTab
@@ -48,7 +51,10 @@ import app.voltplan.cable.ui.overview.OverviewTab
import app.voltplan.cable.ui.sfSymbol
import app.voltplan.cable.ui.systemIconOptions
import app.voltplan.cable.ui.theme.componentColor
+import app.voltplan.cable.pdf.SystemDiagram
import app.voltplan.cable.pdf.SystemOverviewPdf
+import android.widget.Toast
+import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
@@ -82,7 +88,7 @@ fun SystemDetailScreen(
onEditCharger: (String) -> Unit,
onNewCharger: () -> Unit,
onOpenBom: () -> Unit,
- onOpenLibrary: () -> Unit,
+ onOpenLibrary: (ComponentLibraryType) -> Unit,
) {
val context = LocalContext.current
val app = context.applicationContext as CableApplication
@@ -98,8 +104,15 @@ fun SystemDetailScreen(
var tab by rememberSaveableTab()
var showSystemEditor by remember { mutableStateOf(false) }
var showOverviewMenu by remember { mutableStateOf(false) }
+ var exporting by remember { mutableStateOf(false) }
val system = state.system
+ // Switch to the matching tab before opening an editor, so returning from the
+ // editor lands on that tab with the newly created component visible.
+ val newLoad = { tab = ComponentTab.COMPONENTS; onNewLoad() }
+ val newBattery = { tab = ComponentTab.BATTERIES; onNewBattery() }
+ val newCharger = { tab = ComponentTab.CHARGERS; onNewCharger() }
+
Scaffold(
topBar = {
TopAppBar(
@@ -132,28 +145,52 @@ fun SystemDetailScreen(
actions = {
when (tab) {
ComponentTab.OVERVIEW -> {
- IconButton(onClick = { showOverviewMenu = true }) {
- Icon(Icons.Outlined.PictureAsPdf, contentDescription = stringResource(R.string.overview_share_pdf))
+ if (exporting) {
+ CircularProgressIndicator(
+ modifier = Modifier.size(24.dp).padding(end = 12.dp),
+ strokeWidth = 2.dp,
+ )
+ } else {
+ IconButton(onClick = { showOverviewMenu = true }) {
+ Icon(Icons.Outlined.IosShare, contentDescription = stringResource(R.string.overview_share_pdf))
+ }
}
DropdownMenu(expanded = showOverviewMenu, onDismissRequest = { showOverviewMenu = false }) {
DropdownMenuItem(
+ leadingIcon = { Icon(Icons.Outlined.Bolt, contentDescription = null) },
+ text = { Text(stringResource(R.string.overview_share_diagram)) },
+ onClick = {
+ showOverviewMenu = false
+ scope.launch {
+ exporting = true
+ SystemDiagram.exportAndShare(context, state, unitSystem) {
+ Toast.makeText(context, R.string.overview_share_diagram_error, Toast.LENGTH_LONG).show()
+ }
+ exporting = false
+ }
+ },
+ )
+ DropdownMenuItem(
+ leadingIcon = { Icon(Icons.Outlined.PictureAsPdf, contentDescription = null) },
text = { Text(stringResource(R.string.overview_share_pdf)) },
onClick = {
showOverviewMenu = false
scope.launch {
+ exporting = true
SystemOverviewPdf.exportAndShare(context, state, unitSystem)
+ exporting = false
}
},
)
}
}
- ComponentTab.COMPONENTS -> IconButton(onClick = onNewLoad) {
+ ComponentTab.COMPONENTS -> IconButton(onClick = newLoad) {
Icon(Icons.Outlined.Add, contentDescription = stringResource(R.string.action_add))
}
- ComponentTab.BATTERIES -> IconButton(onClick = onNewBattery) {
+ ComponentTab.BATTERIES -> IconButton(onClick = newBattery) {
Icon(Icons.Outlined.Add, contentDescription = stringResource(R.string.action_add))
}
- ComponentTab.CHARGERS -> IconButton(onClick = onNewCharger) {
+ ComponentTab.CHARGERS -> IconButton(onClick = newCharger) {
Icon(Icons.Outlined.Add, contentDescription = stringResource(R.string.action_add))
}
}
@@ -162,10 +199,10 @@ fun SystemDetailScreen(
},
bottomBar = {
NavigationBar {
- NavTab(tab, ComponentTab.OVERVIEW, Icons.Outlined.Dashboard, stringResource(R.string.tab_overview)) { tab = it; vm.logTabChange(it.analytics) }
- NavTab(tab, ComponentTab.COMPONENTS, Icons.Outlined.Layers, stringResource(R.string.tab_components)) { tab = it; vm.logTabChange(it.analytics) }
- NavTab(tab, ComponentTab.BATTERIES, Icons.Outlined.BatteryFull, stringResource(R.string.tab_batteries)) { tab = it; vm.logTabChange(it.analytics) }
- NavTab(tab, ComponentTab.CHARGERS, Icons.Outlined.Bolt, stringResource(R.string.tab_chargers)) { tab = it; vm.logTabChange(it.analytics) }
+ NavTab(tab, ComponentTab.OVERVIEW, Icons.Filled.Dashboard, stringResource(R.string.tab_overview)) { tab = it; vm.logTabChange(it.analytics) }
+ NavTab(tab, ComponentTab.COMPONENTS, Icons.Filled.Layers, stringResource(R.string.tab_components)) { tab = it; vm.logTabChange(it.analytics) }
+ NavTab(tab, ComponentTab.BATTERIES, Icons.Filled.BatteryFull, stringResource(R.string.tab_batteries)) { tab = it; vm.logTabChange(it.analytics) }
+ NavTab(tab, ComponentTab.CHARGERS, Icons.Filled.BoltFilled, stringResource(R.string.tab_chargers)) { tab = it; vm.logTabChange(it.analytics) }
}
},
) { padding ->
@@ -174,11 +211,14 @@ fun SystemDetailScreen(
ComponentTab.OVERVIEW -> OverviewTab(
state = state,
unitSystem = unitSystem,
- onAddLoad = onNewLoad,
- onAddBattery = onNewBattery,
- onAddCharger = onNewCharger,
- onOpenLibrary = onOpenLibrary,
+ onAddLoad = newLoad,
+ onAddBattery = newBattery,
+ onAddCharger = newCharger,
+ onOpenLibrary = { onOpenLibrary(ComponentLibraryType.LOAD) },
onOpenBom = { vm.logBomOpened(); onOpenBom() },
+ onSelectLoads = { tab = ComponentTab.COMPONENTS; vm.logTabChange(ComponentTab.COMPONENTS.analytics) },
+ onSelectBatteries = { tab = ComponentTab.BATTERIES; vm.logTabChange(ComponentTab.BATTERIES.analytics) },
+ onSelectChargers = { tab = ComponentTab.CHARGERS; vm.logTabChange(ComponentTab.CHARGERS.analytics) },
onSetRuntimeGoal = vm::setRuntimeGoal,
onSetChargeGoal = vm::setChargeGoal,
)
@@ -186,20 +226,22 @@ fun SystemDetailScreen(
state = state,
unitSystem = unitSystem,
onOpenLoad = onOpenLoad,
- onNewLoad = onNewLoad,
- onOpenLibrary = onOpenLibrary,
+ onNewLoad = newLoad,
+ onOpenLibrary = { onOpenLibrary(ComponentLibraryType.LOAD) },
onDeleteLoad = vm::deleteLoad,
)
ComponentTab.BATTERIES -> BatteriesTab(
state = state,
onEditBattery = onEditBattery,
- onNewBattery = onNewBattery,
+ onNewBattery = newBattery,
+ onOpenLibrary = { onOpenLibrary(ComponentLibraryType.BATTERY) },
onDeleteBattery = vm::deleteBattery,
)
ComponentTab.CHARGERS -> ChargersTab(
state = state,
onEditCharger = onEditCharger,
- onNewCharger = onNewCharger,
+ onNewCharger = newCharger,
+ onOpenLibrary = { onOpenLibrary(ComponentLibraryType.CHARGER) },
onDeleteCharger = vm::deleteCharger,
)
}
@@ -248,4 +290,4 @@ private fun RowScope.NavTab(
}
@Composable
-private fun rememberSaveableTab() = remember { mutableStateOf(ComponentTab.OVERVIEW) }
+private fun rememberSaveableTab() = rememberSaveable { mutableStateOf(ComponentTab.OVERVIEW) }
diff --git a/android/app/src/main/res/values-de/strings.xml b/android/app/src/main/res/values-de/strings.xml
index 7eb699f..8f0f991 100644
--- a/android/app/src/main/res/values-de/strings.xml
+++ b/android/app/src/main/res/values-de/strings.xml
@@ -5,6 +5,7 @@
Hinzufügen
Zurück
+ Speichern
Löschen
@@ -177,6 +178,8 @@
Füge Landstrom-, DC-DC- oder Solarladegeräte hinzu, um deine Ladeleistung zu verstehen.
Ladegerät hinzufügen
Vollständiger Bericht (PDF)
+ Schaltplan
+ Schaltplan konnte nicht erstellt werden. Überprüfe deine Internetverbindung.
Tage
diff --git a/android/app/src/main/res/values-es/strings.xml b/android/app/src/main/res/values-es/strings.xml
index 9d0279f..9b7e249 100644
--- a/android/app/src/main/res/values-es/strings.xml
+++ b/android/app/src/main/res/values-es/strings.xml
@@ -5,6 +5,7 @@
Añadir
Atrás
+ Guardar
Eliminar
@@ -177,6 +178,8 @@
Añade cargadores de toma de puerto, DC-DC o solares para conocer tu capacidad de carga.
Añadir cargador
Informe completo (PDF)
+ Diagrama de cableado
+ No se pudo generar el diagrama. Comprueba tu conexión a Internet.
Días
diff --git a/android/app/src/main/res/values-fr/strings.xml b/android/app/src/main/res/values-fr/strings.xml
index 5c6b61d..c3fef4d 100644
--- a/android/app/src/main/res/values-fr/strings.xml
+++ b/android/app/src/main/res/values-fr/strings.xml
@@ -5,6 +5,7 @@
Ajouter
Retour
+ Enregistrer
Supprimer
@@ -177,6 +178,8 @@
Ajoutez des chargeurs secteur, DC-DC ou solaires pour comprendre votre capacité de charge.
Ajouter un chargeur
Rapport complet (PDF)
+ Schéma de câblage
+ Impossible de générer le schéma. Vérifiez votre connexion Internet.
Jours
diff --git a/android/app/src/main/res/values-nl/strings.xml b/android/app/src/main/res/values-nl/strings.xml
index 1e18d86..6d25dd0 100644
--- a/android/app/src/main/res/values-nl/strings.xml
+++ b/android/app/src/main/res/values-nl/strings.xml
@@ -5,6 +5,7 @@
Toevoegen
Terug
+ Opslaan
Verwijderen
@@ -177,6 +178,8 @@
Voeg walstroom-, DC-DC- of zonneladers toe om je laadcapaciteit te begrijpen.
Lader toevoegen
Volledig rapport (PDF)
+ Bedradingsschema
+ Diagram kon niet worden gegenereerd. Controleer je internetverbinding.
Dagen
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
index 798cb44..754518d 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/app/src/main/res/values/strings.xml
@@ -5,6 +5,7 @@
Add
Back
+ Save
Delete
@@ -177,6 +178,8 @@
Add shore power, DC-DC, or solar chargers to understand your charging capacity.
Add Charger
Full Report (PDF)
+ Wiring Diagram
+ Could not generate diagram. Check your internet connection.
Days