feat(chats_screen): Real-time работа с lastMsg, галочки.

This commit is contained in:
Jganenok
2026-06-13 16:06:41 +07:00
parent efa50375e0
commit ebc22cd8bd
9 changed files with 564 additions and 93 deletions
+10
View File
@@ -135,6 +135,16 @@ class PresenceFetch {
static void invalidate(int id) => _cache.invalidate(id);
static void clear() => _cache.clear();
static void primeAll(Map<dynamic, dynamic> presence) {
final now = DateTime.now();
presence.forEach((key, value) {
if (value is! Map) return;
final id = key is int ? key : int.tryParse(key.toString());
if (id == null) return;
_cache.putValue(id, Map<String, dynamic>.from(value), at: now);
});
}
static Future<Map<String, dynamic>?> _fetch(int id) async {
final results = await _fetchBatch([id]);
return results[id];
+29 -6
View File
@@ -185,7 +185,7 @@ class AppDatabase {
await _migrateLegacyDb(target);
return openDatabase(
target,
version: 11,
version: 12,
onOpen: (db) => db.execute('PRAGMA foreign_keys = ON'),
onCreate: (db, _) => _createTables(db),
onUpgrade: (db, oldVersion, newVersion) async {
@@ -238,6 +238,11 @@ class AppDatabase {
if (oldVersion < 11) {
await _createIndexes(db);
}
if (oldVersion < 12) {
await db.execute(
'ALTER TABLE chats_cache ADD COLUMN last_msg_status TEXT',
);
}
},
);
}
@@ -313,6 +318,7 @@ class AppDatabase {
last_msg_time INTEGER,
last_msg_text TEXT,
last_msg_sender INTEGER,
last_msg_status TEXT,
unread_count INTEGER NOT NULL DEFAULT 0,
last_event_time INTEGER NOT NULL DEFAULT 0,
cached_at INTEGER NOT NULL,
@@ -480,14 +486,19 @@ class AppDatabase {
if (rows.isEmpty) return;
try {
final db = await _instance;
final cols = rows.first.keys.toList();
final placeholders = List.filled(cols.length, '?').join(', ');
final updates = cols
.where((c) => c != 'id' && c != 'account_id')
.map((c) => '$c = excluded.$c')
.join(', ');
final sql = 'INSERT INTO chats_cache (${cols.join(', ')}) '
'VALUES ($placeholders) '
'ON CONFLICT(id, account_id) DO UPDATE SET $updates';
await db.transaction((txn) async {
final batch = txn.batch();
for (final row in rows) {
batch.insert(
'chats_cache',
row,
conflictAlgorithm: ConflictAlgorithm.replace,
);
batch.rawInsert(sql, cols.map((c) => row[c]).toList());
}
await batch.commit(noResult: true);
});
@@ -661,4 +672,16 @@ class AppDatabase {
whereArgs: [accountId, chatId, messageId],
);
}
static Future<List<Map<String, dynamic>>> loadPendingMessages(
int accountId,
) async {
final db = await _instance;
return db.query(
'messages',
where: 'account_id = ? AND status = ?',
whereArgs: [accountId, 'pending'],
orderBy: 'time ASC',
);
}
}
+57
View File
@@ -0,0 +1,57 @@
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';
class DraftStore {
DraftStore._();
static final DraftStore instance = DraftStore._();
static const String _prefsKey = 'chat_drafts';
final Map<String, String> _drafts = {};
final ValueNotifier<int> revision = ValueNotifier(0);
bool _loaded = false;
String _key(int accountId, int chatId) => '$accountId/$chatId';
Future<void> load() async {
if (_loaded) return;
_loaded = true;
final prefs = await SharedPreferences.getInstance();
final raw = prefs.getString(_prefsKey);
if (raw == null) return;
try {
final map = jsonDecode(raw);
if (map is Map) {
map.forEach((k, v) {
if (k is String && v is String) _drafts[k] = v;
});
}
} catch (_) {}
}
String? get(int accountId, int chatId) {
if (accountId == 0) return null;
return _drafts[_key(accountId, chatId)];
}
Future<void> set(int accountId, int chatId, String text) async {
if (accountId == 0) return;
final key = _key(accountId, chatId);
final current = _drafts[key];
if (text.trim().isEmpty) {
if (current == null) return;
_drafts.remove(key);
} else {
if (current == text) return;
_drafts[key] = text;
}
revision.value++;
final prefs = await SharedPreferences.getInstance();
await prefs.setString(_prefsKey, jsonEncode(_drafts));
}
Future<void> clear(int accountId, int chatId) => set(accountId, chatId, '');
}