Three views share similar UI for avatar selection but have different implementation approaches:
- AddMoreMembers.swift - Adding new family members
- WhatsYourName.swift - Creating self member during onboarding
- EditMember.swift - Editing existing members
- Approach: Uses callback pattern with
continuePressed: (String, UIImage?, String?, String?) async throws -> Void - Flow: Collects all data (name, uploadImage, storagePath, colorHex) → Passes to callback → Callback handles
addMemberImmediate - Custom Memoji Check: Checks
memojiStore.image(UIImage) for custom generated memojis - Code Pattern:
var uploadImage: UIImage? = nil
var storagePath: String? = nil
var colorHex: String? = nil
// Collect data...
try await continuePressed(trimmed, uploadImage, storagePath, colorHex)- Approach: Directly calls FamilyStore methods
- Flow: Directly calls
setPendingSelfMemberAvatarFromMemojiorsetPendingSelfMemberAvatar - Custom Memoji Check: Checks
memojiStore.imageStoragePath(String) for custom generated memojis - Code Pattern:
if selectedImageName.hasPrefix("memoji_") {
await familyStore.setPendingSelfMemberAvatarFromMemoji(
storagePath: selectedImageName,
backgroundColorHex: colorHex
)
} else if let storagePath = memojiStore.imageStoragePath, !storagePath.isEmpty {
await familyStore.setPendingSelfMemberAvatarFromMemoji(...)
}- Approach: Directly calls FamilyStore methods (handles both self and other members)
- Flow: Directly calls
setPendingSelfMemberAvatarFromMemojiorsetAvatarForPendingOtherMemberFromMemoji - Custom Memoji Check: Checks
memojiStore.imageStoragePath(String) for custom generated memojis - Code Pattern:
if isSelf {
// Handle self member
await familyStore.setPendingSelfMemberAvatarFromMemoji(...)
} else {
// Handle other member
await familyStore.setAvatarForPendingOtherMemberFromMemoji(...)
}| View | Custom Memoji Check |
|---|---|
| AddMoreMembers | memojiStore.image (UIImage) |
| WhatsYourName | memojiStore.imageStoragePath (String) |
| EditMember | memojiStore.imageStoragePath (String) |
Issue: AddMoreMembers checks for UIImage while others check for String path. This inconsistency could cause issues.
| View | Validation |
|---|---|
| AddMoreMembers | ✅ Full validation: letters only, 25 char limit, 3 words max |
| WhatsYourName | ✅ Full validation: letters only, 25 char limit, 3 words max |
| EditMember | ❌ Basic validation: only checks if empty |
Issue: EditMember doesn't filter input or enforce limits.
| View | previousRouteForGenerateAvatar |
|---|---|
| AddMoreMembers | Sets to .addMoreMembers |
| WhatsYourName | ❌ Doesn't set (defaults to onboarding) |
| EditMember | Sets to .editMember(memberId, isSelf) or .addMoreMembersMinimal |
Issue: WhatsYourName doesn't set the route, which might cause navigation issues.
| View | State Reset/Cleanup |
|---|---|
| AddMoreMembers | ✅ Has resetMemojiSelectionState() called in onAppear |
| WhatsYourName | ❌ No state reset |
| EditMember | ✅ Seeds initial values from store in onAppear |
| View | Error Handling |
|---|---|
| AddMoreMembers | ✅ Try-catch around continuePressed callback |
| WhatsYourName | ✅ Try-catch around continuePressed callback |
| EditMember | ❌ No error handling (synchronous handleSave) |
| View | Button Text | Action |
|---|---|---|
| AddMoreMembers | "Add Member" | Calls handleAddMember |
| WhatsYourName | "Continue" | Calls handleContinue |
| EditMember | "Save" | Calls handleSave (synchronous) |
All views should check memojiStore.imageStoragePath (String) instead of memojiStore.image (UIImage):
- Update AddMoreMembers to check
imageStoragePathlike the others
EditMember should have the same validation as AddMoreMembers and WhatsYourName:
- Filter to letters and spaces only
- Limit to 25 characters
- Limit to 3 words max
WhatsYourName should set memojiStore.previousRouteForGenerateAvatar when navigating to GenerateAvatar:
memojiStore.previousRouteForGenerateAvatar = .whatsYourNameEditMember's handleSave should handle errors properly, especially for async operations.
The avatar selection UI and logic could be extracted into a reusable component to reduce duplication.
✅ Consistent:
- Avatar list (memoji_1 through memoji_14)
- UI layout (fixed plus button + divider + scrollable memojis)
- Local memoji detection (
hasPrefix("memoji_")) - Color extraction using
toHex()
❌ Inconsistent:
- Custom memoji detection (UIImage vs String)
- Name validation (full vs basic)
- Navigation route setting
- Error handling
- State management