mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-09 01:50:30 +00:00
fix(ui): preserve mobile home route and confirm Android exit
This commit is contained in:
1 parent
8f9bac9e6b
commit
ee6b073bc1
7 files changed
+307
-66
No files matched your search
@@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
@@ -7,18 +9,37 @@ import '../widgets/app_toast.dart';
|
||||
class AppExitConfirmationController {
|
||||
static const confirmationWindow = Duration(seconds: 2);
|
||||
|
||||
DateTime? _lastBackAt;
|
||||
OverlayEntry? _toast;
|
||||
Timer? _timer;
|
||||
|
||||
Future<void> handleBack(BuildContext context) async {
|
||||
final now = DateTime.now();
|
||||
final lastBackAt = _lastBackAt;
|
||||
if (lastBackAt != null && now.difference(lastBackAt) <= confirmationWindow) {
|
||||
_lastBackAt = null;
|
||||
if (_toast != null) {
|
||||
dispose();
|
||||
await SystemNavigator.pop();
|
||||
return;
|
||||
}
|
||||
|
||||
_lastBackAt = now;
|
||||
showAppToast(context, context.l10n.pressBackAgainToExit);
|
||||
final message = context.l10n.pressBackAgainToExit;
|
||||
final themes = InheritedTheme.capture(from: context, to: Overlay.of(context, rootOverlay: true).context);
|
||||
_toast = OverlayEntry(
|
||||
builder: (_) => IgnorePointer(
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: themes.wrap(AppToastContent(message: message)),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
Overlay.of(context, rootOverlay: true).insert(_toast!);
|
||||
_timer = Timer(confirmationWindow, dispose);
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_timer?.cancel();
|
||||
_timer = null;
|
||||
_toast?.remove();
|
||||
_toast?.dispose();
|
||||
_toast = null;
|
||||
}
|
||||
}
|
||||
@@ -11,11 +11,6 @@ enum AppToastType { info, success, error }
|
||||
/// short messages stay compact while long messages wrap before becoming wider
|
||||
/// than the configured maximum. Errors and normal notices use the same layout.
|
||||
void showAppToast(BuildContext context, String message, {AppToastType type = AppToastType.info}) {
|
||||
final palette = AppPalette.of(context);
|
||||
final borderColor = switch (type) {
|
||||
AppToastType.error => palette.error.withValues(alpha: 0.55),
|
||||
AppToastType.success || AppToastType.info => palette.border,
|
||||
};
|
||||
shad.showToast(
|
||||
context: context,
|
||||
location: shad.ToastLocation.topCenter,
|
||||
@@ -23,16 +18,34 @@ void showAppToast(BuildContext context, String message, {AppToastType type = App
|
||||
alignment: Alignment.topCenter,
|
||||
widthFactor: 1,
|
||||
heightFactor: 1,
|
||||
child: Container(
|
||||
key: const ValueKey('app-toast-content'),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: palette.cardBg,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: borderColor),
|
||||
),
|
||||
child: Text(message, style: TextStyle(color: palette.textPrimary, fontSize: 13, height: 1.2)),
|
||||
),
|
||||
child: AppToastContent(message: message, type: type),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Shared toast surface for edge notifications and centered exit prompts.
|
||||
class AppToastContent extends StatelessWidget {
|
||||
const AppToastContent({super.key, required this.message, this.type = AppToastType.info});
|
||||
|
||||
final String message;
|
||||
final AppToastType type;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final palette = AppPalette.of(context);
|
||||
final borderColor = switch (type) {
|
||||
AppToastType.error => palette.error.withValues(alpha: 0.55),
|
||||
AppToastType.success || AppToastType.info => palette.border,
|
||||
};
|
||||
return Container(
|
||||
key: const ValueKey('app-toast-content'),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: palette.cardBg,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: borderColor),
|
||||
),
|
||||
child: Text(message, style: TextStyle(color: palette.textPrimary, fontSize: 13, height: 1.2)),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user