282 lines
7.7 KiB
Dart
282 lines
7.7 KiB
Dart
// ignore_for_file: file_names
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
import 'package:recording_tool/gen/assets.gen.dart';
|
|
|
|
/// 录制页统一弹窗,支持单按钮和双按钮。
|
|
class RecordDialog extends StatelessWidget {
|
|
const RecordDialog({super.key, required this.title, required this.actions});
|
|
|
|
static const _transitionDuration = Duration(milliseconds: 280);
|
|
|
|
final String title;
|
|
final List<RecordDialogAction> actions;
|
|
|
|
static Future<void> showSingle(
|
|
BuildContext context, {
|
|
required String title,
|
|
required String buttonText,
|
|
VoidCallback? onPressed,
|
|
bool barrierDismissible = true,
|
|
}) {
|
|
return _present(
|
|
context,
|
|
barrierDismissible: barrierDismissible,
|
|
builder: (dialogContext) {
|
|
return RecordDialog(
|
|
title: title,
|
|
actions: [
|
|
RecordDialogAction.primary(
|
|
text: buttonText,
|
|
onPressed: () {
|
|
Navigator.of(dialogContext).pop();
|
|
onPressed?.call();
|
|
},
|
|
),
|
|
],
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
static Future<void> showDouble(
|
|
BuildContext context, {
|
|
required String title,
|
|
required String leftText,
|
|
required String rightText,
|
|
VoidCallback? onLeftPressed,
|
|
VoidCallback? onRightPressed,
|
|
bool barrierDismissible = false,
|
|
}) {
|
|
return _present(
|
|
context,
|
|
barrierDismissible: barrierDismissible,
|
|
builder: (dialogContext) {
|
|
return RecordDialog(
|
|
title: title,
|
|
actions: [
|
|
RecordDialogAction.secondary(
|
|
text: leftText,
|
|
onPressed: () {
|
|
Navigator.of(dialogContext).pop();
|
|
onLeftPressed?.call();
|
|
},
|
|
),
|
|
RecordDialogAction.primary(
|
|
text: rightText,
|
|
onPressed: () {
|
|
Navigator.of(dialogContext).pop();
|
|
onRightPressed?.call();
|
|
},
|
|
),
|
|
],
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
static Future<void> _present(
|
|
BuildContext context, {
|
|
required Widget Function(BuildContext dialogContext) builder,
|
|
required bool barrierDismissible,
|
|
}) {
|
|
return showGeneralDialog<void>(
|
|
context: context,
|
|
barrierDismissible: barrierDismissible,
|
|
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
|
|
barrierColor: Colors.black54,
|
|
transitionDuration: _transitionDuration,
|
|
pageBuilder: (dialogContext, animation, secondaryAnimation) {
|
|
return builder(dialogContext);
|
|
},
|
|
transitionBuilder: _buildTransition,
|
|
);
|
|
}
|
|
|
|
static Widget _buildTransition(
|
|
BuildContext context,
|
|
Animation<double> animation,
|
|
Animation<double> secondaryAnimation,
|
|
Widget child,
|
|
) {
|
|
final curved = CurvedAnimation(
|
|
parent: animation,
|
|
curve: Curves.easeOutCubic,
|
|
reverseCurve: Curves.easeInCubic,
|
|
);
|
|
|
|
return FadeTransition(
|
|
opacity: curved,
|
|
child: SlideTransition(
|
|
position: Tween<Offset>(
|
|
begin: const Offset(0, 0.08),
|
|
end: Offset.zero,
|
|
).animate(curved),
|
|
child: ScaleTransition(
|
|
scale: Tween<double>(begin: 0.92, end: 1).animate(curved),
|
|
child: child,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final actionWidgets = actions
|
|
.map((action) => Expanded(child: _RecordDialogButton(action: action)))
|
|
.toList();
|
|
|
|
return Dialog(
|
|
elevation: 0,
|
|
backgroundColor: Colors.transparent,
|
|
insetPadding: EdgeInsets.symmetric(horizontal: 37.w),
|
|
child: ClipRRect(
|
|
clipBehavior: Clip.none,
|
|
|
|
borderRadius: BorderRadius.circular(18.r),
|
|
child: Container(
|
|
width: 315.w,
|
|
// height: 188.r,
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
|
|
borderRadius: BorderRadius.circular(18.r),
|
|
),
|
|
child: Stack(
|
|
clipBehavior: Clip.none,
|
|
children: [
|
|
Positioned(
|
|
top: -88.r,
|
|
left: 0,
|
|
right: 0,
|
|
child: Image.asset(
|
|
Assets.images.imageDialogBg.path,
|
|
width: double.maxFinite,
|
|
height: 155.h,
|
|
fit: BoxFit.fitWidth,
|
|
),
|
|
),
|
|
Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Padding(
|
|
padding: EdgeInsets.fromLTRB(24.w, 44.h, 24.w, 26.h),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Text(
|
|
title,
|
|
textAlign: TextAlign.center,
|
|
style: TextStyle(
|
|
color: const Color(0xFF333333),
|
|
fontSize: 19.sp,
|
|
fontWeight: FontWeight.w600,
|
|
height: 1.35,
|
|
),
|
|
),
|
|
SizedBox(height: 22.h),
|
|
Row(
|
|
children: [
|
|
for (
|
|
var index = 0;
|
|
index < actionWidgets.length;
|
|
index++
|
|
) ...[
|
|
if (index > 0) SizedBox(width: 16.w),
|
|
actionWidgets[index],
|
|
],
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class RecordDialogAction {
|
|
const RecordDialogAction._({
|
|
required this.text,
|
|
required this.onPressed,
|
|
required this.isPrimary,
|
|
});
|
|
|
|
factory RecordDialogAction.primary({
|
|
required String text,
|
|
required VoidCallback onPressed,
|
|
}) {
|
|
return RecordDialogAction._(
|
|
text: text,
|
|
onPressed: onPressed,
|
|
isPrimary: true,
|
|
);
|
|
}
|
|
|
|
factory RecordDialogAction.secondary({
|
|
required String text,
|
|
required VoidCallback onPressed,
|
|
}) {
|
|
return RecordDialogAction._(
|
|
text: text,
|
|
onPressed: onPressed,
|
|
isPrimary: false,
|
|
);
|
|
}
|
|
|
|
final String text;
|
|
final VoidCallback onPressed;
|
|
final bool isPrimary;
|
|
}
|
|
|
|
class _RecordDialogButton extends StatelessWidget {
|
|
const _RecordDialogButton({required this.action});
|
|
|
|
final RecordDialogAction action;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final child = Center(
|
|
child: Text(
|
|
action.text,
|
|
style: TextStyle(
|
|
color: action.isPrimary ? Colors.white : const Color(0xFF333333),
|
|
fontSize: 18.sp,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
),
|
|
);
|
|
|
|
return SizedBox(
|
|
height: 48.h,
|
|
child: TextButton(
|
|
onPressed: action.onPressed,
|
|
style: TextButton.styleFrom(
|
|
padding: EdgeInsets.zero,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(24.r),
|
|
),
|
|
backgroundColor: action.isPrimary ? null : const Color(0xFFF2F2F2),
|
|
),
|
|
child: action.isPrimary
|
|
? DecoratedBox(
|
|
decoration: BoxDecoration(
|
|
gradient: const LinearGradient(
|
|
colors: [Color(0xFF2F85FF), Color(0xFF5DCCF4)],
|
|
),
|
|
borderRadius: BorderRadius.circular(24.r),
|
|
),
|
|
child: SizedBox.expand(child: child),
|
|
)
|
|
: child,
|
|
),
|
|
);
|
|
}
|
|
}
|