fix: Add missing badge check after AI sake registration
## Bug Fix - Badge "初めての一歩" was not unlocking when adding first sake item - Root cause: GamificationService.checkAndUnlockBadges() was never called in camera_screen.dart ## Changes - Import gamification_service.dart - Call checkAndUnlockBadges(ref) after adding sake item to Hive - Display newly unlocked badges in success SnackBar - Extend SnackBar duration when badges are unlocked (4s -> 6s) ## User Impact - Users will now see badge unlock notifications: "バッジ獲得: 初めての一歩 🍶" - All badge unlock conditions (first_step, regional, collector, flavor) now work correctly 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
b600579123
commit
5410c78c6c
|
|
@ -11,6 +11,7 @@ import 'package:gal/gal.dart';
|
||||||
|
|
||||||
import '../services/gemini_service.dart';
|
import '../services/gemini_service.dart';
|
||||||
import '../services/image_compression_service.dart'; // Phase 4 Added
|
import '../services/image_compression_service.dart'; // Phase 4 Added
|
||||||
|
import '../services/gamification_service.dart'; // Badge check
|
||||||
import '../widgets/analyzing_dialog.dart';
|
import '../widgets/analyzing_dialog.dart';
|
||||||
import '../models/sake_item.dart';
|
import '../models/sake_item.dart';
|
||||||
import '../theme/app_theme.dart';
|
import '../theme/app_theme.dart';
|
||||||
|
|
@ -386,9 +387,12 @@ class _CameraScreenState extends ConsumerState<CameraScreen> with SingleTickerPr
|
||||||
// Award EXP
|
// Award EXP
|
||||||
final userProfileState = ref.read(userProfileProvider);
|
final userProfileState = ref.read(userProfileProvider);
|
||||||
final prevLevel = userProfileState.level;
|
final prevLevel = userProfileState.level;
|
||||||
|
|
||||||
await ref.read(userProfileProvider.notifier).updateTotalExp(userProfileState.totalExp + 10);
|
await ref.read(userProfileProvider.notifier).updateTotalExp(userProfileState.totalExp + 10);
|
||||||
|
|
||||||
|
// Check and unlock badges
|
||||||
|
final newBadges = await GamificationService.checkAndUnlockBadges(ref);
|
||||||
|
|
||||||
// Refetch updated state for level comparison
|
// Refetch updated state for level comparison
|
||||||
final updatedProfile = ref.read(userProfileProvider);
|
final updatedProfile = ref.read(userProfileProvider);
|
||||||
final newLevel = updatedProfile.level;
|
final newLevel = updatedProfile.level;
|
||||||
|
|
@ -408,28 +412,49 @@ class _CameraScreenState extends ConsumerState<CameraScreen> with SingleTickerPr
|
||||||
// Close Camera Screen (Return to Home)
|
// Close Camera Screen (Return to Home)
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
|
|
||||||
// Success Message (with EXP/Level Up info)
|
// Success Message (with EXP/Level Up/Badge info)
|
||||||
|
final List<Widget> messageWidgets = [
|
||||||
|
Text('${sakeItem.displayData.name} を登録しました!'),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
const Icon(LucideIcons.sparkles, color: Colors.yellow, size: 16),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Text(
|
||||||
|
'経験値 +10 GET! ${isLevelUp ? " (Level UP!)" : ""}',
|
||||||
|
style: const TextStyle(fontWeight: FontWeight.bold, color: Colors.yellowAccent),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Add badge notifications
|
||||||
|
if (newBadges.isNotEmpty) {
|
||||||
|
messageWidgets.add(const SizedBox(height: 8));
|
||||||
|
for (var badge in newBadges) {
|
||||||
|
messageWidgets.add(
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(badge.icon, style: const TextStyle(fontSize: 16)),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Text(
|
||||||
|
'バッジ獲得: ${badge.name}',
|
||||||
|
style: const TextStyle(fontWeight: FontWeight.bold, color: Colors.greenAccent),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Column(
|
content: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: messageWidgets,
|
||||||
Text('${sakeItem.displayData.name} を登録しました!'),
|
|
||||||
const SizedBox(height: 4),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
const Icon(LucideIcons.sparkles, color: Colors.yellow, size: 16),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
Text(
|
|
||||||
'経験値 +10 GET! ${isLevelUp ? " (Level UP!)" : ""}',
|
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold, color: Colors.yellowAccent),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
duration: const Duration(seconds: 4), // Longer display for level up
|
duration: Duration(seconds: newBadges.isNotEmpty ? 6 : 4), // Longer for badges
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -793,12 +818,10 @@ class _ExposureSliderPainter extends CustomPainter {
|
||||||
// Draw knob
|
// Draw knob
|
||||||
canvas.drawCircle(Offset(trackX, knobY), 6, knobPaint);
|
canvas.drawCircle(Offset(trackX, knobY), 6, knobPaint);
|
||||||
}
|
}
|
||||||
}
|
} @override
|
||||||
|
|
||||||
@override
|
|
||||||
bool shouldRepaint(_ExposureSliderPainter oldDelegate) {
|
bool shouldRepaint(_ExposureSliderPainter oldDelegate) {
|
||||||
return oldDelegate.currentValue != currentValue ||
|
return oldDelegate.currentValue != currentValue ||
|
||||||
oldDelegate.minValue != minValue ||
|
oldDelegate.minValue != minValue ||
|
||||||
oldDelegate.maxValue != maxValue;
|
oldDelegate.maxValue != maxValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue