feat(block2): messaging UI — private 1:1 chat (NIP-17)
- MessagesCubit: 1:1 conversation over MessageTransport. Filters the shared inbox to the peer; tags our own sends with our pubkey (NIP-17 wraps don't come back to the sender) so the UI can align bubbles; degrades gracefully offline. - ChatScreen (mockup 10): message bubbles (mine right / peer left) + a composer; opens a session lazily, shows 'set up sharing' when there's no relay. - Entry point: a 'Message' button on each offer card (hidden on your own listings) → /chat/:pubkey. - Routing + i18n en/es/pt. Tests: 5 cubit (send/receive/order/filter/offline) + chat offline + market, green.
This commit is contained in:
parent
0dd7c28039
commit
efd64c4da4
13 changed files with 627 additions and 9 deletions
|
|
@ -342,6 +342,7 @@
|
|||
"searching": "Looking around your area…",
|
||||
"empty": "No seeds shared near you yet",
|
||||
"near": "Near you",
|
||||
"contact": "Message",
|
||||
"configTitle": "Sharing setup",
|
||||
"setupIntro": "Sharing with people nearby is optional. To turn it on, set your rough area and join a community you trust — a seed network or collective that runs a shared meeting point for passing messages. No company in the middle.",
|
||||
"areaLabel": "Your area",
|
||||
|
|
@ -358,5 +359,12 @@
|
|||
"useLocation": "Use my approximate location",
|
||||
"locationFailed": "Couldn't get your location",
|
||||
"queued": "Saved — we'll share these when you're connected"
|
||||
},
|
||||
"chat": {
|
||||
"title": "Chat",
|
||||
"hint": "Write a message…",
|
||||
"send": "Send",
|
||||
"empty": "No messages yet — say hello",
|
||||
"offline": "Set up sharing to send messages"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -342,6 +342,7 @@
|
|||
"searching": "Buscando por tu zona…",
|
||||
"empty": "Aún no hay semillas compartidas cerca de ti",
|
||||
"near": "Cerca de ti",
|
||||
"contact": "Mensaje",
|
||||
"configTitle": "Configuración de compartir",
|
||||
"setupIntro": "Compartir con gente cercana es opcional. Para activarlo, indica tu zona aproximada y únete a una comunidad de confianza — una red de semillas o un colectivo que mantiene un punto de encuentro compartido para pasar mensajes. Sin ninguna empresa en medio.",
|
||||
"areaLabel": "Tu zona",
|
||||
|
|
@ -358,5 +359,12 @@
|
|||
"useLocation": "Usar mi ubicación aproximada",
|
||||
"locationFailed": "No se pudo obtener tu ubicación",
|
||||
"queued": "Guardado — las compartiremos cuando tengas conexión"
|
||||
},
|
||||
"chat": {
|
||||
"title": "Chat",
|
||||
"hint": "Escribe un mensaje…",
|
||||
"send": "Enviar",
|
||||
"empty": "Aún no hay mensajes — saluda",
|
||||
"offline": "Configura el compartir para enviar mensajes"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -338,6 +338,7 @@
|
|||
"searching": "A procurar pela tua zona…",
|
||||
"empty": "Ainda não há sementes partilhadas perto de ti",
|
||||
"near": "Perto de ti",
|
||||
"contact": "Mensagem",
|
||||
"configTitle": "Configuração de partilha",
|
||||
"setupIntro": "Partilhar com pessoas por perto é opcional. Para ativar, indica a tua zona aproximada e junta-te a uma comunidade de confiança — uma rede de sementes ou um coletivo que mantém um ponto de encontro partilhado para passar mensagens. Sem nenhuma empresa no meio.",
|
||||
"areaLabel": "A tua zona",
|
||||
|
|
@ -354,5 +355,12 @@
|
|||
"useLocation": "Usar a minha localização aproximada",
|
||||
"locationFailed": "Não foi possível obter a tua localização",
|
||||
"queued": "Guardado — vamos partilhá-las quando tiveres ligação"
|
||||
},
|
||||
"chat": {
|
||||
"title": "Conversa",
|
||||
"hint": "Escreve uma mensagem…",
|
||||
"send": "Enviar",
|
||||
"empty": "Ainda não há mensagens — diz olá",
|
||||
"offline": "Configura a partilha para enviar mensagens"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
/// To regenerate, run: `dart run slang`
|
||||
///
|
||||
/// Locales: 3
|
||||
/// Strings: 956 (318 per locale)
|
||||
/// Strings: 974 (324 per locale)
|
||||
///
|
||||
/// Built on 2026-07-10 at 08:49 UTC
|
||||
/// Built on 2026-07-10 at 08:58 UTC
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint, unused_import
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ class Translations with BaseTranslations<AppLocale, Translations> {
|
|||
late final Translations$desiccant$en desiccant = Translations$desiccant$en.internal(_root);
|
||||
late final Translations$unit$en unit = Translations$unit$en.internal(_root);
|
||||
late final Translations$market$en market = Translations$market$en.internal(_root);
|
||||
late final Translations$chat$en chat = Translations$chat$en.internal(_root);
|
||||
}
|
||||
|
||||
// Path: app
|
||||
|
|
@ -1085,6 +1086,9 @@ class Translations$market$en {
|
|||
/// en: 'Near you'
|
||||
String get near => 'Near you';
|
||||
|
||||
/// en: 'Message'
|
||||
String get contact => 'Message';
|
||||
|
||||
/// en: 'Sharing setup'
|
||||
String get configTitle => 'Sharing setup';
|
||||
|
||||
|
|
@ -1134,6 +1138,30 @@ class Translations$market$en {
|
|||
String get queued => 'Saved — we\'ll share these when you\'re connected';
|
||||
}
|
||||
|
||||
// Path: chat
|
||||
class Translations$chat$en {
|
||||
Translations$chat$en.internal(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Chat'
|
||||
String get title => 'Chat';
|
||||
|
||||
/// en: 'Write a message…'
|
||||
String get hint => 'Write a message…';
|
||||
|
||||
/// en: 'Send'
|
||||
String get send => 'Send';
|
||||
|
||||
/// en: 'No messages yet — say hello'
|
||||
String get empty => 'No messages yet — say hello';
|
||||
|
||||
/// en: 'Set up sharing to send messages'
|
||||
String get offline => 'Set up sharing to send messages';
|
||||
}
|
||||
|
||||
// Path: intro.slides
|
||||
class Translations$intro$slides$en {
|
||||
Translations$intro$slides$en.internal(this._root);
|
||||
|
|
@ -1895,6 +1923,7 @@ extension on Translations {
|
|||
'market.searching' => 'Looking around your area…',
|
||||
'market.empty' => 'No seeds shared near you yet',
|
||||
'market.near' => 'Near you',
|
||||
'market.contact' => 'Message',
|
||||
'market.configTitle' => 'Sharing setup',
|
||||
'market.setupIntro' => 'Sharing with people nearby is optional. To turn it on, set your rough area and join a community you trust — a seed network or collective that runs a shared meeting point for passing messages. No company in the middle.',
|
||||
'market.areaLabel' => 'Your area',
|
||||
|
|
@ -1911,6 +1940,11 @@ extension on Translations {
|
|||
'market.useLocation' => 'Use my approximate location',
|
||||
'market.locationFailed' => 'Couldn\'t get your location',
|
||||
'market.queued' => 'Saved — we\'ll share these when you\'re connected',
|
||||
'chat.title' => 'Chat',
|
||||
'chat.hint' => 'Write a message…',
|
||||
'chat.send' => 'Send',
|
||||
'chat.empty' => 'No messages yet — say hello',
|
||||
'chat.offline' => 'Set up sharing to send messages',
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ class TranslationsEs extends Translations with BaseTranslations<AppLocale, Trans
|
|||
@override late final _Translations$desiccant$es desiccant = _Translations$desiccant$es._(_root);
|
||||
@override late final _Translations$unit$es unit = _Translations$unit$es._(_root);
|
||||
@override late final _Translations$market$es market = _Translations$market$es._(_root);
|
||||
@override late final _Translations$chat$es chat = _Translations$chat$es._(_root);
|
||||
}
|
||||
|
||||
// Path: app
|
||||
|
|
@ -612,6 +613,7 @@ class _Translations$market$es extends Translations$market$en {
|
|||
@override String get searching => 'Buscando por tu zona…';
|
||||
@override String get empty => 'Aún no hay semillas compartidas cerca de ti';
|
||||
@override String get near => 'Cerca de ti';
|
||||
@override String get contact => 'Mensaje';
|
||||
@override String get configTitle => 'Configuración de compartir';
|
||||
@override String get setupIntro => 'Compartir con gente cercana es opcional. Para activarlo, indica tu zona aproximada y únete a una comunidad de confianza — una red de semillas o un colectivo que mantiene un punto de encuentro compartido para pasar mensajes. Sin ninguna empresa en medio.';
|
||||
@override String get areaLabel => 'Tu zona';
|
||||
|
|
@ -630,6 +632,20 @@ class _Translations$market$es extends Translations$market$en {
|
|||
@override String get queued => 'Guardado — las compartiremos cuando tengas conexión';
|
||||
}
|
||||
|
||||
// Path: chat
|
||||
class _Translations$chat$es extends Translations$chat$en {
|
||||
_Translations$chat$es._(TranslationsEs root) : this._root = root, super.internal(root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get title => 'Chat';
|
||||
@override String get hint => 'Escribe un mensaje…';
|
||||
@override String get send => 'Enviar';
|
||||
@override String get empty => 'Aún no hay mensajes — saluda';
|
||||
@override String get offline => 'Configura el compartir para enviar mensajes';
|
||||
}
|
||||
|
||||
// Path: intro.slides
|
||||
class _Translations$intro$slides$es extends Translations$intro$slides$en {
|
||||
_Translations$intro$slides$es._(TranslationsEs root) : this._root = root, super.internal(root);
|
||||
|
|
@ -1275,6 +1291,7 @@ extension on TranslationsEs {
|
|||
'market.searching' => 'Buscando por tu zona…',
|
||||
'market.empty' => 'Aún no hay semillas compartidas cerca de ti',
|
||||
'market.near' => 'Cerca de ti',
|
||||
'market.contact' => 'Mensaje',
|
||||
'market.configTitle' => 'Configuración de compartir',
|
||||
'market.setupIntro' => 'Compartir con gente cercana es opcional. Para activarlo, indica tu zona aproximada y únete a una comunidad de confianza — una red de semillas o un colectivo que mantiene un punto de encuentro compartido para pasar mensajes. Sin ninguna empresa en medio.',
|
||||
'market.areaLabel' => 'Tu zona',
|
||||
|
|
@ -1291,6 +1308,11 @@ extension on TranslationsEs {
|
|||
'market.useLocation' => 'Usar mi ubicación aproximada',
|
||||
'market.locationFailed' => 'No se pudo obtener tu ubicación',
|
||||
'market.queued' => 'Guardado — las compartiremos cuando tengas conexión',
|
||||
'chat.title' => 'Chat',
|
||||
'chat.hint' => 'Escribe un mensaje…',
|
||||
'chat.send' => 'Enviar',
|
||||
'chat.empty' => 'Aún no hay mensajes — saluda',
|
||||
'chat.offline' => 'Configura el compartir para enviar mensajes',
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ class TranslationsPt extends Translations with BaseTranslations<AppLocale, Trans
|
|||
@override late final _Translations$desiccant$pt desiccant = _Translations$desiccant$pt._(_root);
|
||||
@override late final _Translations$unit$pt unit = _Translations$unit$pt._(_root);
|
||||
@override late final _Translations$market$pt market = _Translations$market$pt._(_root);
|
||||
@override late final _Translations$chat$pt chat = _Translations$chat$pt._(_root);
|
||||
}
|
||||
|
||||
// Path: app
|
||||
|
|
@ -608,6 +609,7 @@ class _Translations$market$pt extends Translations$market$en {
|
|||
@override String get searching => 'A procurar pela tua zona…';
|
||||
@override String get empty => 'Ainda não há sementes partilhadas perto de ti';
|
||||
@override String get near => 'Perto de ti';
|
||||
@override String get contact => 'Mensagem';
|
||||
@override String get configTitle => 'Configuração de partilha';
|
||||
@override String get setupIntro => 'Partilhar com pessoas por perto é opcional. Para ativar, indica a tua zona aproximada e junta-te a uma comunidade de confiança — uma rede de sementes ou um coletivo que mantém um ponto de encontro partilhado para passar mensagens. Sem nenhuma empresa no meio.';
|
||||
@override String get areaLabel => 'A tua zona';
|
||||
|
|
@ -626,6 +628,20 @@ class _Translations$market$pt extends Translations$market$en {
|
|||
@override String get queued => 'Guardado — vamos partilhá-las quando tiveres ligação';
|
||||
}
|
||||
|
||||
// Path: chat
|
||||
class _Translations$chat$pt extends Translations$chat$en {
|
||||
_Translations$chat$pt._(TranslationsPt root) : this._root = root, super.internal(root);
|
||||
|
||||
final TranslationsPt _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get title => 'Conversa';
|
||||
@override String get hint => 'Escreve uma mensagem…';
|
||||
@override String get send => 'Enviar';
|
||||
@override String get empty => 'Ainda não há mensagens — diz olá';
|
||||
@override String get offline => 'Configura a partilha para enviar mensagens';
|
||||
}
|
||||
|
||||
// Path: intro.slides
|
||||
class _Translations$intro$slides$pt extends Translations$intro$slides$en {
|
||||
_Translations$intro$slides$pt._(TranslationsPt root) : this._root = root, super.internal(root);
|
||||
|
|
@ -1267,6 +1283,7 @@ extension on TranslationsPt {
|
|||
'market.searching' => 'A procurar pela tua zona…',
|
||||
'market.empty' => 'Ainda não há sementes partilhadas perto de ti',
|
||||
'market.near' => 'Perto de ti',
|
||||
'market.contact' => 'Mensagem',
|
||||
'market.configTitle' => 'Configuração de partilha',
|
||||
'market.setupIntro' => 'Partilhar com pessoas por perto é opcional. Para ativar, indica a tua zona aproximada e junta-te a uma comunidade de confiança — uma rede de sementes ou um coletivo que mantém um ponto de encontro partilhado para passar mensagens. Sem nenhuma empresa no meio.',
|
||||
'market.areaLabel' => 'A tua zona',
|
||||
|
|
@ -1283,6 +1300,11 @@ extension on TranslationsPt {
|
|||
'market.useLocation' => 'Usar a minha localização aproximada',
|
||||
'market.locationFailed' => 'Não foi possível obter a tua localização',
|
||||
'market.queued' => 'Guardado — vamos partilhá-las quando tiveres ligação',
|
||||
'chat.title' => 'Conversa',
|
||||
'chat.hint' => 'Escreve uma mensagem…',
|
||||
'chat.send' => 'Enviar',
|
||||
'chat.empty' => 'Ainda não há mensagens — diz olá',
|
||||
'chat.offline' => 'Configura a partilha para enviar mensagens',
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue