я как бы еще не доделал, это такой промежуточный пуш знаете

This commit is contained in:
Jganenokk
2026-04-03 19:35:45 +07:00
parent 98c72e5d16
commit 91069f53ea
17 changed files with 987 additions and 417 deletions
+83 -29
View File
@@ -35,10 +35,12 @@ class ProfileData {
String? lastName;
if (names is List && names.isNotEmpty) {
final name = names.firstWhere(
(n) => n is Map && n['type'] == 'ONEME',
orElse: () => names.first,
) as Map;
final name =
names.firstWhere(
(n) => n is Map && n['type'] == 'ONEME',
orElse: () => names.first,
)
as Map;
firstName = (name['firstName'] as String?) ?? '';
lastName = name['lastName'] as String?;
}
@@ -73,17 +75,17 @@ class ProfileData {
}
Map<String, dynamic> toDbRow() => {
'id': id,
'first_name': firstName,
'last_name': lastName,
'phone': phone,
'photo_id': photoId,
'base_url': baseUrl,
'base_raw_url': baseRawUrl,
'country': country,
'account_status': accountStatus,
'update_time': updateTime,
};
'id': id,
'first_name': firstName,
'last_name': lastName,
'phone': phone,
'photo_id': photoId,
'base_url': baseUrl,
'base_raw_url': baseRawUrl,
'country': country,
'account_status': accountStatus,
'update_time': updateTime,
};
}
abstract class SyncKey {
@@ -118,7 +120,7 @@ class AppDatabase {
final dbPath = await getDatabasesPath();
return openDatabase(
join(dbPath, 'komet.db'),
version: 3,
version: 5,
onOpen: (db) => db.execute('PRAGMA foreign_keys = ON'),
onCreate: (db, _) => _createTables(db),
onUpgrade: (db, oldVersion, newVersion) async {
@@ -132,6 +134,13 @@ class AppDatabase {
if (oldVersion < 3) {
await db.execute(_chatsCacheSchema);
}
if (oldVersion < 4) {
await db.execute(_contactsSchema);
}
if (oldVersion < 5) {
await db.execute('DROP TABLE IF EXISTS chats_cache');
await db.execute(_chatsCacheSchema);
}
},
);
}
@@ -154,8 +163,23 @@ class AppDatabase {
''');
await db.execute(_syncStateSchema);
await db.execute(_chatsCacheSchema);
await db.execute(_contactsSchema);
}
static const _contactsSchema = '''
CREATE TABLE contacts (
id INTEGER PRIMARY KEY,
account_id INTEGER NOT NULL REFERENCES profile(id) ON DELETE CASCADE,
first_name TEXT NOT NULL,
last_name TEXT,
phone INTEGER NOT NULL,
photo_id INTEGER,
base_url TEXT,
base_raw_url TEXT,
update_time INTEGER NOT NULL DEFAULT 0
)
''';
static const _syncStateSchema = '''
CREATE TABLE sync_state (
account_id INTEGER NOT NULL REFERENCES profile(id) ON DELETE CASCADE,
@@ -179,6 +203,10 @@ class AppDatabase {
unread_count INTEGER NOT NULL DEFAULT 0,
last_event_time INTEGER NOT NULL DEFAULT 0,
cached_at INTEGER NOT NULL,
fav_index INTEGER,
dont_disturb_until INTEGER NOT NULL DEFAULT 0,
is_online INTEGER NOT NULL DEFAULT 0,
seen_time INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY (id, account_id)
)
''';
@@ -212,11 +240,7 @@ class AppDatabase {
static Future<ProfileData?> loadActiveProfile() async {
final db = await _instance;
final rows = await db.query(
'profile',
where: 'is_active = 1',
limit: 1,
);
final rows = await db.query('profile', where: 'is_active = 1', limit: 1);
if (rows.isEmpty) return null;
return ProfileData.fromDbRow(rows.first);
}
@@ -245,11 +269,11 @@ class AppDatabase {
String value,
) async {
final db = await _instance;
await db.insert(
'sync_state',
{'account_id': accountId, 'key': key, 'value': value},
conflictAlgorithm: ConflictAlgorithm.replace,
);
await db.insert('sync_state', {
'account_id': accountId,
'key': key,
'value': value,
}, conflictAlgorithm: ConflictAlgorithm.replace);
}
static Future<String?> getSyncValue(int accountId, String key) async {
@@ -281,13 +305,17 @@ class AppDatabase {
_db = null;
}
// Chats cache
// Chats cache
static Future<void> saveChats(List<Map<String, dynamic>> rows) async {
final db = await _instance;
final batch = db.batch();
for (final row in rows) {
batch.insert('chats_cache', row, conflictAlgorithm: ConflictAlgorithm.replace);
batch.insert(
'chats_cache',
row,
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
await batch.commit(noResult: true);
}
@@ -304,6 +332,32 @@ class AppDatabase {
static Future<void> clearChatsCache(int accountId) async {
final db = await _instance;
await db.delete('chats_cache', where: 'account_id = ?', whereArgs: [accountId]);
await db.delete(
'chats_cache',
where: 'account_id = ?',
whereArgs: [accountId],
);
}
static Future<void> saveContacts(List<Map<String, dynamic>> rows) async {
final db = await _instance;
final batch = db.batch();
for (final row in rows) {
batch.insert(
'contacts',
row,
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
await batch.commit(noResult: true);
}
static Future<List<Map<String, dynamic>>> loadContacts(int accountId) async {
final db = await _instance;
return db.query(
'contacts',
where: 'account_id = ?',
whereArgs: [accountId],
);
}
}
+21 -16
View File
@@ -1,27 +1,32 @@
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:shared_preferences/shared_preferences.dart';
class TokenStorage {
static const _tokenPrefix = 'auth_token_';
static const _activeAccountKey = 'active_account_id';
static const _storage = FlutterSecureStorage(
aOptions: AndroidOptions(encryptedSharedPreferences: true),
);
static Future<void> saveToken(String token, int accountId) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('$_tokenPrefix$accountId', token);
}
static Future<void> saveToken(String token, int accountId) =>
_storage.write(key: '$_tokenPrefix$accountId', value: token);
static Future<String?> readToken(int accountId) async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString('$_tokenPrefix$accountId');
}
static Future<String?> readToken(int accountId) =>
_storage.read(key: '$_tokenPrefix$accountId');
static Future<void> deleteToken(int accountId) async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove('$_tokenPrefix$accountId');
}
static Future<void> deleteToken(int accountId) =>
_storage.delete(key: '$_tokenPrefix$accountId');
static Future<void> setActiveAccount(int accountId) =>
_storage.write(key: _activeAccountKey, value: accountId.toString());
static Future<void> setActiveAccount(int accountId) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(_activeAccountKey, accountId.toString());
}
static Future<int?> getActiveAccountId() async {
final val = await _storage.read(key: _activeAccountKey);
final prefs = await SharedPreferences.getInstance();
final val = prefs.getString(_activeAccountKey);
return val != null ? int.tryParse(val) : null;
}
@@ -31,12 +36,12 @@ class TokenStorage {
return readToken(id);
}
/// Удаляет токен аккаунта и, если он был активным, сбрасывает активный аккаунт.
static Future<void> deleteAccount(int accountId) async {
await deleteToken(accountId);
final activeId = await getActiveAccountId();
if (activeId == accountId) {
await _storage.delete(key: _activeAccountKey);
final prefs = await SharedPreferences.getInstance();
await prefs.remove(_activeAccountKey);
}
}
}
+6 -3
View File
@@ -53,8 +53,9 @@ class PacketDispatcher {
if (packet.cmd == CmdType.ok ||
packet.cmd == CmdType.error ||
packet.cmd == CmdType.notFound) {
final status = packet.isOk ? 'OK' : packet.isError ? 'ERR' : 'NOT_FOUND';
logger.i('<= [$tag] seq=${packet.seq} $status\n payload: ${packet.payload}');
logger.i(
'<= {ver: ${packet.api}, cmd: ${packet.cmd}, seq: ${packet.seq}, opcode: ${packet.opcode}, payload: ${packet.payload}}',
);
final completer = _pendingRequests.remove(packet.seq);
_requestTimestamps.remove(packet.seq);
@@ -72,7 +73,9 @@ class PacketDispatcher {
completer.complete(packet);
}
} else if (packet.isPush) {
logger.i('<= push [$tag] ${packet.payload}');
logger.i(
'<= push {ver: ${packet.api}, cmd: ${packet.cmd}, seq: ${packet.seq}, opcode: ${packet.opcode}, payload: ${packet.payload}}',
);
_pushHandlers[packet.opcode]?.call(packet);
_pushController.add(packet);
}
+3 -2
View File
@@ -1,5 +1,4 @@
import '../protocol/packet.dart';
import '../protocol/opcode_map.dart';
import '../utils/logger.dart';
import 'connection.dart';
@@ -19,7 +18,9 @@ class PacketSender {
final seq = _nextSeq();
final data = packPacket(opcode, payload, seq: seq);
connection.write(data);
logger.i('=> [${Opcode.name(opcode)}] seq=$seq\n payload: $payload');
logger.i(
'=> {ver: 10, cmd: 0, seq: $seq, opcode: $opcode, payload: $payload}',
);
return seq;
}
}