Improve snackbar styling and fix business switching

Snackbar Improvements:
- All snackbars now have colored backgrounds (green/red/orange/blue)
- Added icons to snackbar messages (check_circle, error, warning, info)
- Floating behavior with bottom margin to avoid obscuring action buttons
- Consistent styling across menu_browse, cart_view, and login screens

App State Fixes:
- Clear cartItemCount when switching businesses (setBusiness, setServicePoint, setBusinessAndServicePoint, clearAll)
- Prevents stale cart count showing after switching restaurants

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
John Mizerek 2026-01-07 11:46:13 -08:00
parent 846461bf29
commit 924367c70e
8 changed files with 99 additions and 137 deletions

View file

@ -1,5 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
<foreground>
<inset
android:drawable="@drawable/ic_launcher_foreground"
android:inset="25%" />
</foreground>
</adaptive-icon>

View file

@ -1,122 +1 @@
{
"images" : [
{
"filename" : "Icon-App-20x20@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"filename" : "Icon-App-20x20@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"filename" : "Icon-App-29x29@1x.png",
"idiom" : "iphone",
"scale" : "1x",
"size" : "29x29"
},
{
"filename" : "Icon-App-29x29@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"filename" : "Icon-App-29x29@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"filename" : "Icon-App-40x40@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"filename" : "Icon-App-40x40@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"filename" : "Icon-App-60x60@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"filename" : "Icon-App-60x60@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"filename" : "Icon-App-20x20@1x.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"filename" : "Icon-App-20x20@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
"filename" : "Icon-App-29x29@1x.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"filename" : "Icon-App-29x29@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
"filename" : "Icon-App-40x40@1x.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"filename" : "Icon-App-40x40@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
"filename" : "Icon-App-76x76@1x.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "76x76"
},
{
"filename" : "Icon-App-76x76@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
},
{
"filename" : "Icon-App-83.5x83.5@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"filename" : "Icon-App-1024x1024@1x.png",
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{"images":[{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@3x.png","scale":"3x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"Icon-App-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"Icon-App-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}}

View file

@ -40,6 +40,7 @@ class AppState extends ChangeNotifier {
_cartOrderId = null;
_cartOrderUuid = null;
_cartItemCount = 0;
notifyListeners();
}
@ -49,6 +50,7 @@ class AppState extends ChangeNotifier {
_cartOrderId = null;
_cartOrderUuid = null;
_cartItemCount = 0;
notifyListeners();
}
@ -66,6 +68,7 @@ class AppState extends ChangeNotifier {
_cartOrderId = null;
_cartOrderUuid = null;
_cartItemCount = 0;
notifyListeners();
}
@ -122,6 +125,7 @@ class AppState extends ChangeNotifier {
_cartOrderId = null;
_cartOrderUuid = null;
_cartItemCount = 0;
_activeOrderId = null;
_activeOrderStatusId = null;

View file

@ -1,4 +1,4 @@
import 'package:flutter/material.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../app/app_state.dart';
@ -204,8 +204,16 @@ class _CartViewScreenState extends State<CartViewScreen> {
if (paymentResult.error != 'Payment cancelled') {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(paymentResult.error ?? 'Payment failed'),
content: Row(
children: [
Icon(Icons.error, color: Colors.white),
SizedBox(width: 8),
Expanded(child: Text(paymentResult.error ?? 'Payment failed')),
],
),
backgroundColor: Colors.red,
behavior: SnackBarBehavior.floating,
margin: const EdgeInsets.only(bottom: 80, left: 16, right: 16),
),
);
}
@ -230,10 +238,17 @@ class _CartViewScreenState extends State<CartViewScreen> {
// This works even after the cart screen is popped
rootScaffoldMessengerKey.currentState?.showSnackBar(
SnackBar(
content: Text(update.message),
content: Row(
children: [
Icon(Icons.notifications_active, color: Colors.white),
SizedBox(width: 8),
Expanded(child: Text(update.message)),
],
),
backgroundColor: _getStatusColorStatic(update.statusId),
duration: const Duration(seconds: 5),
behavior: SnackBarBehavior.floating,
margin: const EdgeInsets.only(bottom: 80, left: 16, right: 16),
),
);
},
@ -247,11 +262,21 @@ class _CartViewScreenState extends State<CartViewScreen> {
// Show success message
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
"Payment successful! Order placed. You'll receive notifications as your order is prepared.",
content: const Row(
children: [
Icon(Icons.check_circle, color: Colors.white),
SizedBox(width: 8),
Expanded(
child: Text(
"Payment successful! Order placed. You'll receive notifications as your order is prepared.",
),
),
],
),
backgroundColor: Colors.green,
duration: const Duration(seconds: 5),
behavior: SnackBarBehavior.floating,
margin: const EdgeInsets.only(bottom: 80, left: 16, right: 16),
),
);
@ -263,8 +288,16 @@ class _CartViewScreenState extends State<CartViewScreen> {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Error: ${e.toString()}'),
content: Row(
children: [
const Icon(Icons.error, color: Colors.white),
const SizedBox(width: 8),
Expanded(child: Text('Error: ${e.toString()}')),
],
),
backgroundColor: Colors.red,
behavior: SnackBarBehavior.floating,
margin: const EdgeInsets.only(bottom: 80, left: 16, right: 16),
),
);
}

View file

@ -1,4 +1,4 @@
import "package:flutter/material.dart";
import "package:flutter/material.dart";
import "package:provider/provider.dart";
import "../app/app_router.dart";
@ -185,7 +185,16 @@ class _LoginScreenState extends State<LoginScreen> {
onPressed: _isLoading ? null : () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("Registration not yet implemented"),
content: Row(
children: [
Icon(Icons.info, color: Colors.white),
SizedBox(width: 8),
Text("Registration not yet implemented"),
],
),
backgroundColor: Colors.blue,
behavior: SnackBarBehavior.floating,
margin: EdgeInsets.only(bottom: 80, left: 16, right: 16),
),
);
},

