mirror of
https://github.com/zapstore/zapstore.git
synced 2026-10-05 12:38:24 +00:00
Toasts: add technical details besides description, and remove confirmations of copying to clipboard
This commit is contained in:
@@ -645,7 +645,7 @@ class _AppDetailContent extends HookConsumerWidget {
|
||||
SharePlus.instance.share(ShareParams(text: shareUrl));
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
context.showError('Failed to share app', description: '$e');
|
||||
context.showError('Failed to share app', technicalDetails: '$e');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -654,10 +654,9 @@ class _AppDetailContent extends HookConsumerWidget {
|
||||
try {
|
||||
final shareUrl = _getAppUrl(app);
|
||||
Clipboard.setData(ClipboardData(text: shareUrl));
|
||||
context.showInfo('Link copied to clipboard');
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
context.showError('Failed to copy link', description: '$e');
|
||||
context.showError('Failed to copy link', technicalDetails: '$e');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -709,7 +708,8 @@ class _AppDetailContent extends HookConsumerWidget {
|
||||
context.showError(
|
||||
'Could not read existing saved apps',
|
||||
description:
|
||||
'Your previous saved apps could not be decrypted. Starting fresh.\n\n$e',
|
||||
'Your previous saved apps could not be decrypted. Starting fresh.',
|
||||
technicalDetails: '$e',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -752,7 +752,7 @@ class _AppDetailContent extends HookConsumerWidget {
|
||||
}
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
context.showError('Failed to update bookmark', description: '$e');
|
||||
context.showError('Failed to update bookmark', technicalDetails: '$e');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -776,7 +776,7 @@ class _AppDetailContent extends HookConsumerWidget {
|
||||
}
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
context.showError('Failed to open browser', description: '$e');
|
||||
context.showError('Failed to open browser', technicalDetails: '$e');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -790,7 +790,8 @@ class _AppDetailContent extends HookConsumerWidget {
|
||||
context.showError(
|
||||
'Failed to launch ${app.name ?? app.identifier}',
|
||||
description:
|
||||
'The app may have been uninstalled or moved. Try reinstalling.\n\n$e',
|
||||
'The app may have been uninstalled or moved. Try reinstalling.',
|
||||
technicalDetails: '$e',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -808,7 +809,7 @@ class _AppDetailContent extends HookConsumerWidget {
|
||||
// Don't show error for user cancellation
|
||||
final message = e.toString();
|
||||
if (!message.contains('cancelled')) {
|
||||
context.showError('Uninstall failed', description: '$e');
|
||||
context.showError('Uninstall failed', technicalDetails: '$e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ class _AuthenticationSection extends ConsumerWidget {
|
||||
pubkey: pubkey,
|
||||
profile: profile,
|
||||
avatarRadius: 32,
|
||||
onCopiedNpub: () => context.showInfo('Copied npub to clipboard'),
|
||||
onCopiedNpub: null,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// Profile bio with NoteParser (non-interactive)
|
||||
@@ -250,7 +250,7 @@ class _AuthenticationSection extends ConsumerWidget {
|
||||
await ref.read(amberSignerProvider).signOut();
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
context.showError('Sign out failed', description: '$e');
|
||||
context.showError('Sign out failed', technicalDetails: '$e');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1083,11 +1083,6 @@ class _DebugMessagesSection extends HookConsumerWidget {
|
||||
constraints: const BoxConstraints(),
|
||||
onPressed: () {
|
||||
Clipboard.setData(ClipboardData(text: req));
|
||||
context.showInfo(
|
||||
'REQ filter copied',
|
||||
description:
|
||||
'Paste into a Nostr client to debug this query.',
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
@@ -1455,7 +1450,7 @@ class _DataManagementSection extends ConsumerWidget {
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
context.showError('Restart failed', description: e.toString());
|
||||
context.showError('Restart failed', technicalDetails: e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,7 +549,7 @@ class _RepublishStacksButton extends HookConsumerWidget {
|
||||
if (context.mounted) {
|
||||
context.showError(
|
||||
'Failed to republish stacks',
|
||||
description: '$e',
|
||||
technicalDetails: '$e',
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
|
||||
@@ -11,6 +11,7 @@ extension ContextX on BuildContext {
|
||||
void showInfo(
|
||||
String title, {
|
||||
String? description,
|
||||
String? technicalDetails,
|
||||
IconData? icon,
|
||||
List<(String, Future<void> Function())> actions = const [],
|
||||
}) {
|
||||
@@ -18,6 +19,7 @@ extension ContextX on BuildContext {
|
||||
context: this,
|
||||
title: title,
|
||||
description: description,
|
||||
technicalDetails: technicalDetails,
|
||||
icon: icon ?? Icons.info_outline_rounded,
|
||||
type: _ToastType.info,
|
||||
actions: actions,
|
||||
@@ -27,6 +29,7 @@ extension ContextX on BuildContext {
|
||||
void showError(
|
||||
String title, {
|
||||
String? description,
|
||||
String? technicalDetails,
|
||||
IconData? icon,
|
||||
List<(String, Future<void> Function())> actions = const [],
|
||||
}) {
|
||||
@@ -34,6 +37,7 @@ extension ContextX on BuildContext {
|
||||
context: this,
|
||||
title: title,
|
||||
description: description,
|
||||
technicalDetails: technicalDetails,
|
||||
icon: icon ?? Icons.error_outline_rounded,
|
||||
type: _ToastType.error,
|
||||
actions: actions,
|
||||
@@ -49,6 +53,7 @@ void _showCustomToast({
|
||||
required BuildContext context,
|
||||
required String title,
|
||||
String? description,
|
||||
String? technicalDetails,
|
||||
required IconData icon,
|
||||
required _ToastType type,
|
||||
List<(String, Future<void> Function())> actions = const [],
|
||||
@@ -66,6 +71,7 @@ void _showCustomToast({
|
||||
builder: (context) => _ToastOverlay(
|
||||
title: title,
|
||||
description: description,
|
||||
technicalDetails: technicalDetails,
|
||||
icon: icon,
|
||||
type: type,
|
||||
actions: actions,
|
||||
@@ -83,6 +89,7 @@ void _showCustomToast({
|
||||
class _ToastOverlay extends HookWidget {
|
||||
final String title;
|
||||
final String? description;
|
||||
final String? technicalDetails;
|
||||
final IconData icon;
|
||||
final _ToastType type;
|
||||
final List<(String, Future<void> Function())> actions;
|
||||
@@ -91,6 +98,7 @@ class _ToastOverlay extends HookWidget {
|
||||
const _ToastOverlay({
|
||||
required this.title,
|
||||
this.description,
|
||||
this.technicalDetails,
|
||||
required this.icon,
|
||||
required this.type,
|
||||
required this.actions,
|
||||
@@ -233,6 +241,7 @@ class _ToastOverlay extends HookWidget {
|
||||
accentColor: accentColor,
|
||||
title: title,
|
||||
description: description,
|
||||
technicalDetails: technicalDetails,
|
||||
actions: actions,
|
||||
onDismiss: dismiss,
|
||||
),
|
||||
@@ -257,6 +266,7 @@ class _ToastContent extends HookWidget {
|
||||
final Color accentColor;
|
||||
final String title;
|
||||
final String? description;
|
||||
final String? technicalDetails;
|
||||
final List<(String, Future<void> Function())> actions;
|
||||
final VoidCallback onDismiss;
|
||||
|
||||
@@ -266,6 +276,7 @@ class _ToastContent extends HookWidget {
|
||||
required this.accentColor,
|
||||
required this.title,
|
||||
this.description,
|
||||
this.technicalDetails,
|
||||
required this.actions,
|
||||
required this.onDismiss,
|
||||
});
|
||||
@@ -275,8 +286,10 @@ class _ToastContent extends HookWidget {
|
||||
final detailsExpanded = useState(false);
|
||||
|
||||
final hasDescription = description != null && description!.isNotEmpty;
|
||||
final hasTechnicalDetails =
|
||||
technicalDetails != null && technicalDetails!.isNotEmpty;
|
||||
final hasActions = actions.isNotEmpty;
|
||||
final hasExtraContent = hasDescription || hasActions;
|
||||
final hasExtraContent = hasDescription || hasTechnicalDetails || hasActions;
|
||||
|
||||
// Use Stack to position X at top-right always
|
||||
return Stack(
|
||||
@@ -318,8 +331,22 @@ class _ToastContent extends HookWidget {
|
||||
height: 1.35,
|
||||
),
|
||||
),
|
||||
// Expandable technical details
|
||||
// Inline description (always visible)
|
||||
if (hasDescription) ...[
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
description!,
|
||||
style: TextStyle(
|
||||
fontFamily: kFontFamily,
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Colors.white.withValues(alpha: 0.85),
|
||||
height: 1.35,
|
||||
),
|
||||
),
|
||||
],
|
||||
// Expandable technical details
|
||||
if (hasTechnicalDetails) ...[
|
||||
const SizedBox(height: 8),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
@@ -348,7 +375,7 @@ class _ToastContent extends HookWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
// Expanded description
|
||||
// Expanded technical details
|
||||
if (detailsExpanded.value) ...[
|
||||
const SizedBox(height: 6),
|
||||
Container(
|
||||
@@ -358,7 +385,7 @@ class _ToastContent extends HookWidget {
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: SelectableText(
|
||||
description!,
|
||||
technicalDetails!,
|
||||
style: TextStyle(
|
||||
fontFamily: 'monospace',
|
||||
fontSize: 11,
|
||||
|
||||
@@ -257,7 +257,7 @@ class SocialActionsRow extends HookConsumerWidget {
|
||||
}
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
context.showError('Failed to save app', description: '$e');
|
||||
context.showError('Failed to save app', technicalDetails: '$e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import 'package:models/models.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:zapstore/utils/extensions.dart';
|
||||
import 'package:zapstore/widgets/download_text_container.dart';
|
||||
import 'package:zapstore/services/notification_service.dart';
|
||||
import 'package:zapstore/theme.dart';
|
||||
|
||||
class AppInfoTable extends HookConsumerWidget {
|
||||
@@ -313,7 +312,6 @@ class _InfoRow extends StatelessWidget {
|
||||
),
|
||||
onPressed: () {
|
||||
Clipboard.setData(ClipboardData(text: copyValue!));
|
||||
context.showInfo('Copied to clipboard');
|
||||
},
|
||||
),
|
||||
],
|
||||
|
||||
@@ -46,7 +46,8 @@ class SignInPrompt extends HookConsumerWidget {
|
||||
context.showError(
|
||||
'Sign-in failed',
|
||||
description:
|
||||
'Amber could not complete the sign-in. Make sure Amber is installed and try again.\n\n$e',
|
||||
'Amber could not complete the sign-in. Make sure Amber is installed and try again.',
|
||||
technicalDetails: '$e',
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
|
||||
@@ -132,7 +132,8 @@ class SaveAppDialog extends HookConsumerWidget {
|
||||
context.showError(
|
||||
'Could not read existing saved apps',
|
||||
description:
|
||||
'Your previous saved apps could not be decrypted. Starting fresh.\n\n$e',
|
||||
'Your previous saved apps could not be decrypted. Starting fresh.',
|
||||
technicalDetails: '$e',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -176,7 +177,7 @@ class SaveAppDialog extends HookConsumerWidget {
|
||||
}
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
context.showError('Failed to update bookmark', description: '$e');
|
||||
context.showError('Failed to update bookmark', technicalDetails: '$e');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -695,7 +696,7 @@ class _AddToStackDialogSignedIn extends HookConsumerWidget {
|
||||
}
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
context.showError('Failed to save', description: '$e');
|
||||
context.showError('Failed to save', technicalDetails: '$e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -683,7 +683,7 @@ class _CommentComposer extends HookConsumerWidget {
|
||||
}
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
context.showError('Failed to post comment', description: '$e');
|
||||
context.showError('Failed to post comment', technicalDetails: '$e');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -895,7 +895,7 @@ class _ReplyComposer extends HookConsumerWidget {
|
||||
}
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
context.showError('Failed to post reply', description: '$e');
|
||||
context.showError('Failed to post reply', technicalDetails: '$e');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1025,7 +1025,7 @@ class _StackCommentComposer extends HookConsumerWidget {
|
||||
}
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
context.showError('Failed to post comment', description: '$e');
|
||||
context.showError('Failed to post comment', technicalDetails: '$e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -609,7 +609,8 @@ class InstallButton extends ConsumerWidget {
|
||||
if (!context.mounted) return;
|
||||
context.showError(
|
||||
'Failed to launch ${app.name ?? app.identifier}',
|
||||
description: 'The app may have been uninstalled or moved.\n\n$e',
|
||||
description: 'The app may have been uninstalled or moved.',
|
||||
technicalDetails: '$e',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -622,7 +623,7 @@ class InstallButton extends ConsumerWidget {
|
||||
if (context.mounted) {
|
||||
final errorMessage = e.toString();
|
||||
if (!errorMessage.contains('cancelled')) {
|
||||
context.showError('Uninstall failed', description: errorMessage);
|
||||
context.showError('Uninstall failed', technicalDetails: errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -657,19 +658,12 @@ class InstallButton extends ConsumerWidget {
|
||||
|
||||
context.showError(
|
||||
operation.message,
|
||||
description: operation.description,
|
||||
technicalDetails: operation.description,
|
||||
actions: [
|
||||
(
|
||||
'Copy',
|
||||
() async {
|
||||
await Clipboard.setData(ClipboardData(text: errorText));
|
||||
if (context.mounted) {
|
||||
context.showInfo(
|
||||
'Copied to clipboard',
|
||||
description:
|
||||
'Share on nostr or the zapstore Signal support group.',
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
@@ -768,7 +762,7 @@ class InstallButton extends ConsumerWidget {
|
||||
} catch (e) {
|
||||
final errorMessage = e.toString();
|
||||
if (context.mounted && !errorMessage.contains('cancelled')) {
|
||||
context.showError('Update failed', description: errorMessage);
|
||||
context.showError('Update failed', technicalDetails: errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -816,7 +810,6 @@ class InstallButton extends ConsumerWidget {
|
||||
tooltip: 'Copy certificate hash',
|
||||
onPressed: () {
|
||||
Clipboard.setData(ClipboardData(text: hash));
|
||||
context.showInfo('Copied $tooltipText');
|
||||
},
|
||||
),
|
||||
],
|
||||
|
||||
@@ -206,7 +206,7 @@ class NWCConnectionCard extends HookConsumerWidget {
|
||||
}
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
context.showError('Failed to disconnect wallet', description: '$e');
|
||||
context.showError('Failed to disconnect wallet', technicalDetails: '$e');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -337,7 +337,8 @@ class NWCConnectionDialog extends HookWidget {
|
||||
context.showError(
|
||||
'Wallet connection failed',
|
||||
description:
|
||||
'Could not connect to the wallet. Verify the connection string and try again.\n\n$e',
|
||||
'Could not connect to the wallet. Verify the connection string and try again.',
|
||||
technicalDetails: '$e',
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
|
||||
@@ -177,7 +177,7 @@ class RelayManagementCard extends HookConsumerWidget {
|
||||
if (context.mounted) {
|
||||
context.showError(
|
||||
'Failed to apply relay changes',
|
||||
description: '$e',
|
||||
technicalDetails: '$e',
|
||||
actions: [('Retry', () => applyChanges())],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ class SignInButton extends ConsumerWidget {
|
||||
await onSignInSuccess(ref.read(refProvider));
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
context.showError('Sign-in failed: $e');
|
||||
context.showError('Sign-in failed', technicalDetails: '$e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -500,14 +500,14 @@ class ZapAmountDialog extends HookConsumerWidget {
|
||||
if (toastContext != null && toastContext.mounted) {
|
||||
toastContext.showError(
|
||||
'Zap failed',
|
||||
description: '$e',
|
||||
technicalDetails: '$e',
|
||||
);
|
||||
}
|
||||
}
|
||||
}());
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
context.showError('Zap failed', description: '$e');
|
||||
context.showError('Zap failed', technicalDetails: '$e');
|
||||
Navigator.of(context).pop(false);
|
||||
}
|
||||
}
|
||||
@@ -696,7 +696,7 @@ class NWCZapDialog extends HookConsumerWidget {
|
||||
}
|
||||
} catch (e) {
|
||||
if (toastContext != null && toastContext.mounted) {
|
||||
toastContext.showError('Zap failed', description: '$e');
|
||||
toastContext.showError('Zap failed', technicalDetails: '$e');
|
||||
}
|
||||
}
|
||||
}());
|
||||
|
||||
Reference in New Issue
Block a user