✨ Login & register
This commit is contained in:
151
lib/widgets/dialog.dart
Normal file
151
lib/widgets/dialog.dart
Normal 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)}";
|
||||
}
|
||||
}
|
@ -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,
|
||||
|
Reference in New Issue
Block a user