material_3_demos/lib/main.dart

367 lines
11 KiB
Dart

import 'package:flutter/material.dart';
enum AppMenu {
about,
privacy,
settings,
}
void main() {
runApp(const PlantsApp());
}
class PlantsApp extends StatelessWidget {
const PlantsApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
themeMode: ThemeMode.light,
title: 'Flutter Demo',
theme: ThemeData(
useMaterial3: true,
brightness: Brightness.light,
colorSchemeSeed: Colors.green[700],
),
darkTheme: ThemeData(
useMaterial3: true,
brightness: Brightness.dark,
colorSchemeSeed: Colors.green[700],
),
home: const PlantsHome(),
);
}
}
class PlantsHome extends StatelessWidget {
const PlantsHome({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Plants Shop'),
shadowColor: Theme.of(context).shadowColor,
scrolledUnderElevation: 4.0,
leading: const Center(
child: CircleAvatar(
radius: 16,
child: Icon(Icons.person),
),
),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(64.0),
child: Container(
alignment: Alignment.centerLeft,
padding: const EdgeInsets.only(left: 16, bottom: 10, right: 16),
child: const TextField(
decoration: InputDecoration(
hintText: 'Browse indoor plants',
prefixIcon: Icon(Icons.search_off_rounded),
border: OutlineInputBorder(),
filled: true,
isDense: true,
),
),
),
),
actions: [
IconButton(
onPressed: () {},
style: enabledFilledButtonStyle(
true,
Theme.of(context).colorScheme,
),
icon: const Icon(Icons.sort_rounded),
),
PopupMenuButton<AppMenu>(
itemBuilder: (context) {
return const <PopupMenuEntry<AppMenu>>[
PopupMenuItem(
value: AppMenu.about,
child: Text('About us'),
),
PopupMenuItem(
value: AppMenu.privacy,
child: Text('Privacy Policy'),
),
PopupMenuItem(
value: AppMenu.settings,
child: Text('Settings'),
),
];
},
)
],
),
body: GridView.builder(
padding: const EdgeInsets.symmetric(horizontal: 16),
itemCount: 8,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 12 / 15.5,
),
itemBuilder: (context, index) {
final String image = 'assets/plants/plant_$index.jpg';
return Card(
child: InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => PlantDetailPage(image: image),
),
);
},
child: PlantItem(image: image),
),
);
},
),
bottomNavigationBar: NavigationBar(
destinations: const [
NavigationDestination(
icon: Icon(Icons.home),
label: 'Browse',
),
NavigationDestination(
icon: Icon(Icons.favorite_rounded),
label: 'Favorites',
),
NavigationDestination(
icon: Icon(Icons.payment_rounded),
label: 'Payments',
),
],
selectedIndex: 0,
),
floatingActionButton: FloatingActionButton(
onPressed: () async => _shoppingCartDialog(context),
child: const Icon(Icons.shopping_cart_rounded),
),
);
}
Future<void> _shoppingCartDialog(BuildContext context) {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('Shopping Cart'),
icon: const Icon(Icons.shopping_cart_rounded),
content: const Column(
mainAxisSize: MainAxisSize.min,
children: [
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('1 x Lorem Ipsum'),
Text('\$9.99'),
],
)
],
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Dismiss'),
),
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Checkout'),
),
],
);
},
);
}
ButtonStyle enabledFilledButtonStyle(bool selected, ColorScheme colors) {
return IconButton.styleFrom(
foregroundColor: selected ? colors.onPrimary : colors.primary,
backgroundColor: selected ? colors.primary : colors.surfaceVariant,
disabledForegroundColor: colors.onSurface.withOpacity(0.38),
disabledBackgroundColor: colors.onSurface.withOpacity(0.12),
hoverColor: selected
? colors.onPrimary.withOpacity(0.08)
: colors.primary.withOpacity(0.08),
focusColor: selected
? colors.onPrimary.withOpacity(0.12)
: colors.primary.withOpacity(0.12),
highlightColor: selected
? colors.onPrimary.withOpacity(0.12)
: colors.primary.withOpacity(0.12),
);
}
}
class PlantItem extends StatelessWidget {
final String image;
const PlantItem({super.key, required this.image});
@override
Widget build(BuildContext context) {
final ThemeData themeData = Theme.of(context);
final TextTheme textTheme = themeData.textTheme;
return Hero(
tag: image,
child: Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(4),
topRight: Radius.circular(4),
),
image: DecorationImage(
image: AssetImage(image),
fit: BoxFit.contain,
alignment: Alignment.topCenter,
),
),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
'Lorem Ipsum',
style: textTheme.titleMedium,
),
Text(
'\$9.99',
style: textTheme.bodySmall,
),
],
),
),
),
);
}
}
class PlantDetailPage extends StatelessWidget {
const PlantDetailPage({super.key, required this.image});
final String image;
@override
Widget build(BuildContext context) {
final ThemeData themeData = Theme.of(context);
final TextTheme textTheme = themeData.textTheme;
return Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar.large(
title: const Text("Lorem Ipsum"),
),
SliverFillRemaining(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Hero(
tag: image,
child: Image.asset(
image,
fit: BoxFit.contain,
),
),
MaterialBanner(
content: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Lorem Ipsum',
style: textTheme.titleLarge,
),
Text(
'\$9.99',
style: textTheme.titleMedium,
),
],
),
),
actions: [
ActionChip(
onPressed: () {},
label: const Text('Indoor'),
),
ActionChip(
onPressed: () {},
label: const Text('Small'),
),
],
)
],
),
)
],
),
bottomNavigationBar: BottomAppBar(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
OutlinedButton.icon(
onPressed: () {},
icon: const Icon(Icons.favorite_outline_rounded),
label: const Text('Save'),
),
FilledButton(
onPressed: () {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return SizedBox(
height: 200,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
title: const Text('Include base'),
trailing: Switch(
onChanged: (value) {},
value: true,
),
),
ListTile(
title: const Text('Gifting'),
trailing: Checkbox(
onChanged: (value) {},
value: true,
),
),
TextButton(
onPressed: () {},
child: const Text('Proceed to payment'),
)
],
),
),
);
},
);
},
child: const Text('Buy Now'),
),
],
),
),
),
);
}
}