mobile_nebula/lib/main.dart
Ian VanSchooten 991837676a
Add DangerButton component (#219)
This pulls out a component that we can use for "dangerous" operations like deleting, and styles it in one place.

It also starts to move us slowly towards Material 3, with the rounded corners on these buttons in Android.  

Android:

|Before Light|Before Dark|After Light|After Dark|
|---|---|---|---|
|<img width="425" alt="Android Studio 2025-01-15 14 16 36" src="https://github.com/user-attachments/assets/4823e551-6a40-48dd-9bc1-3004699b90ea" />|<img width="417" alt="Android Studio 2025-01-15 14 16 47" src="https://github.com/user-attachments/assets/df5461fd-586e-47bb-99b9-0212e63f0454" />|<img width="413" alt="Android Studio 2025-01-15 14 15 59" src="https://github.com/user-attachments/assets/d88a6225-b71a-4886-8387-e35811a3a6ec" />|<img width="418" alt="Android Studio 2025-01-15 14 16 15" src="https://github.com/user-attachments/assets/d4f23b1c-7003-4a00-b865-4a123d8fe3e9" />|


iOS:

|Before Light|Before Dark|After Light|After Dark|
|---|---|---|---|
|<img width="437" alt="Simulator 2025-01-15 15 56 26" src="https://github.com/user-attachments/assets/87c4eed3-6d07-4858-8ad8-d8c011538154" />|<img width="445" alt="Simulator 2025-01-15 15 56 36" src="https://github.com/user-attachments/assets/9dc5b174-7bc7-48ec-a3c0-61633168c31a" />|<img width="439" alt="Simulator 2025-01-15 16 05 23" src="https://github.com/user-attachments/assets/31dc9ab6-8a3c-49c7-892d-627f16e2a8cd" />|<img width="444" alt="Simulator 2025-01-15 16 05 37" src="https://github.com/user-attachments/assets/979280d6-e1f4-4d57-a86a-10bb4def729a" />|
2025-01-16 08:16:23 -05:00

158 lines
5.2 KiB
Dart

import 'dart:async';
import 'package:flutter/cupertino.dart' show CupertinoThemeData, DefaultCupertinoLocalizations, CupertinoColors;
import 'package:flutter/material.dart'
show BottomSheetThemeData, ColorScheme, Colors, DefaultMaterialLocalizations, ThemeData, ThemeMode;
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:mobile_nebula/screens/MainScreen.dart';
import 'package:mobile_nebula/screens/EnrollmentScreen.dart';
import 'package:mobile_nebula/services/settings.dart';
import 'package:flutter_web_plugins/url_strategy.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
Future<void> main() async {
usePathUrlStrategy();
var settings = Settings();
if (settings.trackErrors) {
await SentryFlutter.init(
(options) {
options.dsn = 'https://96106df405ade3f013187dfc8e4200e7@o920269.ingest.us.sentry.io/4508132321001472';
// Capture all traces. May need to adjust if overwhelming
options.tracesSampleRate = 1.0;
// For each trace, capture all profiles
options.profilesSampleRate = 1.0;
},
appRunner: () => runApp(Main()),
);
} else {
runApp(Main());
}
}
//TODO: EventChannel might be better than the stream controller we are using now
class Main extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) => App();
}
class App extends StatefulWidget {
@override
_AppState createState() => _AppState();
}
class _AppState extends State<App> {
final settings = Settings();
Brightness brightness = SchedulerBinding.instance.platformDispatcher.platformBrightness;
StreamController dnEnrolled = StreamController.broadcast();
@override
void initState() {
//TODO: wait until settings is ready?
settings.onChange().listen((_) {
setState(() {
if (settings.useSystemColors) {
brightness = SchedulerBinding.instance.platformDispatcher.platformBrightness;
} else {
brightness = settings.darkMode ? Brightness.dark : Brightness.light;
}
});
});
// Listen to changes to the system brightness mode, update accordingly
final dispatcher = SchedulerBinding.instance.platformDispatcher;
dispatcher.onPlatformBrightnessChanged = () {
if (settings.useSystemColors) {
setState(() {
brightness = dispatcher.platformBrightness;
});
}
};
super.initState();
}
@override
void dispose() {
dnEnrolled.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
final ThemeData lightTheme = ThemeData(
useMaterial3: false,
colorScheme: ColorScheme.fromSwatch(
brightness: Brightness.light,
primarySwatch: Colors.blueGrey,
errorColor: CupertinoColors.systemRed.resolveFrom(context),
),
primaryColor: Colors.blueGrey[900],
fontFamily: 'PublicSans',
//scaffoldBackgroundColor: Colors.grey[100],
scaffoldBackgroundColor: Colors.white,
bottomSheetTheme: BottomSheetThemeData(
backgroundColor: Colors.blueGrey[50],
),
);
final ThemeData darkTheme = ThemeData(
useMaterial3: false,
colorScheme: ColorScheme.fromSwatch(
brightness: Brightness.dark,
primarySwatch: Colors.grey,
errorColor: CupertinoColors.systemRed.resolveFrom(context),
),
primaryColor: Colors.grey[900],
fontFamily: 'PublicSans',
scaffoldBackgroundColor: Colors.grey[800],
bottomSheetTheme: BottomSheetThemeData(
backgroundColor: Colors.grey[850],
),
);
return PlatformProvider(
settings: PlatformSettingsData(iosUsesMaterialWidgets: true),
builder: (context) => PlatformApp(
debugShowCheckedModeBanner: false,
localizationsDelegates: <LocalizationsDelegate<dynamic>>[
DefaultMaterialLocalizations.delegate,
DefaultWidgetsLocalizations.delegate,
DefaultCupertinoLocalizations.delegate,
],
title: 'Nebula',
material: (_, __) {
return new MaterialAppData(
themeMode: brightness == Brightness.light ? ThemeMode.light : ThemeMode.dark,
theme: brightness == Brightness.light ? lightTheme : darkTheme,
);
},
cupertino: (_, __) => CupertinoAppData(
theme: CupertinoThemeData(brightness: brightness),
),
onGenerateRoute: (settings) {
if (settings.name == '/') {
return platformPageRoute(context: context, builder: (context) => MainScreen(this.dnEnrolled));
}
final uri = Uri.parse(settings.name!);
if (uri.path == EnrollmentScreen.routeName) {
// TODO: maybe implement this as a dialog instead of a page, you can stack multiple enrollment screens which is annoying in dev
return platformPageRoute(
context: context,
builder: (context) =>
EnrollmentScreen(code: EnrollmentScreen.parseCode(settings.name!), stream: this.dnEnrolled),
);
}
return null;
},
),
);
}
}