Flutter App Changes:
- Fixed modifier saving to maintain full hierarchy (containers + selections)
- Fixed cart display to show breadcrumb paths (e.g., "Customize Patties > Mustard grilled")
- Added order status polling service (30-second intervals)
- Updated AppState to track active order and status
- Fixed Android Bluetooth permissions for release builds
- Disabled minification to preserve beacon library in release builds
- Added ProGuard rules for beacon/Bluetooth classes
- Added foreground service permissions for beacon monitoring
Technical Details:
- menu_browse_screen.dart: Added _hasSelectedDescendants() to ensure container items are saved
- cart_view_screen.dart: Added _buildModifierPaths() for breadcrumb display
- order_polling_service.dart: Polls checkStatusUpdate.cfm every 30s
- api.dart: Added checkOrderStatus() method
- Android permissions: Removed neverForLocation flag, added FOREGROUND_SERVICE
- ProGuard: Disabled shrinking, added keep rules for beacon classes
🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
114 lines
3.3 KiB
Dart
114 lines
3.3 KiB
Dart
import 'dart:async';
|
||
import 'package:flutter/material.dart';
|
||
import 'api.dart';
|
||
|
||
/// Service that polls the backend API for order status updates
|
||
/// Uses a simple polling approach (Option 2) with 30-second intervals
|
||
class OrderPollingService {
|
||
static Timer? _pollingTimer;
|
||
static int? _currentOrderId;
|
||
static int? _lastKnownStatusId;
|
||
static Function(OrderStatusUpdate)? _onStatusUpdate;
|
||
|
||
/// Start polling for order status updates
|
||
static void startPolling({
|
||
required int orderId,
|
||
required int initialStatusId,
|
||
required Function(OrderStatusUpdate) onStatusUpdate,
|
||
}) {
|
||
print('[OrderPolling] 🔄 Starting polling for OrderID=$orderId, Status=$initialStatusId');
|
||
|
||
// Stop any existing polling
|
||
stopPolling();
|
||
|
||
_currentOrderId = orderId;
|
||
_lastKnownStatusId = initialStatusId;
|
||
_onStatusUpdate = onStatusUpdate;
|
||
|
||
// Poll every 30 seconds
|
||
_pollingTimer = Timer.periodic(const Duration(seconds: 30), (_) {
|
||
_checkForUpdate();
|
||
});
|
||
|
||
// Also check immediately
|
||
_checkForUpdate();
|
||
}
|
||
|
||
/// Stop polling
|
||
static void stopPolling() {
|
||
print('[OrderPolling] ⏹️ Stopping polling');
|
||
_pollingTimer?.cancel();
|
||
_pollingTimer = null;
|
||
_currentOrderId = null;
|
||
_lastKnownStatusId = null;
|
||
_onStatusUpdate = null;
|
||
}
|
||
|
||
/// Check if currently polling
|
||
static bool get isPolling => _pollingTimer != null && _pollingTimer!.isActive;
|
||
|
||
/// Get current order ID being polled
|
||
static int? get currentOrderId => _currentOrderId;
|
||
|
||
/// Internal method to check for updates
|
||
static Future<void> _checkForUpdate() async {
|
||
if (_currentOrderId == null || _lastKnownStatusId == null) {
|
||
print('[OrderPolling] ⚠️ No order to poll, stopping');
|
||
stopPolling();
|
||
return;
|
||
}
|
||
|
||
try {
|
||
print('[OrderPolling] 🔍 Checking status for OrderID=$_currentOrderId');
|
||
|
||
final data = await Api.checkOrderStatus(
|
||
orderId: _currentOrderId!,
|
||
lastKnownStatusId: _lastKnownStatusId!,
|
||
);
|
||
|
||
if (data['OK'] == true && data['HAS_UPDATE'] == true) {
|
||
final orderStatus = data['ORDER_STATUS'];
|
||
final newStatusId = (orderStatus['StatusID'] as num).toInt();
|
||
final statusName = orderStatus['StatusName'] as String;
|
||
final message = orderStatus['Message'] as String;
|
||
|
||
print('[OrderPolling] ✅ Status update detected: $statusName (ID=$newStatusId)');
|
||
|
||
// Update last known status
|
||
_lastKnownStatusId = newStatusId;
|
||
|
||
// Notify listener
|
||
if (_onStatusUpdate != null) {
|
||
_onStatusUpdate!(OrderStatusUpdate(
|
||
orderId: _currentOrderId!,
|
||
statusId: newStatusId,
|
||
statusName: statusName,
|
||
message: message,
|
||
));
|
||
}
|
||
} else {
|
||
print('[OrderPolling] ℹ️ No status update');
|
||
}
|
||
} catch (e) {
|
||
print('[OrderPolling] ❌ Error checking status: $e');
|
||
}
|
||
}
|
||
}
|
||
|
||
/// Data class representing an order status update
|
||
class OrderStatusUpdate {
|
||
final int orderId;
|
||
final int statusId;
|
||
final String statusName;
|
||
final String message;
|
||
|
||
const OrderStatusUpdate({
|
||
required this.orderId,
|
||
required this.statusId,
|
||
required this.statusName,
|
||
required this.message,
|
||
});
|
||
|
||
@override
|
||
String toString() => 'OrderStatusUpdate(orderId: $orderId, statusId: $statusId, statusName: $statusName, message: $message)';
|
||
}
|