453 lines
14 KiB
Dart
453 lines
14 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:receive_sharing_intent/receive_sharing_intent.dart';
|
|
import '../../core/utils/logger.dart';
|
|
import '../providers/share_provider.dart';
|
|
|
|
/// 分享测试组件 - 用于验证分享接收功能
|
|
/// 显示当前分享状态和待处理文件信息
|
|
class ShareTestWidget extends ConsumerWidget {
|
|
const ShareTestWidget({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final shareState = ref.watch(shareProvider);
|
|
|
|
return Card(
|
|
margin: const EdgeInsets.all(16),
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
// 标题
|
|
Text(
|
|
'分享接收测试',
|
|
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
const SizedBox(height: 16),
|
|
|
|
// 分享状态显示
|
|
_buildShareStatus(context, shareState),
|
|
const SizedBox(height: 16),
|
|
|
|
// 批量处理进度显示
|
|
if (shareState.isBatchProcessing) ...[
|
|
_buildBatchProgress(context, shareState),
|
|
const SizedBox(height: 8),
|
|
_buildBatchInfo(context, shareState),
|
|
const SizedBox(height: 16),
|
|
],
|
|
|
|
// 待处理文件列表
|
|
_buildPendingFilesList(context, shareState),
|
|
const SizedBox(height: 16),
|
|
|
|
// 操作按钮
|
|
_buildActionButtons(context, ref, shareState),
|
|
|
|
// 错误信息显示
|
|
if (shareState.error != null) ...[
|
|
const SizedBox(height: 16),
|
|
_buildErrorDisplay(context, shareState.error!, ref),
|
|
],
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
/// 构建分享状态显示
|
|
Widget _buildShareStatus(BuildContext context, ShareState shareState) {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
'当前状态:',
|
|
style: Theme.of(context).textTheme.titleMedium,
|
|
),
|
|
const SizedBox(height: 8),
|
|
Row(
|
|
children: [
|
|
Icon(
|
|
shareState.isProcessing
|
|
? Icons.sync
|
|
: shareState.hasPendingShare
|
|
? Icons.notifications_active
|
|
: Icons.check_circle,
|
|
color: shareState.isProcessing
|
|
? Colors.orange
|
|
: shareState.hasPendingShare
|
|
? Colors.blue
|
|
: Colors.green,
|
|
),
|
|
const SizedBox(width: 8),
|
|
Text(
|
|
shareState.isProcessing
|
|
? '处理中...'
|
|
: shareState.hasPendingShare
|
|
? '有待处理分享'
|
|
: '无待处理分享',
|
|
style: Theme.of(context).textTheme.bodyMedium,
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
'文件数量: ${shareState.pendingFiles.length}',
|
|
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
|
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
/// 构建待处理文件列表
|
|
Widget _buildPendingFilesList(BuildContext context, ShareState shareState) {
|
|
if (shareState.pendingFiles.isEmpty) {
|
|
return Text(
|
|
'暂无待处理文件',
|
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
|
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
|
),
|
|
);
|
|
}
|
|
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
'待处理文件:',
|
|
style: Theme.of(context).textTheme.titleMedium,
|
|
),
|
|
const SizedBox(height: 8),
|
|
...shareState.pendingFiles.map((file) => _buildFileItem(context, file)),
|
|
],
|
|
);
|
|
}
|
|
|
|
/// 构建文件项
|
|
Widget _buildFileItem(BuildContext context, SharedMediaFile file) {
|
|
return Container(
|
|
margin: const EdgeInsets.only(bottom: 8),
|
|
padding: const EdgeInsets.all(12),
|
|
decoration: BoxDecoration(
|
|
color: Theme.of(context).colorScheme.surfaceVariant.withOpacity(0.5),
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Icon(
|
|
_getFileIcon(file.type),
|
|
size: 24,
|
|
color: Theme.of(context).colorScheme.primary,
|
|
),
|
|
const SizedBox(width: 12),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
_getFileName(file.path),
|
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
const SizedBox(height: 2),
|
|
Text(
|
|
file.path,
|
|
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
|
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
|
),
|
|
maxLines: 2,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
'类型: ${_getFileType(file.type)}',
|
|
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
|
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
/// 构建操作按钮
|
|
Widget _buildActionButtons(BuildContext context, WidgetRef ref, ShareState shareState) {
|
|
return Row(
|
|
children: [
|
|
ElevatedButton.icon(
|
|
onPressed: shareState.hasPendingShare && !shareState.isProcessing
|
|
? () => _handleSaveShare(ref)
|
|
: null,
|
|
icon: const Icon(Icons.save),
|
|
label: const Text('保存分享'),
|
|
style: ElevatedButton.styleFrom(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
|
),
|
|
),
|
|
const SizedBox(width: 12),
|
|
OutlinedButton.icon(
|
|
onPressed: shareState.hasPendingShare && !shareState.isProcessing
|
|
? () => _handleClearShare(ref)
|
|
: null,
|
|
icon: const Icon(Icons.clear),
|
|
label: const Text('清除'),
|
|
),
|
|
const SizedBox(width: 12),
|
|
OutlinedButton.icon(
|
|
onPressed: !shareState.isProcessing
|
|
? () => _handleRefreshShare(ref)
|
|
: null,
|
|
icon: const Icon(Icons.refresh),
|
|
label: const Text('刷新'),
|
|
),
|
|
const SizedBox(width: 12),
|
|
OutlinedButton.icon(
|
|
onPressed: !shareState.isProcessing
|
|
? () => _simulateShareTest(ref)
|
|
: null,
|
|
icon: const Icon(Icons.photo),
|
|
label: const Text('模拟分享'),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
/// 构建错误信息显示
|
|
Widget _buildErrorDisplay(BuildContext context, String error, WidgetRef ref) {
|
|
return Container(
|
|
padding: const EdgeInsets.all(12),
|
|
decoration: BoxDecoration(
|
|
color: Theme.of(context).colorScheme.errorContainer,
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
child: Row(
|
|
children: [
|
|
Icon(
|
|
Icons.error_outline,
|
|
color: Theme.of(context).colorScheme.error,
|
|
),
|
|
const SizedBox(width: 8),
|
|
Expanded(
|
|
child: Text(
|
|
error,
|
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
|
color: Theme.of(context).colorScheme.error,
|
|
),
|
|
),
|
|
),
|
|
IconButton(
|
|
onPressed: () => _handleClearError(ref),
|
|
icon: Icon(
|
|
Icons.close,
|
|
color: Theme.of(context).colorScheme.error,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
/// 构建批量处理进度显示
|
|
Widget _buildBatchProgress(BuildContext context, ShareState shareState) {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
'批量处理进度:',
|
|
style: Theme.of(context).textTheme.titleMedium,
|
|
),
|
|
const SizedBox(height: 8),
|
|
Row(
|
|
children: [
|
|
Expanded(
|
|
child: LinearProgressIndicator(
|
|
value: shareState.totalBatches > 0
|
|
? shareState.currentBatchIndex / shareState.totalBatches
|
|
: 0,
|
|
backgroundColor: Theme.of(context).colorScheme.surfaceVariant,
|
|
valueColor: AlwaysStoppedAnimation<Color>(
|
|
Theme.of(context).colorScheme.primary,
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(width: 12),
|
|
Text(
|
|
'${shareState.currentBatchIndex}/${shareState.totalBatches}',
|
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
'第 ${shareState.currentBatchIndex} 批,共 ${shareState.totalBatches} 批',
|
|
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
|
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
/// 构建批量处理信息
|
|
Widget _buildBatchInfo(BuildContext context, ShareState shareState) {
|
|
final remainingBatches = shareState.totalBatches - shareState.currentBatchIndex;
|
|
final progressPercent = shareState.totalBatches > 0
|
|
? (shareState.currentBatchIndex / shareState.totalBatches * 100).toStringAsFixed(1)
|
|
: '0.0';
|
|
|
|
return Container(
|
|
padding: const EdgeInsets.all(12),
|
|
decoration: BoxDecoration(
|
|
color: Theme.of(context).colorScheme.primaryContainer.withOpacity(0.3),
|
|
borderRadius: BorderRadius.circular(8),
|
|
border: Border.all(
|
|
color: Theme.of(context).colorScheme.primary.withOpacity(0.3),
|
|
width: 1,
|
|
),
|
|
),
|
|
child: Row(
|
|
children: [
|
|
Icon(
|
|
Icons.batch_prediction,
|
|
color: Theme.of(context).colorScheme.primary,
|
|
size: 20,
|
|
),
|
|
const SizedBox(width: 8),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
'批量保存模式',
|
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
|
fontWeight: FontWeight.w500,
|
|
color: Theme.of(context).colorScheme.primary,
|
|
),
|
|
),
|
|
const SizedBox(height: 2),
|
|
Text(
|
|
'进度: $progressPercent% (${shareState.currentBatchIndex}/${shareState.totalBatches} 批次)',
|
|
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
|
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7),
|
|
),
|
|
),
|
|
if (remainingBatches > 0) ...[
|
|
const SizedBox(height: 2),
|
|
Text(
|
|
'剩余 $remainingBatches 批次待处理',
|
|
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
|
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
|
),
|
|
),
|
|
],
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
/// 获取文件图标
|
|
IconData _getFileIcon(SharedMediaType type) {
|
|
switch (type) {
|
|
case SharedMediaType.image:
|
|
return Icons.image;
|
|
case SharedMediaType.video:
|
|
return Icons.videocam;
|
|
case SharedMediaType.file:
|
|
return Icons.insert_drive_file;
|
|
default:
|
|
return Icons.description;
|
|
}
|
|
}
|
|
|
|
/// 获取文件类型描述
|
|
String _getFileType(SharedMediaType type) {
|
|
switch (type) {
|
|
case SharedMediaType.image:
|
|
return '图片';
|
|
case SharedMediaType.video:
|
|
return '视频';
|
|
case SharedMediaType.file:
|
|
return '文件';
|
|
default:
|
|
return '未知';
|
|
}
|
|
}
|
|
|
|
/// 获取文件名
|
|
String _getFileName(String filePath) {
|
|
return filePath.split('/').last;
|
|
}
|
|
|
|
/// 处理保存分享
|
|
void _handleSaveShare(WidgetRef ref) {
|
|
Logger.info('用户点击保存分享');
|
|
final shareNotifier = ref.read(shareProvider.notifier);
|
|
shareNotifier.startSavingSharedImages();
|
|
}
|
|
|
|
/// 处理清除分享
|
|
void _handleClearShare(WidgetRef ref) {
|
|
Logger.info('用户点击清除分享');
|
|
final shareNotifier = ref.read(shareProvider.notifier);
|
|
shareNotifier.cancelShareSaving();
|
|
}
|
|
|
|
/// 处理刷新分享
|
|
void _handleRefreshShare(WidgetRef ref) {
|
|
Logger.info('用户点击刷新分享');
|
|
final shareNotifier = ref.read(shareProvider.notifier);
|
|
shareNotifier.refreshShareStatus();
|
|
}
|
|
|
|
/// 处理清除错误
|
|
void _handleClearError(WidgetRef ref) {
|
|
final shareNotifier = ref.read(shareProvider.notifier);
|
|
shareNotifier.clearError();
|
|
}
|
|
|
|
/// 模拟分享测试 - 创建模拟的分享数据来测试保存对话框
|
|
void _simulateShareTest(WidgetRef ref) {
|
|
Logger.info('用户点击模拟分享测试');
|
|
|
|
// 创建模拟的分享文件
|
|
final mockFiles = [
|
|
SharedMediaFile(
|
|
path: 'test://image1.jpg',
|
|
type: SharedMediaType.image,
|
|
),
|
|
SharedMediaFile(
|
|
path: 'test://image2.png',
|
|
type: SharedMediaType.image,
|
|
),
|
|
];
|
|
|
|
// 模拟接收到分享文件
|
|
final shareNotifier = ref.read(shareProvider.notifier);
|
|
shareNotifier.handleSharedFiles(mockFiles);
|
|
|
|
Logger.info('模拟分享测试完成,创建了${mockFiles.length}个测试文件');
|
|
}
|
|
} |