Only save annotations on changes
This commit is contained in:
@@ -51,6 +51,9 @@ class DrawingController extends ChangeNotifier {
|
|||||||
/// Maximum number of history steps to keep
|
/// Maximum number of history steps to keep
|
||||||
final int maxHistorySteps;
|
final int maxHistorySteps;
|
||||||
|
|
||||||
|
/// Whether there are unsaved changes since last load/clear
|
||||||
|
bool _hasUnsavedChanges = false;
|
||||||
|
|
||||||
DrawingController({this.maxHistorySteps = 50});
|
DrawingController({this.maxHistorySteps = 50});
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -75,6 +78,9 @@ class DrawingController extends ChangeNotifier {
|
|||||||
/// Whether redo is available
|
/// Whether redo is available
|
||||||
bool get canRedo => _redoStack.isNotEmpty;
|
bool get canRedo => _redoStack.isNotEmpty;
|
||||||
|
|
||||||
|
/// Whether there are unsaved changes since last load/clear/markSaved
|
||||||
|
bool get hasUnsavedChanges => _hasUnsavedChanges;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Drawing Operations
|
// Drawing Operations
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -120,6 +126,7 @@ class DrawingController extends ChangeNotifier {
|
|||||||
_redoStack.clear();
|
_redoStack.clear();
|
||||||
_trimHistory();
|
_trimHistory();
|
||||||
_currentErasedLines.clear();
|
_currentErasedLines.clear();
|
||||||
|
_hasUnsavedChanges = true;
|
||||||
notifyListeners(); // Update UI to enable undo button
|
notifyListeners(); // Update UI to enable undo button
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -133,6 +140,7 @@ class DrawingController extends ChangeNotifier {
|
|||||||
_undoStack.add(AddLineAction(_currentLine!));
|
_undoStack.add(AddLineAction(_currentLine!));
|
||||||
_redoStack.clear();
|
_redoStack.clear();
|
||||||
_trimHistory();
|
_trimHistory();
|
||||||
|
_hasUnsavedChanges = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_currentLine = null;
|
_currentLine = null;
|
||||||
@@ -257,6 +265,7 @@ class DrawingController extends ChangeNotifier {
|
|||||||
_redoStack.add(action);
|
_redoStack.add(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_hasUnsavedChanges = true;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,6 +288,7 @@ class DrawingController extends ChangeNotifier {
|
|||||||
_undoStack.add(action);
|
_undoStack.add(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_hasUnsavedChanges = true;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,6 +299,7 @@ class DrawingController extends ChangeNotifier {
|
|||||||
_redoStack.clear();
|
_redoStack.clear();
|
||||||
_currentLine = null;
|
_currentLine = null;
|
||||||
_currentErasedLines.clear();
|
_currentErasedLines.clear();
|
||||||
|
_hasUnsavedChanges = false;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,6 +335,7 @@ class DrawingController extends ChangeNotifier {
|
|||||||
_redoStack.clear();
|
_redoStack.clear();
|
||||||
_currentLine = null;
|
_currentLine = null;
|
||||||
_currentErasedLines.clear();
|
_currentErasedLines.clear();
|
||||||
|
_hasUnsavedChanges = false;
|
||||||
|
|
||||||
for (final json in jsonList) {
|
for (final json in jsonList) {
|
||||||
_lines.add(DrawingLine.fromJson(json));
|
_lines.add(DrawingLine.fromJson(json));
|
||||||
@@ -354,6 +366,11 @@ class DrawingController extends ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Marks the current state as saved (resets unsaved changes flag).
|
||||||
|
void markSaved() {
|
||||||
|
_hasUnsavedChanges = false;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_lines.clear();
|
_lines.clear();
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ class _SheetViewerPageState extends State<SheetViewerPage>
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Sync annotations from server (downloads newer versions)
|
// Sync annotations from server (downloads newer versions)
|
||||||
await _syncService.syncAnnotationsFromServer(widget.sheet.uuid);
|
await _syncService.syncFromServer(widget.sheet.uuid);
|
||||||
|
|
||||||
// Load annotations for current page(s)
|
// Load annotations for current page(s)
|
||||||
await _loadAnnotationsForCurrentPages();
|
await _loadAnnotationsForCurrentPages();
|
||||||
@@ -143,32 +143,40 @@ class _SheetViewerPageState extends State<SheetViewerPage>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Saves the current page(s) annotations to storage and uploads to server.
|
/// Saves the current page(s) annotations to storage and uploads to server.
|
||||||
|
///
|
||||||
|
/// Only saves if there are actual changes to avoid unnecessary writes/uploads.
|
||||||
Future<void> _saveCurrentAnnotations() async {
|
Future<void> _saveCurrentAnnotations() async {
|
||||||
final now = DateTime.now();
|
final now = DateTime.now();
|
||||||
|
|
||||||
// Save left page
|
// Save left page only if changed
|
||||||
final leftJson = _leftDrawingController.toJsonString();
|
if (_leftDrawingController.hasUnsavedChanges) {
|
||||||
final leftHasContent = leftJson.isNotEmpty && leftJson != '[]';
|
final leftJson = _leftDrawingController.toJsonString();
|
||||||
|
final leftHasContent = leftJson.isNotEmpty && leftJson != '[]';
|
||||||
|
|
||||||
await _storageService.writeAnnotationsWithMetadata(
|
await _storageService.writeAnnotationsWithMetadata(
|
||||||
widget.sheet.uuid,
|
widget.sheet.uuid,
|
||||||
_currentPage,
|
_currentPage,
|
||||||
leftHasContent ? leftJson : null,
|
leftHasContent ? leftJson : null,
|
||||||
now,
|
now,
|
||||||
);
|
|
||||||
|
|
||||||
// Upload left page to server
|
|
||||||
if (leftHasContent) {
|
|
||||||
_syncService.uploadAnnotation(
|
|
||||||
sheetUuid: widget.sheet.uuid,
|
|
||||||
page: _currentPage,
|
|
||||||
annotationsJson: leftJson,
|
|
||||||
lastModified: now,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Upload left page to server
|
||||||
|
if (leftHasContent) {
|
||||||
|
_syncService.uploadAnnotation(
|
||||||
|
sheetUuid: widget.sheet.uuid,
|
||||||
|
page: _currentPage,
|
||||||
|
annotationsJson: leftJson,
|
||||||
|
lastModified: now,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_leftDrawingController.markSaved();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save right page (two-page mode)
|
// Save right page (two-page mode) only if changed
|
||||||
if (widget.config.twoPageMode && _currentPage < _totalPages) {
|
if (widget.config.twoPageMode &&
|
||||||
|
_currentPage < _totalPages &&
|
||||||
|
_rightDrawingController.hasUnsavedChanges) {
|
||||||
final rightJson = _rightDrawingController.toJsonString();
|
final rightJson = _rightDrawingController.toJsonString();
|
||||||
final rightHasContent = rightJson.isNotEmpty && rightJson != '[]';
|
final rightHasContent = rightJson.isNotEmpty && rightJson != '[]';
|
||||||
|
|
||||||
@@ -188,6 +196,8 @@ class _SheetViewerPageState extends State<SheetViewerPage>
|
|||||||
lastModified: now,
|
lastModified: now,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_rightDrawingController.markSaved();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,9 +300,8 @@ class _SheetViewerPageState extends State<SheetViewerPage>
|
|||||||
icon: Icon(
|
icon: Icon(
|
||||||
widget.config.fullscreen ? Icons.fullscreen_exit : Icons.fullscreen,
|
widget.config.fullscreen ? Icons.fullscreen_exit : Icons.fullscreen,
|
||||||
),
|
),
|
||||||
tooltip: widget.config.fullscreen
|
tooltip:
|
||||||
? 'Exit Fullscreen'
|
widget.config.fullscreen ? 'Exit Fullscreen' : 'Enter Fullscreen',
|
||||||
: 'Enter Fullscreen',
|
|
||||||
onPressed: _toggleFullscreen,
|
onPressed: _toggleFullscreen,
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
@@ -304,9 +313,8 @@ class _SheetViewerPageState extends State<SheetViewerPage>
|
|||||||
icon: Icon(
|
icon: Icon(
|
||||||
widget.config.twoPageMode ? Icons.filter_1 : Icons.filter_2,
|
widget.config.twoPageMode ? Icons.filter_1 : Icons.filter_2,
|
||||||
),
|
),
|
||||||
tooltip: widget.config.twoPageMode
|
tooltip:
|
||||||
? 'Single Page Mode'
|
widget.config.twoPageMode ? 'Single Page Mode' : 'Two Page Mode',
|
||||||
: 'Two Page Mode',
|
|
||||||
onPressed: _toggleTwoPageMode,
|
onPressed: _toggleTwoPageMode,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -338,9 +346,8 @@ class _SheetViewerPageState extends State<SheetViewerPage>
|
|||||||
currentPageNumber: _currentPage,
|
currentPageNumber: _currentPage,
|
||||||
config: widget.config,
|
config: widget.config,
|
||||||
leftDrawingController: _leftDrawingController,
|
leftDrawingController: _leftDrawingController,
|
||||||
rightDrawingController: widget.config.twoPageMode
|
rightDrawingController:
|
||||||
? _rightDrawingController
|
widget.config.twoPageMode ? _rightDrawingController : null,
|
||||||
: null,
|
|
||||||
drawingEnabled: _isPaintMode,
|
drawingEnabled: _isPaintMode,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user