1.UI 优化
2.新增打包构建脚本
This commit is contained in:
BIN
assets/images/image_copy.png
Normal file
BIN
assets/images/image_copy.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 795 B |
BIN
assets/images/image_delete.png
Normal file
BIN
assets/images/image_delete.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1011 B |
Binary file not shown.
|
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 4.6 KiB |
BIN
assets/images/image_vs.png
Normal file
BIN
assets/images/image_vs.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
1
build-apk-split.sh
Normal file
1
build-apk-split.sh
Normal file
@@ -0,0 +1 @@
|
|||||||
|
flutter build apk --release --split-per-abi
|
||||||
1
build-apk.sh
Normal file
1
build-apk.sh
Normal file
@@ -0,0 +1 @@
|
|||||||
|
flutter build apk --release
|
||||||
@@ -29,7 +29,7 @@ class RecordHeaderWidget extends StatelessWidget {
|
|||||||
|
|
||||||
void _mockCopyEventInfo() {
|
void _mockCopyEventInfo() {
|
||||||
const strTemp =
|
const strTemp =
|
||||||
'{"title":"郑昌梦 丨黄伟依 空中格斗赛 小学组","address":"广东省汕头市番禺区青蓝街 111 号","filename":"郑昌梦_黄伟依_6月3日测试-1_空中格斗赛"}';
|
'{"title":"蔡依婷vs夏志豪 空中格斗赛 初中组","address":"黑龙江省鹤岗市11111","filename":"蔡依婷_夏志豪_测试循环赛-7_空中格斗赛"}';
|
||||||
Clipboard.setData(const ClipboardData(text: strTemp));
|
Clipboard.setData(const ClipboardData(text: strTemp));
|
||||||
AppToast.show('模拟复制赛事信息成功');
|
AppToast.show('模拟复制赛事信息成功');
|
||||||
}
|
}
|
||||||
@@ -47,7 +47,7 @@ class RecordHeaderWidget extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Image.asset(
|
Image.asset(
|
||||||
Assets.images.imageLogo.path,
|
Assets.images.imageLogo.path,
|
||||||
width: 84.r,
|
width: 24.r,
|
||||||
height: 24.r,
|
height: 24.r,
|
||||||
fit: BoxFit.contain,
|
fit: BoxFit.contain,
|
||||||
),
|
),
|
||||||
@@ -92,7 +92,7 @@ class _HeaderEventTitleRow extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
@@ -101,7 +101,7 @@ class _HeaderEventTitleRow extends StatelessWidget {
|
|||||||
fontSize: 12.sp,
|
fontSize: 12.sp,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
),
|
||||||
textAlign: TextAlign.right,
|
textAlign: TextAlign.center,
|
||||||
maxLines: 3,
|
maxLines: 3,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
@@ -109,7 +109,12 @@ class _HeaderEventTitleRow extends StatelessWidget {
|
|||||||
if (!isRecording)
|
if (!isRecording)
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: onClearEventInfo,
|
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,
|
padding: EdgeInsets.zero,
|
||||||
constraints: BoxConstraints(minWidth: 40.r, minHeight: 40.r),
|
constraints: BoxConstraints(minWidth: 40.r, minHeight: 40.r),
|
||||||
tooltip: '删除',
|
tooltip: '删除',
|
||||||
@@ -137,6 +142,12 @@ class _HeaderPasteActions extends StatelessWidget {
|
|||||||
_HeaderActionButton(
|
_HeaderActionButton(
|
||||||
label: '粘贴选手信息',
|
label: '粘贴选手信息',
|
||||||
onPressed: () => onPasteEventInfo(),
|
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 {
|
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 String label;
|
||||||
final VoidCallback onPressed;
|
final VoidCallback onPressed;
|
||||||
|
final Widget? icon;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return TextButton.icon(
|
return TextButton.icon(
|
||||||
onPressed: onPressed,
|
onPressed: onPressed,
|
||||||
icon: Icon(Icons.content_paste, size: 18.r),
|
icon: icon ?? Icon(Icons.content_paste, size: 10.r),
|
||||||
label: Text(label),
|
label: Text(label),
|
||||||
|
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
|
minimumSize: Size.zero, // 取消 40dp 最小高度
|
||||||
|
tapTargetSize: MaterialTapTargetSize.shrinkWrap, // 取消额外点击热区
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
backgroundColor: Colors.black.withValues(alpha: 0.5),
|
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(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(20.r),
|
borderRadius: BorderRadius.circular(25.r),
|
||||||
side: const BorderSide(color: Colors.white30),
|
side: const BorderSide(color: Colors.white30),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class _RecordTimerWidgetState extends ConsumerState<RecordTimerWidget> {
|
|||||||
child: Text(
|
child: Text(
|
||||||
displayTime,
|
displayTime,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: isRecording ? Colors.white : Colors.white70,
|
color: Colors.white,
|
||||||
fontSize: 20.sp,
|
fontSize: 20.sp,
|
||||||
shadows: [Shadow(color: Colors.black54, blurRadius: 6.r)],
|
shadows: [Shadow(color: Colors.black54, blurRadius: 6.r)],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -14,6 +14,14 @@ import 'package:flutter/widgets.dart';
|
|||||||
class $AssetsImagesGen {
|
class $AssetsImagesGen {
|
||||||
const $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
|
/// File path: assets/images/image_dialog_bg.png
|
||||||
AssetGenImage get imageDialogBg =>
|
AssetGenImage get imageDialogBg =>
|
||||||
const AssetGenImage('assets/images/image_dialog_bg.png');
|
const AssetGenImage('assets/images/image_dialog_bg.png');
|
||||||
@@ -23,7 +31,12 @@ class $AssetsImagesGen {
|
|||||||
const AssetGenImage('assets/images/image_logo.png');
|
const AssetGenImage('assets/images/image_logo.png');
|
||||||
|
|
||||||
/// List of all assets
|
/// List of all assets
|
||||||
List<AssetGenImage> get values => [imageDialogBg, imageLogo];
|
List<AssetGenImage> get values => [
|
||||||
|
imageCopy,
|
||||||
|
imageDelete,
|
||||||
|
imageDialogBg,
|
||||||
|
imageLogo,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
class Assets {
|
class Assets {
|
||||||
|
|||||||
53
test/features/recording/widget_record_header_test.dart
Normal file
53
test/features/recording/widget_record_header_test.dart
Normal file
@@ -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<void> 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);
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user