Clean up: move docs to Obsidian vault, remove outdated md files

This commit is contained in:
2026-04-21 15:54:20 +05:00
parent 448403d7ee
commit 4c50036172
22 changed files with 1295 additions and 2869 deletions
+180
View File
@@ -0,0 +1,180 @@
import 'dart:convert';
import 'package:hive/hive.dart';
/// Hive модель для кэшированного mindmap-файла
class CachedMindmap {
final String path;
final String content;
final String? sha;
final DateTime lastSync;
final DateTime lastModified;
final String branch;
CachedMindmap({
required this.path,
required this.content,
this.sha,
required this.lastSync,
required this.lastModified,
this.branch = 'main',
});
Map<String, dynamic> toJson() => {
'path': path,
'content': content,
'sha': sha,
'lastSync': lastSync.toIso8601String(),
'lastModified': lastModified.toIso8601String(),
'branch': branch,
};
factory CachedMindmap.fromJson(Map<String, dynamic> json) {
return CachedMindmap(
path: json['path'] ?? '',
content: json['content'] ?? '',
sha: json['sha'],
lastSync:
DateTime.parse(json['lastSync'] ?? DateTime.now().toIso8601String()),
lastModified: DateTime.parse(
json['lastModified'] ?? DateTime.now().toIso8601String()),
branch: json['branch'] ?? 'main',
);
}
}
/// Оффлайн репозиторий для mindmaps
/// Хранит кэш файлов из Gitea и очередь изменений для синхронизации
class OfflineMindmapRepository {
static const String _boxName = 'mindmaps_cache';
static const String _queueBoxName = 'mindmaps_queue';
static const String _metaKey = '_meta_sync_state';
Box<String>? _box;
Box<String>? _queueBox;
Future<void> initialize() async {
_box = await Hive.openBox<String>(_boxName);
_queueBox = await Hive.openBox<String>(_queueBoxName);
}
bool get isInitialized => _box != null && _box!.isOpen;
// ==================== CACHE ====================
/// Сохранить файл в кэш
Future<void> cacheMindmap(CachedMindmap mindmap) async {
if (!isInitialized) throw Exception('Repository not initialized');
await _box!.put(mindmap.path, jsonEncode(mindmap.toJson()));
}
/// Получить файл из кэша
CachedMindmap? getMindmap(String path) {
if (!isInitialized) return null;
final raw = _box!.get(path);
if (raw == null) return null;
try {
return CachedMindmap.fromJson(jsonDecode(raw));
} catch (_) {
return null;
}
}
/// Получить все кэшированные mindmaps
List<CachedMindmap> getAllMindmaps() {
if (!isInitialized) return [];
return _box!.values
.map((raw) {
try {
return CachedMindmap.fromJson(jsonDecode(raw));
} catch (_) {
return null;
}
})
.whereType<CachedMindmap>()
.toList();
}
/// Удалить файл из кэша
Future<void> deleteMindmap(String path) async {
if (!isInitialized) return;
await _box!.delete(path);
}
/// Очистить весь кэш
Future<void> clearCache() async {
if (!isInitialized) return;
await _box!.clear();
}
// ==================== SYNC QUEUE ====================
/// Добавить изменение в очередь (для offline → online sync)
Future<void> queueChange({
required String path,
required String content,
required String operation, // 'create' | 'update' | 'delete'
String? commitMessage,
}) async {
if (!isInitialized) throw Exception('Repository not initialized');
final entry = {
'path': path,
'content': content,
'operation': operation,
'commitMessage': commitMessage ?? 'Mobile sync: $path',
'timestamp': DateTime.now().toIso8601String(),
};
await _queueBox!.put(
'${DateTime.now().millisecondsSinceEpoch}_$path', jsonEncode(entry));
}
/// Получить все изменения из очереди
List<Map<String, dynamic>> getPendingChanges() {
if (!isInitialized) return [];
return _queueBox!.values
.map((raw) {
try {
return jsonDecode(raw) as Map<String, dynamic>;
} catch (_) {
return null;
}
})
.whereType<Map<String, dynamic>>()
.toList()
..sort((a, b) => (a['timestamp'] ?? '').compareTo(b['timestamp'] ?? ''));
}
/// Удалить выполненное изменение из очереди
Future<void> removeQueuedChange(String key) async {
if (!isInitialized) return;
await _queueBox!.delete(key);
}
/// Очистить очередь
Future<void> clearQueue() async {
if (!isInitialized) return;
await _queueBox!.clear();
}
bool get hasPendingChanges => (_queueBox?.length ?? 0) > 0;
// ==================== SYNC STATE ====================
/// Сохранить время последней успешной синхронизации
Future<void> setLastSync(DateTime time) async {
if (!isInitialized) return;
await _box!.put(_metaKey, jsonEncode({'lastSync': time.toIso8601String()}));
}
/// Получить время последней синхронизации
DateTime? getLastSync() {
if (!isInitialized) return null;
final raw = _box!.get(_metaKey);
if (raw == null) return null;
try {
final data = jsonDecode(raw) as Map<String, dynamic>;
return DateTime.tryParse(data['lastSync'] ?? '');
} catch (_) {
return null;
}
}
}