| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348 | import 'package:english_words/english_words.dart';import 'package:flutter/material.dart';import 'package:provider/provider.dart';void main() {  runApp(MyApp());}class MyApp extends StatelessWidget {  const MyApp({super.key});  @override  Widget build(BuildContext context) {    return ChangeNotifierProvider(      create: (context) => MyAppState(),      child: MaterialApp(        title: 'Namer App',        theme: ThemeData(          useMaterial3: true,          colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepOrange),        ),        home: MyHomePage(),      ),    );  }}class MyAppState extends ChangeNotifier {  var current = WordPair.random();  var history = <WordPair>[];  GlobalKey? historyListKey;  void getNext() {    history.insert(0, current);    var animatedList = historyListKey?.currentState as AnimatedListState?;    animatedList?.insertItem(0);    current = WordPair.random();    notifyListeners();  }  var favorites = <WordPair>[];  void toggleFavorite([WordPair? pair]) {    pair = pair ?? current;    if (favorites.contains(pair)) {      favorites.remove(pair);    } else {      favorites.add(pair);    }    notifyListeners();  }  void removeFavorite(WordPair pair) {    favorites.remove(pair);    notifyListeners();  }}class MyHomePage extends StatefulWidget {  @override  State<MyHomePage> createState() => _MyHomePageState();}class _MyHomePageState extends State<MyHomePage> {  var selectedIndex = 0;  @override  Widget build(BuildContext context) {// ← 1    var colorScheme = Theme.of(context).colorScheme;    Widget page;    switch (selectedIndex) {      case 0:        page = GeneratorPage();        break;      case 1:        page = FavoritesPage();        break;      default:        throw UnimplementedError('no widget for $selectedIndex');    }    var mainArea = ColoredBox(      color: colorScheme.surfaceVariant,      child: AnimatedSwitcher(        duration: Duration(milliseconds: 200),        child: page,        ),      );return Scaffold(  body: LayoutBuilder(    builder: (context, constraints) {      if (constraints.maxWidth < 450) {        return Column(          children: [            Expanded(child: mainArea),            SafeArea(              child: BottomNavigationBar(                items: [                  BottomNavigationBarItem(                    icon: Icon(Icons.home),                    label: 'Home',                  ),                  BottomNavigationBarItem(                    icon: Icon(Icons.favorite),                    label: 'Favorites',                  ),                ],                currentIndex: selectedIndex,                onTap: (value) {                  setState(() {                    selectedIndex = value;                  });                },              ),            )          ],        );      } else {        return Row(          children: [            SafeArea(              child: NavigationRail(                extended: constraints.maxWidth >= 600,                destinations: [                  NavigationRailDestination(                    icon: Icon(Icons.home),                     label: Text('Home'),                  ),                  NavigationRailDestination(                    icon: Icon(Icons.favorite),                     label: Text('Favorites'),                  ),                ],                selectedIndex: selectedIndex,                onDestinationSelected: (value) {                      setState(() {                        selectedIndex = value;                      });                    },                  ),                ),                Expanded(child: mainArea),              ],            );          }        },      ),    );  }} class GeneratorPage extends StatelessWidget {  @override  Widget build(BuildContext context) {    var  appState = context.watch<MyAppState>();    var pair = appState.current;    IconData icon;    if (appState.favorites.contains(pair)) {      icon = Icons.favorite;    } else {      icon = Icons.favorite_border;    }    return Center(      child: Column(        mainAxisAlignment: MainAxisAlignment.center,        children: [          Expanded(            flex: 3,            child: HistoryListView(),          ),          SizedBox(height: 10),          BigCard(pair: pair),          SizedBox(height: 10,),          Row(            mainAxisSize: MainAxisSize.min,            children: [              ElevatedButton.icon(                onPressed: () {                  appState.toggleFavorite();                },                icon: Icon(icon),                label: Text('Like'),              ),              SizedBox(width: 10,),              ElevatedButton(                onPressed: () {                  appState.getNext();                },                child: Text('Next'),              ),            ],          ),          Spacer(flex: 2),        ],      ),    );  }}class BigCard extends StatelessWidget {  const BigCard({    Key? key,    required this.pair,  }) : super(key: key);  final WordPair pair;  @override  Widget build(BuildContext context) {    var theme = Theme.of(context);    var style = theme.textTheme.displayMedium!.copyWith(      color: theme.colorScheme.onPrimary,    );    return Card(      color: theme.colorScheme.primary,            child: Padding(        padding: const EdgeInsets.all(20),        child: AnimatedSize(          duration: Duration(milliseconds: 200),          child: MergeSemantics(            child: Wrap(              children: [                Text(                  pair.first,                  style: style.copyWith(fontWeight: FontWeight.w200),                ),                Text(                  pair.second,                  style: style.copyWith(fontWeight: FontWeight.bold),                )              ],            ),          ),        ),      ),    );  }}class FavoritesPage extends StatelessWidget {  @override  Widget build(BuildContext context) {    var theme = Theme.of(context);    var appState = context.watch<MyAppState>();    if (appState.favorites.isEmpty) {      return Center(        child: Text('No favorites yet.'),      );    }    return Column(      crossAxisAlignment: CrossAxisAlignment.start,      children: [        Padding(          padding: const EdgeInsets.all(30),          child: Text('You have '              '${appState.favorites.length} favorites:'),        ),        Expanded(          child: GridView(            gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(              maxCrossAxisExtent: 400,              childAspectRatio: 400 / 80,            ),            children: [              for (var pair in appState.favorites)              ListTile(                leading: IconButton(                  icon: Icon(Icons.delete_outline, semanticLabel: 'Delete'),                  color: theme.colorScheme.primary,                  onPressed: () {                    appState.removeFavorite(pair);                    },                  ),                  title: Text(                    pair.asLowerCase,                    semanticsLabel: pair.asPascalCase,                   ),                ),            ],          ),        ),      ],    );  }}class HistoryListView extends StatefulWidget {  const HistoryListView({Key? key}) : super(key: key);  @override  State<HistoryListView> createState() => _HistoryListViewState();}class _HistoryListViewState extends State<HistoryListView> {  final _key = GlobalKey();  static const Gradient _maskingGradient = LinearGradient(    colors: [Colors.transparent, Colors.black],    stops: [0.0, 0.5],    begin: Alignment.topCenter,    end: Alignment.bottomCenter,  );  @override  Widget build(BuildContext context) {    final appState = context.watch<MyAppState>();    appState.historyListKey = _key;    return ShaderMask(      shaderCallback: (bounds) => _maskingGradient.createShader(bounds),      blendMode: BlendMode.dstIn,      child: AnimatedList(        key: _key,        reverse: true,        padding: EdgeInsets.only(top: 100),        initialItemCount: appState.history.length,        itemBuilder: (context, index, animation) {          final pair = appState.history[index];          return SizeTransition(            sizeFactor: animation,            child: Center(              child: TextButton.icon(                onPressed: () {                  appState.toggleFavorite(pair);                },                icon: appState.favorites.contains(pair)                  ? Icon(Icons.favorite, size: 12)                  : SizedBox(),                label: Text(                  pair.asLowerCase,                  semanticsLabel: pair.asPascalCase,                ),              ),            ),          );        },      ),    );  }}
 |