Files
pyramid/lib/widgets/update_banner.dart
T
Bernd Steckmeister cdf48c4d45 feat: in-app update downloader with progress, Gitea auto-push hook
- update_checker: Gitea at git.steggi-matrix.work, Windows + Android support, asset URL detection
- update_download_dialog: animated Pyramid logo, progress bar, platform install (exe/apk)
- update_banner: Herunterladen button triggers dialog, dismiss option
- Android: REQUEST_INSTALL_PACKAGES permission + FileProvider for APK install
- post-commit hook: auto-push to Gitea on every commit
- chat_input: larger send button (60px desktop), more padding, bigger icon
- rooms_panel: space menu visible on mobile (leave space fix)
- docs: feature-checklist.md added

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 15:35:59 +02:00

145 lines
4.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:pyramid/core/theme.dart';
import 'package:pyramid/core/update_checker.dart';
import 'package:pyramid/widgets/update_download_dialog.dart';
/// Slim top banner shown when a new Pyramid version is available.
class UpdateBanner extends ConsumerWidget {
const UpdateBanner({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return ref.watch(updateInfoProvider).when(
loading: () => const SizedBox.shrink(),
error: (e, _) => const SizedBox.shrink(),
data: (info) =>
info == null ? const SizedBox.shrink() : _Banner(info: info),
);
}
}
class _Banner extends ConsumerWidget {
final UpdateInfo info;
const _Banner({required this.info});
@override
Widget build(BuildContext context, WidgetRef ref) {
final pt = PyramidTheme.of(context);
final canDownload = info.canDownload;
return Container(
width: double.infinity,
decoration: BoxDecoration(
color: pt.accent.withAlpha(28),
border: Border(
bottom: BorderSide(color: pt.accent.withAlpha(80)),
),
),
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Row(
children: [
Icon(Icons.system_update_alt_rounded, size: 15, color: pt.accent),
const SizedBox(width: 8),
Expanded(
child: Text(
'Pyramid ${info.tagName} ist verfügbar',
style: TextStyle(
color: pt.fg, fontSize: 12.5, fontWeight: FontWeight.w500),
overflow: TextOverflow.ellipsis,
),
),
const SizedBox(width: 8),
_BannerBtn(
label: 'Was ist neu',
icon: Icons.open_in_new_rounded,
color: pt.bg3,
fgColor: pt.fg,
onTap: () => _openUrl(info.htmlUrl),
),
const SizedBox(width: 6),
_BannerBtn(
label: canDownload ? 'Herunterladen' : 'Öffnen',
icon: canDownload
? Icons.download_rounded
: Icons.open_in_new_rounded,
color: pt.accent,
fgColor: pt.accentFg,
onTap: () {
if (canDownload) {
showUpdateDownloadDialog(context, info);
} else {
_openUrl(info.htmlUrl);
}
},
),
const SizedBox(width: 6),
Tooltip(
message: 'Für diese Version ausblenden',
child: InkWell(
borderRadius: BorderRadius.circular(4),
onTap: () async {
await skipUpdateVersion(info.tagName);
ref.invalidate(updateInfoProvider);
},
child: Padding(
padding: const EdgeInsets.all(4),
child: Icon(Icons.close_rounded, size: 14, color: pt.fgDim),
),
),
),
],
),
);
}
Future<void> _openUrl(String url) async {
final uri = Uri.parse(url);
if (await canLaunchUrl(uri)) {
await launchUrl(uri, mode: LaunchMode.externalApplication);
}
}
}
class _BannerBtn extends StatelessWidget {
final String label;
final IconData icon;
final Color color;
final Color fgColor;
final VoidCallback onTap;
const _BannerBtn({
required this.label,
required this.icon,
required this.color,
required this.fgColor,
required this.onTap,
});
@override
Widget build(BuildContext context) {
return InkWell(
borderRadius: BorderRadius.circular(6),
onTap: onTap,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration:
BoxDecoration(color: color, borderRadius: BorderRadius.circular(6)),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: 12, color: fgColor),
const SizedBox(width: 4),
Text(label,
style: TextStyle(
color: fgColor,
fontSize: 12,
fontWeight: FontWeight.w600)),
],
),
),
);
}
}