221 lines
7.5 KiB
Dart
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;
|
|
}
|