ponshu-room-lite/lib/widgets/gamification/level_title_card.dart

241 lines
8.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../providers/theme_provider.dart';
import 'package:google_fonts/google_fonts.dart';
import '../contextual_help_icon.dart';
import '../../theme/app_colors.dart';
class LevelTitleCard extends ConsumerWidget {
const LevelTitleCard({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final userProfile = ref.watch(userProfileProvider);
final totalExp = userProfile.totalExp;
final appColors = Theme.of(context).extension<AppColors>()!;
final level = userProfile.level;
final title = userProfile.title;
final progress = userProfile.nextLevelProgress;
final expToNext = userProfile.expToNextLevel;
return Container(
width: double.infinity,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Theme.of(context).cardColor,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.05),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
border: Border.all(
color: Theme.of(context).dividerColor.withValues(alpha: 0.1),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
'現在の称号',
style: Theme.of(context).textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.bold,
),
),
const SizedBox(width: 4),
ContextualHelpIcon(
title: 'レベルと称号について',
customContent: _buildLevelHelpContent(context),
),
],
),
const SizedBox(height: 4),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: Text(
title,
style: GoogleFonts.zenOldMincho(
fontSize: 28,
fontWeight: FontWeight.bold,
color: appColors.brandPrimary,
),
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
margin: const EdgeInsets.only(bottom: 4, left: 8), // Align baseline-ish
decoration: BoxDecoration(
color: appColors.brandPrimary.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: appColors.brandPrimary.withValues(alpha: 0.3)),
),
child: Text(
'Lv.$level',
style: TextStyle(
fontWeight: FontWeight.w900,
fontSize: 16,
color: appColors.brandPrimary,
),
),
),
],
),
],
),
),
],
),
const SizedBox(height: 20),
// Progress Bar
ClipRRect(
borderRadius: BorderRadius.circular(4),
child: LinearProgressIndicator(
value: progress,
minHeight: 8,
backgroundColor: appColors.divider,
valueColor: AlwaysStoppedAnimation<Color>(appColors.brandPrimary),
),
),
const SizedBox(height: 8),
// EXP Text
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Total EXP: $totalExp',
style: TextStyle(fontSize: 12, color: appColors.textSecondary),
),
Text(
expToNext > 0 ? '次のレベルまで: ${expToNext}exp' : 'Max Level',
style: TextStyle(
fontSize: 12,
color: appColors.brandPrimary,
fontWeight: FontWeight.bold,
),
),
],
),
],
),
);
}
static Widget _buildLevelHelpContent(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'レベルの上げ方',
style: Theme.of(context).textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text(
'日本酒を1本登録するごとに 10 EXP 獲得できます。\nメニューを作成するとボーナスが入ることも!',
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
height: 1.6,
),
),
const SizedBox(height: 16),
Text(
'称号一覧',
style: Theme.of(context).textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
_buildLevelTable(context),
],
);
}
static Widget _buildLevelTable(BuildContext context) {
// Level data from LevelCalculator
final levels = [
{'level': 1, 'requiredExp': 0, 'title': '見習い'},
{'level': 2, 'requiredExp': 10, 'title': '歩き飲み'},
{'level': 5, 'requiredExp': 50, 'title': '嗜み人'},
{'level': 10, 'requiredExp': 100, 'title': '呑兵衛'},
{'level': 20, 'requiredExp': 200, 'title': '酒豪'},
{'level': 30, 'requiredExp': 300, 'title': '利き酒師'},
{'level': 50, 'requiredExp': 500, 'title': '日本酒伝道師'},
{'level': 100, 'requiredExp': 1000, 'title': 'ポンシュマスター'},
];
return Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainerHighest.withValues(alpha: 0.3),
borderRadius: BorderRadius.circular(8),
),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: DataTable(
headingRowHeight: 40,
dataRowMinHeight: 32,
dataRowMaxHeight: 32,
columns: [
DataColumn(
label: Text(
'Lv',
style: TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.bold,
),
),
),
DataColumn(
label: Text(
'称号',
style: TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.bold,
),
),
),
DataColumn(
label: Text(
'必要EXP',
style: TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.bold,
),
),
),
],
rows: levels.map((levelData) {
return DataRow(
cells: [
DataCell(Text((levelData['level'] as int).toString(), style: const TextStyle(fontSize: 12))),
DataCell(Text(levelData['title'] as String, style: const TextStyle(fontSize: 12))),
DataCell(Text((levelData['requiredExp'] as int).toString(), style: const TextStyle(fontSize: 12))),
],
);
}).toList(),
),
),
);
}
}