## StoreKit 2 Refactor - Rewrote IAPManager with clean enum-based state model (SubscriptionState) - Added native SubscriptionStoreView for iOS 17+ purchase UI - Subscription status now checked on every app launch - Synced subscription status to UserDefaults for widget access - Simplified PurchaseButtonView and IAPWarningView - Removed unused StatusInfoView ## Interactive Vote Widget - New FeelsVoteWidget with App Intents for mood voting - Subscribers can vote directly from widget, shows stats after voting - Non-subscribers see "Tap to subscribe" which opens subscription store - Added feels:// URL scheme for deep linking ## Firebase Removal - Commented out Firebase imports and initialization - EventLogger now prints to console in DEBUG mode only ## Other Changes - Added fallback for Core Data when App Group unavailable - Added new localization strings for subscription UI - Updated entitlements and Info.plist 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
5.6 KiB
5.6 KiB
Feels - iOS Mood Tracking App
Overview
Feels is a daily mood tracking iOS application that allows users to rate their emotional state each day on a 5-point scale (Horrible, Bad, Average, Good, Great) and visualize patterns over time through multiple view modes.
Core Features
- Daily Mood Tracking: Rate your day on a 5-point scale
- Multiple View Modes: Day (chronological list), Month (calendar grid), Year (aggregate stats)
- Customization: Themes, color schemes, icon packs, notification personalities
- Widgets: iOS home screen widgets showing recent moods
- Local Notifications: Daily reminders with action buttons for quick mood entry
- Data Export/Import: CSV format for data portability
- Subscription Model: 30-day free trial, then monthly/yearly subscriptions
- Localization: English and Spanish
Architecture
Pattern: MVVM (Model-View-ViewModel) with SwiftUI
Project Structure
Feels/
├── Shared/ # Core app code
│ ├── Models/ # Data models (Mood, Theme, MoodTintable, etc.)
│ ├── Views/ # SwiftUI views organized by feature
│ │ ├── DayView/ # Chronological list view
│ │ ├── MonthView/ # Calendar grid view
│ │ ├── YearView/ # Yearly statistics view
│ │ ├── CustomizeView/ # Settings and customization
│ │ └── Components/ # Reusable UI components
│ ├── Persisence/ # Core Data persistence layer
│ ├── Onboarding/ # First-run experience
│ └── Protocols/ # Protocol definitions
├── FeelsWidget/ # iOS Widget Extension (3 widget types)
├── en.lproj/ # English localization
├── es.lproj/ # Spanish localization
└── Tests iOS/ # Test targets
Key Files
App Entry
| File | Purpose |
|---|---|
FeelsApp.swift |
Main app entry, Core Data setup, IAP manager, tab navigation |
Data Layer
| File | Purpose |
|---|---|
Feels.xcdatamodeld |
Core Data model with MoodEntry entity |
Persistence.swift |
Core Data stack, App Group container |
PersistenceGET.swift |
Fetch operations |
PersistenceADD.swift |
Create/fill missing entries |
PersistenceUPDATE.swift |
Update operations |
PersistenceDELETE.swift |
Delete operations |
Main Views
| File | Purpose |
|---|---|
MainTabView.swift |
Root navigation (Day, Month, Year, Customize tabs) |
DayView.swift |
Chronological mood list with edit/delete |
MonthView.swift |
Calendar grid with color-coded moods |
YearView.swift |
Aggregate yearly statistics |
CustomizeView.swift |
Theme, colors, icons, shape settings |
Services
| File | Purpose |
|---|---|
IAPManager.swift |
StoreKit 2 subscriptions, 30-day trial |
LocalNotification.swift |
Daily reminders with quick actions |
BGTask.swift |
Background task for filling missing dates |
EventLogger.swift |
Analytics event tracking |
Data Models
MoodEntry (Core Data Entity)
- moodValue: Int16 (0-4 for mood ratings)
- forDate: Date (the day being rated)
- timestamp: Date (when entry was created)
- weekDay: Int16 (1-7)
- canEdit, canDelete: Boolean
- entryType: Int16 (header, list, filled-in-missing)
Mood Enum
enum Mood: Int {
case horrible = 0
case bad = 1
case average = 2
case good = 3
case great = 4
case missing = 5
case placeholder = 6
}
Customization System
Themes (Theme.swift)
- System, iFeel (gradient), Dark, Light
- Protocol:
Themeable
Color Schemes (MoodTintable.swift)
- Default, Neon, Pastel, Custom (user-defined)
- Each mood has primary and secondary colors
Icon Packs (MoodImagable.swift)
- FontAwesome, Emoji, Hand Emoji
- Protocol:
MoodImagable
Shapes
- Circle, Square, Diamond for calendar visualization
Notification Personalities (PersonalityPackable.swift)
- "Nice": Friendly text
- "Rude": Sarcastic/aggressive text
Widget System
Three widget types in FeelsWidget/:
- FeelsWidget: Small/Medium/Large showing recent moods
- FeelsGraphicWidget: Small widget with mood graphic
- FeelsIconWidget: Custom icon widget
Data shared via App Groups: group.com.88oakapps.ifeel
Dependencies
Apple Frameworks
- SwiftUI, CoreData, WidgetKit, StoreKit, UserNotifications, CloudKit, BackgroundTasks
Third-Party
- CloudKitSyncMonitor
- Firebase (GoogleService-Info.plist)
Configuration
App Groups
- Production:
group.com.88oakapps.ifeel - Debug:
group.com.88oakapps.ifeelDebug
Background Tasks
- Identifier:
com.88oak.Feels.dbUpdateMissing
StoreKit Products
- Monthly subscription
- Yearly subscription
- 30-day free trial
Data Flow
User Input → Persistence (Core Data) → ViewModel Update → SwiftUI Re-render
↓
Widget Update (WidgetCenter.shared.reloadAllTimelines())
Localization
| Language | File |
|---|---|
| English | en.lproj/Localizable.strings |
| Spanish | es.lproj/Localizable.strings |
Covers: Onboarding, mood names, UI labels, notifications, settings
Notable Implementation Details
- Automatic Missing Date Fill: Creates placeholder entries for days without ratings
- Entry Types:
header,listView,filledInMissing- tracks how entries were created - Day Filtering: Users can filter which weekdays appear in visualizations
- CSV Export: Full data portability with all metadata preserved