forked from firka/firka
@@ -9,6 +9,10 @@ import 'package:firka_wear/services/wear_sync_store.dart';
|
|||||||
late final Logger logger;
|
late final Logger logger;
|
||||||
|
|
||||||
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
||||||
|
|
||||||
|
/// When non-null, the app should show [WearErrorScreen] with this error.
|
||||||
|
final ValueNotifier<FlutterErrorDetails?> globalErrorNotifier =
|
||||||
|
ValueNotifier<FlutterErrorDetails?>(null);
|
||||||
late WearAppInitialization initData;
|
late WearAppInitialization initData;
|
||||||
bool initDone = false;
|
bool initDone = false;
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
import 'package:wear_plus/wear_plus.dart';
|
|
||||||
|
|
||||||
import 'package:firka_wear/app/app_state.dart';
|
import 'package:firka_wear/app/app_state.dart';
|
||||||
import 'package:firka_wear/app/initialization.dart';
|
import 'package:firka_wear/app/initialization.dart';
|
||||||
import 'package:firka_wear/core/bloc/wear_sync_cubit.dart';
|
import 'package:firka_wear/core/bloc/wear_sync_cubit.dart';
|
||||||
import 'package:firka_wear/l10n/app_localizations.dart';
|
import 'package:firka_wear/l10n/app_localizations.dart';
|
||||||
import 'package:firka_wear/ui/theme/style.dart';
|
import 'package:firka_wear/ui/theme/style.dart';
|
||||||
|
import 'package:firka_wear/ui/wear/screens/error/error_screen.dart';
|
||||||
import 'package:firka_wear/ui/wear/screens/home/home_screen.dart';
|
import 'package:firka_wear/ui/wear/screens/home/home_screen.dart';
|
||||||
import 'package:firka_wear/ui/wear/screens/login/login_screen.dart';
|
import 'package:firka_wear/ui/wear/screens/login/login_screen.dart';
|
||||||
|
|
||||||
@@ -25,25 +25,7 @@ class WearInitializationScreen extends StatelessWidget {
|
|||||||
if (snapshot.hasError) {
|
if (snapshot.hasError) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
key: ValueKey('firkaErrorPage'),
|
key: ValueKey('firkaErrorPage'),
|
||||||
home: Scaffold(
|
home: WearErrorScreen(exception: snapshot.error!),
|
||||||
body: Center(
|
|
||||||
child: WatchShape(
|
|
||||||
builder: (context, shape, child) {
|
|
||||||
return Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
'Error initializing app: ${snapshot.error}',
|
|
||||||
style: TextStyle(color: Colors.red),
|
|
||||||
),
|
|
||||||
child!,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: SizedBox(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:firka_wear/app/app_state.dart';
|
import 'package:firka_wear/app/app_state.dart';
|
||||||
import 'package:firka_wear/app/initialization_screen.dart';
|
import 'package:firka_wear/app/initialization_screen.dart';
|
||||||
|
import 'package:firka_wear/ui/wear/screens/error/error_screen.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
@@ -26,5 +28,49 @@ void main() async {
|
|||||||
|
|
||||||
await ScreenUtil.ensureScreenSize();
|
await ScreenUtil.ensureScreenSize();
|
||||||
|
|
||||||
runApp(WearInitializationScreen());
|
FlutterError.onError = (FlutterErrorDetails details) {
|
||||||
|
FlutterError.presentError(details);
|
||||||
|
if (_isFatalError(details.exception)) {
|
||||||
|
globalErrorNotifier.value = details;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
runZonedGuarded(() => runApp(const _WearAppWrapper()), (
|
||||||
|
Object error,
|
||||||
|
StackTrace stackTrace,
|
||||||
|
) {
|
||||||
|
if (_isFatalError(error)) {
|
||||||
|
globalErrorNotifier.value = FlutterErrorDetails(
|
||||||
|
exception: error,
|
||||||
|
stack: stackTrace,
|
||||||
|
library: 'firka_wear',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isFatalError(Object error) {
|
||||||
|
return error is! AssertionError;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _WearAppWrapper extends StatelessWidget {
|
||||||
|
const _WearAppWrapper();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ValueListenableBuilder<FlutterErrorDetails?>(
|
||||||
|
valueListenable: globalErrorNotifier,
|
||||||
|
builder: (context, error, _) {
|
||||||
|
if (error != null) {
|
||||||
|
return MaterialApp(
|
||||||
|
home: WearErrorScreen(
|
||||||
|
exception: error.exception,
|
||||||
|
stackTrace: error.stack,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return WearInitializationScreen();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
65
firka_wear/lib/ui/wear/screens/error/error_screen.dart
Normal file
65
firka_wear/lib/ui/wear/screens/error/error_screen.dart
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
import 'package:qr_flutter/qr_flutter.dart';
|
||||||
|
import 'package:wear_plus/wear_plus.dart';
|
||||||
|
|
||||||
|
import 'package:firka_wear/ui/theme/style.dart';
|
||||||
|
|
||||||
|
final int _kMaxQrPayloadChars = 410;
|
||||||
|
|
||||||
|
String errorPayload(Object exception, [StackTrace? stackTrace]) {
|
||||||
|
final buffer = StringBuffer();
|
||||||
|
buffer.writeln(exception.toString());
|
||||||
|
if (stackTrace != null) buffer.write(stackTrace.toString());
|
||||||
|
final s = buffer.toString();
|
||||||
|
return s.length > _kMaxQrPayloadChars
|
||||||
|
? s.substring(0, _kMaxQrPayloadChars)
|
||||||
|
: s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Full-screen error UI: encodes [exception] (and [stackTrace]) into a QR code
|
||||||
|
/// scaled to fit the watch's circular display so it is not clipped.
|
||||||
|
class WearErrorScreen extends StatelessWidget {
|
||||||
|
final Object exception;
|
||||||
|
final StackTrace? stackTrace;
|
||||||
|
|
||||||
|
const WearErrorScreen({super.key, required this.exception, this.stackTrace});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
ScreenUtil.init(context);
|
||||||
|
|
||||||
|
final payload = errorPayload(exception, stackTrace);
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: wearStyle.colors.background,
|
||||||
|
body: LayoutBuilder(
|
||||||
|
builder: (context, constraints) {
|
||||||
|
return Center(
|
||||||
|
child: WatchShape(
|
||||||
|
builder: (context, shape, child) {
|
||||||
|
return SizedBox(
|
||||||
|
width: 350.w,
|
||||||
|
height: 350.h,
|
||||||
|
child: QrImageView(
|
||||||
|
data: payload,
|
||||||
|
version: 13,
|
||||||
|
backgroundColor: wearStyle.colors.background,
|
||||||
|
eyeStyle: QrEyeStyle(
|
||||||
|
eyeShape: QrEyeShape.square,
|
||||||
|
color: wearStyle.colors.textPrimary,
|
||||||
|
),
|
||||||
|
dataModuleStyle: QrDataModuleStyle(
|
||||||
|
dataModuleShape: QrDataModuleShape.square,
|
||||||
|
color: wearStyle.colors.textPrimary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: const SizedBox.shrink(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -62,6 +62,7 @@ dependencies:
|
|||||||
flutter_svg: ^1.1.6
|
flutter_svg: ^1.1.6
|
||||||
logging: ^1.3.0
|
logging: ^1.3.0
|
||||||
flutter_bloc: ^9.0.0
|
flutter_bloc: ^9.0.0
|
||||||
|
qr_flutter: ^4.1.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
build_runner: any
|
build_runner: any
|
||||||
|
|||||||
Reference in New Issue
Block a user