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

View File

@@ -25,7 +25,8 @@ struct YearView: View {
@EnvironmentObject var iapManager: IAPManager
@StateObject public var viewModel: YearViewModel
@StateObject private var filteredDays = DaysFilterClass.shared
@State private var iAPWarningViewHidden = false
@State private var trialWarningHidden = false
@State private var showSubscriptionStore = false
//[
// 2001: [0: [], 1: [], 2: []],
// 2002: [0: [], 1: [], 2: []]
@@ -60,24 +61,44 @@ struct YearView: View {
}
)
}
.disabled(iapManager.showIAP)
.disabled(iapManager.shouldShowPaywall)
.padding(.bottom, 5)
}
if iapManager.showIAP {
if iapManager.shouldShowPaywall {
// Paywall overlay - tap to show subscription store
Color.black.opacity(0.3)
.ignoresSafeArea()
.onTapGesture {
showSubscriptionStore = true
}
VStack {
Spacer()
PurchaseButtonView(height: 250, iapManager: iapManager)
Button {
showSubscriptionStore = true
} label: {
Text(String(localized: "subscription_required_button"))
.font(.headline)
.foregroundColor(.white)
.frame(maxWidth: .infinity)
.padding()
.background(RoundedRectangle(cornerRadius: 10).fill(Color.pink))
}
.padding()
}
} else if iapManager.showIAPWarning {
} else if iapManager.shouldShowTrialWarning {
VStack {
Spacer()
if !iAPWarningViewHidden {
IAPWarningView(height: 75, iapManager: iapManager)
if !trialWarningHidden {
IAPWarningView(iapManager: iapManager)
}
}
}
}
.sheet(isPresented: $showSubscriptionStore) {
FeelsSubscriptionStoreView()
}
.onAppear(perform: {
self.viewModel.filterEntries(startDate: Date(timeIntervalSince1970: 0), endDate: Date())
})
@@ -87,7 +108,7 @@ struct YearView: View {
)
.onPreferenceChange(ViewOffsetKey.self) { value in
withAnimation {
iAPWarningViewHidden = value < 0
trialWarningHidden = value < 0
}
}
.padding([.top])