/// 分享二维码对话框(P3 计划 Task 4)。 /// /// viewer 链接构造:`{VIEWER_BASE}/a/{publicToken}`([ApiConfig. /// viewerAlbumUrl],VIEWER_BASE 经 --dart-define 覆盖,dev=模拟器宿主 /// 回环 5175)。QrImageView 渲染链接 + 链接文本可长按选中 + 一键复制。 /// /// 用 [Dialog] 而非 [AlertDialog]:AlertDialog 内容经 IntrinsicWidth /// 测量,而 QrImageView 内部使用 LayoutBuilder(不支持 intrinsic 计算) /// 会抛布局断言,普通 Dialog 无此路径。 library; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:qr_flutter/qr_flutter.dart'; import '../core/config.dart'; import '../l10n/app_localizations.dart'; /// 观众分享二维码对话框([publicToken] 来自相册详情)。 class ShareQrDialog extends StatelessWidget { const ShareQrDialog({required this.publicToken, super.key}); final String publicToken; Future _copy(BuildContext context, String url) async { await Clipboard.setData(ClipboardData(text: url)); if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(AppLocalizations.of(context).copiedToClipboard), ), ); } @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context); final theme = Theme.of(context); final url = ApiConfig.viewerAlbumUrl(publicToken); return Dialog( child: Padding( padding: const EdgeInsets.all(20), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( l10n.shareQrTitle, style: theme.textTheme.titleMedium ?.copyWith(fontWeight: FontWeight.w600), textAlign: TextAlign.center, ), const SizedBox(height: 16), Center( // 白底保证暗色主题下的扫码对比度。 child: Container( color: Colors.white, padding: const EdgeInsets.all(8), child: QrImageView( data: url, version: QrVersions.auto, size: 216, backgroundColor: Colors.white, ), ), ), const SizedBox(height: 12), SelectableText( url, textAlign: TextAlign.center, style: theme.textTheme.bodySmall, ), const SizedBox(height: 8), Text( l10n.qrHint, textAlign: TextAlign.center, style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.onSurfaceVariant, ), ), const SizedBox(height: 12), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ TextButton.icon( onPressed: () => _copy(context, url), icon: const Icon(Icons.copy_outlined), label: Text(l10n.copyLink), ), TextButton( onPressed: () => Navigator.of(context).pop(), child: Text(l10n.ok), ), ], ), ], ), ), ); } }