Files
kooltab/lib/models/remote_command.dart
T
2026-10-08 04:12:36 +02:00

169 lines
3.7 KiB
Dart

import '../utils/app_config.dart';
enum CommandType {
closeTab('close_tab');
final String value;
const CommandType(this.value);
static CommandType? fromValue(String value) {
for (final type in CommandType.values) {
if (type.value == value) return type;
}
return null;
}
}
enum CommandResult { completed, conflict, failed, expired }
class RemoteCommand {
final String id;
final String rawType;
final String tabId;
final int expectedVersion;
final String paymentMethod;
final String requestedBy;
final DateTime createdAt;
const RemoteCommand({
required this.id,
required this.rawType,
required this.tabId,
required this.expectedVersion,
required this.paymentMethod,
required this.requestedBy,
required this.createdAt,
});
factory RemoteCommand.fromJson(Map<String, dynamic> json) {
return RemoteCommand(
id: json['id'] as String,
rawType: json['type'] as String,
tabId: json['tabId'] as String,
expectedVersion: json['expectedVersion'] as int,
paymentMethod: json['paymentMethod'] as String? ?? 'cash',
requestedBy: json['requestedBy'] as String? ?? '',
createdAt: DateTime.parse(json['createdAt'] as String),
);
}
/// Null when the server sends a command this app version doesn't know.
CommandType? get type => CommandType.fromValue(rawType);
bool get isExpired {
final cutoff = DateTime.now().subtract(
const Duration(hours: kCommandExpiryHours),
);
return createdAt.isBefore(cutoff);
}
}
class SyncResponse {
final List<RemoteCommand> commands;
final String? cursor;
final List<String> plannedTabNames;
const SyncResponse({
required this.commands,
this.cursor,
this.plannedTabNames = const [],
});
factory SyncResponse.fromJson(Map<String, dynamic> json) {
return SyncResponse(
commands: [
for (final command in json['commands'] as List<dynamic>? ?? [])
RemoteCommand.fromJson(command as Map<String, dynamic>),
],
cursor: json['cursor'] as String?,
plannedTabNames: [
for (final name in json['plannedTabNames'] as List<dynamic>? ?? [])
name as String,
],
);
}
}
class SnapshotTab {
final String id;
final String customerName;
final int version;
final int totalInCents;
final int itemCount;
const SnapshotTab({
required this.id,
required this.customerName,
required this.version,
required this.totalInCents,
required this.itemCount,
});
Map<String, dynamic> toJson() => {
'id': id,
'customerName': customerName,
'version': version,
'totalInCents': totalInCents,
'itemCount': itemCount,
};
}
class SyncRequest {
final String deviceId;
final String? cursor;
final List<SnapshotTab> openTabs;
const SyncRequest({
required this.deviceId,
this.cursor,
required this.openTabs,
});
Map<String, dynamic> toJson() => {
'deviceId': deviceId,
if (cursor != null) 'cursor': cursor,
'openTabs': openTabs.map((tab) => tab.toJson()).toList(),
};
}
class CommandAck {
final String commandId;
final CommandResult status;
final String? result;
const CommandAck({
required this.commandId,
required this.status,
this.result,
});
Map<String, dynamic> toJson() => {
'commandId': commandId,
'status': status.name,
if (result != null) 'result': result,
};
}
enum RemoteSyncEventType {
tabClosedRemotely,
syncCompleted,
syncFailed,
conflict,
unauthorized,
}
class RemoteSyncEvent {
final RemoteSyncEventType type;
final String? tabCustomerName;
final String? requestedBy;
final String? message;
const RemoteSyncEvent({
required this.type,
this.tabCustomerName,
this.requestedBy,
this.message,
});
}