diff --git a/Feels.xcodeproj/project.pbxproj b/Feels.xcodeproj/project.pbxproj index cef27b5..c3c6215 100644 --- a/Feels.xcodeproj/project.pbxproj +++ b/Feels.xcodeproj/project.pbxproj @@ -35,6 +35,7 @@ 1C26190327960CE500FDC148 /* ChartDataBuildable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C26190227960CE500FDC148 /* ChartDataBuildable.swift */; }; 1C26190727960DC900FDC148 /* ChartViewItemBuildable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C26190627960DC900FDC148 /* ChartViewItemBuildable.swift */; }; 1C2C5B2A27DD7D300092A308 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1CD90AF0278C7DE0001C4FEA /* Assets.xcassets */; }; + 1C2C5B2B27DEBE260092A308 /* EventLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C414C2F27DB1C2400BC1720 /* EventLogger.swift */; }; 1C358FAD27ADD0C3002C83A6 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C358FAC27ADD0C3002C83A6 /* Theme.swift */; }; 1C358FB127B0AD87002C83A6 /* SharingListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C358FB027B0AD87002C83A6 /* SharingListView.swift */; }; 1C358FB327B0ADA4002C83A6 /* SharingTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C358FB227B0ADA4002C83A6 /* SharingTemplate.swift */; }; @@ -937,6 +938,7 @@ 1C4FF3C827BEE09E00BE8F34 /* PersistenceADD.swift in Sources */, 1C2162F527C16061004353D1 /* MoodImagable.swift in Sources */, 1C2162EC27C14FC5004353D1 /* Date+Extensions.swift in Sources */, + 1C2C5B2B27DEBE260092A308 /* EventLogger.swift in Sources */, 1C4FF3C127BEE06900BE8F34 /* PersistenceGET.swift in Sources */, 1C361F0D27C03BDF00E832FC /* OnboardingData.swift in Sources */, 1CD90B52278C7E7A001C4FEA /* FeelsWidget.intentdefinition in Sources */, diff --git a/Shared/AppDelegate.swift b/Shared/AppDelegate.swift index f22b753..b8453a8 100644 --- a/Shared/AppDelegate.swift +++ b/Shared/AppDelegate.swift @@ -44,6 +44,8 @@ class AppDelegate: NSObject, UIApplicationDelegate { // reschedule notifications so there's a new title next notification LocalNotification.rescheduleNotifiations() + + EventLogger.log(event: "app_foregorund") } } diff --git a/Shared/LocalNotification.swift b/Shared/LocalNotification.swift index bad1b1e..6df211d 100644 --- a/Shared/LocalNotification.swift +++ b/Shared/LocalNotification.swift @@ -21,8 +21,10 @@ class LocalNotification { public class func testIfEnabled(completion: @escaping (Result) -> Void) { UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { success, error in if success { + EventLogger.log(event: "local_notification_enabled") completion(.success(true)) } else if let error = error { + EventLogger.log(event: "local_notification_disabled") completion(.failure(error)) } } diff --git a/Shared/Onboarding/views/OnboardingWrapup.swift b/Shared/Onboarding/views/OnboardingWrapup.swift index 099639a..4961a2e 100644 --- a/Shared/Onboarding/views/OnboardingWrapup.swift +++ b/Shared/Onboarding/views/OnboardingWrapup.swift @@ -71,6 +71,9 @@ struct OnboardingWrapup: View { .padding([.top], 15) Button(action: { + EventLogger.log(event: "onboarding_complete") + EventLogger.log(event: "onboarding_complete_day_id", + withData: ["id": onboardingData.inputDay.rawValue]) completionClosure(onboardingData) }, label: { Text(String(localized: "onboarding_wrap_up_complete_button")) diff --git a/Shared/Persisence/PersistenceADD.swift b/Shared/Persisence/PersistenceADD.swift index 6b886e9..16c0cbb 100644 --- a/Shared/Persisence/PersistenceADD.swift +++ b/Shared/Persisence/PersistenceADD.swift @@ -23,6 +23,8 @@ extension PersistenceController { newItem.canDelete = true newItem.entryType = Int16(entryType.rawValue) + EventLogger.log(event: "add_entry", withData: ["entry_type": entryType.rawValue]) + saveAndRunDataListerners() } @@ -57,6 +59,10 @@ extension PersistenceController { let adjustedDate = Calendar.current.date(byAdding: .hour, value: 12, to: date)! add(mood: .missing, forDate: adjustedDate, entryType: .filledInMissing) } + + if !missing.isEmpty { + EventLogger.log(event: "filled_in_missing_entries", withData: ["count": missing.count]) + } } } @@ -72,5 +78,6 @@ extension PersistenceController { return } } + EventLogger.log(event: "removed_entry_no_for_date", withData: ["count": entries.count]) } } diff --git a/Shared/Persisence/PersistenceUPDATE.swift b/Shared/Persisence/PersistenceUPDATE.swift index 4babc10..1cd401e 100644 --- a/Shared/Persisence/PersistenceUPDATE.swift +++ b/Shared/Persisence/PersistenceUPDATE.swift @@ -16,6 +16,9 @@ extension PersistenceController { existingEntry.setValue(mood.rawValue, forKey: "moodValue") saveAndRunDataListerners() + + EventLogger.log(event: "update_entry") + return true } } diff --git a/Shared/views/CustomIcon/CreateWidgetView.swift b/Shared/views/CustomIcon/CreateWidgetView.swift index 832dafb..0f4cd09 100644 --- a/Shared/views/CustomIcon/CreateWidgetView.swift +++ b/Shared/views/CustomIcon/CreateWidgetView.swift @@ -45,6 +45,8 @@ struct CreateWidgetView: View { } func update(eye: CustomWidgetEyes, eyeOption: CustomWidgeImageOptions) { + EventLogger.log(event: "create_widget_view_update_eye", + withData: ["eye_value": eye.rawValue, "eye_option_value": eyeOption.rawValue]) switch eye { case .left: customWidget.leftEye = eyeOption @@ -54,6 +56,7 @@ struct CreateWidgetView: View { } func createRandom() { + EventLogger.log(event: "create_widget_view_create_random") customWidget.bgColor = Color.random() customWidget.innerColor = Color.random() customWidget.bgOverlayColor = Color.random() @@ -70,10 +73,14 @@ struct CreateWidgetView: View { } func update(mouthOption: CustomWidgeImageOptions) { + EventLogger.log(event: "create_widget_view_update_mouth", + withData: ["mouthOption": mouthOption.rawValue]) customWidget.mouth = mouthOption } func update(background: CustomWidgetBackGroundOptions) { + EventLogger.log(event: "create_widget_view_update_background", + withData: ["background": background.rawValue]) customWidget.background = background } @@ -94,6 +101,7 @@ struct CreateWidgetView: View { Group { HStack(alignment: .center, spacing: 0) { Button(action: { + EventLogger.log(event: "create_widget_view_shuffle") createRandom() }, label: { Image(systemName: "shuffle") @@ -106,6 +114,7 @@ struct CreateWidgetView: View { .background(.blue) Button(action: { + EventLogger.log(event: "create_widget_view_save_widget") UserDefaultsStore.saveCustomWidget(widgetModel: customWidget, inUse: false) let impactMed = UIImpactFeedbackGenerator(style: .heavy) impactMed.impactOccurred() @@ -122,6 +131,7 @@ struct CreateWidgetView: View { .background(.green) Button(action: { + EventLogger.log(event: "customize_view_use_widget") UserDefaultsStore.saveCustomWidget(widgetModel: customWidget, inUse: true) let impactMed = UIImpactFeedbackGenerator(style: .heavy) impactMed.impactOccurred() @@ -139,6 +149,7 @@ struct CreateWidgetView: View { if customWidget.isSaved { Button(action: { + EventLogger.log(event: "customize_view_delete_widget") UserDefaultsStore.deleteCustomWidget(withUUID: customWidget.uuid) let impactMed = UIImpactFeedbackGenerator(style: .heavy) impactMed.impactOccurred() @@ -164,6 +175,9 @@ struct CreateWidgetView: View { VStack(alignment: .center) { Text(String(localized: "create_widget_background_color")) ColorPicker("", selection: $customWidget.bgColor) + .onChange(of: customWidget.mouthColor, perform: { newValue in + EventLogger.log(event: "create_widget_view_update_background_color") + }) .labelsHidden() } .frame(minWidth: 0, maxWidth: .infinity) @@ -171,6 +185,9 @@ struct CreateWidgetView: View { VStack(alignment: .center) { Text(String(localized: "create_widget_inner_color")) ColorPicker("", selection: $customWidget.innerColor) + .onChange(of: customWidget.mouthColor, perform: { newValue in + EventLogger.log(event: "create_widget_view_update_inner_color") + }) .labelsHidden() } .frame(minWidth: 0, maxWidth: .infinity) @@ -178,6 +195,9 @@ struct CreateWidgetView: View { VStack(alignment: .center) { Text(String(localized: "create_widget_face_outline_color")) ColorPicker("", selection: $customWidget.circleStrokeColor) + .onChange(of: customWidget.mouthColor, perform: { newValue in + EventLogger.log(event: "create_widget_view_update_outline_color") + }) .labelsHidden() } .frame(minWidth: 0, maxWidth: .infinity) @@ -187,6 +207,9 @@ struct CreateWidgetView: View { VStack(alignment: .center) { Text(String(localized: "create_widget_view_left_eye_color")) ColorPicker("", selection: $customWidget.leftEyeColor) + .onChange(of: customWidget.mouthColor, perform: { newValue in + EventLogger.log(event: "create_widget_view_update_left_eye_color") + }) .labelsHidden() } .frame(minWidth: 0, maxWidth: .infinity) @@ -194,6 +217,9 @@ struct CreateWidgetView: View { VStack(alignment: .center) { Text(String(localized: "create_widget_view_right_eye_color")) ColorPicker("", selection: $customWidget.rightEyeColor) + .onChange(of: customWidget.mouthColor, perform: { newValue in + EventLogger.log(event: "create_widget_view_update_right_eye_color") + }) .labelsHidden() } .frame(minWidth: 0, maxWidth: .infinity) @@ -201,6 +227,9 @@ struct CreateWidgetView: View { VStack(alignment: .center) { Text(String(localized: "create_widget_view_mouth_color")) ColorPicker("", selection: $customWidget.mouthColor) + .onChange(of: customWidget.mouthColor, perform: { newValue in + EventLogger.log(event: "create_widget_view_update_mouth_color") + }) .labelsHidden() } .frame(minWidth: 0, maxWidth: .infinity) diff --git a/Shared/views/CustomizeView/CustomizeView.swift b/Shared/views/CustomizeView/CustomizeView.swift index a164822..60bc44a 100644 --- a/Shared/views/CustomizeView/CustomizeView.swift +++ b/Shared/views/CustomizeView/CustomizeView.swift @@ -61,6 +61,9 @@ struct CustomizeView: View { pickPeronsalityPack } } + .onAppear(perform: { + EventLogger.log(event: "show_customize_view") + }) .padding() .sheet(isPresented: $selectedWidget.showFuckingSheet) { if let fuckingWrapped = selectedWidget.fuckingWrapped { @@ -81,6 +84,7 @@ struct CustomizeView: View { HStack { Button(action: { UIApplication.shared.setAlternateIconName(nil) + EventLogger.log(event: "change_icon_title", withData: ["title": "default"]) }, label: { Image("AppIconImage", bundle: .main) .resizable() @@ -94,6 +98,7 @@ struct CustomizeView: View { UIApplication.shared.setAlternateIconName(iconSet.1) { (error) in // FIXME: Handle error } + EventLogger.log(event: "change_icon_title", withData: ["title": iconSet.1]) }, label: { Image(iconSet.0, bundle: .main) .resizable() @@ -122,6 +127,7 @@ struct CustomizeView: View { ForEach(Theme.allCases, id:\.rawValue) { aTheme in Button(action: { theme = aTheme + EventLogger.log(event: "change_theme_id", withData: ["id": aTheme.rawValue]) }, label: { VStack { aTheme.currentTheme.preview @@ -163,6 +169,7 @@ struct CustomizeView: View { .frame(width: 50, height: 50) .cornerRadius(10) .onTapGesture { + EventLogger.log(event: "show_widget") selectedWidget.fuckingWrapped = widget.copy() as? CustomWidgetModel selectedWidget.showFuckingSheet = true } @@ -173,6 +180,7 @@ struct CustomizeView: View { Image(systemName: "plus") ) .onTapGesture { + EventLogger.log(event: "tap_create_new_widget") selectedWidget.fuckingWrapped = CustomWidgetModel.randomWidget selectedWidget.showFuckingSheet = true } @@ -221,6 +229,7 @@ struct CustomizeView: View { let impactMed = UIImpactFeedbackGenerator(style: .heavy) impactMed.impactOccurred() imagePack = images + EventLogger.log(event: "change_image_pack_id", withData: ["id": images.rawValue]) } if images.rawValue != (MoodImages.allCases.sorted(by: { $0.rawValue > $1.rawValue }).first?.rawValue) ?? 0 { Divider() @@ -261,6 +270,7 @@ struct CustomizeView: View { let impactMed = UIImpactFeedbackGenerator(style: .heavy) impactMed.impactOccurred() moodTint = tint + EventLogger.log(event: "change_mood_tint_id", withData: ["id": tint.rawValue]) } Divider() } @@ -376,6 +386,7 @@ struct CustomizeView: View { private func saveCustomMoodTint() { UserDefaultsStore.saveCustomMoodTint(customTint: customMoodTint) moodTint = .Custom + EventLogger.log(event: "change_mood_tint_id", withData: ["id": MoodTints.Custom.rawValue]) customMoodTintUpdateNumber += 1 } @@ -407,10 +418,12 @@ struct CustomizeView: View { .onTapGesture { if aPack.rawValue == PersonalityPack.Rude.rawValue && !showNSFW { showOver18Alert = true + EventLogger.log(event: "show_over_18_alert") } else { let impactMed = UIImpactFeedbackGenerator(style: .heavy) impactMed.impactOccurred() personalityPack = aPack + EventLogger.log(event: "change_personality_pack", withData: ["pack_title": aPack.title()]) LocalNotification.rescheduleNotifiations() } } diff --git a/Shared/views/FilterView/FilterView.swift b/Shared/views/FilterView/FilterView.swift index 6466c63..3953a44 100644 --- a/Shared/views/FilterView/FilterView.swift +++ b/Shared/views/FilterView/FilterView.swift @@ -106,6 +106,9 @@ struct FilterView: View { Text(mood.strValue) .foregroundColor(moodTint.color(forMood: mood)) } + .onAppear(perform: { + EventLogger.log(event: "show_filter_view") + }) } } diff --git a/Shared/views/HomeView/HomeView.swift b/Shared/views/HomeView/HomeView.swift index bf1e0f2..2067514 100644 --- a/Shared/views/HomeView/HomeView.swift +++ b/Shared/views/HomeView/HomeView.swift @@ -82,6 +82,9 @@ struct HomeView: View { showUpdateEntryAlert = false }) } + .onAppear(perform: { + EventLogger.log(event: "show_home_view") + }) } // MARK: functions that do view type work diff --git a/Shared/views/MonthView/MonthDetailView.swift b/Shared/views/MonthView/MonthDetailView.swift index e76d3b1..73d00f2 100644 --- a/Shared/views/MonthView/MonthDetailView.swift +++ b/Shared/views/MonthView/MonthDetailView.swift @@ -82,6 +82,9 @@ struct MonthDetailView: View { showUpdateEntryAlert = false }) } + .onAppear(perform: { + EventLogger.log(event: "show_month_detail_view") + }) .background( theme.currentTheme.bg ) diff --git a/Shared/views/MonthView/MonthView.swift b/Shared/views/MonthView/MonthView.swift index 820b467..870518a 100644 --- a/Shared/views/MonthView/MonthView.swift +++ b/Shared/views/MonthView/MonthView.swift @@ -76,6 +76,9 @@ struct MonthView: View { } } } + .onAppear(perform: { + EventLogger.log(event: "show_month_view") + }) .padding([.top, .bottom]) .background( theme.currentTheme.bg diff --git a/Shared/views/SettingsView/SettingsView.swift b/Shared/views/SettingsView/SettingsView.swift index 9954264..d66106a 100644 --- a/Shared/views/SettingsView/SettingsView.swift +++ b/Shared/views/SettingsView/SettingsView.swift @@ -66,6 +66,9 @@ struct SettingsView: View { showOnboarding = false }) } + .onAppear(perform: { + EventLogger.log(event: "show_settings_view") + }) .background( theme.currentTheme.bg .edgesIgnoringSafeArea(.all) @@ -78,6 +81,7 @@ struct SettingsView: View { onCompletion: { result in switch result { case .success(let url): + EventLogger.log(event: "exported_file") print("Saved to \(url)") case .failure(let error): print(error.localizedDescription) @@ -112,11 +116,13 @@ struct SettingsView: View { try! PersistenceController.shared.viewContext.save() } PersistenceController.shared.saveAndRunDataListerners() + EventLogger.log(event: "import_file") } else { - // Handle denied access + EventLogger.log(event: "error_import_file") } } catch { // Handle failure. + EventLogger.log(event: "error_import_file", withData: ["error": error.localizedDescription]) print("Unable to read file contents") print(error.localizedDescription) } @@ -127,6 +133,7 @@ struct SettingsView: View { HStack{ Spacer() Button(action: { + EventLogger.log(event: "tap_settings_close") dismiss() }, label: { Text(String(localized: "settings_view_exit")) @@ -141,6 +148,7 @@ struct SettingsView: View { theme.currentTheme.secondaryBGColor VStack { Button(action: { + EventLogger.log(event: "tap_show_special_thanks") withAnimation{ showSpecialThanks.toggle() } @@ -222,14 +230,11 @@ struct SettingsView: View { .cornerRadius(10, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight]) } - - - - private var showOnboardingButton: some View { ZStack { theme.currentTheme.secondaryBGColor Button(action: { + EventLogger.log(event: "tap_show_onboarding") showOnboarding.toggle() }, label: { Text(String(localized: "settings_view_show_onboarding")) @@ -249,6 +254,9 @@ struct SettingsView: View { Text(String(localized: "settings_use_cloudkit_title")) .foregroundColor(textColor) }) + .onChange(of: useCloudKit) { newValue in + EventLogger.log(event: "toggle_use_cloudkit", withData: ["value": newValue]) + } .padding() Text(String(localized: "settings_use_cloudkit_body")) .foregroundColor(textColor) @@ -280,6 +288,9 @@ struct SettingsView: View { VStack { Toggle(String(localized: "settings_use_delete_enable"), isOn: $deleteEnabled) + .onChange(of: deleteEnabled) { newValue in + EventLogger.log(event: "toggle_can_delete", withData: ["value": newValue]) + } .foregroundColor(textColor) .padding() } @@ -293,6 +304,7 @@ struct SettingsView: View { theme.currentTheme.secondaryBGColor Button(action: { showingExporter.toggle() + EventLogger.log(event: "export_data", withData: ["title": "default"]) }, label: { Text("Export") }) @@ -307,6 +319,7 @@ struct SettingsView: View { theme.currentTheme.secondaryBGColor Button(action: { showingImporter.toggle() + EventLogger.log(event: "import_data", withData: ["title": "default"]) }, label: { Text("Import") }) diff --git a/Shared/views/SwitchableView.swift b/Shared/views/SwitchableView.swift index 6c33e5b..c9fe04a 100644 --- a/Shared/views/SwitchableView.swift +++ b/Shared/views/SwitchableView.swift @@ -96,6 +96,8 @@ struct SwitchableView: View { .onTapGesture { viewType = viewType.next() self.headerTypeChanged(viewType) + EventLogger.log(event: "switchable_view_header_changed", + withData: ["view_type_id": viewType.rawValue, "days_back": daysBack]) } } }