diff --git a/lib/features/auth/pages/page_auth.dart b/lib/features/auth/pages/page_auth.dart index 6ce0839..2b9774f 100644 --- a/lib/features/auth/pages/page_auth.dart +++ b/lib/features/auth/pages/page_auth.dart @@ -3,7 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:recording_tool/app/router/app_navigator.dart'; import 'package:recording_tool/features/auth/view_model_auth/view_model_auth.dart'; -import 'package:recording_tool/features/scan_qrcode/pages/page_scan_qrcode.dart'; +import 'package:recording_tool/features/events/pages/page_event_info.dart'; import 'package:recording_tool/shared/widgets/widgets.dart'; class AuthPageWidget extends ConsumerStatefulWidget { @@ -62,7 +62,7 @@ class _AuthPageWidgetState extends ConsumerState { .auth(code ?? ''); if (!mounted) return; if (success) { - AppNavigator.push(const ScanQrCodePage()); + AppNavigator.push(const EventInfoPage()); return; } final message = ref.read(authProvider).errorMessage; diff --git a/lib/features/events/pages/page_event_info.dart b/lib/features/events/pages/page_event_info.dart new file mode 100644 index 0000000..90b7e65 --- /dev/null +++ b/lib/features/events/pages/page_event_info.dart @@ -0,0 +1,359 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:recording_tool/app/router/app_navigator.dart'; +import 'package:recording_tool/features/recording/pages/page_record.dart'; + +class EventInfoPage extends StatelessWidget { + const EventInfoPage({super.key}); + + static const _profile = EventProfile( + avatarLabel: '头像', + name: '王东方', + phone: '199966666527', + eventTitle: '全国青少年无人机大赛', + ); + + static const _items = [ + EventScheduleItem( + name: '个人飞行赛', + group: '小学组', + venue: '场地 1', + time: '7月1日 12:00-15:00', + laneNo: '10号', + ), + EventScheduleItem( + name: '空中足球赛', + group: '小学组', + venue: '场地 1', + time: '7月2日 12:00-15:00', + status: '已完成', + ), + EventScheduleItem( + name: '穿越竞速赛', + group: '小学组', + venue: '场地 2', + time: '7月3日 09:00-11:30', + laneNo: '06号', + ), + EventScheduleItem( + name: '编队飞行赛', + group: '小学组', + venue: '场地 3', + time: '7月3日 14:00-16:00', + status: '待开始', + ), + ]; + void onItemTap(EventScheduleItem item) { + debugPrint('item tapped: ${item.name}'); + AppNavigator.push(const RecordingPage()); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _Header(onBack: () => AppNavigator.pop(context: context)), + Expanded( + child: SingleChildScrollView( + padding: EdgeInsets.fromLTRB(62.w, 8.h, 62.w, 40.h), + child: Column( + children: [ + const _ProfileSection(profile: _profile), + SizedBox(height: 82.h), + Text( + _profile.eventTitle, + style: TextStyle( + fontSize: 20.sp, + height: 1.2, + color: const Color(0xFF2F2F2F), + fontWeight: FontWeight.w500, + ), + ), + SizedBox(height: 24.h), + SizedBox( + height: 400.h, + child: ListView.builder( + itemCount: _items.length, + itemBuilder: (context, index) => _ScheduleCard( + item: _items[index], + onTap: () => onItemTap(_items[index]), + ), + ), + ), + ], + ), + ), + ), + ], + ), + ), + ); + } +} + +class EventProfile { + const EventProfile({ + required this.avatarLabel, + required this.name, + required this.phone, + required this.eventTitle, + }); + + final String avatarLabel; + final String name; + final String phone; + final String eventTitle; +} + +class EventScheduleItem { + const EventScheduleItem({ + required this.name, + required this.group, + required this.venue, + required this.time, + this.laneNo, + this.status, + }); + + final String name; + final String group; + final String venue; + final String time; + final String? laneNo; + final String? status; +} + +class _Header extends StatelessWidget { + const _Header({required this.onBack}); + + final VoidCallback onBack; + + @override + Widget build(BuildContext context) { + return SizedBox( + height: 52.h, + child: Align( + alignment: Alignment.centerLeft, + child: IconButton( + onPressed: onBack, + icon: Icon(Icons.arrow_back_ios_new, size: 32.r), + color: Colors.black, + tooltip: '返回', + padding: EdgeInsets.only(left: 16.w), + constraints: BoxConstraints(minWidth: 56.w, minHeight: 52.h), + ), + ), + ); + } +} + +class _ProfileSection extends StatelessWidget { + const _ProfileSection({required this.profile}); + + final EventProfile profile; + + @override + Widget build(BuildContext context) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + // width: 225.w, + // height: 184.h, + alignment: Alignment.center, + decoration: BoxDecoration( + border: Border.all(color: const Color(0xFF7A7A7A)), + ), + child: Text( + profile.avatarLabel, + style: TextStyle(fontSize: 20.sp, color: const Color(0xFF2F2F2F)), + ), + ), + SizedBox(width: 28.w), + Expanded( + child: Padding( + padding: EdgeInsets.only(top: 30.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + profile.name, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 22.sp, + height: 1.2, + color: const Color(0xFF2F2F2F), + ), + ), + SizedBox(height: 36.h), + Text( + profile.phone, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 22.sp, + height: 1.2, + color: const Color(0xFF2F2F2F), + ), + ), + ], + ), + ), + ), + ], + ); + } +} + +class _ScheduleCard extends StatelessWidget { + const _ScheduleCard({required this.item, required this.onTap}); + + final EventScheduleItem item; + final VoidCallback onTap; + + @override + Widget build(BuildContext context) { + return Material( + color: Colors.white, + child: InkWell( + onTap: onTap, + child: Container( + constraints: BoxConstraints(minHeight: 138.h), + padding: EdgeInsets.fromLTRB(10.w, 14.h, 14.w, 0), + decoration: BoxDecoration( + border: Border.all(color: const Color(0xFF7A7A7A)), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '${item.name} (${item.group})', + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 20.sp, + height: 1.2, + color: const Color(0xFF2F2F2F), + fontWeight: FontWeight.w500, + ), + ), + SizedBox(height: 26.h), + Text( + item.venue, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 20.sp, + height: 1.2, + color: const Color(0xFF2F2F2F), + ), + ), + SizedBox(height: 26.h), + Text( + item.time, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 20.sp, + height: 1.2, + color: const Color(0xFF2F2F2F), + ), + ), + ], + ), + ), + SizedBox(width: 12.w), + SizedBox( + width: 148.w, + height: 120.h, + child: Align( + alignment: Alignment.center, + child: _ScheduleBadge(item: item), + ), + ), + ], + ), + ), + ), + ); + } +} + +class _ScheduleBadge extends StatelessWidget { + const _ScheduleBadge({required this.item}); + + final EventScheduleItem item; + + @override + Widget build(BuildContext context) { + if (item.status != null) { + return CustomPaint( + painter: _CutCornerBorderPainter(color: const Color(0xFF7A7A7A)), + child: SizedBox( + width: 148.w, + height: 90.h, + child: Center( + child: Text( + item.status!, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 20.sp, color: const Color(0xFF2F2F2F)), + ), + ), + ), + ); + } + + return Text( + item.laneNo ?? '', + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 34.sp, + height: 1, + color: const Color(0xFF2F2F2F), + fontWeight: FontWeight.w700, + ), + ); + } +} + +class _CutCornerBorderPainter extends CustomPainter { + const _CutCornerBorderPainter({required this.color}); + + final Color color; + + @override + void paint(Canvas canvas, Size size) { + final side = 12.r; + final path = Path() + ..moveTo(side, 0) + ..lineTo(size.width - side, 0) + ..lineTo(size.width, side) + ..lineTo(size.width, size.height - side) + ..lineTo(size.width - side, size.height) + ..lineTo(side, size.height) + ..lineTo(0, size.height - side) + ..lineTo(0, side) + ..close(); + final paint = Paint() + ..style = PaintingStyle.stroke + ..strokeWidth = 1 + ..color = color; + canvas.drawPath(path, paint); + } + + @override + bool shouldRepaint(covariant _CutCornerBorderPainter oldDelegate) { + return oldDelegate.color != color; + } +} diff --git a/lib/features/scan_qrcode/pages/page_scan_qrcode.dart b/lib/features/scan_qrcode/pages/page_scan_qrcode.dart index 35263b7..1e7cc74 100644 --- a/lib/features/scan_qrcode/pages/page_scan_qrcode.dart +++ b/lib/features/scan_qrcode/pages/page_scan_qrcode.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:recording_tool/app/router/app_navigator.dart'; import 'package:recording_tool/features/recording/pages/page_record.dart'; -import 'package:recording_tool/features/scan_qrcode/pages/page_push_test.dart'; import 'package:recording_tool/shared/widgets/app_bar.dart'; import 'package:recording_tool/shared/widgets/app_button.dart'; import 'package:recording_tool/shared/widgets/app_qr_scanner_dialog.dart'; diff --git a/lib/shared/widgets/app_webview.dart b/lib/shared/widgets/app_webview.dart index 140112d..be2677b 100644 --- a/lib/shared/widgets/app_webview.dart +++ b/lib/shared/widgets/app_webview.dart @@ -250,16 +250,16 @@ class WebviewPageState extends State { final ok = await showDialog( context: context, builder: (context) => AlertDialog( - title: const Text("提示"), - content: const Text("是否返回上一页?"), + title: const Text('提示'), + content: const Text('是否返回上一页?'), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(false), - child: const Text("取消"), + child: const Text('取消'), ), TextButton( onPressed: () => Navigator.of(context).pop(true), - child: const Text("确定"), + child: const Text('确定'), ), ], ),