diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts
index 819f0cf..4281bae 100644
--- a/android/app/build.gradle.kts
+++ b/android/app/build.gradle.kts
@@ -35,6 +35,14 @@ android {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.getByName("debug")
+
+ // Disable minification and shrinking to preserve beacon library
+ isMinifyEnabled = false
+ isShrinkResources = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
}
}
}
diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro
new file mode 100644
index 0000000..ca726b8
--- /dev/null
+++ b/android/app/proguard-rules.pro
@@ -0,0 +1,9 @@
+# Keep beacon library classes
+-keep class com.flutterbeacon.** { *; }
+-keep class org.altbeacon.** { *; }
+
+# Keep Bluetooth classes
+-keep class android.bluetooth.** { *; }
+
+# Keep location classes
+-keep class android.location.** { *; }
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index c901fa0..c9ecef0 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -3,12 +3,21 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
names;
+ final double price;
+
+ const ModifierPath({
+ required this.names,
+ required this.price,
+ });
+}
+
class CartViewScreen extends StatefulWidget {
const CartViewScreen({super.key});
@@ -286,12 +297,13 @@ class _CartViewScreenState extends State {
final menuItem = _menuItemsById[rootItem.itemId];
final itemName = menuItem?.name ?? "Item #${rootItem.itemId}";
- // Find all modifiers for this root item
- final modifiers = _cart!.lineItems
- .where((item) =>
- item.parentOrderLineItemId == rootItem.orderLineItemId &&
- !item.isDeleted)
- .toList();
+ print('[Cart] Building card for root item: $itemName (OrderLineItemID=${rootItem.orderLineItemId})');
+ print('[Cart] Total line items in cart: ${_cart!.lineItems.length}');
+
+ // Find ALL modifiers (recursively) and build breadcrumb paths for leaf items only
+ final modifierPaths = _buildModifierPaths(rootItem.orderLineItemId);
+
+ print('[Cart] Found ${modifierPaths.length} modifier paths for this root item');
return Card(
child: Padding(
@@ -316,9 +328,9 @@ class _CartViewScreenState extends State {
),
],
),
- if (modifiers.isNotEmpty) ...[
+ if (modifierPaths.isNotEmpty) ...[
const SizedBox(height: 8),
- ...modifiers.map((mod) => _buildModifierRow(mod)),
+ ...modifierPaths.map((path) => _buildModifierPathRow(path)),
],
const SizedBox(height: 8),
Row(
@@ -357,9 +369,51 @@ class _CartViewScreenState extends State {
);
}
- Widget _buildModifierRow(OrderLineItem modifier) {
- final menuItem = _menuItemsById[modifier.itemId];
- final modName = menuItem?.name ?? "Modifier #${modifier.itemId}";
+ /// Build breadcrumb paths for all leaf modifiers
+ List _buildModifierPaths(int rootOrderLineItemId) {
+ final paths = [];
+
+ // Get direct children of root
+ final directChildren = _cart!.lineItems
+ .where((item) =>
+ item.parentOrderLineItemId == rootOrderLineItemId &&
+ !item.isDeleted)
+ .toList();
+
+ // Recursively collect leaf items with their paths
+ void collectLeafPaths(OrderLineItem item, List currentPath) {
+ final children = _cart!.lineItems
+ .where((child) =>
+ child.parentOrderLineItemId == item.orderLineItemId &&
+ !child.isDeleted)
+ .toList();
+
+ final menuItem = _menuItemsById[item.itemId];
+ final itemName = menuItem?.name ?? "Item #${item.itemId}";
+
+ if (children.isEmpty) {
+ // This is a leaf - add its path
+ paths.add(ModifierPath(
+ names: [...currentPath, itemName],
+ price: item.price,
+ ));
+ } else {
+ // This has children - recurse into them
+ for (final child in children) {
+ collectLeafPaths(child, [...currentPath, itemName]);
+ }
+ }
+ }
+
+ for (final child in directChildren) {
+ collectLeafPaths(child, []);
+ }
+
+ return paths;
+ }
+
+ Widget _buildModifierPathRow(ModifierPath path) {
+ final displayText = path.names.join(' > ');
return Padding(
padding: const EdgeInsets.only(left: 16, top: 4),
@@ -369,16 +423,16 @@ class _CartViewScreenState extends State {
const SizedBox(width: 4),
Expanded(
child: Text(
- modName,
+ displayText,
style: const TextStyle(
fontSize: 14,
color: Colors.grey,
),
),
),
- if (modifier.price > 0)
+ if (path.price > 0)
Text(
- "+\$${modifier.price.toStringAsFixed(2)}",
+ "+\$${path.price.toStringAsFixed(2)}",
style: const TextStyle(
fontSize: 14,
color: Colors.grey,
diff --git a/lib/screens/menu_browse_screen.dart b/lib/screens/menu_browse_screen.dart
index d1c510b..64a156c 100644
--- a/lib/screens/menu_browse_screen.dart
+++ b/lib/screens/menu_browse_screen.dart
@@ -417,6 +417,7 @@ class _MenuBrowseScreenState extends State {
);
// Add all selected modifiers recursively
+ print('[MenuBrowse] Adding ${selectedModifierIds.length} modifiers to root item OrderLineItemID=${rootLineItem.orderLineItemId}');
await _addModifiersRecursively(
cart.orderId,
rootLineItem.orderLineItemId,
@@ -425,7 +426,9 @@ class _MenuBrowseScreenState extends State {
);
// Refresh cart to get final state
+ print('[MenuBrowse] Refreshing cart to get final state');
cart = await Api.getCart(orderId: cart.orderId);
+ print('[MenuBrowse] Final cart has ${cart.lineItems.length} total line items');
appState.updateCartItemCount(cart.itemCount);
@@ -454,38 +457,58 @@ class _MenuBrowseScreenState extends State {
Set selectedItemIds,
) async {
final children = _itemsByParent[parentItemId] ?? [];
+ print('[MenuBrowse] _addModifiersRecursively: parentItemId=$parentItemId has ${children.length} children');
for (final child in children) {
final isSelected = selectedItemIds.contains(child.itemId);
+ final grandchildren = _itemsByParent[child.itemId] ?? [];
+ final hasGrandchildren = grandchildren.isNotEmpty;
+ final hasSelectedDescendants = _hasSelectedDescendants(child.itemId, selectedItemIds);
- // Only add selected items to the cart
- if (!isSelected) {
- continue;
+ print('[MenuBrowse] Child ${child.name} (ItemID=${child.itemId}): selected=$isSelected, hasChildren=$hasGrandchildren, hasSelectedDescendants=$hasSelectedDescendants');
+
+ // Add this item if it's selected OR if it has selected descendants (to maintain hierarchy)
+ if (isSelected || hasSelectedDescendants) {
+ print('[MenuBrowse] Adding ${isSelected ? "selected" : "container"} item ${child.name} with ParentOrderLineItemID=$parentOrderLineItemId');
+ final cart = await Api.setLineItem(
+ orderId: orderId,
+ parentOrderLineItemId: parentOrderLineItemId,
+ itemId: child.itemId,
+ isSelected: true,
+ );
+
+ // Find the OrderLineItemID of this item we just added
+ final childLineItem = cart.lineItems.lastWhere(
+ (li) => li.itemId == child.itemId && li.parentOrderLineItemId == parentOrderLineItemId && !li.isDeleted,
+ orElse: () => throw StateError('Child line item not found for ItemID=${child.itemId}'),
+ );
+
+ // Recursively add children with this item as the new parent
+ if (hasGrandchildren) {
+ await _addModifiersRecursively(
+ orderId,
+ childLineItem.orderLineItemId,
+ child.itemId,
+ selectedItemIds,
+ );
+ }
}
-
- // Add this modifier with the correct parent OrderLineItemID
- final cart = await Api.setLineItem(
- orderId: orderId,
- parentOrderLineItemId: parentOrderLineItemId,
- itemId: child.itemId,
- isSelected: true,
- );
-
- // Find the OrderLineItemID of this modifier we just added
- final childLineItem = cart.lineItems.lastWhere(
- (li) => li.itemId == child.itemId && li.parentOrderLineItemId == parentOrderLineItemId && !li.isDeleted,
- orElse: () => throw StateError('Child line item not found for ItemID=${child.itemId}'),
- );
-
- // Recursively add grandchildren
- await _addModifiersRecursively(
- orderId,
- childLineItem.orderLineItemId,
- child.itemId,
- selectedItemIds,
- );
}
}
+
+ /// Check if any descendants of this item are selected
+ bool _hasSelectedDescendants(int itemId, Set selectedItemIds) {
+ final children = _itemsByParent[itemId] ?? [];
+ for (final child in children) {
+ if (selectedItemIds.contains(child.itemId)) {
+ return true;
+ }
+ if (_hasSelectedDescendants(child.itemId, selectedItemIds)) {
+ return true;
+ }
+ }
+ return false;
+ }
}
/// Recursive item customization sheet with full rule support
diff --git a/lib/services/api.dart b/lib/services/api.dart
index 0b001b2..c20cae7 100644
--- a/lib/services/api.dart
+++ b/lib/services/api.dart
@@ -386,6 +386,29 @@ class Api {
}
}
+ static Future