Comments and zaps fixes

This commit is contained in:
franzap
2025-12-13 12:02:38 -03:00
parent 13e05daa47
commit ecab49fcda
4 changed files with 35 additions and 35 deletions
-6
View File
@@ -12,11 +12,5 @@ const kFranzapPubkey =
/// Shareable identifier for the Nostr curation set
const kNostrCurationSetShareableId = '30267:$kFranzapPubkey:nostr';
/// Anonymous private key for error reporting and anonymous operations
/// This key is used when the user is not signed in
const kAnonymousPrivateKey =
'c86eda2daae768374526bc54903f388d9a866c00740ec8db418d7ef2dca77b5b';
/// Identifier for storing user bookmarks
const kAppBookmarksIdentifier = 'zapstore-bookmarks';
+7 -14
View File
@@ -7,8 +7,8 @@ import 'package:zapstore/utils/extensions.dart';
/// Service for reporting errors via NIP-44 encrypted DMs to Zapstore team.
///
/// Uses [kAnonymousPrivateKey] for signing so error reports can be sent
/// even when the user is not signed in.
/// Generates an ephemeral signer per report so errors can be sent even when
/// the user is not signed in.
class ErrorReportingService {
ErrorReportingService(this.ref);
@@ -31,8 +31,6 @@ class ErrorReportingService {
Future<void> reportError(Object exception, StackTrace? stackTrace) async {
// Don't report in debug mode
if (kDebugMode) {
debugPrint('Error (not reported in debug): $exception');
debugPrint('$stackTrace');
return;
}
@@ -50,8 +48,8 @@ class ErrorReportingService {
}
try {
// Create anonymous signer for error reporting
final signer = Bip340PrivateKeySigner(kAnonymousPrivateKey, ref);
// Create ephemeral signer for error reporting
final signer = Bip340PrivateKeySigner(Utils.generateRandomHex64(), ref);
await signer.signIn(setAsActive: false, registerSigner: false);
// Format error report
@@ -65,19 +63,15 @@ class ErrorReportingService {
// Sign and publish
final signedDm = await dm.signWith(signer);
await ref.read(storageNotifierProvider.notifier).publish(
{signedDm},
source: const RemoteSource(relays: 'social', stream: false),
);
await ref.read(storageNotifierProvider.notifier).publish({
signedDm,
}, source: const RemoteSource(relays: 'social', stream: false));
// Update rate limiting
_reportedErrors[errorHash] = DateTime.now();
_sessionReportCount++;
debugPrint('Error report sent successfully');
} catch (e) {
// Silently fail - we don't want error reporting to cause more errors
debugPrint('Failed to send error report: $e');
}
}
@@ -112,4 +106,3 @@ class ErrorReportingService {
final errorReportingServiceProvider = Provider<ErrorReportingService>(
ErrorReportingService.new,
);
+8 -6
View File
@@ -66,7 +66,8 @@ class CommentsSection extends ConsumerWidget {
context,
).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold),
),
if (comments.isNotEmpty) _CommentCountBadge(count: comments.length),
if (comments.isNotEmpty)
_CommentCountBadge(count: comments.length),
],
),
const SizedBox(height: 12),
@@ -80,7 +81,8 @@ class CommentsSection extends ConsumerWidget {
// Comments list - only when there are comments
if (comments.isNotEmpty) ...[
const SizedBox(height: 16),
...(comments.toList()..sort((a, b) => b.createdAt.compareTo(a.createdAt)))
...(comments.toList()
..sort((a, b) => b.createdAt.compareTo(a.createdAt)))
.map(
(comment) => Padding(
padding: const EdgeInsets.only(bottom: 16),
@@ -154,8 +156,8 @@ class _CommentCard extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final author = comment.author.value;
// Extract version from d tag (thread key)
final version = comment.event.getFirstTagValue('d');
// Extract version from v tag (per NIP-22 guidance)
final version = comment.event.getFirstTagValue('v');
return Card(
margin: EdgeInsets.zero,
@@ -408,8 +410,8 @@ class _CommentComposer extends HookConsumerWidget {
// No parentModel for root comments - only A/K/P tags, no e/k/p
);
// Add d tag as thread key (version)
comment.event.addTagValue('d', versionToComment);
// Add v tag for version (per NIP-22 guidance, not d tag)
comment.event.addTagValue('v', versionToComment);
final signedComment = await comment.signWith(signer);
+20 -9
View File
@@ -473,11 +473,11 @@ class ZapAmountDialog extends HookConsumerWidget {
try {
final navigator = Navigator.of(context);
// Prepare signer (anonymous if needed)
// Prepare signer (ephemeral if needed)
var signer = ref.read(Signer.activeSignerProvider);
if (signer == null) {
signer = Bip340PrivateKeySigner(
kAnonymousPrivateKey,
Utils.generateRandomHex64(),
ref.ref,
);
await signer.signIn(registerSigner: false);
@@ -489,6 +489,7 @@ class ZapAmountDialog extends HookConsumerWidget {
// Build zap request
final latestMetadata = app.latestFileMetadata;
final author = app.author.value;
if (latestMetadata == null || author == null) {
throw Exception(
'App or author not ready. Please try again.',
@@ -521,17 +522,24 @@ class ZapAmountDialog extends HookConsumerWidget {
// Fire payment in background - errors shown via ScaffoldMessenger
// ignore: unawaited_futures
_executeZapPayment(signedZapRequest, nwcString, ref.ref)
.catchError((Object e, StackTrace st) {
debugPrint('Zap payment failed: $e\n$st');
messenger?.showSnackBar(
_executeZapPayment(
signedZapRequest,
nwcString,
ref.ref,
).then(
(_) {},
onError: (Object e, StackTrace st) {
if (messenger != null) {
messenger.showSnackBar(
SnackBar(
content: Text('Zap failed: $e'),
backgroundColor: Colors.red,
duration: const Duration(seconds: 5),
),
);
return Future<PayInvoiceResult>.error(e, st);
});
}
},
);
} else {
final invoice = await signedZapRequest.getInvoice();
await Clipboard.setData(ClipboardData(text: invoice));
@@ -586,11 +594,14 @@ Future<PayInvoiceResult> _executeZapPayment(
) async {
final lightningInvoice = await signedZapRequest.getInvoice();
final command = PayInvoiceCommand(invoice: lightningInvoice);
return await command.execute(
final result = await command.execute(
connectionUri: nwcString,
ref: ref,
timeout: const Duration(seconds: 30),
);
return result;
}
/// Dialog for entering a custom zap amount