feat(block2): Ğ1 — publish a Ğ1 address + 'Pay in Ğ1' in chat (levels 1-2)
The optional Ğ1 (free currency) integration, per g1-integration.md. - Profile: an optional 'Ğ1 address' field, persisted locally and published in your NIP-01 kind:0 metadata (separate from the Nostr key). - commons_core: UserProfile/ProfileTransport carry a 'g1' field (round-trip tested). - Chat: when the peer published a Ğ1 address, a 'Pay in Ğ1' app-bar action opens their wallet (url_launcher) so value moves in the wallet, not the app — copies the address as a fallback. No payment rails in-app (sharing-model §4.3). NOTE (vjrj): the wallet deep-link uses the Cesium web wallet as a universal fallback; swap the URI in chat_screen._payG1 for the Ğ1nkgo/Ğecko scheme you prefer. Analyzer clean (both packages); profile transport test covers g1.
This commit is contained in:
parent
3067d9ca7f
commit
a9c6030dde
13 changed files with 138 additions and 14 deletions
|
|
@ -1,7 +1,9 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
import '../i18n/strings.g.dart';
|
||||
import '../services/message_store.dart';
|
||||
|
|
@ -45,6 +47,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||
TrustCubit? _trust;
|
||||
bool _loading = true;
|
||||
String? _peerName;
|
||||
String? _peerG1;
|
||||
final _input = TextEditingController();
|
||||
|
||||
@override
|
||||
|
|
@ -94,9 +97,15 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||
unawaited(() async {
|
||||
try {
|
||||
final profile = await live.profile.fetch(widget.peerPubkey);
|
||||
if (profile != null && profile.name.isNotEmpty && mounted) {
|
||||
await widget.profileCache!.setName(widget.peerPubkey, profile.name);
|
||||
setState(() => _peerName = profile.name);
|
||||
if (profile != null && mounted) {
|
||||
if (profile.name.isNotEmpty) {
|
||||
await widget.profileCache!
|
||||
.setName(widget.peerPubkey, profile.name);
|
||||
}
|
||||
setState(() {
|
||||
if (profile.name.isNotEmpty) _peerName = profile.name;
|
||||
if (profile.g1.isNotEmpty) _peerG1 = profile.g1;
|
||||
});
|
||||
}
|
||||
} catch (_) {
|
||||
// best effort
|
||||
|
|
@ -105,6 +114,30 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Opens the peer's Ğ1 wallet so you can pay them (Ğ1 is separate from the
|
||||
/// Nostr key — this uses the address they published in their profile). Falls
|
||||
/// back to copying the address if no wallet handles the link.
|
||||
///
|
||||
/// NOTE: confirm the deep-link scheme for the target wallet (Ğ1nkgo / Ğecko /
|
||||
/// Cesium) — this uses the Cesium web wallet as a universal fallback.
|
||||
Future<void> _payG1() async {
|
||||
final g1 = _peerG1;
|
||||
if (g1 == null) return;
|
||||
final messenger = ScaffoldMessenger.of(context);
|
||||
final t = context.t;
|
||||
final uri = Uri.parse('https://demo.cesium.app/#/app/wallet/$g1/');
|
||||
var launched = false;
|
||||
try {
|
||||
launched = await launchUrl(uri, mode: LaunchMode.externalApplication);
|
||||
} catch (_) {
|
||||
launched = false;
|
||||
}
|
||||
if (!launched && mounted) {
|
||||
await Clipboard.setData(ClipboardData(text: g1));
|
||||
messenger.showSnackBar(SnackBar(content: Text(t.chat.g1Copied)));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _send() async {
|
||||
final cubit = _messages;
|
||||
if (cubit == null || _input.text.trim().isEmpty) return;
|
||||
|
|
@ -126,9 +159,19 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||
Widget build(BuildContext context) {
|
||||
final messages = _messages;
|
||||
final trust = _trust;
|
||||
final t = context.t;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(_peerName ?? shortPubkey(widget.peerPubkey)),
|
||||
actions: [
|
||||
if (_peerG1 != null)
|
||||
IconButton(
|
||||
key: const Key('chat.payG1'),
|
||||
icon: const Icon(Icons.payments_outlined),
|
||||
tooltip: t.chat.payG1,
|
||||
onPressed: _payG1,
|
||||
),
|
||||
],
|
||||
),
|
||||
body: _loading || messages == null || trust == null
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue