feat(update): AlertDialog bei verfuegbarem Update anzeigen
- AlertDialog in MainScreen zeigt verfuegbare Version mit Bestaetigung - UpdateBanner blendet bei UpdateStatus.Available aus (Dialog uebernimmt) - FEATURE_CAMERA_ENABLED temporaer deaktiviert fix(server): Logo-Pfad und statische Ressourcen bereinigen - /res-Route fuer classpath-Assets (logo.png etc.) hinzugefuegt - Logo-Pfad von /static/logo.png auf /res/logo.png korrigiert - Build-Nummer aus Versionsanzeige auf der Homepage entfernt ci: GitHub Actions Workflow fuer Swift-Tests hinzugefuegt style: Tabellenformatierung im Code-Reviewer-Agenten bereinigt
This commit is contained in:
parent
9ff21cbc4b
commit
3d7c01cef5
8 changed files with 121 additions and 11 deletions
10
.github/agents/code-reviewer.agent.md
vendored
10
.github/agents/code-reviewer.agent.md
vendored
|
|
@ -150,11 +150,11 @@ Korrektur: <wie es sein sollte>
|
||||||
|
|
||||||
#### Schweregrade
|
#### Schweregrade
|
||||||
|
|
||||||
| Schwere | Bedeutung |
|
| Schwere | Bedeutung |
|
||||||
|---|---|
|
| ------------ | ------------------------------------------------------------------------------- |
|
||||||
| **KRITISCH** | Falsches Verhalten, Crash-Potenzial, Sicherheitslücke – muss behoben werden |
|
| **KRITISCH** | Falsches Verhalten, Crash-Potenzial, Sicherheitslücke – muss behoben werden |
|
||||||
| **WICHTIG** | Standard-Verletzung, Codedopplung, schlechte Lesbarkeit – sollte behoben werden |
|
| **WICHTIG** | Standard-Verletzung, Codedopplung, schlechte Lesbarkeit – sollte behoben werden |
|
||||||
| **OPTIONAL** | Vereinfachung ohne funktionalen Einfluss – kann behoben werden |
|
| **OPTIONAL** | Vereinfachung ohne funktionalen Einfluss – kann behoben werden |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
86
.github/workflows/ci.yml
vendored
Normal file
86
.github/workflows/ci.yml
vendored
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
name: CI – Swift Tests (macOS)
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
name: Swift Tests (macOS)
|
||||||
|
runs-on: macos-15
|
||||||
|
|
||||||
|
env:
|
||||||
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: Migration
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Select Xcode 16.3
|
||||||
|
run: sudo xcode-select -s /Applications/Xcode_16.3.app/Contents/Developer
|
||||||
|
|
||||||
|
- name: Show Swift version
|
||||||
|
run: swift --version
|
||||||
|
|
||||||
|
- name: Install SwiftLint
|
||||||
|
run: brew install swiftlint
|
||||||
|
|
||||||
|
- name: Run SwiftLint
|
||||||
|
run: swiftlint lint --reporter github-actions-logging
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: swift build 2>&1 | tee build.log; exit ${PIPESTATUS[0]}
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: swift test 2>&1 | tee test.log; exit ${PIPESTATUS[0]}
|
||||||
|
|
||||||
|
- name: Start MockServer
|
||||||
|
run: |
|
||||||
|
cd "$GITHUB_WORKSPACE/MockServer"
|
||||||
|
npm install --silent
|
||||||
|
node server.js &
|
||||||
|
echo "MOCK_PID=$!" >> "$GITHUB_ENV"
|
||||||
|
sleep 2
|
||||||
|
curl -sf http://localhost:3000/auth/login \
|
||||||
|
-X POST -H 'Content-Type: application/json' \
|
||||||
|
-d '{"username":"ci","password":"ci"}' > /dev/null
|
||||||
|
echo "MockServer running on :3000"
|
||||||
|
|
||||||
|
- name: Run integration tests
|
||||||
|
env:
|
||||||
|
MOCKSERVER_INTEGRATION: "1"
|
||||||
|
run: swift test --filter MockServerIntegration 2>&1 | tee integration.log; exit ${PIPESTATUS[0]}
|
||||||
|
|
||||||
|
- name: Stop MockServer
|
||||||
|
if: always()
|
||||||
|
run: kill $MOCK_PID 2>/dev/null || true
|
||||||
|
|
||||||
|
demonstrator:
|
||||||
|
name: Demonstrator Build + Test (macOS)
|
||||||
|
runs-on: macos-15
|
||||||
|
|
||||||
|
env:
|
||||||
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: Demonstrator/App
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Select Xcode 16.3
|
||||||
|
run: sudo xcode-select -s /Applications/Xcode_16.3.app/Contents/Developer
|
||||||
|
|
||||||
|
- name: Show Swift version
|
||||||
|
run: swift --version
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: swift build 2>&1 | tee build.log; exit ${PIPESTATUS[0]}
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: swift test 2>&1 | tee test.log; exit ${PIPESTATUS[0]}
|
||||||
|
|
@ -19,7 +19,7 @@ android {
|
||||||
versionName = "1.3"
|
versionName = "1.3"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
buildConfigField("boolean", "FEATURE_CAMERA_ENABLED", "true")
|
buildConfigField("boolean", "FEATURE_CAMERA_ENABLED", "false")
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.SwapHoriz
|
import androidx.compose.material.icons.filled.SwapHoriz
|
||||||
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
|
|
@ -17,6 +18,7 @@ import androidx.compose.material3.NavigationBarDefaults
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
|
@ -37,6 +39,7 @@ import de.bollwerk.app.ui.inventory.InventoryPickerViewModel
|
||||||
import de.bollwerk.app.ui.navigation.BollwerkNavGraph
|
import de.bollwerk.app.ui.navigation.BollwerkNavGraph
|
||||||
import de.bollwerk.app.ui.navigation.TopLevelDestination
|
import de.bollwerk.app.ui.navigation.TopLevelDestination
|
||||||
import de.bollwerk.app.ui.update.UpdateBanner
|
import de.bollwerk.app.ui.update.UpdateBanner
|
||||||
|
import de.bollwerk.app.ui.update.UpdateStatus
|
||||||
import de.bollwerk.app.ui.update.UpdateViewModel
|
import de.bollwerk.app.ui.update.UpdateViewModel
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
|
@ -142,6 +145,25 @@ internal fun MainScreen() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (updateState.status is UpdateStatus.Available) {
|
||||||
|
val available = updateState.status as UpdateStatus.Available
|
||||||
|
AlertDialog(
|
||||||
|
onDismissRequest = updateViewModel::dismiss,
|
||||||
|
title = { Text("Update verf\u00fcgbar") },
|
||||||
|
text = { Text("Version ${available.versionName} ist verf\u00fcgbar. Jetzt aktualisieren?") },
|
||||||
|
confirmButton = {
|
||||||
|
TextButton(onClick = updateViewModel::startDownload) {
|
||||||
|
Text("Aktualisieren")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dismissButton = {
|
||||||
|
TextButton(onClick = updateViewModel::dismiss) {
|
||||||
|
Text("Sp\u00e4ter")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (isInventoryPickerVisible) {
|
if (isInventoryPickerVisible) {
|
||||||
InventoryPickerSheet(
|
InventoryPickerSheet(
|
||||||
onDismiss = { isInventoryPickerVisible = false },
|
onDismiss = { isInventoryPickerVisible = false },
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ internal fun UpdateBanner(
|
||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val isVisible = status !is UpdateStatus.Hidden && status !is UpdateStatus.Checking
|
val isVisible = status !is UpdateStatus.Hidden && status !is UpdateStatus.Checking && status !is UpdateStatus.Available
|
||||||
|
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
visible = isVisible,
|
visible = isVisible,
|
||||||
|
|
|
||||||
|
|
@ -93,5 +93,8 @@ internal fun Application.configureRouting(
|
||||||
|
|
||||||
// Admin web UI (static)
|
// Admin web UI (static)
|
||||||
staticResources("/admin", "static/admin")
|
staticResources("/admin", "static/admin")
|
||||||
|
|
||||||
|
// Classpath assets (logo etc.)
|
||||||
|
staticResources("/res", "static")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -248,11 +248,11 @@ private fun buildHomepageHtml(versionName: String, versionCode: Int, apkUrl: Str
|
||||||
<div class="panel">
|
<div class="panel">
|
||||||
<span class="rivet-bl"></span>
|
<span class="rivet-bl"></span>
|
||||||
<span class="rivet-br"></span>
|
<span class="rivet-br"></span>
|
||||||
<img src="/static/logo.png" alt="Bollwerk" class="logo">
|
<img src="/res/logo.png" alt="Bollwerk" class="logo">
|
||||||
<h1>Bollwerk</h1>
|
<h1>Bollwerk</h1>
|
||||||
<p class="subtitle">Inventar • Vorsorge • Sicherheit</p>
|
<p class="subtitle">Inventar • Vorsorge • Sicherheit</p>
|
||||||
<div class="rust-line"></div>
|
<div class="rust-line"></div>
|
||||||
<p class="version">V.<span>$versionName</span> // Build <span>$versionCode</span></p>
|
<p class="version">v<span>$versionName</span></p>
|
||||||
<div id="qrcode"></div>
|
<div id="qrcode"></div>
|
||||||
<a href="${apkUrl.replace("\"", """)}" class="download-link">⬇ APK herunterladen</a>
|
<a href="${apkUrl.replace("\"", """)}" class="download-link">⬇ APK herunterladen</a>
|
||||||
<p class="hint">QR-Code scannen oder Link antippen, um die App zu installieren.</p>
|
<p class="hint">QR-Code scannen oder Link antippen, um die App zu installieren.</p>
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,6 @@ class VersionEndpointTest {
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
assertTrue(body.contains("2.1.0"))
|
assertTrue(body.contains("2.1.0"))
|
||||||
assertTrue(body.contains("42"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue