110807d239
- Eating out: tap any empty slot → "Mark as eating out"; shows teal indicator, skipped by auto-assign, counts as complete, tap again to unmark - Rule violations panel: access via wand long-press context menu when conflicts exist; shows all isRuleOverridden slots with Fix (clear) or Ignore (acknowledge) actions - Firebase Crashlytics integrated: CrashlyticsService + dSYM upload build phase, isPremium property tracked per session - PremiumSyncService: extracted premium state machine, StoreKit Transaction.updates listener, isPremium no longer synced via iCloud to avoid stale state - StoreManager: analytics on purchase/restore, bundle ID fallback for product ID lookup - Search bar contrast bug fixed: TextField now has explicit foreground color for dark mode - WelcomeStepView: redesigned onboarding welcome screen with week preview - Version bump: 1.0.5 build 22 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
27 lines
851 B
Swift
27 lines
851 B
Swift
import FirebaseCrashlytics
|
|
|
|
enum CrashlyticsService {
|
|
|
|
static func setUserProperties(isPremium: Bool) {
|
|
Crashlytics.crashlytics().setCustomValue(isPremium, forKey: "is_premium")
|
|
}
|
|
|
|
static func log(_ message: String) {
|
|
Crashlytics.crashlytics().log(message)
|
|
}
|
|
|
|
static func record(_ error: Error, context: String? = nil) {
|
|
var userInfo: [String: Any] = [:]
|
|
if let context { userInfo["context"] = context }
|
|
Crashlytics.crashlytics().record(error: error, userInfo: userInfo)
|
|
}
|
|
|
|
static func record(message: String, context: String? = nil) {
|
|
let userInfo: [String: Any] = context.map { ["context": $0] } ?? [:]
|
|
Crashlytics.crashlytics().record(
|
|
exceptionModel: ExceptionModel(name: "AppError", reason: message),
|
|
userInfo: userInfo
|
|
)
|
|
}
|
|
}
|