From 06fa017c04a8587ac54cd8067370bc3a0b38550f Mon Sep 17 00:00:00 2001 From: Jens Reinemann Date: Mon, 18 May 2026 18:04:50 +0200 Subject: [PATCH] chore: update generaltest_admin_message.cpython-313.pyc, receive_admin_messages.cpython-313.pyc, send_admin_messages.cpython-313.pyc --- .../generaltest_admin_message.cpython-313.pyc | Bin 0 -> 7930 bytes .../receive_admin_messages.cpython-313.pyc | Bin 0 -> 4911 bytes .../send_admin_messages.cpython-313.pyc | Bin 0 -> 4850 bytes .github/skills/android-device/SKILL.md | 22 ++ .../skills/android-device/deploy-device.py | 228 ++++++++++++++++++ .../__pycache__/publish-apk.cpython-313.pyc | Bin 0 -> 20572 bytes .../app/ui/settings/SettingsScreen.kt | 2 +- .../de/bollwerk/app/ui/update/UpdateBanner.kt | 4 +- 8 files changed, 253 insertions(+), 3 deletions(-) create mode 100644 .github/skills/admin-message-e2ee/__pycache__/generaltest_admin_message.cpython-313.pyc create mode 100644 .github/skills/admin-message-e2ee/__pycache__/receive_admin_messages.cpython-313.pyc create mode 100644 .github/skills/admin-message-e2ee/__pycache__/send_admin_messages.cpython-313.pyc create mode 100644 .github/skills/android-device/deploy-device.py create mode 100644 .github/skills/publish/__pycache__/publish-apk.cpython-313.pyc diff --git a/.github/skills/admin-message-e2ee/__pycache__/generaltest_admin_message.cpython-313.pyc b/.github/skills/admin-message-e2ee/__pycache__/generaltest_admin_message.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..98c1a00bbae562d97fcfc23097a203967e9ea61f GIT binary patch literal 7930 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 literal 0 HcmV?d00001 diff --git a/.github/skills/admin-message-e2ee/__pycache__/send_admin_messages.cpython-313.pyc b/.github/skills/admin-message-e2ee/__pycache__/send_admin_messages.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..11d3debf8512fae96c27b7939e190fd40a5f81a4 GIT binary patch literal 4850 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 REwU|nre&Q*Op~GUe*ri{EY|=4 literal 0 HcmV?d00001 diff --git a/.github/skills/android-device/SKILL.md b/.github/skills/android-device/SKILL.md index 42dfe65..743f119 100644 --- a/.github/skills/android-device/SKILL.md +++ b/.github/skills/android-device/SKILL.md @@ -88,6 +88,28 @@ $adb = "C:\Users\JensR\AppData\Local\Android\Sdk\platform-tools\adb.exe" **Hinweis:** Die Skript-Aktionen `deploy-device` und `install-device` verwenden `adb -d` und funktionieren nur über USB. Bei Wireless ADB die manuellen Kommandos verwenden. +### Robustes Python-Deployment (empfohlen) + +Neues Skript: `.github/skills/android-device/deploy-device.py` + +```powershell +# Standard: Build + Device erkennen + Install + Launch +python ".github/skills/android-device/deploy-device.py" --repo-root "X:\bollwerk" + +# Explizites Wireless-Geraet +python ".github/skills/android-device/deploy-device.py" --repo-root "X:\bollwerk" --serial "192.168.68.107:42539" + +# Ohne Build (wenn APK schon gebaut), nur Install +python ".github/skills/android-device/deploy-device.py" --repo-root "X:\bollwerk" --skip-build --no-launch +``` + +Funktionen: + +- ADB-Autodetect ueber `--adb`, `ANDROID_SDK_ROOT`/`ANDROID_HOME` oder `local.properties` +- Robuste Device-Erkennung (USB oder Wireless) +- Install-Retries mit klaren Fehlern +- Definierte Exitcodes (`0` Erfolg, `1` Fehler) + ```powershell # App bauen + auf Gerät installieren + starten (nur USB) & ".github/skills/android-build/android-dev.ps1" -Action deploy-device diff --git a/.github/skills/android-device/deploy-device.py b/.github/skills/android-device/deploy-device.py new file mode 100644 index 0000000..5190073 --- /dev/null +++ b/.github/skills/android-device/deploy-device.py @@ -0,0 +1,228 @@ +#!/usr/bin/env python3 +"""Robustes Deployment der Debug-APK auf ein physisches Android-Geraet. + +Features: +- ADB automatisch finden (Argument, ENV, local.properties) +- USB oder Wireless-Device robust erkennen +- Optional Build via Gradle +- Install mit Retry +- Optional App-Start +- Klare Exitcodes und kompakte Logs +""" + +from __future__ import annotations + +import argparse +import os +import re +import subprocess +import sys +import time +from pathlib import Path +from typing import List, Optional, Tuple + +PACKAGE_NAME = "de.bollwerk.app" +MAIN_ACTIVITY = "de.bollwerk.app/.MainActivity" +DEFAULT_APK_REL = Path("app/build/outputs/apk/debug/app-debug.apk") +DEFAULT_GRADLEW = Path("gradlew.bat") + + +def log(msg: str) -> None: + print(msg, flush=True) + + +def run_cmd(cmd: List[str], cwd: Optional[Path] = None, timeout: Optional[int] = None) -> subprocess.CompletedProcess: + return subprocess.run( + cmd, + cwd=str(cwd) if cwd else None, + text=True, + capture_output=True, + timeout=timeout, + check=False, + ) + + +def normalize_sdk_dir(raw: str) -> str: + # local.properties encodes ':' as '\:' on Windows. + val = raw.strip() + val = val.replace("\\:", ":") + val = val.replace("\\\\", "\\") + return val + + +def read_sdk_from_local_properties(repo_root: Path) -> Optional[Path]: + local_props = repo_root / "local.properties" + if not local_props.exists(): + return None + for line in local_props.read_text(encoding="utf-8").splitlines(): + if line.strip().startswith("sdk.dir="): + _, value = line.split("=", 1) + sdk = normalize_sdk_dir(value) + p = Path(sdk) + return p if p.exists() else None + return None + + +def find_adb(repo_root: Path, explicit_adb: Optional[str]) -> Path: + candidates: List[Path] = [] + + if explicit_adb: + candidates.append(Path(explicit_adb)) + + env_android_sdk = os.environ.get("ANDROID_SDK_ROOT") or os.environ.get("ANDROID_HOME") + if env_android_sdk: + candidates.append(Path(env_android_sdk) / "platform-tools" / "adb.exe") + candidates.append(Path(env_android_sdk) / "platform-tools" / "adb") + + sdk_from_local = read_sdk_from_local_properties(repo_root) + if sdk_from_local: + candidates.append(sdk_from_local / "platform-tools" / "adb.exe") + candidates.append(sdk_from_local / "platform-tools" / "adb") + + # Last fallback: rely on PATH. + path_adb = shutil_which("adb") + if path_adb: + candidates.append(Path(path_adb)) + + for candidate in candidates: + if candidate.exists(): + return candidate + + raise FileNotFoundError( + "ADB nicht gefunden. Setze --adb oder ANDROID_SDK_ROOT/ANDROID_HOME oder local.properties sdk.dir." + ) + + +def shutil_which(binary: str) -> Optional[str]: + for folder in os.environ.get("PATH", "").split(os.pathsep): + p = Path(folder) / binary + if p.exists(): + return str(p) + if os.name == "nt": + p_exe = Path(folder) / f"{binary}.exe" + if p_exe.exists(): + return str(p_exe) + return None + + +def parse_adb_devices(output: str) -> List[Tuple[str, str]]: + devices: List[Tuple[str, str]] = [] + for line in output.splitlines(): + line = line.strip() + if not line or line.startswith("List of devices"): + continue + # serial state [extra] + parts = re.split(r"\s+", line) + if len(parts) >= 2: + devices.append((parts[0], parts[1])) + return devices + + +def resolve_target_serial(adb: Path, prefer_serial: Optional[str], prefer_usb: bool, timeout_sec: int) -> str: + start = time.time() + while True: + cp = run_cmd([str(adb), "devices", "-l"]) + if cp.returncode == 0: + devices = parse_adb_devices(cp.stdout) + + if prefer_serial: + for serial, state in devices: + if serial == prefer_serial and state == "device": + return serial + else: + live = [(s, st) for s, st in devices if st == "device"] + if prefer_usb: + usb = [s for s, _ in live if not re.match(r"\d+\.\d+\.\d+\.\d+:\d+", s)] + if usb: + return usb[0] + if live: + return live[0][0] + + if (time.time() - start) >= timeout_sec: + break + time.sleep(2) + + raise RuntimeError("Kein geeignetes ADB-Geraet gefunden (USB/Wireless, Debugging, Autorisierung pruefen).") + + +def ensure_apk(repo_root: Path, apk_path: Path, gradlew_path: Path, skip_build: bool) -> None: + if skip_build and apk_path.exists(): + return + + if not gradlew_path.exists(): + raise FileNotFoundError(f"Gradle Wrapper nicht gefunden: {gradlew_path}") + + log("[1/4] Build Debug-APK ...") + cp = run_cmd([str(gradlew_path), "assembleDebug"], cwd=repo_root) + if cp.returncode != 0: + tail = "\n".join((cp.stdout + "\n" + cp.stderr).splitlines()[-40:]) + raise RuntimeError(f"Gradle Build fehlgeschlagen.\n{tail}") + + if not apk_path.exists(): + raise FileNotFoundError(f"APK nach Build nicht gefunden: {apk_path}") + + +def adb_install(adb: Path, serial: str, apk_path: Path, retries: int) -> None: + last_err = "" + for attempt in range(1, retries + 1): + log(f"[3/4] Installiere APK (Versuch {attempt}/{retries}) ...") + cp = run_cmd([str(adb), "-s", serial, "install", "-r", str(apk_path)], timeout=180) + out = (cp.stdout + "\n" + cp.stderr).strip() + if cp.returncode == 0 and "Success" in out: + log("Install OK") + return + last_err = out + time.sleep(2) + + raise RuntimeError(f"APK-Installation fehlgeschlagen.\n{last_err}") + + +def adb_launch(adb: Path, serial: str) -> None: + cp = run_cmd([str(adb), "-s", serial, "shell", "am", "start", "-n", MAIN_ACTIVITY], timeout=60) + out = (cp.stdout + "\n" + cp.stderr).strip() + if cp.returncode != 0 or "Error" in out or "Exception" in out: + raise RuntimeError(f"App-Start fehlgeschlagen.\n{out}") + + +def main() -> int: + parser = argparse.ArgumentParser(description="Deploy app-debug.apk robust auf ein physisches Android-Geraet") + parser.add_argument("--repo-root", default=".", help="Pfad zum Repo-Root (Standard: aktuelles Verzeichnis)") + parser.add_argument("--adb", default=None, help="Expliziter Pfad zu adb(.exe)") + parser.add_argument("--serial", default=None, help="Geraete-Serial explizit (z. B. USB-Serial oder 192.168.x.x:port)") + parser.add_argument("--prefer-usb", action="store_true", help="Bevorzuge USB-Geraet, wenn --serial nicht gesetzt") + parser.add_argument("--timeout-device", type=int, default=30, help="Maximale Wartezeit auf Device-Erkennung in Sekunden") + parser.add_argument("--retries-install", type=int, default=3, help="Install-Retries") + parser.add_argument("--skip-build", action="store_true", help="Build ueberspringen, wenn APK bereits existiert") + parser.add_argument("--no-launch", action="store_true", help="App nach Installation nicht starten") + args = parser.parse_args() + + repo_root = Path(args.repo_root).resolve() + apk_path = (repo_root / DEFAULT_APK_REL).resolve() + gradlew_path = (repo_root / DEFAULT_GRADLEW).resolve() + + try: + adb = find_adb(repo_root, args.adb) + log(f"ADB: {adb}") + + ensure_apk(repo_root, apk_path, gradlew_path, skip_build=args.skip_build) + + log("[2/4] Suche Device ...") + serial = resolve_target_serial(adb, args.serial, args.prefer_usb, args.timeout_device) + log(f"Device: {serial}") + + adb_install(adb, serial, apk_path, retries=args.retries_install) + + if not args.no_launch: + log("[4/4] Starte App ...") + adb_launch(adb, serial) + log("Launch OK") + + log("DEPLOY SUCCESS") + return 0 + except Exception as exc: + log(f"DEPLOY FAILED: {exc}") + return 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/.github/skills/publish/__pycache__/publish-apk.cpython-313.pyc b/.github/skills/publish/__pycache__/publish-apk.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e1d4fcec3bc0f15b65eb0e4864da2509f36674a7 GIT binary patch literal 20572 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 literal 0 HcmV?d00001 diff --git a/app/src/main/java/de/bollwerk/app/ui/settings/SettingsScreen.kt b/app/src/main/java/de/bollwerk/app/ui/settings/SettingsScreen.kt index 8205053..da2d48b 100644 --- a/app/src/main/java/de/bollwerk/app/ui/settings/SettingsScreen.kt +++ b/app/src/main/java/de/bollwerk/app/ui/settings/SettingsScreen.kt @@ -438,7 +438,7 @@ internal fun SettingsScreen( style = MaterialTheme.typography.bodyMedium ) Text( - text = "Version ${BuildConfig.VERSION_NAME}.${BuildConfig.VERSION_CODE}", + text = "Version ${BuildConfig.VERSION_NAME}", style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant ) diff --git a/app/src/main/java/de/bollwerk/app/ui/update/UpdateBanner.kt b/app/src/main/java/de/bollwerk/app/ui/update/UpdateBanner.kt index 470787e..20f021b 100644 --- a/app/src/main/java/de/bollwerk/app/ui/update/UpdateBanner.kt +++ b/app/src/main/java/de/bollwerk/app/ui/update/UpdateBanner.kt @@ -47,7 +47,7 @@ internal fun UpdateBanner( ) { when (status) { is UpdateStatus.Available -> AvailableBanner( - versionName = "${status.versionName}.${status.versionCode}", + versionName = status.versionName, onDownloadClick = onDownloadClick, onDismiss = onDismiss ) @@ -55,7 +55,7 @@ internal fun UpdateBanner( progress = status.progress ) is UpdateStatus.ReadyToInstall -> ReadyBanner( - versionName = "${status.versionName}.${status.versionCode}", + versionName = status.versionName, onDismiss = onDismiss ) is UpdateStatus.Error -> ErrorBanner(