import 'dart:collection'; import 'sheet.dart'; /// Types of changes that can be queued for server synchronization. enum ChangeType { sheetNameChange, composerNameChange, addTagChange, removeTagChange, } /// Represents a single pending change to be synced with the server. /// /// Changes are stored locally when offline and applied once /// the device regains connectivity. Each change has a [createdAt] timestamp /// that the server uses to resolve conflicts between devices. class Change { final ChangeType type; final String sheetUuid; final String value; final DateTime createdAt; Change({ required this.type, required this.sheetUuid, required this.value, DateTime? createdAt, }) : createdAt = createdAt ?? DateTime.now(); /// Serializes this change to a map for storage. Map toMap() => { 'type': type.index, 'sheetUuid': sheetUuid, 'value': value, 'createdAt': createdAt.toIso8601String(), }; /// Serializes this change to JSON for API requests. Map toJson() => { 'type': type.name, 'sheetUuid': sheetUuid, 'value': value, 'createdAt': createdAt.toIso8601String(), }; /// Deserializes a change from a stored map. /// /// Note: Adding new [ChangeType] values may cause issues with /// previously stored changes that use index-based serialization. factory Change.fromMap(Map map) { return Change( type: ChangeType.values[map['type']], sheetUuid: map['sheetUuid'], value: map['value'], createdAt: map['createdAt'] != null ? DateTime.parse(map['createdAt']) : DateTime.now(), ); } } /// A queue of pending changes to be synchronized with the server. /// /// Changes are stored in FIFO order (oldest first) and applied /// to sheets in sequence when syncing. class ChangeQueue { final Queue _queue = Queue(); ChangeQueue(); /// Adds a change to the end of the queue. void addChange(Change change) { _queue.addLast(change); } /// Returns the number of pending changes. int get length => _queue.length; /// Whether the queue has any pending changes. bool get isEmpty => _queue.isEmpty; /// Whether the queue has pending changes. bool get isNotEmpty => _queue.isNotEmpty; /// Applies all queued changes to the provided list of sheets. /// /// Each change modifies the corresponding sheet's properties /// based on the change type. void applyToSheets(List sheets) { for (final change in _queue) { final sheet = sheets.firstWhere( (s) => s.uuid == change.sheetUuid, orElse: () => throw StateError( 'Sheet with UUID ${change.sheetUuid} not found', ), ); switch (change.type) { case ChangeType.sheetNameChange: sheet.name = change.value; case ChangeType.composerNameChange: sheet.composerName = change.value; case ChangeType.addTagChange: throw UnimplementedError('Tag support not yet implemented'); case ChangeType.removeTagChange: throw UnimplementedError('Tag support not yet implemented'); } } } }