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
Widget build(BuildContext context) {
return SafeArea(
child: Column(
children: [
Expanded(
child: Consumer<CartRepo>(
builder: (_, cartRepo, __) {
final cart = cartRepo.allCartItems();
return ListView.builder(
shrinkWrap: true,
itemBuilder: (_, idx) => CartItemView(
cartRepo: cartRepo,
productId: cart[idx].product.id,
name: cart[idx].product.name,
price: cart[idx].product.priceInDkkCents,
amount: cart[idx].amount),
itemCount: cart.length,
);
},
),
return Column(
children: [
Expanded(
child: Consumer<CartRepo>(
builder: (_, cartRepo, __) {
final cart = cartRepo.allCartItems();
return ListView.builder(
shrinkWrap: true,
itemBuilder: (_, idx) => CartItemView(
cartRepo: cartRepo,
productId: cart[idx].product.id,
name: cart[idx].product.name,
price: cart[idx].product.priceInDkkCents,
amount: cart[idx].amount),
itemCount: cart.length,
);
},
),
Container(
decoration:
const BoxDecoration(color: Color(0xFFFFFFFF), boxShadow: [
BoxShadow(
blurRadius: 10,
spreadRadius: -4,
)
]),
padding: const EdgeInsets.all(10),
child: Column(
children: [
Row(
children: [
Expanded(
child: Container(
margin: const EdgeInsets.only(right: 10),
child: PrimaryButton(
onPressed: () {
final inputController = TextEditingController();
showDialog(
context: context,
builder: (BuildContext context) =>
AlertDialog(
title: const Text(
"Indtast stregkode nummer"),
content: TextField(
keyboardType: TextInputType.number,
controller: inputController,
),
actions: [
TextButton(
onPressed: () =>
Navigator.of(context).pop(),
child: const Text("Cancel")),
TextButton(
onPressed: () {
final productRepo =
context.read<ProductRepo>();
final CartRepo cartRepo =
context.read<CartRepo>();
final productResult =
productRepo
.productWithBarcode(
inputController
.text);
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(
"Den indtastede stregkode eksistere ikke"));
ScaffoldMessenger.of(
context)
.showSnackBar(snackBar);
}
Navigator.of(context).pop();
},
child: const Text("Ok"))
],
));
},
child: const Text("Indtast vare")),
),
),
Container(
decoration: const BoxDecoration(color: Color(0xFFFFFFFF), boxShadow: [
BoxShadow(
blurRadius: 10,
spreadRadius: -4,
)
]),
padding: const EdgeInsets.all(10),
child: Column(
children: [
Row(
children: [
Expanded(
child: Container(
margin: const EdgeInsets.only(right: 10),
child: PrimaryButton(
onPressed: () {
final inputController = TextEditingController();
showDialog(
context: context,
builder: (BuildContext context) => AlertDialog(
title: const Text(
"Indtast stregkode nummer"),
content: TextField(
keyboardType: TextInputType.number,
controller: inputController,
),
actions: [
TextButton(
onPressed: () =>
Navigator.of(context).pop(),
child: const Text("Cancel")),
TextButton(
onPressed: () {
final productRepo =
context.read<ProductRepo>();
final CartRepo cartRepo =
context.read<CartRepo>();
final productResult = productRepo
.productWithBarcode(
inputController.text);
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(
"Den indtastede stregkode eksistere ikke"));
ScaffoldMessenger.of(context)
.showSnackBar(snackBar);
}
Navigator.of(context).pop();
},
child: const Text("Ok"))
],
));
},
child: const Text("Indtast vare")),
),
Expanded(
child: Container(
margin: const EdgeInsets.only(left: 10),
child: PrimaryButton(
onPressed: () async {
final result = await BarcodeScanner.scan(
options: const ScanOptions(
android: AndroidOptions(
appBarTitle: "Skan varer"),
strings: {
"cancel": "Annullér",
"flash_on": "Lommelygte til",
"flash_off": "Lommelygte fra"
}));
switch (result.type.name) {
case "Cancelled":
final snackBar = const SnackBar(
content:
Text("Skanning af varer annulleret"));
if (context.mounted) {
ScaffoldMessenger.of(context)
.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"));
),
Expanded(
child: Container(
margin: const EdgeInsets.only(left: 10),
child: PrimaryButton(
onPressed: () async {
final result = await BarcodeScanner.scan(
options: const ScanOptions(
android: AndroidOptions(
appBarTitle: "Skan varer"),
strings: {
"cancel": "Annullér",
"flash_on": "Lommelygte til",
"flash_off": "Lommelygte fra"
}));
switch (result.type.name) {
case "Cancelled":
final snackBar = const SnackBar(
content:
Text("Skanning af varer annulleret"));
if (context.mounted) {
ScaffoldMessenger.of(context)
.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:
throw Exception("Unreachable");
}
},
child: const Text("Skan vare")),
),
case "Error":
if (!context.mounted) {
return;
}
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: [
Expanded(
child: Container(
margin: const EdgeInsets.only(top: 10),
child: PrimaryButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
FinishShoppingPage(user: user)));
},
child: const Text("Afslut indkøb")),
),
),
],
),
Row(
children: [
Expanded(
child: Container(
margin: const EdgeInsets.only(top: 10),
child: PrimaryButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
FinishShoppingPage(user: user)));
},
child: const Text("Afslut indkøb")),
),
],
),
],
),
),
],
),
],
),
],
),
),
],
);
}
}

View File

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

View File

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