blob: 1f6f979120c981a5012f8f2598701f1e458c84dd [file] [log] [blame]
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:gallery/data/gallery_options.dart';
import 'package:gallery/l10n/gallery_localizations.dart';
import 'package:gallery/layout/adaptive.dart';
import 'package:gallery/studies/shrine/backdrop.dart';
import 'package:gallery/studies/shrine/category_menu_page.dart';
import 'package:gallery/studies/shrine/colors.dart';
import 'package:gallery/studies/shrine/expanding_bottom_sheet.dart';
import 'package:gallery/studies/shrine/home.dart';
import 'package:gallery/studies/shrine/login.dart';
import 'package:gallery/studies/shrine/model/app_state_model.dart';
import 'package:gallery/studies/shrine/page_status.dart';
import 'package:gallery/studies/shrine/scrim.dart';
import 'package:gallery/studies/shrine/supplemental/cut_corners_border.dart';
import 'package:scoped_model/scoped_model.dart';
class ShrineApp extends StatefulWidget {
const ShrineApp({Key key, this.navigatorKey}) : super(key: key);
final GlobalKey<NavigatorState> navigatorKey;
@override
_ShrineAppState createState() => _ShrineAppState();
}
class _ShrineAppState extends State<ShrineApp> with TickerProviderStateMixin {
// Controller to coordinate both the opening/closing of backdrop and sliding
// of expanding bottom sheet
AnimationController _controller;
// Animation Controller for expanding/collapsing the cart menu.
AnimationController _expandingController;
AppStateModel _model;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 450),
value: 1,
);
_expandingController = AnimationController(
duration: const Duration(milliseconds: 500),
vsync: this,
);
_model = AppStateModel()..loadProducts();
}
@override
void dispose() {
_controller.dispose();
_expandingController.dispose();
super.dispose();
}
Widget mobileBackdrop() {
return Backdrop(
frontLayer: const ProductPage(),
backLayer: CategoryMenuPage(onCategoryTap: () => _controller.forward()),
frontTitle: const Text('SHRINE'),
backTitle: Text(GalleryLocalizations.of(context).shrineMenuCaption),
controller: _controller,
);
}
Widget desktopBackdrop() {
return DesktopBackdrop(
frontLayer: ProductPage(),
backLayer: CategoryMenuPage(),
);
}
@override
Widget build(BuildContext context) {
final bool isDesktop = isDisplayDesktop(context);
final Widget backdrop = isDesktop ? desktopBackdrop() : mobileBackdrop();
return ScopedModel<AppStateModel>(
model: _model,
child: MaterialApp(
navigatorKey: widget.navigatorKey,
title: 'Shrine',
debugShowCheckedModeBanner: false,
home: PageStatus(
menuController: _controller,
cartController: _expandingController,
child: HomePage(
backdrop: backdrop,
scrim: Scrim(controller: _expandingController),
expandingBottomSheet: ExpandingBottomSheet(
hideController: _controller,
expandingController: _expandingController,
),
),
),
initialRoute: '/login',
onGenerateRoute: _getRoute,
theme: _shrineTheme.copyWith(
platform: GalleryOptions.of(context).platform,
),
// L10n settings.
localizationsDelegates: GalleryLocalizations.localizationsDelegates,
supportedLocales: GalleryLocalizations.supportedLocales,
locale: GalleryOptions.of(context).locale,
),
);
}
}
Route<dynamic> _getRoute(RouteSettings settings) {
if (settings.name != '/login') {
return null;
}
return MaterialPageRoute<void>(
settings: settings,
builder: (context) => LoginPage(),
fullscreenDialog: true,
);
}
final ThemeData _shrineTheme = _buildShrineTheme();
IconThemeData _customIconTheme(IconThemeData original) {
return original.copyWith(color: shrineBrown900);
}
ThemeData _buildShrineTheme() {
final ThemeData base = ThemeData.light();
return base.copyWith(
colorScheme: shrineColorScheme,
accentColor: shrineBrown900,
primaryColor: shrinePink100,
buttonColor: shrinePink100,
scaffoldBackgroundColor: shrineBackgroundWhite,
cardColor: shrineBackgroundWhite,
textSelectionColor: shrinePink100,
errorColor: shrineErrorRed,
buttonTheme: const ButtonThemeData(
colorScheme: shrineColorScheme,
textTheme: ButtonTextTheme.normal,
),
primaryIconTheme: _customIconTheme(base.iconTheme),
inputDecorationTheme: const InputDecorationTheme(
border: CutCornersBorder(
borderSide: BorderSide(color: shrineBrown900, width: 0.5),
),
contentPadding: EdgeInsets.symmetric(vertical: 20, horizontal: 16),
),
textTheme: _buildShrineTextTheme(base.textTheme),
primaryTextTheme: _buildShrineTextTheme(base.primaryTextTheme),
accentTextTheme: _buildShrineTextTheme(base.accentTextTheme),
iconTheme: _customIconTheme(base.iconTheme),
);
}
TextTheme _buildShrineTextTheme(TextTheme base) {
return base
.copyWith(
headline: base.headline.copyWith(fontWeight: FontWeight.w500),
title: base.title.copyWith(fontSize: 18),
caption:
base.caption.copyWith(fontWeight: FontWeight.w400, fontSize: 14),
body2: base.body2.copyWith(fontWeight: FontWeight.w500, fontSize: 16),
button: base.button.copyWith(fontWeight: FontWeight.w500, fontSize: 14),
)
.apply(
fontFamily: 'Rubik',
displayColor: shrineBrown900,
bodyColor: shrineBrown900,
);
}
const ColorScheme shrineColorScheme = ColorScheme(
primary: shrinePink100,
primaryVariant: shrineBrown900,
secondary: shrinePink50,
secondaryVariant: shrineBrown900,
surface: shrineSurfaceWhite,
background: shrineBackgroundWhite,
error: shrineErrorRed,
onPrimary: shrineBrown900,
onSecondary: shrineBrown900,
onSurface: shrineBrown900,
onBackground: shrineBrown900,
onError: shrineSurfaceWhite,
brightness: Brightness.light,
);