Applies verified fixes from deep audit (concurrency, performance, security,
accessibility), standardizes CRUD form buttons to Add/Save pattern, removes
.drawingGroup() that broke search bar TextFields, and converts vulnerable
.sheet(isPresented:) + if-let patterns to safe presentation to prevent
blank white modals.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rewrite ResidenceFormView to use standard Form/Section pattern matching TaskFormView
- Remove unused organic form components (OrganicFormSection, OrganicFormTextField, etc.)
- Fix DocumentFormView: NavigationView→NavigationStack, WarmGradientBackground→appBackgroundPrimary, listRowBackground→sectionBackground
- Add Required footer to residence name field and task title/property fields
- Remove redundant Required footers from pickers that always have values
- Fix grey priority dots on kanban cards by guarding PriorityBadge in DynamicTaskCard and TaskCard
- Fix empty frequency labels showing on task cards
- Fix contractor Maps URL building to filter empty strings
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Completion animations: play user-selected animation on task card after completing,
with DataManager guard to prevent race condition during animation playback.
Works in both AllTasksView and ResidenceDetailView. Animation preference
persisted via @AppStorage and configurable from Settings.
- Subscription: add trial fields (trialStart, trialEnd, trialActive) and
subscriptionSource to model, cross-platform purchase guard, trial banner
in upgrade prompt, and platform-aware subscription management in profile.
- Analytics: disable PostHog SDK debug logging and remove console print
statements to reduce debug console noise.
- Documents: remove redundant nested do-catch blocks in ViewModel wrapper.
- Widgets: add debounced timeline reloads and thread-safe file I/O queue.
- Onboarding: fix animation leak on disappear, remove unused state vars.
- Remove unused files (ContentView, StateFlowExtensions, CustomView).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove old PostHogAnalytics singleton and replace with guide-based
two-file architecture: AnalyticsManager (singleton wrapper with super
properties, session replay, opt-out, subscription funnel) and
AnalyticsEvent (type-safe enum with associated values).
Key changes:
- New API key, self-hosted analytics endpoint
- All 19 events ported to type-safe AnalyticsEvent enum
- Screen tracking via AnalyticsManager.Screen enum + SwiftUI modifier
- Remove all identify() calls — fully anonymous analytics
- Add lifecycle hooks: flush on background, update super properties on foreground
- Add privacy opt-out toggle in Settings
- Subscription funnel methods ready for IAP integration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Create centralized shared utilities in iosApp/Shared/:
- Extensions: ViewExtensions, DateExtensions, StringExtensions, DoubleExtensions
- Components: FormComponents, SharedEmptyStateView, ButtonStyles
- Modifiers: CardModifiers
- Utilities: ValidationHelpers, ErrorMessages
Migrate existing views to use shared utilities:
- LoginView: Use IconTextField, FieldLabel, FieldError, OrganicPrimaryButton
- TaskFormView: Use .loadingOverlay() modifier
- TaskCard/DynamicTaskCard: Use .toFormattedDate() extension
- CompletionCardView: Use .toCurrency() (with KotlinDouble support)
- ResidenceDetailView: Use OrganicEmptyState, StandardLoadingView
- Profile views: Use .standardFormStyle(), .sectionBackground()
- Form views: Use consistent form styling modifiers
Benefits:
- Eliminates ~180 lines of duplicate code
- Consistent styling across all forms and components
- KotlinDouble extensions for seamless KMM interop
- Single source of truth for UI patterns
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Creates a reusable KeyboardDismissToolbar view modifier that adds a
"Done" button to dismiss keyboards that don't have a return key.
Applied to all numeric keyboards (numberPad, decimalPad, phonePad)
and multi-line text inputs (TextEditor, TextField with axis: .vertical).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add customIntervalDays field to Kotlin models (TaskResponse, TaskCreateRequest, TaskUpdateRequest)
- Update Android AddTaskDialog to show interval field only for "Custom" frequency
- Update Android EditTaskScreen for custom frequency support
- Update iOS TaskFormView for custom frequency support
- Fix preview data in TaskCard and TasksSection to include new field
- Add customIntervalDays to OnboardingFirstTaskView
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add nextDueDate field to TaskResponse model (from API's next_due_date)
- Add effectiveDueDate computed property (nextDueDate ?? dueDate)
- Update DynamicTaskCard, TaskCard to display effectiveDueDate
- Update WidgetDataManager to save effectiveDueDate to widget cache
- Update TaskFormView to use effectiveDueDate when editing
- Fix preview mock data to include nextDueDate parameter
This ensures recurring tasks show the correct next due date after completion
instead of the original due date.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove TaskStatus model and status_id foreign key references
- Add in_progress boolean field to task models and forms
- Update TaskApi to use dedicated POST endpoints for task actions:
- POST /tasks/:id/cancel/ instead of PATCH with is_cancelled
- POST /tasks/:id/uncancel/
- POST /tasks/:id/archive/
- POST /tasks/:id/unarchive/
- Fix iOS TaskViewModel to use error-first pattern for Kotlin-Swift
generic type bridging issues
- Update iOS callback signatures to pass full TaskResponse instead
of just taskId to avoid stale closure lookups
- Add in_progress localization strings
- Update widget preview data to use inProgress boolean
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add TaskTemplate model with category grouping support
- Add TaskTemplateApi for fetching templates from backend
- Add TaskSuggestionDropdown component for Android task form
- Add TaskTemplatesBrowserSheet for browsing all templates
- Add TaskSuggestionsView and TaskTemplatesBrowserView for iOS
- Update DataManager to cache task templates
- Update APILayer with template fetch and search methods
- Update TaskFormView (iOS) with template suggestions
- Update AddTaskDialog (Android) with template suggestions
- Update onboarding task view to use templates
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add Suite0_OnboardingTests with fresh install and login test flows
- Add accessibility identifiers to onboarding views for UI testing
- Remove deprecated DataCache in favor of unified DataManager
- Update API layer to support public upgrade-triggers endpoint
- Improve onboarding first task view with better date handling
- Update various views with accessibility identifiers for testing
- Fix subscription feature comparison view layout
- Update document detail view improvements
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
KMM (Android/Shared):
- Add strings.xml with 200+ localized strings
- Add translation files for es, fr, de, pt languages
- Update all screens to use stringResource() for i18n
- Add Accept-Language header to API client for all platforms
iOS:
- Add L10n.swift helper with type-safe string accessors
- Add Localizable.xcstrings with translations for all 5 languages
- Update all SwiftUI views to use L10n.* for localized strings
- Localize Auth, Residence, Task, Contractor, Document, and Profile views
Supported languages: English, Spanish, French, German, Portuguese
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add CompletionHistorySheet for viewing task completion history (Android & iOS)
- Update TaskCard and DynamicTaskCard with completion history access
- Add getTaskCompletions API endpoint to TaskApi and APILayer
- Update models (CustomTask, Document, TaskCompletion, User) for Go API alignment
- Improve TaskKanbanView with completion history integration
- Update iOS TaskViewModel with completion history loading
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Update all Kotlin API models to match Go API response structures
- Fix Swift type aliases (TaskDetail→TaskResponse, Residence→ResidenceResponse, etc.)
- Update TaskCompletionCreateRequest to simplified Go API format (taskId, notes, actualCost, photoUrl)
- Fix optional handling for frequency, priority, category, status in task models
- Replace isPrimaryOwner with ownerId comparison against current user
- Update ResidenceUsersResponse to use owner.id instead of ownerId
- Fix non-optional String fields to use isEmpty checks instead of optional binding
- Add type aliases for backwards compatibility in Kotlin models
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Apply consistent branding colors (BlueGreen, Cerulean, BrightAmber, PrimaryScarlet,
cream backgrounds) to all screens, components, buttons, icons, and text throughout
the app. Update all Form/List views with proper list row backgrounds to ensure
visual consistency with card-based layouts.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added AccessibilityIdentifiers helper struct with identifiers for all major
UI elements across the app. Applied identifiers throughout authentication,
navigation, forms, and feature screens to enable reliable UI testing.
Changes:
- Added Helpers/AccessibilityIdentifiers.swift with centralized ID definitions
- LoginView: Added identifiers for username, password, login button fields
- RegisterView: Added identifiers for registration form fields
- MainTabView: Added identifiers for all tab bar items
- ProfileTabView: Added identifiers for logout and settings buttons
- ResidencesListView: Added identifier for add button
- Task views: Added identifiers for add, save, and form fields
- Document forms: Added identifiers for form fields and buttons
Identifiers follow naming pattern: [Feature].[Element]
Example: AccessibilityIdentifiers.Authentication.loginButton
This enables UI tests to reliably locate elements using:
app.buttons[AccessibilityIdentifiers.Authentication.loginButton]
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed type conversion issues in iOS Swift files to handle KotlinDouble for
cost fields instead of String. Updated all task-related views to properly
convert between String (for TextField input) and KotlinDouble (for API calls).
Changes:
- TaskCard.swift: Updated preview data with new TaskDetail signature (added
residenceName, createdBy, createdByUsername, intervalDays; changed
estimatedCost from String to Double; removed actualCost and notes)
- TasksSection.swift: Updated two preview TaskDetail instances with new signature
- CompleteTaskView.swift: Convert actualCost String to KotlinDouble for API
- EditTaskView.swift: Convert estimatedCost between KotlinDouble and String
for display and API calls
- TaskFormView.swift: Convert estimatedCost String to KotlinDouble for API
Pattern used:
- Display: KotlinDouble -> String using .doubleValue
- API: String -> Double -> KotlinDouble using KotlinDouble(double:)
Build now succeeds with all type conversions properly handling Decimal/Double
values from backend instead of String.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implemented user-friendly error handling for network call failures:
Android (Compose):
- Created reusable ErrorDialog component with retry and cancel buttons
- Updated TasksScreen to show error dialog popup instead of inline error
- Error dialog appears when network calls fail with option to retry
iOS (SwiftUI):
- Created ErrorAlertModifier and ErrorAlertInfo helpers
- Added .errorAlert() view modifier for consistent error handling
- Updated TaskFormView to show error alerts with retry/cancel options
- Error alerts appear when task creation or other network calls fail
Both platforms now provide a consistent user experience when network
errors occur, giving users the choice to retry the operation or cancel.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Refactored ContractorFormSheet to follow SwiftUI best practices
- Moved Field enum outside struct and renamed to ContractorFormField
- Extracted body into computed properties for better readability
- Replaced deprecated NavigationView with NavigationStack
- Fixed input field contrast in light mode by adding borders
- Fixed force cast in loadContractorSpecialties
- Refactored TaskFormView to eliminate screen flickering
- Moved Field enum outside struct and renamed to TaskFormField
- Fixed conditional view structure that caused flicker on load
- Used ZStack with overlay instead of if/else for loading state
- Changed to .task modifier for proper async initialization
- Made loadLookups properly async and fixed force casts
- Replaced deprecated NavigationView with NavigationStack
- Integrated PushNotificationManager with APILayer
- Updated registerDeviceWithBackend to use APILayer.shared.registerDevice()
- Updated updateNotificationPreferences to use APILayer
- Updated getNotificationPreferences to use APILayer
- Added proper error handling with try-catch pattern
- Added notification operations to APILayer
- Added NotificationApi instance
- Implemented registerDevice, unregisterDevice
- Implemented getNotificationPreferences, updateNotificationPreferences
- Implemented getNotificationHistory, markNotificationAsRead
- Implemented markAllNotificationsAsRead, getUnreadCount
- All methods follow consistent pattern with auth token handling
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Major architectural improvements:
- Created APILayer as single entry point for all network operations
- Integrated cache-first reads with automatic cache updates on mutations
- Migrated all shared Kotlin ViewModels to use APILayer instead of direct API calls
- Migrated iOS ViewModels to wrap shared Kotlin ViewModels with StateFlow observation
- Replaced LookupsManager with DataCache for centralized lookup data management
- Added password reset methods to AuthViewModel
- Added task completion and update methods to APILayer
- Added residence user management methods to APILayer
iOS specific changes:
- Updated LoginViewModel, RegisterViewModel, ProfileViewModel to use shared AuthViewModel
- Updated ContractorViewModel, DocumentViewModel to use shared ViewModels
- Updated ResidenceViewModel to use shared ViewModel and APILayer
- Updated TaskViewModel to wrap shared ViewModel with callback-based interface
- Migrated PasswordResetViewModel and VerifyEmailViewModel to shared AuthViewModel
- Migrated AllTasksView, CompleteTaskView, EditTaskView to use APILayer
- Migrated ManageUsersView, ResidenceDetailView to use APILayer
- Migrated JoinResidenceView to use async/await pattern with APILayer
- Removed LookupsManager.swift in favor of DataCache
- Fixed PushNotificationManager @MainActor issue
- Converted all direct API calls to use async/await with proper error handling
Benefits:
- Reduced code duplication between iOS and Android
- Consistent error handling across platforms
- Automatic cache management for better performance
- Centralized network layer for easier testing and maintenance
- Net reduction of ~700 lines of code through shared logic
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit completes the DRY refactoring by implementing the missing document form functionality and enhancing user experience with better error messages.
## iOS Document Forms
- Implemented complete createDocument() method in DocumentViewModel:
- Support for all warranty-specific fields (itemName, modelNumber, serialNumber, provider, etc.)
- Multiple image uploads with JPEG compression
- Proper UIImage to KotlinByteArray conversion
- Async completion handlers
- Implemented updateDocument() method with full field support
- Completed DocumentFormView submitForm() implementation with proper API calls
- Fixed type conversion issues (Bool/KotlinBoolean, Int32/KotlinInt)
- Added proper error handling and user feedback
## iOS Login Error Handling
- Enhanced error messages to be user-friendly and concise
- Added specific messages for common HTTP error codes (400, 401, 403, 404, 500+)
- Implemented cleanErrorMessage() helper to remove technical jargon
- Added network-specific error handling (connection, timeout)
- Fixed MainActor isolation warnings with proper Task wrapping
## Code Quality
- Removed ~4,086 lines of duplicate code through form consolidation
- Added 429 lines of new shared form components
- Fixed Swift compiler performance issues
- Ensured both iOS and Android builds succeed
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>