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,
- ),
- ),
- ),
- );
- },
- ),
- );
- }
- }
|