fix: Уведомление приходит, хотя чат открыт. Нет зелёной точки «в сети» в списке чатов. Тап по уведомлению не открывает чат. Реакции на сторис. Пропали галочки в папке «Все».

This commit is contained in:
Jganenokk
2026-08-19 22:07:16 +07:00
parent 3e6254bc5d
commit 3e4edc535c
14 changed files with 461 additions and 360 deletions
+28 -1
View File
@@ -112,7 +112,10 @@ class ContactInfoFetch {
static void clear() => _cache.clear();
static void putContact(int id, Map<dynamic, dynamic> contact) {
_cache.putValue(id, ContactInfo.fromMap(Map<String, dynamic>.from(contact)));
_cache.putValue(
id,
ContactInfo.fromMap(Map<String, dynamic>.from(contact)),
);
}
static Future<Map<int, ContactInfo>> getMany(
@@ -243,19 +246,43 @@ class PresenceFetch {
if (missing.isNotEmpty) {
final fetched = await _fetchBatch(missing);
final now = DateTime.now();
var changed = false;
for (final id in missing) {
final value = fetched[id];
if (value != null) {
_cache.putValue(id, value, at: now);
_live[id] = value;
result[id] = value;
changed = true;
} else {
_cache.markFailed(id, at: now);
}
}
if (changed) revision.value++;
}
return result;
}
static const _batchSize = 100;
static Future<void> ensureFor(Iterable<int> ids) async {
final wanted = <int>{};
for (final id in ids) {
if (id <= 0) continue;
if (_cache.peek(id) != null) continue;
wanted.add(id);
}
if (wanted.isEmpty) return;
final list = wanted.toList();
for (var i = 0; i < list.length; i += _batchSize) {
final chunk = list.sublist(
i,
i + _batchSize > list.length ? list.length : i + _batchSize,
);
await getMany(chunk);
}
}
static Future<Map<int, Map<String, dynamic>>> _fetchBatch(
List<int> ids,
) async {
+113
View File
@@ -0,0 +1,113 @@
import 'dart:async';
import 'dart:io' show Platform;
import 'package:flutter/services.dart';
import '../../backend/api.dart';
import '../../frontend/widgets/max_link_nav.dart';
import '../../main.dart';
import '../utils/logger.dart';
class NotificationBridge {
NotificationBridge._();
static final NotificationBridge instance = NotificationBridge._();
static const _method = MethodChannel('ru.komet.app/notifications');
static const _events = EventChannel('ru.komet.app/notification_events');
static const _retryDelay = Duration(milliseconds: 300);
static const _maxRetries = 100;
bool _started = false;
bool _ready = false;
int _pendingChatId = 0;
int _activeChatId = 0;
int _retriesLeft = 0;
Timer? _retry;
bool get _android {
try {
return Platform.isAndroid;
} catch (_) {
return false;
}
}
void init() {
if (_started || !_android) return;
_started = true;
_events.receiveBroadcastStream().listen(
_onEvent,
onError: (e) => logger.w('NotificationBridge: events stream error: $e'),
);
api.stateStream.listen((state) {
if (state == SessionState.online) _flushPending();
});
}
void markReady() {
_ready = true;
_flushPending();
}
Future<void> checkInitialChat() async {
if (!_android) return;
try {
_onEvent(await _method.invokeMethod<dynamic>('consumeInitialChat'));
} catch (e) {
logger.w('NotificationBridge.checkInitialChat: $e');
}
}
Future<void> setActiveChat(int chatId) async {
if (!_android || chatId <= 0) return;
if (_activeChatId == chatId) return;
_activeChatId = chatId;
try {
await _method.invokeMethod<void>('setActiveChat', {'chatId': chatId});
} catch (e) {
logger.w('NotificationBridge.setActiveChat: $e');
}
}
Future<void> clearActiveChat(int chatId) async {
if (!_android) return;
if (chatId > 0 && _activeChatId != chatId) return;
_activeChatId = 0;
try {
await _method.invokeMethod<void>('clearActiveChat');
} catch (e) {
logger.w('NotificationBridge.clearActiveChat: $e');
}
}
void _onEvent(Object? event) {
final chatId = event is int ? event : int.tryParse(event?.toString() ?? '');
if (chatId == null || chatId <= 0) return;
_pendingChatId = chatId;
_retriesLeft = _maxRetries;
_flushPending();
}
void _flushPending() {
final chatId = _pendingChatId;
if (chatId <= 0) return;
final context = KometApp.navigatorKey.currentContext;
if (!_ready || context == null || api.state != SessionState.online) {
if (_retriesLeft <= 0) {
_pendingChatId = 0;
return;
}
_retriesLeft--;
_retry ??= Timer(_retryDelay, () {
_retry = null;
_flushPending();
});
return;
}
_pendingChatId = 0;
if (_activeChatId == chatId) return;
unawaited(openChatById(context, chatId));
}
}
+19
View File
@@ -847,6 +847,25 @@ class AppDatabase {
}
}
static Future<void> repairLastMessageSenders(int accountId) async {
try {
final db = await _instance;
await db.rawUpdate(
'UPDATE chats_cache SET last_msg_sender = ('
' SELECT m.sender_id FROM messages m'
' WHERE m.account_id = chats_cache.account_id'
' AND m.chat_id = chats_cache.id'
' AND m.id = CAST(chats_cache.last_msg_id AS TEXT)'
') '
'WHERE account_id = ? AND last_msg_sender IS NULL '
'AND last_msg_id IS NOT NULL',
[accountId],
);
} catch (e) {
logger.w('Не удалось восстановить отправителей последних сообщений: $e');
}
}
static Future<List<Map<String, dynamic>>> loadChat(
int accountId,
int chatId,