Refactor StoreKit 2 subscription system and add interactive vote widget

## 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>
This commit is contained in:
Trey t
2025-12-09 23:07:16 -06:00
parent c8248429dd
commit f2c510de50
34 changed files with 1267 additions and 1048 deletions

197
PROJECT_OVERVIEW.md Normal file
View File

@@ -0,0 +1,197 @@
# 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
```swift
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/`:
1. **FeelsWidget**: Small/Medium/Large showing recent moods
2. **FeelsGraphicWidget**: Small widget with mood graphic
3. **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
1. **Automatic Missing Date Fill**: Creates placeholder entries for days without ratings
2. **Entry Types**: `header`, `listView`, `filledInMissing` - tracks how entries were created
3. **Day Filtering**: Users can filter which weekdays appear in visualizations
4. **CSV Export**: Full data portability with all metadata preserved