140 lines
3.7 KiB
Dart
140 lines
3.7 KiB
Dart
import 'dart:developer';
|
|
|
|
import 'package:dio/dio.dart';
|
|
import 'package:easy_localization/easy_localization.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_platform_alert/flutter_platform_alert.dart';
|
|
import 'package:gap/gap.dart';
|
|
import 'package:styled_widget/styled_widget.dart';
|
|
|
|
// TODO support web here
|
|
|
|
String _parseRemoteError(DioException err) {
|
|
log('${err.requestOptions.method} ${err.requestOptions.uri} ${err.message}');
|
|
if (err.response?.data is String) return err.response?.data;
|
|
if (err.response?.data?['errors'] != null) {
|
|
final errors = err.response?.data['errors'] as Map<String, dynamic>;
|
|
return errors.values
|
|
.map(
|
|
(ele) =>
|
|
(ele as List<dynamic>).map((ele) => ele.toString()).join('\n'),
|
|
)
|
|
.join('\n');
|
|
}
|
|
return err.message ?? err.toString();
|
|
}
|
|
|
|
void showErrorAlert(dynamic err) async {
|
|
final text = switch (err) {
|
|
String _ => err,
|
|
DioException _ => _parseRemoteError(err),
|
|
Exception _ => err.toString(),
|
|
_ => err.toString(),
|
|
};
|
|
FlutterPlatformAlert.showAlert(
|
|
windowTitle: 'somethingWentWrong'.tr(),
|
|
text: text,
|
|
alertStyle: AlertButtonStyle.ok,
|
|
iconStyle: IconStyle.error,
|
|
);
|
|
}
|
|
|
|
void showInfoAlert(String message, String title) async {
|
|
FlutterPlatformAlert.showAlert(
|
|
windowTitle: title,
|
|
text: message,
|
|
alertStyle: AlertButtonStyle.ok,
|
|
iconStyle: IconStyle.information,
|
|
);
|
|
}
|
|
|
|
Future<bool> showConfirmAlert(String message, String title) async {
|
|
final result = await FlutterPlatformAlert.showAlert(
|
|
windowTitle: title,
|
|
text: message,
|
|
alertStyle: AlertButtonStyle.okCancel,
|
|
iconStyle: IconStyle.question,
|
|
);
|
|
return result == AlertButton.okButton;
|
|
}
|
|
|
|
OverlayEntry? _loadingOverlay;
|
|
GlobalKey<_FadeOverlayState> _loadingOverlayKey = GlobalKey();
|
|
|
|
class _FadeOverlay extends StatefulWidget {
|
|
const _FadeOverlay({super.key, required this.child});
|
|
final Widget child;
|
|
|
|
@override
|
|
State<_FadeOverlay> createState() => _FadeOverlayState();
|
|
}
|
|
|
|
class _FadeOverlayState extends State<_FadeOverlay> {
|
|
bool _visible = false;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
setState(() => _visible = true);
|
|
});
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return AnimatedOpacity(
|
|
opacity: _visible ? 1.0 : 0.0,
|
|
duration: const Duration(milliseconds: 200),
|
|
child: widget.child,
|
|
);
|
|
}
|
|
}
|
|
|
|
void showLoadingModal(BuildContext context) {
|
|
if (_loadingOverlay != null) return;
|
|
|
|
_loadingOverlay = OverlayEntry(
|
|
builder:
|
|
(context) => _FadeOverlay(
|
|
key: _loadingOverlayKey,
|
|
child: Material(
|
|
color: Colors.black54,
|
|
child: Center(
|
|
child: Material(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(8),
|
|
elevation: 4,
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
CircularProgressIndicator(year2023: true),
|
|
const Gap(24),
|
|
Text('loading'.tr()),
|
|
],
|
|
).padding(all: 32),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
Overlay.of(context).insert(_loadingOverlay!);
|
|
}
|
|
|
|
void hideLoadingModal(BuildContext context) async {
|
|
if (_loadingOverlay == null) return;
|
|
|
|
final entry = _loadingOverlay!;
|
|
_loadingOverlay = null;
|
|
|
|
final state = entry.mounted ? _loadingOverlayKey.currentState : null;
|
|
|
|
if (state != null) {
|
|
// ignore: invalid_use_of_protected_member
|
|
state.setState(() => state._visible = false);
|
|
await Future.delayed(const Duration(milliseconds: 200));
|
|
}
|
|
|
|
entry.remove();
|
|
}
|