Summary
Multi-step registration wizard that collects account type, personal info, interests/genre tags, username, birthday, and credentials. Deep-reworked at commit 841ec58 (branch edit/mobile-audit-ux-polish). For screen visual design spec see auth-screens.
Files
| File | Role |
|---|---|
lib/features/auth/screens/registration_wizard_screen.dart | UI, step rendering, animations |
lib/features/auth/notifiers/registration_wizard_notifier.dart | State, validation, Supabase submit |
lib/shared/widgets/flow_date_wheel_picker.dart | Birthday date picker widget |
State Model — RegistrationWizardState
Key fields (all others in the file itself):
final WizardStep currentStep; // enum-driven step machine
final AccountType? selectedType; // personal | creator | business
final String? fieldError; // inline per-step error message
final bool isValidating; // async check in progress → CTA spinner
final bool isSubmitting; // final submit in progress
final String? lastSelectedInterest; // drives tag affinity ordering
final UsernameCheckStatus usernameCheckStatus; // idle|checking|available|takenField is
selectedType— notselectedAccountType. Any screen code referencing the old name will throw a getter-not-found error.
Step Machine — WizardStep Enum
welcome → accountType → personal (name+birthday+username) →
[creator: stageName+genre] | [business: name+category+location] →
vibeCheck → credentials → submit
Sub-steps within personal/creator/business are tracked by pageIndex inside each step group.
Notifier — Key Methods
validateThenCall(l10n, onValid)
Every “Continue” button calls this. Flow:
- Sets
isValidating = true, clearsfieldError - Runs
_validateCurrentStep(l10n)— async (may hit Supabase) - Error → sets
fieldError, clearsisValidating(CTA re-enables) - OK → clears
isValidating, callsonValid()
setUsername(value) — Live availability
Debounces 450 ms, then calls _runUsernameAvailabilityCheck() which queries profiles.username with .maybeSingle(). Sets usernameCheckStatus → available or taken. Network failures reset to idle silently — the hard check on submit is the authoritative guard.
orderedTags(allTags, selectedNames, lastSelectedName, {affinityWeights})
Static method. Order:
- Selected (in selection order)
- Neural path: unselected sorted by
P(B|lastSelected)desc (ifaffinityWeightsnon-empty) - Structural fallback: same
parentIdor samecategory, sorted byusageCount - Rest by
usageCountdesc
Validation Matrix
| Step | Rule |
|---|---|
| Personal name | First name not empty |
| Birthday | Age ≥ 18 |
| Username | Format [a-zA-Z0-9_.] 3–30 chars + Supabase uniqueness |
| Creator stage name | Not empty |
| Business name + category | Both not empty |
| Business location | Address not empty |
| Credentials | Email format + password ≥ 8 chars |
| Submit | Re-validate credentials; email already registered → fieldError (not SnackBar) |
Tag System
Tables: tags (id, name, category ENUM, parent_id, usage_count), tag_affinity (tag_a_id, tag_b_id, weight FLOAT, co_occurrences, computed_at)
Weight formula: P(B|A) = co_occurrences(A,B) / count(profiles_with_A) — asymmetric.
Providers:
tagListProvider— all tags, global singleton, prefetched at wizard mount viaref.watchin_WizardBody.buildtagAffinityProvider(tagId)—FutureProvider.autoDispose.family, per-tag weights
Chip styling (_tagChip):
- Selected:
electricCoralfill, white label,FontWeight.w600,showCheckmark: false - Unselected: white fill,
textPrimary,FontWeight.w400,dividerLightborder - Shape:
RoundedRectangleBorder(borderRadius: 20)— pill
Date Picker — FlowDateWheelPicker
Two modes toggled by top-right button:
- Wheel (default): Three
ListWheelScrollViewcolumns (DD / MMM / YYYY). Arrow Up/Down scrolls; Arrow Right/Tab advances focus; focused column has coral border. - Keyboard: Three
TextFieldfields, day and month auto-advance after 2 digits.
Tab-escape fix: Tab on year column returns KeyEventResult.ignored (not handled) so Flutter’s tab order advances naturally to the “Continue” button.
Provider Setup
final registrationWizardNotifierProvider =
StateNotifierProvider.autoDispose<RegistrationWizardNotifier, RegistrationWizardState>(
(ref) => RegistrationWizardNotifier(),
);autoDispose ensures state resets on every navigation away — the welcome step is always shown fresh on re-entry.
Firebase Guard
NotificationService._firebaseAvailable is set only after successful Firebase.initializeApp(). All FCM calls are gated behind this flag to prevent [core/no-app] exceptions when google-services.json is absent.
l10n Keys
All in app_en.arb, app_it.arb, app_es.arb:
wizardValidationFirstNameRequired wizardValidationAgeRestriction
wizardValidationUsernameRequired wizardValidationUsernameFormat
wizardValidationUsernameTaken wizardValidationEmailRequired
wizardValidationEmailFormat wizardValidationPasswordTooShort
wizardValidationBusinessNameRequired wizardValidationBusinessCategoryRequired
wizardValidationStageNameRequired wizardValidationLocationRequired
wizardValidationEmailTaken
dateInputDay dateInputMonth dateInputYear
dateInputModeKeyboard dateInputModeWheel
For welcome/auth screen keys see auth-screens.
Related
auth-screens — visual design spec for all auth screens localization — ARB workflow context-map — tag & recommendation system inline spec