chatapp3-flutter/lib/ui_kit/widgets/room/room_game_bottom_sheet.dart
2026-04-15 14:44:27 +08:00

221 lines
7.5 KiB
Dart

import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:yumi/shared/tools/sc_lk_dialog_util.dart';
import 'package:yumi/ui_kit/components/sc_debounce_widget.dart';
import 'package:yumi/ui_kit/components/text/sc_text.dart';
class RoomGameEntryButton extends StatelessWidget {
const RoomGameEntryButton({super.key});
@override
Widget build(BuildContext context) {
return SCDebounceWidget(
onTap: () {
showBottomInBottomDialog(
context,
const RoomGameBottomSheet(),
barrierColor: Colors.black54,
);
},
child: Container(
width: 44.w,
height: 44.w,
alignment: Alignment.center,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: const Color(0xff09372E).withValues(alpha: 0.72),
border: Border.all(
color: Colors.white.withValues(alpha: 0.22),
width: 1.w,
),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.18),
blurRadius: 10.w,
offset: Offset(0, 4.w),
),
],
),
child: Text(
// 当前先用代码绘制的 `🎮` 作为语言房游戏入口占位,
// 后续设计图到位后直接替换成正式 UI 图片资源即可。
'🎮',
style: TextStyle(fontSize: 22.sp),
),
),
);
}
}
class RoomGameBottomSheet extends StatelessWidget {
const RoomGameBottomSheet({super.key});
static const int _itemsPerRow = 5;
/// 静态占位数据,后续接入真实接口后直接替换这里的数据源即可。
static const List<_RoomGameItem> _mockGames = [
_RoomGameItem(name: 'Ludo', icon: Icons.casino_outlined),
_RoomGameItem(name: 'Dice', icon: Icons.casino),
_RoomGameItem(name: 'UNO', icon: Icons.style_outlined),
_RoomGameItem(name: 'Quiz', icon: Icons.psychology_outlined),
_RoomGameItem(name: 'Race', icon: Icons.sports_motorsports_outlined),
_RoomGameItem(name: 'Poker', icon: Icons.style),
_RoomGameItem(name: 'Lucky', icon: Icons.auto_awesome_outlined),
_RoomGameItem(name: 'Bingo', icon: Icons.grid_on_outlined),
_RoomGameItem(name: '2048', icon: Icons.apps_outlined),
_RoomGameItem(name: 'Chess', icon: Icons.extension_outlined),
_RoomGameItem(name: 'Keno', icon: Icons.confirmation_number_outlined),
_RoomGameItem(name: 'Cards', icon: Icons.view_carousel_outlined),
_RoomGameItem(name: 'Darts', icon: Icons.gps_fixed),
_RoomGameItem(name: 'Puzzle', icon: Icons.interests_outlined),
_RoomGameItem(name: 'Slots', icon: Icons.local_activity_outlined),
_RoomGameItem(name: 'Spin', icon: Icons.blur_circular_outlined),
_RoomGameItem(name: 'Snake', icon: Icons.route_outlined),
_RoomGameItem(name: 'Party', icon: Icons.celebration_outlined),
_RoomGameItem(name: 'Hero', icon: Icons.shield_outlined),
_RoomGameItem(name: 'Arena', icon: Icons.sports_esports_outlined),
];
@override
Widget build(BuildContext context) {
final rowCount = (_mockGames.length / _itemsPerRow).ceil();
return SafeArea(
top: false,
child: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(18.w),
topRight: Radius.circular(18.w),
),
child: BackdropFilter(
filter: ui.ImageFilter.blur(sigmaX: 16, sigmaY: 16),
child: Container(
width: ScreenUtil().screenWidth,
height: ScreenUtil().screenHeight / 3,
color: const Color(0xff09372E).withValues(alpha: 0.88),
child: Column(
children: [
SizedBox(height: 10.w),
Container(
width: 34.w,
height: 4.w,
decoration: BoxDecoration(
color: Colors.white.withValues(alpha: 0.28),
borderRadius: BorderRadius.circular(99.w),
),
),
Padding(
padding: EdgeInsets.fromLTRB(16.w, 14.w, 16.w, 10.w),
child: Row(
children: [
text(
'Games',
fontSize: 16,
fontWeight: FontWeight.w700,
textColor: Colors.white,
),
const Spacer(),
text(
'Static mock data',
fontSize: 11,
textColor: Colors.white70,
),
],
),
),
Expanded(
child: ListView.builder(
padding: EdgeInsets.fromLTRB(12.w, 0, 12.w, 20.w),
itemCount: rowCount,
itemBuilder: (context, rowIndex) {
return Padding(
padding: EdgeInsets.only(bottom: 12.w),
child: Row(
children: List.generate(_itemsPerRow, (columnIndex) {
final itemIndex =
rowIndex * _itemsPerRow + columnIndex;
return Expanded(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 4.w),
child:
itemIndex < _mockGames.length
? _RoomGameTile(
item: _mockGames[itemIndex],
)
: const SizedBox.shrink(),
),
);
}),
),
);
},
),
),
],
),
),
),
),
);
}
}
class _RoomGameTile extends StatelessWidget {
const _RoomGameTile({required this.item});
final _RoomGameItem item;
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 48.w,
height: 48.w,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
const Color(0xff18F2B1).withValues(alpha: 0.26),
Colors.white.withValues(alpha: 0.08),
],
),
border: Border.all(
color: Colors.white.withValues(alpha: 0.2),
width: 1.w,
),
),
alignment: Alignment.center,
child: Icon(
// 当前先用系统 Icon 占位,后续会替换成具体游戏 UI 图标/图片资源。
item.icon,
size: 22.w,
color: Colors.white,
),
),
SizedBox(height: 6.w),
text(
item.name,
fontSize: 11,
textColor: Colors.white,
fontWeight: FontWeight.w500,
textAlign: TextAlign.center,
maxLines: 1,
),
],
);
}
}
class _RoomGameItem {
const _RoomGameItem({required this.name, required this.icon});
final String name;
final IconData icon;
}