102 lines
3.4 KiB
Dart
102 lines
3.4 KiB
Dart
|
|
/// 分享二维码对话框(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<void> _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),
|
|||
|
|
),
|
|||
|
|
],
|
|||
|
|
),
|
|||
|
|
],
|
|||
|
|
),
|
|||
|
|
),
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
}
|