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:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user