feat(messages): unread badges + OS notification for private messages
Private messages (NIP-17) arrived in the foreground with no signal: no unread count, no badge, no OS notification. Hook both into the single InboxService.ingest choke point. - UnreadService: per-peer "last read" in the keystore (timestamps+pubkey only, no message text), live count via a changes stream, active-peer suppression so the open chat never badges or notifies. - UnreadBadge: reusable, RTL-aware (Flutter Badge) — on the home hamburger, the drawer "Chat" item, and per-conversation in the messages list. - Mark-read on chat open (ChatScreen). - NotificationService over flutter_local_notifications: generic "New message from <name>" (no message text, for privacy), payload = pubkey, tap opens /chat/:pubkey. No-op on web/Windows; Android POST_NOTIFICATIONS. - i18n notifications.newMessageFrom (en/es/pt/ast). Background/push stays out of scope (foreground-only by design). Tests: UnreadService, NotificationService (mock plugin), InboxService hooks (new peer notifies/counts; duplicate, own, and open-chat do not), and a UnreadBadge widget test. dart analyze clean; commons_core green.
This commit is contained in:
parent
4d110e8082
commit
d026376993
27 changed files with 1238 additions and 114 deletions
|
|
@ -75,6 +75,7 @@ class TranslationsAst extends Translations with BaseTranslations<AppLocale, Tran
|
|||
@override late final _Translations$chatList$ast chatList = _Translations$chatList$ast._(_root);
|
||||
@override late final _Translations$chat$ast chat = _Translations$chat$ast._(_root);
|
||||
@override late final _Translations$trust$ast trust = _Translations$trust$ast._(_root);
|
||||
@override late final _Translations$notifications$ast notifications = _Translations$notifications$ast._(_root);
|
||||
}
|
||||
|
||||
// Path: app
|
||||
|
|
@ -756,6 +757,16 @@ class _Translations$trust$ast extends Translations$trust$en {
|
|||
@override String get circle => 'Nel to círculu';
|
||||
}
|
||||
|
||||
// Path: notifications
|
||||
class _Translations$notifications$ast extends Translations$notifications$en {
|
||||
_Translations$notifications$ast._(TranslationsAst root) : this._root = root, super.internal(root);
|
||||
|
||||
final TranslationsAst _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String newMessageFrom({required Object name}) => 'Mensaxe nuevu de ${name}';
|
||||
}
|
||||
|
||||
// Path: intro.slides
|
||||
class _Translations$intro$slides$ast extends Translations$intro$slides$en {
|
||||
_Translations$intro$slides$ast._(TranslationsAst root) : this._root = root, super.internal(root);
|
||||
|
|
@ -1483,6 +1494,7 @@ extension on TranslationsAst {
|
|||
'trust.vouch' => 'Conozo a esta persona',
|
||||
'trust.vouched' => 'Avales a esta persona',
|
||||
'trust.circle' => 'Nel to círculu',
|
||||
'notifications.newMessageFrom' => ({required Object name}) => 'Mensaxe nuevu de ${name}',
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue