优化人工处理弹窗 UI
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
import 'package:recording_tool/features/competition_teams/model/model_competition_team_detail.dart';
|
import 'package:recording_tool/features/competition_teams/model/model_competition_team_detail.dart';
|
||||||
import 'package:recording_tool/shared/widgets/app_button.dart';
|
import 'package:recording_tool/gen/assets.gen.dart';
|
||||||
|
|
||||||
/// 弹窗回传选中侧索引:0 = teamA(红队),1 = teamB(蓝队)
|
/// 弹窗回传选中侧索引:0 = teamA(红队),1 = teamB(蓝队)
|
||||||
class ManualWinnerDialog extends StatefulWidget {
|
class ManualWinnerDialog extends StatefulWidget {
|
||||||
@@ -62,35 +62,41 @@ class _ManualWinnerDialogState extends State<ManualWinnerDialog> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final teamA = _teamA;
|
final teamA = _teamA;
|
||||||
final teamB = _teamB;
|
final teamB = _teamB;
|
||||||
|
final maxHeight = MediaQuery.sizeOf(context).height * 0.78;
|
||||||
|
|
||||||
return AlertDialog(
|
return Dialog(
|
||||||
insetPadding: EdgeInsets.symmetric(horizontal: 22.w),
|
insetPadding: EdgeInsets.symmetric(horizontal: 48.w),
|
||||||
contentPadding: EdgeInsets.zero,
|
backgroundColor: Colors.transparent,
|
||||||
clipBehavior: Clip.antiAlias,
|
elevation: 0,
|
||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(18.r)),
|
child: ConstrainedBox(
|
||||||
content: SizedBox(
|
constraints: BoxConstraints(maxWidth: 380.w, maxHeight: maxHeight),
|
||||||
width: 320.w,
|
child: Stack(
|
||||||
|
clipBehavior: Clip.none,
|
||||||
|
children: [
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(16.r),
|
||||||
|
child: Material(
|
||||||
|
color: Colors.white,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Image.asset(
|
|
||||||
'assets/images/image_dialog_bg.png',
|
|
||||||
width: 320.w,
|
|
||||||
height: 112.h,
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
),
|
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.fromLTRB(20.w, 8.h, 20.w, 20.h),
|
padding: EdgeInsets.fromLTRB(18.w, 18.h, 18.w, 18.h),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
|
SizedBox(height: 26.h),
|
||||||
Text(
|
Text(
|
||||||
'请在比赛结束前处理',
|
'请在比赛结束前处理',
|
||||||
key: const ValueKey('manual-winner-dialog-title'),
|
key: const ValueKey('manual-winner-dialog-title'),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 20.sp,
|
fontSize: 18.sp,
|
||||||
|
height: 1.3,
|
||||||
fontWeight: FontWeight.w700,
|
fontWeight: FontWeight.w700,
|
||||||
color: const Color(0xFF20242B),
|
color: const Color(0xFF20242B),
|
||||||
|
fontFamily: 'PingFang SC',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 16.h),
|
SizedBox(height: 16.h),
|
||||||
@@ -98,9 +104,10 @@ class _ManualWinnerDialogState extends State<ManualWinnerDialog> {
|
|||||||
_TeamChoice(
|
_TeamChoice(
|
||||||
team: teamA,
|
team: teamA,
|
||||||
sideIndex: 0,
|
sideIndex: 0,
|
||||||
color: const Color(0xFFFF6B75),
|
color: const Color(0xFFFF6575),
|
||||||
selected: _selectedSideIndex == 0,
|
selected: _selectedSideIndex == 0,
|
||||||
onTap: () => setState(() => _selectedSideIndex = 0),
|
onTap: () =>
|
||||||
|
setState(() => _selectedSideIndex = 0),
|
||||||
),
|
),
|
||||||
SizedBox(height: 10.h),
|
SizedBox(height: 10.h),
|
||||||
],
|
],
|
||||||
@@ -108,24 +115,26 @@ class _ManualWinnerDialogState extends State<ManualWinnerDialog> {
|
|||||||
_TeamChoice(
|
_TeamChoice(
|
||||||
team: teamB,
|
team: teamB,
|
||||||
sideIndex: 1,
|
sideIndex: 1,
|
||||||
color: const Color(0xFF20BFA9),
|
color: const Color(0xFF21C5AC),
|
||||||
selected: _selectedSideIndex == 1,
|
selected: _selectedSideIndex == 1,
|
||||||
onTap: () => setState(() => _selectedSideIndex = 1),
|
onTap: () =>
|
||||||
|
setState(() => _selectedSideIndex = 1),
|
||||||
),
|
),
|
||||||
SizedBox(height: 20.h),
|
SizedBox(height: 18.h),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: AppButton(
|
child: _DialogActionButton(
|
||||||
label: '取消',
|
label: '取消',
|
||||||
variant: AppButtonVariant.secondary,
|
onPressed: () =>
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
Navigator.of(context).pop(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(width: 14.w),
|
SizedBox(width: 14.w),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: AppButton(
|
child: _DialogActionButton(
|
||||||
label: '确定',
|
label: '确定',
|
||||||
|
filled: true,
|
||||||
onPressed: _selectedSideIndex == null
|
onPressed: _selectedSideIndex == null
|
||||||
? null
|
? null
|
||||||
: () => Navigator.of(
|
: () => Navigator.of(
|
||||||
@@ -142,6 +151,22 @@ class _ManualWinnerDialogState extends State<ManualWinnerDialog> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
top: -90.h,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
child: Image.asset(
|
||||||
|
Assets.images.imageDialogBg.path,
|
||||||
|
width: double.infinity,
|
||||||
|
height: 112.h,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
alignment: Alignment.topCenter,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,12 +192,15 @@ class _TeamChoice extends StatelessWidget {
|
|||||||
? team.teamName!
|
? team.teamName!
|
||||||
: '未命名队伍';
|
: '未命名队伍';
|
||||||
final players = team.playerNames;
|
final players = team.playerNames;
|
||||||
|
final backgroundColor = selected
|
||||||
|
? color.withValues(alpha: 0.13)
|
||||||
|
: color.withValues(alpha: 0.07);
|
||||||
return Semantics(
|
return Semantics(
|
||||||
selected: selected,
|
selected: selected,
|
||||||
button: true,
|
button: true,
|
||||||
label: '选择$name直接获胜',
|
label: '选择$name直接获胜',
|
||||||
child: Material(
|
child: Material(
|
||||||
color: color.withValues(alpha: selected ? 0.16 : 0.08),
|
color: backgroundColor,
|
||||||
borderRadius: BorderRadius.circular(12.r),
|
borderRadius: BorderRadius.circular(12.r),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
key: ValueKey('winner-choice-side-$sideIndex'),
|
key: ValueKey('winner-choice-side-$sideIndex'),
|
||||||
@@ -180,12 +208,12 @@ class _TeamChoice extends StatelessWidget {
|
|||||||
borderRadius: BorderRadius.circular(12.r),
|
borderRadius: BorderRadius.circular(12.r),
|
||||||
child: Container(
|
child: Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
padding: EdgeInsets.symmetric(horizontal: 14.w, vertical: 12.h),
|
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 12.h),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(12.r),
|
borderRadius: BorderRadius.circular(12.r),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: selected ? color : color.withValues(alpha: 0.35),
|
color: selected ? color : color.withValues(alpha: 0.32),
|
||||||
width: selected ? 2 : 1,
|
width: 1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
@@ -196,11 +224,23 @@ class _TeamChoice extends StatelessWidget {
|
|||||||
height: 22.r,
|
height: 22.r,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
border: Border.all(color: selected ? color : Colors.grey),
|
border: Border.all(
|
||||||
color: selected ? color : Colors.transparent,
|
color: selected ? color : const Color(0xFFB0B4BB),
|
||||||
|
width: 1.2.r,
|
||||||
|
),
|
||||||
|
color: Colors.transparent,
|
||||||
),
|
),
|
||||||
child: selected
|
child: selected
|
||||||
? Icon(Icons.check, size: 15.r, color: Colors.white)
|
? Center(
|
||||||
|
child: Container(
|
||||||
|
width: 10.r,
|
||||||
|
height: 10.r,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: color,
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
SizedBox(width: 12.w),
|
SizedBox(width: 12.w),
|
||||||
@@ -210,19 +250,27 @@ class _TeamChoice extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
name,
|
name,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 17.sp,
|
fontSize: 17.sp,
|
||||||
fontWeight: FontWeight.w600,
|
height: 1.25,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
color: const Color(0xFF20242B),
|
color: const Color(0xFF20242B),
|
||||||
|
fontFamily: 'PingFang SC',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (players.isNotEmpty) ...[
|
if (players.isNotEmpty) ...[
|
||||||
SizedBox(height: 4.h),
|
SizedBox(height: 4.h),
|
||||||
Text(
|
Text(
|
||||||
players,
|
players,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14.sp,
|
fontSize: 15.sp,
|
||||||
color: const Color(0xFF606874),
|
height: 1.25,
|
||||||
|
color: const Color(0xFF69717E),
|
||||||
|
fontFamily: 'PingFang SC',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -232,10 +280,12 @@ class _TeamChoice extends StatelessWidget {
|
|||||||
SizedBox(width: 8.w),
|
SizedBox(width: 8.w),
|
||||||
Text(
|
Text(
|
||||||
'直接获胜',
|
'直接获胜',
|
||||||
|
maxLines: 1,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13.sp,
|
fontSize: 15.sp,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w700,
|
||||||
color: color,
|
color: color,
|
||||||
|
fontFamily: 'PingFang SC',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -246,3 +296,58 @@ class _TeamChoice extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _DialogActionButton extends StatelessWidget {
|
||||||
|
const _DialogActionButton({
|
||||||
|
required this.label,
|
||||||
|
required this.onPressed,
|
||||||
|
this.filled = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String label;
|
||||||
|
final VoidCallback? onPressed;
|
||||||
|
final bool filled;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final enabled = onPressed != null;
|
||||||
|
final radius = BorderRadius.circular(24.r);
|
||||||
|
final backgroundColor = filled
|
||||||
|
? (enabled ? null : const Color(0xFFD2D3D8))
|
||||||
|
: const Color(0xFFF1F1F1);
|
||||||
|
final gradient = filled && enabled
|
||||||
|
? const LinearGradient(colors: [Color(0xFF2F8DFF), Color(0xFF58D1EE)])
|
||||||
|
: null;
|
||||||
|
|
||||||
|
return SizedBox(
|
||||||
|
height: 40.h,
|
||||||
|
child: DecoratedBox(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: backgroundColor,
|
||||||
|
gradient: gradient,
|
||||||
|
borderRadius: radius,
|
||||||
|
),
|
||||||
|
child: Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: onPressed,
|
||||||
|
borderRadius: radius,
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
label,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 15.sp,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: filled
|
||||||
|
? (enabled ? Colors.white : const Color(0xFF8D9098))
|
||||||
|
: const Color(0xFF343941),
|
||||||
|
fontFamily: 'PingFang SC',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user