241 lines
8.5 KiB
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(),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|