wrap pages in SafeArea widget

This commit is contained in:
Mikkel Troels Kongsted 2025-03-06 10:55:20 +01:00
parent 3991b835fd
commit f58dfae118
4 changed files with 293 additions and 299 deletions

View File

@ -149,191 +149,182 @@ class CartPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SafeArea( return Column(
child: Column( children: [
children: [ Expanded(
Expanded( child: Consumer<CartRepo>(
child: Consumer<CartRepo>( builder: (_, cartRepo, __) {
builder: (_, cartRepo, __) { final cart = cartRepo.allCartItems();
final cart = cartRepo.allCartItems(); return ListView.builder(
return ListView.builder( shrinkWrap: true,
shrinkWrap: true, itemBuilder: (_, idx) => CartItemView(
itemBuilder: (_, idx) => CartItemView( cartRepo: cartRepo,
cartRepo: cartRepo, productId: cart[idx].product.id,
productId: cart[idx].product.id, name: cart[idx].product.name,
name: cart[idx].product.name, price: cart[idx].product.priceInDkkCents,
price: cart[idx].product.priceInDkkCents, amount: cart[idx].amount),
amount: cart[idx].amount), itemCount: cart.length,
itemCount: cart.length, );
); },
},
),
), ),
Container( ),
decoration: Container(
const BoxDecoration(color: Color(0xFFFFFFFF), boxShadow: [ decoration: const BoxDecoration(color: Color(0xFFFFFFFF), boxShadow: [
BoxShadow( BoxShadow(
blurRadius: 10, blurRadius: 10,
spreadRadius: -4, spreadRadius: -4,
) )
]), ]),
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
child: Column( child: Column(
children: [ children: [
Row( Row(
children: [ children: [
Expanded( Expanded(
child: Container( child: Container(
margin: const EdgeInsets.only(right: 10), margin: const EdgeInsets.only(right: 10),
child: PrimaryButton( child: PrimaryButton(
onPressed: () { onPressed: () {
final inputController = TextEditingController(); final inputController = TextEditingController();
showDialog( showDialog(
context: context, context: context,
builder: (BuildContext context) => builder: (BuildContext context) => AlertDialog(
AlertDialog( title: const Text(
title: const Text( "Indtast stregkode nummer"),
"Indtast stregkode nummer"), content: TextField(
content: TextField( keyboardType: TextInputType.number,
keyboardType: TextInputType.number, controller: inputController,
controller: inputController, ),
), actions: [
actions: [ TextButton(
TextButton( onPressed: () =>
onPressed: () => Navigator.of(context).pop(),
Navigator.of(context).pop(), child: const Text("Cancel")),
child: const Text("Cancel")), TextButton(
TextButton( onPressed: () {
onPressed: () { final productRepo =
final productRepo = context.read<ProductRepo>();
context.read<ProductRepo>(); final CartRepo cartRepo =
final CartRepo cartRepo = context.read<CartRepo>();
context.read<CartRepo>(); final productResult = productRepo
final productResult = .productWithBarcode(
productRepo inputController.text);
.productWithBarcode( switch (productResult) {
inputController case Ok<Product, String>():
.text); cartRepo.addToCart(
switch (productResult) { productResult.value);
case Ok<Product, String>(): final snackBar = SnackBar(
cartRepo.addToCart( content: Text(
productResult.value); "Tilføjet ${productResult.value.name} til indkøbskurven"));
final snackBar = SnackBar( ScaffoldMessenger.of(context)
content: Text( .showSnackBar(snackBar);
"Tilføjet ${productResult.value.name} til indkøbskurven")); case Err<Product, String>():
ScaffoldMessenger.of( final snackBar = const SnackBar(
context) content: Text(
.showSnackBar(snackBar); "Den indtastede stregkode eksistere ikke"));
case Err<Product, String>(): ScaffoldMessenger.of(context)
final snackBar = const SnackBar( .showSnackBar(snackBar);
content: Text( }
"Den indtastede stregkode eksistere ikke")); Navigator.of(context).pop();
ScaffoldMessenger.of( },
context) child: const Text("Ok"))
.showSnackBar(snackBar); ],
} ));
Navigator.of(context).pop(); },
}, child: const Text("Indtast vare")),
child: const Text("Ok"))
],
));
},
child: const Text("Indtast vare")),
),
), ),
Expanded( ),
child: Container( Expanded(
margin: const EdgeInsets.only(left: 10), child: Container(
child: PrimaryButton( margin: const EdgeInsets.only(left: 10),
onPressed: () async { child: PrimaryButton(
final result = await BarcodeScanner.scan( onPressed: () async {
options: const ScanOptions( final result = await BarcodeScanner.scan(
android: AndroidOptions( options: const ScanOptions(
appBarTitle: "Skan varer"), android: AndroidOptions(
strings: { appBarTitle: "Skan varer"),
"cancel": "Annullér", strings: {
"flash_on": "Lommelygte til", "cancel": "Annullér",
"flash_off": "Lommelygte fra" "flash_on": "Lommelygte til",
})); "flash_off": "Lommelygte fra"
switch (result.type.name) { }));
case "Cancelled": switch (result.type.name) {
final snackBar = const SnackBar( case "Cancelled":
content: final snackBar = const SnackBar(
Text("Skanning af varer annulleret")); content:
if (context.mounted) { Text("Skanning af varer annulleret"));
ScaffoldMessenger.of(context) if (context.mounted) {
.showSnackBar(snackBar);
}
case "Barcode":
if (!context.mounted) {
return;
}
final CartRepo cartRepo =
context.read<CartRepo>();
final productRepo =
context.read<ProductRepo>();
final productResult = productRepo
.productWithBarcode(result.rawContent);
switch (productResult) {
case Ok<Product, String>():
{
cartRepo.addToCart(productResult.value);
final snackBar = SnackBar(
content: Text(
"Tilføjet ${productResult.value.name} til indkøbskurven"));
ScaffoldMessenger.of(context)
.showSnackBar(snackBar);
}
case Err<Product, String>():
final snackBar = const SnackBar(
content: Text(
"Varen du prøver at tilføje eksistere ikke"));
ScaffoldMessenger.of(context)
.showSnackBar(snackBar);
}
case "Error":
if (!context.mounted) {
return;
}
final snackBar = const SnackBar(
content:
Text("Der skete en fejl, prøv igen"));
ScaffoldMessenger.of(context) ScaffoldMessenger.of(context)
.showSnackBar(snackBar); .showSnackBar(snackBar);
}
case "Barcode":
if (!context.mounted) {
return;
}
final CartRepo cartRepo =
context.read<CartRepo>();
final productRepo = context.read<ProductRepo>();
final productResult = productRepo
.productWithBarcode(result.rawContent);
switch (productResult) {
case Ok<Product, String>():
{
cartRepo.addToCart(productResult.value);
final snackBar = SnackBar(
content: Text(
"Tilføjet ${productResult.value.name} til indkøbskurven"));
ScaffoldMessenger.of(context)
.showSnackBar(snackBar);
}
case Err<Product, String>():
final snackBar = const SnackBar(
content: Text(
"Varen du prøver at tilføje eksistere ikke"));
ScaffoldMessenger.of(context)
.showSnackBar(snackBar);
}
default: case "Error":
throw Exception("Unreachable"); if (!context.mounted) {
} return;
}, }
child: const Text("Skan vare")), final snackBar = const SnackBar(
), content:
Text("Der skete en fejl, prøv igen"));
ScaffoldMessenger.of(context)
.showSnackBar(snackBar);
default:
throw Exception("Unreachable");
}
},
child: const Text("Skan vare")),
), ),
], ),
), ],
Row( ),
children: [ Row(
Expanded( children: [
child: Container( Expanded(
margin: const EdgeInsets.only(top: 10), child: Container(
child: PrimaryButton( margin: const EdgeInsets.only(top: 10),
onPressed: () { child: PrimaryButton(
Navigator.push( onPressed: () {
context, Navigator.push(
MaterialPageRoute( context,
builder: (context) => MaterialPageRoute(
FinishShoppingPage(user: user))); builder: (context) =>
}, FinishShoppingPage(user: user)));
child: const Text("Afslut indkøb")), },
), child: const Text("Afslut indkøb")),
), ),
], ),
), ],
], ),
), ],
), ),
], ),
), ],
); );
} }
} }

