93 lines
3.0 KiB
Dart
93 lines
3.0 KiB
Dart
import 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
|
|
|
import '../../models/attachment.dart';
|
|
import '../config/qlyra_settings.dart';
|
|
import '../storage/app_database.dart';
|
|
import '../utils/logger.dart';
|
|
import '../utils/media_cache.dart';
|
|
import '../utils/media_cache_names.dart';
|
|
|
|
// #***! удалённое сообщение остаётся, а файл на сервере умирает: пока ссылка
|
|
// ещё жива, снимаем копию в закреплённый кэш и прописываем её в payload
|
|
Future<void> keepDeletedMedia(
|
|
int accountId,
|
|
int chatId,
|
|
List<String> messageIds,
|
|
) async {
|
|
if (!QlyraSettings.viewDeleted.value || messageIds.isEmpty) return;
|
|
|
|
final List<Map<String, dynamic>> rows;
|
|
try {
|
|
rows = await AppDatabase.loadMessagesByIds(accountId, chatId, messageIds);
|
|
} catch (e) {
|
|
logger.w('keepDeletedMedia: не прочитал сообщения: $e');
|
|
return;
|
|
}
|
|
|
|
for (final row in rows) {
|
|
final payload = _decodePayload(row['payload']);
|
|
final attaches = payload?['attaches'];
|
|
if (payload == null || attaches is! List) continue;
|
|
var changed = false;
|
|
for (final attach in attaches.whereType<Map>()) {
|
|
if (await _keepPhoto(attach)) changed = true;
|
|
}
|
|
if (!changed) continue;
|
|
if (!QlyraSettings.viewDeleted.value) return;
|
|
try {
|
|
await AppDatabase.updateMessageMediaPayload(
|
|
accountId, chatId, row['id'].toString(),
|
|
row['payload'] as String, jsonEncode(payload),
|
|
);
|
|
} catch (e) {
|
|
logger.w('keepDeletedMedia: не сохранил локальные пути: $e');
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<bool> _keepPhoto(Map<dynamic, dynamic> attach) async {
|
|
if ((attach['_type'] as String?)?.toUpperCase() != 'PHOTO') return false;
|
|
final saved = attach['localPath'] as String?;
|
|
if (saved != null && saved.isNotEmpty && await File(saved).exists()) {
|
|
return false;
|
|
}
|
|
|
|
final photo = PhotoAttachment.fromMap(Map<String, dynamic>.from(attach));
|
|
final url = photo.baseUrl ?? '';
|
|
if (url.isEmpty || url.startsWith('data:')) return false;
|
|
|
|
final name = photoCacheName(photo, url);
|
|
final source = await MediaCache.existing(name) ?? await _shownCopy(url);
|
|
final kept = await MediaCache.keep(name, source: source, url: url);
|
|
if (kept == null) return false;
|
|
|
|
attach['localPath'] = kept.path;
|
|
return true;
|
|
}
|
|
|
|
// #***! то что уже показывали лежит в кэше картинок, из него и копируем
|
|
Future<File?> _shownCopy(String url) async {
|
|
try {
|
|
final info = await DefaultCacheManager().getFileFromCache(url);
|
|
final path = info?.file.path;
|
|
if (path == null) return null;
|
|
final file = File(path);
|
|
return await file.exists() ? file : null;
|
|
} catch (_) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
Map<String, dynamic>? _decodePayload(Object? raw) {
|
|
if (raw is! String || raw.isEmpty) return null;
|
|
try {
|
|
final decoded = jsonDecode(raw);
|
|
return decoded is Map ? Map<String, dynamic>.from(decoded) : null;
|
|
} catch (_) {
|
|
return null;
|
|
}
|
|
}
|