View file

@ -736,7 +736,18 @@ class _MenuBrowseScreenState extends State<MenuBrowseScreen> {
if (_businessId == null || _servicePointId == null) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Missing required information")),
const SnackBar(
content: Row(
children: [
Icon(Icons.warning, color: Colors.white),
SizedBox(width: 8),
Text("Missing required information"),
],
),
backgroundColor: Colors.orange,
behavior: SnackBarBehavior.floating,
margin: EdgeInsets.only(bottom: 80, left: 16, right: 16),
),
);
return;
}
@ -808,13 +819,35 @@ class _MenuBrowseScreenState extends State<MenuBrowseScreen> {
: "Added ${item.name} with ${selectedModifierIds.length} customizations (${cart.itemCount} item${cart.itemCount == 1 ? '' : 's'})";
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message)),
SnackBar(
content: Row(
children: [
const Icon(Icons.check_circle, color: Colors.white),
const SizedBox(width: 8),
Expanded(child: Text(message)),
],
),
backgroundColor: Colors.green,
behavior: SnackBarBehavior.floating,
margin: const EdgeInsets.only(bottom: 80, left: 16, right: 16),
),
);
} catch (e) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Error adding to cart: $e")),
SnackBar(
content: Row(
children: [
const Icon(Icons.error, color: Colors.white),
const SizedBox(width: 8),
Expanded(child: Text("Error adding to cart: $e")),
],
),
backgroundColor: Colors.red,
behavior: SnackBarBehavior.floating,
margin: const EdgeInsets.only(bottom: 80, left: 16, right: 16),
),
);
}
}

View file

@ -122,10 +122,10 @@ packages:
dependency: "direct dev"
description:
name: flutter_launcher_icons
sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea"
sha256: "10f13781741a2e3972126fae08393d3c4e01fa4cd7473326b94b72cf594195e7"
url: "https://pub.dev"
source: hosted
version: "0.13.1"
version: "0.14.4"
flutter_lints:
dependency: "direct dev"
description:

View file

@ -21,7 +21,7 @@ dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^4.0.0
flutter_launcher_icons: ^0.13.1
flutter_launcher_icons: ^0.14.4
flutter_launcher_icons:
android: true