View File

@ -63,7 +63,7 @@ class Dashboard extends StatelessWidget {
label: "Kvitteringer") label: "Kvitteringer")
], ],
), ),
body: pages[currentIndex], body: SafeArea(child: pages[currentIndex]),
); );
} }
} }

View File

@ -10,49 +10,47 @@ class HomePage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SafeArea( return Column(
child: Column( children: [
children: [ Row(
Row( mainAxisAlignment: MainAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end, children: [
Container(
margin: const EdgeInsets.only(right: 10),
child: IconButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => SettingsPage()));
},
icon: const Icon(Icons.settings),
)),
],
),
Card(
child: Container(
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10)),
color: Color(0xFFFFFFFF),
),
padding: const EdgeInsets.all(10),
child: Consumer<UsersRepo>(
builder: (context, usersRepo, _) => Text(
"Saldo: ${formatDkkCents(user.balanceInDkkCents)}",
style: Theme.of(context).textTheme.headlineSmall)),
),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Container( Text(
margin: const EdgeInsets.only(right: 10), "Velkommen ${user.name}",
child: IconButton( style: Theme.of(context).textTheme.headlineMedium,
onPressed: () { ),
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => SettingsPage()));
},
icon: const Icon(Icons.settings),
)),
], ],
), ),
Card( ),
child: Container( ],
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10)),
color: Color(0xFFFFFFFF),
),
padding: const EdgeInsets.all(10),
child: Consumer<UsersRepo>(
builder: (context, usersRepo, _) => Text(
"Saldo: ${formatDkkCents(user.balanceInDkkCents)}",
style: Theme.of(context).textTheme.headlineSmall)),
),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Velkommen ${user.name}",
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
],
),
); );
} }
} }

