Login & register

This commit is contained in:
2024-11-09 18:28:45 +08:00
parent 5e12a8860c
commit 4d12d243b3
22 changed files with 3798 additions and 20 deletions

151
lib/widgets/dialog.dart Normal file
View File

@ -0,0 +1,151 @@
import 'dart:math' as math;
import 'package:dio/dio.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
extension AppPromptExtension on BuildContext {
void showSnackbar(String content, {SnackBarAction? action}) {
ScaffoldMessenger.of(this).showSnackBar(SnackBar(
content: Text(content),
action: action,
));
}
void clearSnackbar() {
ScaffoldMessenger.of(this).clearSnackBars();
}
Future<void> showModalDialog(String title, desc) {
return showDialog<void>(
useRootNavigator: true,
context: this,
builder: (ctx) => AlertDialog(
title: Text(title),
content: Text(desc),
actions: [
TextButton(
onPressed: () => Navigator.pop(ctx),
child: Text('dialogDismiss').tr(),
)
],
),
);
}
Future<void> showInfoDialog(String title, body) {
return showDialog<void>(
useRootNavigator: true,
context: this,
builder: (ctx) => AlertDialog(
title: Text(title),
content: Text(body),
actions: [
TextButton(
onPressed: () => Navigator.pop(ctx),
child: Text('dialogDismiss').tr(),
)
],
),
);
}
Future<bool> showConfirmDialog(String title, body) async {
return await showDialog<bool>(
useRootNavigator: true,
context: this,
builder: (ctx) => AlertDialog(
title: Text(title),
content: Text(body),
actions: [
TextButton(
onPressed: () => Navigator.pop(ctx, false),
child: Text('dialogCancel').tr(),
),
TextButton(
onPressed: () => Navigator.pop(ctx, true),
child: Text('dialogConfirm').tr(),
)
],
),
) ??
false;
}
Future<void> showErrorDialog(dynamic exception) {
Widget content = Text(exception.toString().capitalize());
if (exception is DioException) {
String preview;
switch (exception.response?.statusCode) {
case 400:
preview = 'errorRequestBad'.tr();
break;
case 401:
preview = 'errorRequestUnauthorized'.tr();
break;
case 403:
preview = 'errorRequestForbidden'.tr();
break;
case 404:
preview = 'errorRequestNotFound'.tr();
break;
case null:
preview = 'errorRequestConnection'.tr();
break;
default:
preview = 'errorRequestUnknown'.tr();
break;
}
if (exception.response != null) {
content = Text(
'$preview\n\n(${exception.response?.statusCode}) ${exception.response?.data}',
);
} else {
content = Text(preview);
}
}
return showDialog<void>(
useRootNavigator: true,
context: this,
builder: (ctx) => AlertDialog(
title: Text('dialogError').tr(),
content: content,
actions: [
TextButton(
onPressed: () => Navigator.pop(ctx),
child: Text('dialogDismiss').tr(),
)
],
),
);
}
}
extension ByteFormatter on int {
String formatBytes({int decimals = 2}) {
if (this == 0) return '0 Bytes';
const k = 1024;
final dm = decimals < 0 ? 0 : decimals;
final sizes = [
'Bytes',
'KiB',
'MiB',
'GiB',
'TiB',
'PiB',
'EiB',
'ZiB',
'YiB'
];
final i = (math.log(this) / math.log(k)).floor().toInt();
return '${(this / math.pow(k, i)).toStringAsFixed(dm)} ${sizes[i]}';
}
}
extension StringFormatter on String {
String capitalize() {
return "${this[0].toUpperCase()}${substring(1)}";
}
}

View File

@ -1,24 +1,48 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:responsive_framework/responsive_framework.dart';
import 'package:surface/widgets/dialog.dart';
import 'package:surface/widgets/navigation/app_background.dart';
import 'package:surface/widgets/navigation/app_bottom_navigation.dart';
class AppScaffold extends StatelessWidget {
final PreferredSizeWidget? appBar;
final String? title;
final Widget? body;
final bool? showBottomNavigation;
const AppScaffold(
{super.key, this.appBar, this.body, this.showBottomNavigation});
final bool autoImplyAppBar;
final bool showBottomNavigation;
const AppScaffold({
super.key,
this.appBar,
this.title,
this.body,
this.autoImplyAppBar = false,
this.showBottomNavigation = false,
});
@override
Widget build(BuildContext context) {
final isShowBottomNavigation = (showBottomNavigation ?? false)
final isShowBottomNavigation = (showBottomNavigation)
? ResponsiveBreakpoints.of(context).smallerOrEqualTo(MOBILE)
: false;
final state = GoRouter.maybeOf(context);
return AppBackground(
child: Scaffold(
appBar: appBar,
appBar: appBar ??
(autoImplyAppBar
? AppBar(
title: title != null
? Text(title!)
: state != null
? Text(
('screen${state.routerDelegate.currentConfiguration.last.route.name?.capitalize()}')
.tr(),
)
: null)
: null),
body: body,
bottomNavigationBar:
isShowBottomNavigation ? AppBottomNavigationBar() : null,