blob: 745b96a788916844e104e1a7d93c38772a1c4bb6 [file] [log] [blame]
import 'package:animations/animations.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/gallery_localizations.dart';
import 'package:gallery/data/gallery_options.dart';
import 'package:gallery/layout/letter_spacing.dart';
import 'package:gallery/studies/reply/adaptive_nav.dart';
import 'package:gallery/studies/reply/colors.dart';
import 'package:gallery/studies/reply/compose_page.dart';
import 'package:gallery/studies/reply/model/email_store.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
final rootNavKey = GlobalKey<NavigatorState>();
class ReplyApp extends StatelessWidget {
const ReplyApp();
static const String homeRoute = '/reply';
static const String composeRoute = '/reply/compose';
static Route createComposeRoute(RouteSettings settings) {
return PageRouteBuilder<void>(
pageBuilder: (context, animation, secondaryAnimation) =>
const ComposePage(),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
return FadeThroughTransition(
fillColor: Theme.of(context).cardColor,
animation: animation,
secondaryAnimation: secondaryAnimation,
child: child,
);
},
settings: settings,
);
}
@override
Widget build(BuildContext context) {
final galleryThemeMode = GalleryOptions.of(context).themeMode;
final isDark = galleryThemeMode == ThemeMode.system
? Theme.of(context).brightness == Brightness.dark
: galleryThemeMode == ThemeMode.dark;
final replyTheme =
isDark ? _buildReplyDarkTheme(context) : _buildReplyLightTheme(context);
return MultiProvider(
providers: [
ChangeNotifierProvider<EmailStore>.value(value: EmailStore()),
],
child: MaterialApp(
navigatorKey: rootNavKey,
title: 'Reply',
debugShowCheckedModeBanner: false,
theme: replyTheme,
localizationsDelegates: GalleryLocalizations.localizationsDelegates,
supportedLocales: GalleryLocalizations.supportedLocales,
locale: GalleryOptions.of(context).locale,
initialRoute: homeRoute,
onGenerateRoute: (settings) {
switch (settings.name) {
case homeRoute:
return MaterialPageRoute<void>(
builder: (context) => const AdaptiveNav(),
settings: settings,
);
break;
case composeRoute:
return createComposeRoute(settings);
break;
}
return null;
},
),
);
}
}
ThemeData _buildReplyLightTheme(BuildContext context) {
final base = ThemeData.light();
return base.copyWith(
accentColor: ReplyColors.orange500,
bottomAppBarColor: ReplyColors.blue700,
bottomSheetTheme: BottomSheetThemeData(
backgroundColor: ReplyColors.blue700,
modalBackgroundColor: Colors.white.withOpacity(0.7),
),
navigationRailTheme: NavigationRailThemeData(
backgroundColor: ReplyColors.blue700,
selectedIconTheme: const IconThemeData(color: ReplyColors.orange500),
selectedLabelTextStyle:
GoogleFonts.workSansTextTheme().headline5.copyWith(
color: ReplyColors.orange500,
),
unselectedIconTheme: const IconThemeData(color: ReplyColors.blue200),
unselectedLabelTextStyle:
GoogleFonts.workSansTextTheme().headline5.copyWith(
color: ReplyColors.blue200,
),
),
canvasColor: ReplyColors.white50,
cardColor: ReplyColors.white50,
chipTheme: _buildChipTheme(
ReplyColors.blue700,
ReplyColors.lightChipBackground,
Brightness.light,
),
colorScheme: const ColorScheme.light(
primary: ReplyColors.blue700,
primaryVariant: ReplyColors.blue800,
secondary: ReplyColors.orange500,
secondaryVariant: ReplyColors.orange400,
surface: ReplyColors.white50,
error: ReplyColors.red400,
onPrimary: ReplyColors.white50,
onSecondary: ReplyColors.black900,
onBackground: ReplyColors.black900,
onSurface: ReplyColors.black900,
onError: ReplyColors.black900,
background: ReplyColors.blue50,
),
textTheme: _buildReplyLightTextTheme(base.textTheme),
scaffoldBackgroundColor: ReplyColors.blue50,
);
}
ThemeData _buildReplyDarkTheme(BuildContext context) {
final base = ThemeData.dark();
return base.copyWith(
accentColor: ReplyColors.orange300,
bottomAppBarColor: ReplyColors.darkBottomAppBarBackground,
bottomSheetTheme: BottomSheetThemeData(
backgroundColor: ReplyColors.darkDrawerBackground,
modalBackgroundColor: Colors.black.withOpacity(0.7),
),
navigationRailTheme: NavigationRailThemeData(
backgroundColor: ReplyColors.darkBottomAppBarBackground,
selectedIconTheme: const IconThemeData(color: ReplyColors.orange300),
selectedLabelTextStyle:
GoogleFonts.workSansTextTheme().headline5.copyWith(
color: ReplyColors.orange300,
),
unselectedIconTheme: const IconThemeData(color: ReplyColors.greyLabel),
unselectedLabelTextStyle:
GoogleFonts.workSansTextTheme().headline5.copyWith(
color: ReplyColors.greyLabel,
),
),
canvasColor: ReplyColors.black900,
cardColor: ReplyColors.darkCardBackground,
chipTheme: _buildChipTheme(
ReplyColors.blue200,
ReplyColors.darkChipBackground,
Brightness.dark,
),
colorScheme: const ColorScheme.dark(
primary: ReplyColors.blue200,
primaryVariant: ReplyColors.blue300,
secondary: ReplyColors.orange300,
secondaryVariant: ReplyColors.orange300,
surface: ReplyColors.black800,
error: ReplyColors.red200,
onPrimary: ReplyColors.black900,
onSecondary: ReplyColors.black900,
onBackground: ReplyColors.white50,
onSurface: ReplyColors.white50,
onError: ReplyColors.black900,
background: ReplyColors.black900Alpha087,
),
textTheme: _buildReplyDarkTextTheme(base.textTheme),
scaffoldBackgroundColor: ReplyColors.black900,
);
}
ChipThemeData _buildChipTheme(
Color primaryColor,
Color chipBackground,
Brightness brightness,
) {
return ChipThemeData(
backgroundColor: primaryColor.withOpacity(0.12),
disabledColor: primaryColor.withOpacity(0.87),
selectedColor: primaryColor.withOpacity(0.05),
secondarySelectedColor: chipBackground,
padding: const EdgeInsets.all(4),
shape: const StadiumBorder(),
labelStyle: GoogleFonts.workSansTextTheme().bodyText2.copyWith(
color: brightness == Brightness.dark
? ReplyColors.white50
: ReplyColors.black900,
),
secondaryLabelStyle: GoogleFonts.workSansTextTheme().bodyText2,
brightness: brightness,
);
}
TextTheme _buildReplyLightTextTheme(TextTheme base) {
return base.copyWith(
headline4: GoogleFonts.workSans(
fontWeight: FontWeight.w600,
fontSize: 34,
letterSpacing: letterSpacingOrNone(0.4),
height: 0.9,
color: ReplyColors.black900,
),
headline5: GoogleFonts.workSans(
fontWeight: FontWeight.bold,
fontSize: 24,
letterSpacing: letterSpacingOrNone(0.27),
color: ReplyColors.black900,
),
headline6: GoogleFonts.workSans(
fontWeight: FontWeight.w600,
fontSize: 20,
letterSpacing: letterSpacingOrNone(0.18),
color: ReplyColors.black900,
),
subtitle2: GoogleFonts.workSans(
fontWeight: FontWeight.w600,
fontSize: 14,
letterSpacing: letterSpacingOrNone(-0.04),
color: ReplyColors.black900,
),
bodyText1: GoogleFonts.workSans(
fontWeight: FontWeight.normal,
fontSize: 18,
letterSpacing: letterSpacingOrNone(0.2),
color: ReplyColors.black900,
),
bodyText2: GoogleFonts.workSans(
fontWeight: FontWeight.normal,
fontSize: 14,
letterSpacing: letterSpacingOrNone(-0.05),
color: ReplyColors.black900,
),
caption: GoogleFonts.workSans(
fontWeight: FontWeight.normal,
fontSize: 12,
letterSpacing: letterSpacingOrNone(0.2),
color: ReplyColors.black900,
),
);
}
TextTheme _buildReplyDarkTextTheme(TextTheme base) {
return base.copyWith(
headline4: GoogleFonts.workSans(
fontWeight: FontWeight.w600,
fontSize: 34,
letterSpacing: letterSpacingOrNone(0.4),
height: 0.9,
color: ReplyColors.white50,
),
headline5: GoogleFonts.workSans(
fontWeight: FontWeight.bold,
fontSize: 24,
letterSpacing: letterSpacingOrNone(0.27),
color: ReplyColors.white50,
),
headline6: GoogleFonts.workSans(
fontWeight: FontWeight.w600,
fontSize: 20,
letterSpacing: letterSpacingOrNone(0.18),
color: ReplyColors.white50,
),
subtitle2: GoogleFonts.workSans(
fontWeight: FontWeight.w600,
fontSize: 14,
letterSpacing: letterSpacingOrNone(-0.04),
color: ReplyColors.white50,
),
bodyText1: GoogleFonts.workSans(
fontWeight: FontWeight.normal,
fontSize: 18,
letterSpacing: letterSpacingOrNone(0.2),
color: ReplyColors.white50,
),
bodyText2: GoogleFonts.workSans(
fontWeight: FontWeight.normal,
fontSize: 14,
letterSpacing: letterSpacingOrNone(-0.05),
color: ReplyColors.white50,
),
caption: GoogleFonts.workSans(
fontWeight: FontWeight.normal,
fontSize: 12,
letterSpacing: letterSpacingOrNone(0.2),
color: ReplyColors.white50,
),
);
}