View File

@ -17,90 +17,95 @@ class ProductPage extends StatelessWidget {
final AddToCartStateRepo addToCartStateRepo = final AddToCartStateRepo addToCartStateRepo =
context.watch<AddToCartStateRepo>(); context.watch<AddToCartStateRepo>();
return Scaffold( return Scaffold(
body: Card( body: SafeArea(
color: Colors.white, child: Card(
margin: const EdgeInsets.all(10), color: Colors.white,
child: Container( margin: const EdgeInsets.all(10),
padding: const EdgeInsets.symmetric(vertical: 10), child: Container(
child: Column(children: [ padding: const EdgeInsets.symmetric(vertical: 10),
Row( child: Column(children: [
children: [ Row(
Row( children: [
crossAxisAlignment: CrossAxisAlignment.start, Row(
children: [ crossAxisAlignment: CrossAxisAlignment.start,
const BackButton(), children: [
Column( const BackButton(),
crossAxisAlignment: CrossAxisAlignment.start, Column(
children: [ crossAxisAlignment: CrossAxisAlignment.start,
Text( children: [
product.name, Text(
style: const TextStyle( product.name,
fontSize: 20, style: const TextStyle(
fontSize: 20,
),
), ),
), Text(
Text( formatDkkCents(product.priceInDkkCents),
formatDkkCents(product.priceInDkkCents), style: const TextStyle(
style: const TextStyle( fontSize: 16,
fontSize: 16, ),
), )
) ])
]) ],
], ),
), ],
], ),
), Expanded(
Expanded( child: Container(
child: Container( padding: const EdgeInsets.all(20),
padding: const EdgeInsets.all(20), child: Column(
child: Column( crossAxisAlignment: CrossAxisAlignment.stretch,
crossAxisAlignment: CrossAxisAlignment.stretch, children: [
children: [ Image(
Image( image:
image: AssetImage("assets/products/${product.name}.png"), AssetImage("assets/products/${product.name}.png"),
errorBuilder: (_, __, ___) => const Image( errorBuilder: (_, __, ___) => const Image(
image: AssetImage("assets/placeholder.png")), image: AssetImage("assets/placeholder.png")),
height: 250, height: 250,
fit: BoxFit.fitHeight, fit: BoxFit.fitHeight,
), ),
Text( Text(
product.name, product.name,
style: Theme.of(context).textTheme.bodyLarge, style: Theme.of(context).textTheme.bodyLarge,
), ),
Text( Text(
formatDkkCents(product.priceInDkkCents), formatDkkCents(product.priceInDkkCents),
style: Theme.of(context).textTheme.bodyLarge, style: Theme.of(context).textTheme.bodyLarge,
), ),
Padding( Padding(
padding: const EdgeInsets.only(top: 20, bottom: 20), padding: const EdgeInsets.only(top: 20, bottom: 20),
child: Text(product.description), child: Text(product.description),
), ),
PrimaryButton( PrimaryButton(
onPressed: () { onPressed: () {
Navigator.of(context).push(MaterialPageRoute( Navigator.of(context).push(MaterialPageRoute(
builder: (context) => builder: (context) =>
ProductLocationPage(product: product))); ProductLocationPage(product: product)));
}, },
child: const Text("Find i butik")), child: const Text("Find i butik")),
PrimaryButton( PrimaryButton(
onPressed: () { onPressed: () {
final snackBarDuration = const Duration(seconds: 2); final snackBarDuration = const Duration(seconds: 2);
addToCartStateRepo.notify(snackBarDuration); addToCartStateRepo.notify(snackBarDuration);
final snackBar = SnackBar( final snackBar = SnackBar(
content: Text( content: Text(
'Tilføjet ${addToCartStateRepo.currentAmount} ${product.name} til kurven'), 'Tilføjet ${addToCartStateRepo.currentAmount} ${product.name} til kurven'),
duration: const Duration(seconds: 2), duration: const Duration(seconds: 2),
); );
ScaffoldMessenger.of(context).removeCurrentSnackBar(); ScaffoldMessenger.of(context)
final cartRepo = context.read<CartRepo>(); .removeCurrentSnackBar();
cartRepo.addToCart(product); final cartRepo = context.read<CartRepo>();
ScaffoldMessenger.of(context).showSnackBar(snackBar); cartRepo.addToCart(product);
}, ScaffoldMessenger.of(context)
child: const Text("Tilføj til indkøbskurv")), .showSnackBar(snackBar);
], },
child: const Text("Tilføj til indkøbskurv")),
],
),
), ),
), ),
), ]),
]), ),
), ),
), ),
); );