wip: Sicherungs-Commit aller Änderungen seit April + Arbeitsstruktur (CLAUDE.md, ROADMAP.md, PROGRESS.md, Autopilot)

6 Wochen uncommittete Arbeit (Voice-Channels, LiveKit-Manager, Settings-Modal u.v.m.)
als ein WIP-Commit gesichert, damit nichts verloren geht und der Pi den aktuellen
Stand klonen kann. Thematische Aufarbeitung: siehe ROADMAP M0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CPrAGBxBT6GfPXzeWQ4AXb
This commit is contained in:
Bernd Steckmeister
2026-07-03 05:47:18 +02:00
parent d706ace35f
commit 25ed765a03
195 changed files with 47784 additions and 1236 deletions
+33 -49
View File
@@ -8,7 +8,7 @@ import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import 'package:pyramid/core/theme.dart';
import 'package:pyramid/core/update_checker.dart';
import 'package:pyramid/widgets/pyramid_logo.dart';
import 'package:pyramid/widgets/pyramid_loader.dart';
// ─── Entry point ──────────────────────────────────────────────────────────────
@@ -36,10 +36,7 @@ class _UpdateDownloadDialog extends ConsumerStatefulWidget {
_UpdateDownloadDialogState();
}
class _UpdateDownloadDialogState extends ConsumerState<_UpdateDownloadDialog>
with SingleTickerProviderStateMixin {
late final AnimationController _spinCtrl;
class _UpdateDownloadDialogState extends ConsumerState<_UpdateDownloadDialog> {
_DownloadState _state = _DownloadState.idle;
double _progress = 0.0;
int _received = 0;
@@ -49,19 +46,9 @@ class _UpdateDownloadDialogState extends ConsumerState<_UpdateDownloadDialog>
@override
void initState() {
super.initState();
_spinCtrl = AnimationController(
vsync: this,
duration: const Duration(seconds: 3),
)..repeat();
_startDownload();
}
@override
void dispose() {
_spinCtrl.dispose();
super.dispose();
}
// ─── Download ───────────────────────────────────────────────────────────────
Future<void> _startDownload() async {
@@ -127,6 +114,22 @@ class _UpdateDownloadDialogState extends ConsumerState<_UpdateDownloadDialog>
.invokeMethod('installApk', {'path': file.path});
if (mounted) setState(() => _state = _DownloadState.done);
}
} on PlatformException catch (e) {
if (e.code == 'PERMISSION_REQUIRED') {
if (mounted) {
setState(() {
_state = _DownloadState.error;
_errorMsg = 'Bitte "Unbekannte Apps installieren" für Pyramid erlauben (Einstellungen geöffnet) — dann erneut versuchen.';
});
}
} else {
if (mounted) {
setState(() {
_state = _DownloadState.error;
_errorMsg = e.message ?? e.toString();
});
}
}
} catch (e) {
if (mounted) {
setState(() {
@@ -170,21 +173,24 @@ class _UpdateDownloadDialogState extends ConsumerState<_UpdateDownloadDialog>
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// ── Animated Pyramid ──
_AnimatedPyramid(ctrl: _spinCtrl, pt: pt),
// ── Loading animation ──
const PyramidLoader(size: 72),
const SizedBox(height: 24),
// ── Title ──
Text(
_titleText(),
style: TextStyle(
color: pt.fg,
fontSize: 16,
fontWeight: FontWeight.w700,
// ── Title (hidden while actively downloading) ──
if (_state != _DownloadState.downloading &&
_state != _DownloadState.installing) ...[
Text(
_titleText(),
style: TextStyle(
color: pt.fg,
fontSize: 16,
fontWeight: FontWeight.w700,
),
textAlign: TextAlign.center,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 6),
const SizedBox(height: 6),
],
Text(
widget.info.tagName,
style: TextStyle(color: pt.accent, fontSize: 13),
@@ -285,28 +291,6 @@ class _UpdateDownloadDialogState extends ConsumerState<_UpdateDownloadDialog>
}
}
// ─── Animated pyramid ─────────────────────────────────────────────────────────
class _AnimatedPyramid extends StatelessWidget {
final AnimationController ctrl;
final PyramidTheme pt;
const _AnimatedPyramid({required this.ctrl, required this.pt});
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: ctrl,
builder: (context, _) {
final pulse = 0.9 + 0.1 * (0.5 - (ctrl.value - 0.5).abs()) * 2;
return Transform.scale(
scale: pulse,
child: PyramidLogo(size: 72, color: pt.accent),
);
},
);
}
}
// ─── Progress bar ─────────────────────────────────────────────────────────────
class _ProgressBar extends StatelessWidget {