Files
focusflow/lib/core/widgets/reward_popup.dart
Oracle Public Cloud User 50931d839d Initial scaffold: FocusFlow ADHD Task Manager Flutter app
BLoC/Cubit state management, ADHD-friendly theme (calming teal, no red),
GetIt DI, GoRouter navigation. Screens: task dashboard, focus mode,
task create/detail, streaks, time perception, settings, onboarding, auth.
Custom widgets: TaskCard, RewardPopup, StreakRing, GentleNudgeCard.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 15:53:58 +00:00

132 lines
4.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:focusflow_shared/focusflow_shared.dart';
import '../theme/app_colors.dart';
/// Reward celebration overlay.
///
/// Shows after a task is completed:
/// - Placeholder area for a Lottie animation.
/// - Points / magnitude display.
/// - Encouraging message.
/// - "Nice!" dismiss button.
/// - Surprise rewards get extra fanfare (larger, longer animation).
class RewardPopup extends StatelessWidget {
final Reward reward;
final VoidCallback onDismiss;
const RewardPopup({
super.key,
required this.reward,
required this.onDismiss,
});
/// Messages shown at random — always positive.
static const _messages = [
'You did it!',
'Awesome work!',
'One more down!',
'Keep that momentum!',
'Look at you go!',
'Your brain thanks you!',
'Small wins add up!',
'That felt good, right?',
];
String get _message {
if (reward.description != null && reward.description!.isNotEmpty) {
return reward.description!;
}
// Deterministic pick based on reward id hashCode so the same reward
// always shows the same message during a session.
return _messages[reward.id.hashCode.abs() % _messages.length];
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final isSurprise = reward.isSurprise;
final size = isSurprise ? 140.0 : 100.0;
return Center(
child: Material(
color: Colors.transparent,
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 32),
padding: const EdgeInsets.all(28),
decoration: BoxDecoration(
color: theme.colorScheme.surface,
borderRadius: BorderRadius.circular(24),
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(40),
blurRadius: 24,
offset: const Offset(0, 8),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// ── Animation placeholder ────────────────────────────
Container(
width: size,
height: size,
decoration: BoxDecoration(
color: AppColors.rewardGold.withAlpha(40),
shape: BoxShape.circle,
),
child: Icon(
isSurprise ? Icons.auto_awesome : Icons.celebration_rounded,
size: size * 0.5,
color: AppColors.rewardGold,
),
),
const SizedBox(height: 20),
// ── Title ────────────────────────────────────────────
if (reward.title != null)
Text(
reward.title!,
style: theme.textTheme.headlineSmall?.copyWith(
fontWeight: FontWeight.w700,
),
textAlign: TextAlign.center,
),
if (reward.title != null) const SizedBox(height: 8),
// ── Points ───────────────────────────────────────────
Text(
'+${reward.magnitude} pts',
style: theme.textTheme.titleLarge?.copyWith(
color: AppColors.rewardGoldDark,
fontWeight: FontWeight.w800,
),
),
const SizedBox(height: 12),
// ── Message ──────────────────────────────────────────
Text(
_message,
style: theme.textTheme.bodyLarge,
textAlign: TextAlign.center,
),
const SizedBox(height: 24),
// ── Dismiss ──────────────────────────────────────────
FilledButton(
onPressed: onDismiss,
style: FilledButton.styleFrom(
backgroundColor: AppColors.primary,
minimumSize: const Size(160, 52),
),
child: const Text('Nice!'),
),
],
),
),
),
);
}
}