diff --git a/assets/images/image_copy.png b/assets/images/image_copy.png new file mode 100644 index 0000000..fba2f9a Binary files /dev/null and b/assets/images/image_copy.png differ diff --git a/assets/images/image_delete.png b/assets/images/image_delete.png new file mode 100644 index 0000000..7e2ee03 Binary files /dev/null and b/assets/images/image_delete.png differ diff --git a/assets/images/image_logo.png b/assets/images/image_logo.png index f543645..cdc9bfa 100644 Binary files a/assets/images/image_logo.png and b/assets/images/image_logo.png differ diff --git a/assets/images/image_vs.png b/assets/images/image_vs.png new file mode 100644 index 0000000..6848454 Binary files /dev/null and b/assets/images/image_vs.png differ diff --git a/build-apk-split.sh b/build-apk-split.sh new file mode 100644 index 0000000..e5af4e4 --- /dev/null +++ b/build-apk-split.sh @@ -0,0 +1 @@ +flutter build apk --release --split-per-abi \ No newline at end of file diff --git a/build-apk.sh b/build-apk.sh new file mode 100644 index 0000000..88f597b --- /dev/null +++ b/build-apk.sh @@ -0,0 +1 @@ +flutter build apk --release \ No newline at end of file diff --git a/lib/features/recording/widgets/widget_record_header.dart b/lib/features/recording/widgets/widget_record_header.dart index 2434cca..7d11d16 100644 --- a/lib/features/recording/widgets/widget_record_header.dart +++ b/lib/features/recording/widgets/widget_record_header.dart @@ -29,7 +29,7 @@ class RecordHeaderWidget extends StatelessWidget { void _mockCopyEventInfo() { const strTemp = - '{"title":"郑昌梦 丨黄伟依 空中格斗赛 小学组","address":"广东省汕头市番禺区青蓝街 111 号","filename":"郑昌梦_黄伟依_6月3日测试-1_空中格斗赛"}'; + '{"title":"蔡依婷vs夏志豪 空中格斗赛 初中组","address":"黑龙江省鹤岗市11111","filename":"蔡依婷_夏志豪_测试循环赛-7_空中格斗赛"}'; Clipboard.setData(const ClipboardData(text: strTemp)); AppToast.show('模拟复制赛事信息成功'); } @@ -47,7 +47,7 @@ class RecordHeaderWidget extends StatelessWidget { children: [ Image.asset( Assets.images.imageLogo.path, - width: 84.r, + width: 24.r, height: 24.r, fit: BoxFit.contain, ), @@ -92,7 +92,7 @@ class _HeaderEventTitleRow extends StatelessWidget { @override Widget build(BuildContext context) { return Row( - mainAxisAlignment: MainAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( child: Text( @@ -101,7 +101,7 @@ class _HeaderEventTitleRow extends StatelessWidget { fontSize: 12.sp, fontWeight: FontWeight.w600, ), - textAlign: TextAlign.right, + textAlign: TextAlign.center, maxLines: 3, overflow: TextOverflow.ellipsis, ), @@ -109,7 +109,12 @@ class _HeaderEventTitleRow extends StatelessWidget { if (!isRecording) IconButton( onPressed: onClearEventInfo, - icon: Icon(Icons.delete_outline, color: Colors.white, size: 22.r), + icon: Assets.images.imageDelete.image( + width: 15.r, + height: 15.r, + fit: BoxFit.contain, + excludeFromSemantics: true, + ), padding: EdgeInsets.zero, constraints: BoxConstraints(minWidth: 40.r, minHeight: 40.r), tooltip: '删除', @@ -137,6 +142,12 @@ class _HeaderPasteActions extends StatelessWidget { _HeaderActionButton( label: '粘贴选手信息', onPressed: () => onPasteEventInfo(), + icon: Assets.images.imageCopy.image( + width: 10.r, + height: 10.r, + fit: BoxFit.contain, + excludeFromSemantics: true, + ), ), ], ); @@ -144,23 +155,32 @@ class _HeaderPasteActions extends StatelessWidget { } class _HeaderActionButton extends StatelessWidget { - const _HeaderActionButton({required this.label, required this.onPressed}); + const _HeaderActionButton({ + required this.label, + required this.onPressed, + this.icon, + }); final String label; final VoidCallback onPressed; + final Widget? icon; @override Widget build(BuildContext context) { return TextButton.icon( onPressed: onPressed, - icon: Icon(Icons.content_paste, size: 18.r), + icon: icon ?? Icon(Icons.content_paste, size: 10.r), label: Text(label), + style: TextButton.styleFrom( + minimumSize: Size.zero, // 取消 40dp 最小高度 + tapTargetSize: MaterialTapTargetSize.shrinkWrap, // 取消额外点击热区 foregroundColor: Colors.white, backgroundColor: Colors.black.withValues(alpha: 0.5), - padding: EdgeInsets.symmetric(horizontal: 14.r, vertical: 8.r), + textStyle: TextStyle(fontSize: 10.sp), + padding: EdgeInsets.symmetric(horizontal: 7.r, vertical: 4.r), shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(20.r), + borderRadius: BorderRadius.circular(25.r), side: const BorderSide(color: Colors.white30), ), ), diff --git a/lib/features/recording/widgets/widget_record_timer.dart b/lib/features/recording/widgets/widget_record_timer.dart index fa0269f..15c47a0 100644 --- a/lib/features/recording/widgets/widget_record_timer.dart +++ b/lib/features/recording/widgets/widget_record_timer.dart @@ -33,7 +33,7 @@ class _RecordTimerWidgetState extends ConsumerState { child: Text( displayTime, style: TextStyle( - color: isRecording ? Colors.white : Colors.white70, + color: Colors.white, fontSize: 20.sp, shadows: [Shadow(color: Colors.black54, blurRadius: 6.r)], ), diff --git a/lib/gen/assets.gen.dart b/lib/gen/assets.gen.dart index 15be050..d2870ba 100644 --- a/lib/gen/assets.gen.dart +++ b/lib/gen/assets.gen.dart @@ -14,6 +14,14 @@ import 'package:flutter/widgets.dart'; class $AssetsImagesGen { const $AssetsImagesGen(); + /// File path: assets/images/image_copy.png + AssetGenImage get imageCopy => + const AssetGenImage('assets/images/image_copy.png'); + + /// File path: assets/images/image_delete.png + AssetGenImage get imageDelete => + const AssetGenImage('assets/images/image_delete.png'); + /// File path: assets/images/image_dialog_bg.png AssetGenImage get imageDialogBg => const AssetGenImage('assets/images/image_dialog_bg.png'); @@ -23,7 +31,12 @@ class $AssetsImagesGen { const AssetGenImage('assets/images/image_logo.png'); /// List of all assets - List get values => [imageDialogBg, imageLogo]; + List get values => [ + imageCopy, + imageDelete, + imageDialogBg, + imageLogo, + ]; } class Assets { diff --git a/test/features/recording/widget_record_header_test.dart b/test/features/recording/widget_record_header_test.dart new file mode 100644 index 0000000..11cc954 --- /dev/null +++ b/test/features/recording/widget_record_header_test.dart @@ -0,0 +1,53 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:recording_tool/features/recording/widgets/widget_record_header.dart'; +import 'package:recording_tool/gen/assets.gen.dart'; + +void main() { + Future pumpHeader( + WidgetTester tester, { + required bool hasValidClipboardInfo, + String? eventTitle, + }) async { + await tester.pumpWidget( + ScreenUtilInit( + designSize: const Size(375, 812), + builder: (context, _) { + return MaterialApp( + home: Scaffold( + body: RecordHeaderWidget( + hasValidClipboardInfo: hasValidClipboardInfo, + eventTitle: eventTitle, + isRecording: false, + elapsedLabel: '00:00', + onPasteEventInfo: () async {}, + onClearEventInfo: () {}, + ), + ), + ); + }, + ), + ); + } + + testWidgets('paste player info button uses copy image asset', (tester) async { + await pumpHeader(tester, hasValidClipboardInfo: false); + + expect(find.text('粘贴选手信息'), findsOneWidget); + expect(find.image(AssetImage(Assets.images.imageCopy.path)), findsOne); + }); + + testWidgets('clear player info button uses delete image asset', ( + tester, + ) async { + await pumpHeader( + tester, + hasValidClipboardInfo: true, + eventTitle: '王东方 丨李想 空中格斗赛', + ); + + expect(find.text('王东方 丨李想 空中格斗赛'), findsOneWidget); + expect(find.image(AssetImage(Assets.images.imageDelete.path)), findsOne); + }); +}