Files
mav 93042cbb4c feat: complete 20-screen onboarding flow
Full quiz flow s01-s20: splash, intro, value prop, social proof,
name/skin-type/age/concerns/goal quiz with insights, analysing loader,
result with skin score, AM/PM routines, ingredient science, signup, welcome.

Duolingo-style design: flat cards, pressable SButton (Stack trick),
4px progress bar, mascot moods (wave/think/analyze/celebrate),
confetti on result+welcome, personalized content throughout.
2026-05-28 17:11:27 +02:00

93 lines
3.6 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart';
import '../../theme.dart';
import '../../widgets/s_card.dart';
import '../../widgets/s_button.dart';
import '../../widgets/s_progress_bar.dart';
import '../../model/quiz_state.dart';
import '../../router.dart';
import 's09_concerns.dart';
import '_quiz_nav.dart';
class AgeScreen extends StatefulWidget {
final QuizState state;
const AgeScreen({super.key, required this.state});
@override
State<AgeScreen> createState() => _State();
}
class _State extends State<AgeScreen> {
String _selected = '';
static const _opts = [
(Icons.star_rounded, 'Under 25', 'Young & preventive care'),
(Icons.hourglass_bottom_rounded, '2535', 'Early anti-aging focus'),
(Icons.wb_sunny_rounded, '3545', 'Targeted treatments'),
(Icons.nightlight_round, '4560', 'Deep renewal & firming'),
(Icons.diamond_rounded, '60+', 'Intensive care & radiance'),
];
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: SColors.bgSurface,
body: SafeArea(
child: Column(
children: [
QuizNav(step: 3, total: 7, onBack: () => Navigator.of(context).pop()),
const SizedBox(height: 10),
Padding(padding: const EdgeInsets.symmetric(horizontal: 16), child: SProgressBar(value: 3 / 7)),
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.fromLTRB(16, 24, 16, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('How old\nare you?', style: SText.headline2(SColors.textHead))
.animate().fadeIn(duration: 350.ms),
const SizedBox(height: 6),
Text('Skin changes with age — helps us tailor advice.', style: SText.subtitle(SColors.textSub))
.animate().fadeIn(duration: 350.ms, delay: 80.ms),
const SizedBox(height: 20),
],
),
),
..._opts.asMap().entries.map((e) {
final i = e.key; final (icon, label, sub) = e.value;
return Padding(
padding: const EdgeInsets.only(bottom: 8),
child: SCard(
icon: icon, label: label, sub: sub,
isSelected: _selected == label,
onTap: () => setState(() => _selected = label),
).animate().fadeIn(duration: 280.ms, delay: (100 + i * 55).ms)
.slideX(begin: 0.03, end: 0, duration: 280.ms),
);
}),
],
),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(16, 12, 16, 20),
child: SButton(
label: 'CONTINUE',
enabled: _selected.isNotEmpty,
onTap: _selected.isNotEmpty ? () {
widget.state.age = _selected;
Navigator.of(context).push(slideRoute(ConcernsScreen(state: widget.state)));
} : null,
),
),
],
),
),
);
}
}