Refactor ZStack layouts to .background(), add Year View accessibility IDs, triage QA test plan
Replace ZStack-with-gradient patterns with idiomatic .background() modifier across onboarding, customize, and settings views. Add accessibility identifiers to Year View charts for UI test automation. Mark 67 impossible-to-automate tests RED in QA plan and scaffold initial Year View and Settings onboarding tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,9 +8,9 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
06E4767B5977FAC8B644FC92 /* IntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CFAE86F485C853DB3239DD9 /* IntegrationTests.swift */; };
|
||||
A1B2C3D4E5F607080910ABCD /* DayViewViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4E5F60708091011ABCDE001 /* DayViewViewModelTests.swift */; };
|
||||
1C0DAB51279DB0FB003B1F21 /* Feels/Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 1C0DAB50279DB0FB003B1F21 /* Feels/Localizable.xcstrings */; };
|
||||
1C0DAB52279DB0FB003B1F22 /* Feels/Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 1C0DAB50279DB0FB003B1F21 /* Feels/Localizable.xcstrings */; };
|
||||
1AB245144C89927264D16645 /* InsightsEmptyStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6988985985DE9C29CFDFA96 /* InsightsEmptyStateTests.swift */; };
|
||||
1C0DAB51279DB0FB003B1F21 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 1C0DAB50279DB0FB003B1F21 /* Localizable.xcstrings */; };
|
||||
1C0DAB52279DB0FB003B1F22 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 1C0DAB50279DB0FB003B1F21 /* Localizable.xcstrings */; };
|
||||
1C9566442EF8F5F70032E68F /* Algorithms in Frameworks */ = {isa = PBXBuildFile; productRef = 1C9566432EF8F5F70032E68F /* Algorithms */; };
|
||||
1CB4D0A028787D8A00902A56 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1CB4D09F28787D8A00902A56 /* StoreKit.framework */; };
|
||||
1CD90B07278C7DE0001C4FEA /* Tests_iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CD90B06278C7DE0001C4FEA /* Tests_iOS.swift */; };
|
||||
@@ -25,50 +25,52 @@
|
||||
1CDE000F2F3BBD26006AE6A1 /* PostHog in Frameworks */ = {isa = PBXBuildFile; productRef = 1CA00002300000000000002A /* PostHog */; };
|
||||
1CDEFBBF2F3B8736006AE6A1 /* Configuration.storekit in Resources */ = {isa = PBXBuildFile; fileRef = 1CDEFBBE2F3B8736006AE6A1 /* Configuration.storekit */; };
|
||||
1CDEFBC02F3B8736006AE6A1 /* Configuration.storekit in Resources */ = {isa = PBXBuildFile; fileRef = 1CDEFBBE2F3B8736006AE6A1 /* Configuration.storekit */; };
|
||||
2EE4D94530F6BF39B26FB4D4 /* DayScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 427CD9C91D43AB6A0302B4DD /* DayScreen.swift */; };
|
||||
46F07FA9D330456697C9AC29 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1CD90B47278C7E7A001C4FEA /* WidgetKit.framework */; };
|
||||
4F1C717B7747918A459322CB /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F4D304CD05CC7C662CCD7DCB /* Foundation.framework */; };
|
||||
54259F7B3F4E959B3F4055E4 /* StreakTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29E2A2FC314F88244CA946BF /* StreakTests.swift */; };
|
||||
9559409B5AEEAB40EBCB6AF9 /* VoteLogicsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD717F91BD65382B7DDFE3C4 /* VoteLogicsTests.swift */; };
|
||||
EEB21B1CAA8EAEB497BD9FB3 /* DataControllerCRUDTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5566271983AEDF1D33C34FE6 /* DataControllerCRUDTests.swift */; };
|
||||
A018FE95582C04ED0F1806DC /* BaseUITestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29CE4110A0D8FBBAD7F92BDF /* BaseUITestCase.swift */; };
|
||||
E0579E66FFBBF124AC625ACD /* WaitHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5354C23DD5FC67C1C97482F2 /* WaitHelpers.swift */; };
|
||||
C26D40397E1AA24816FB3751 /* TabBarScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7CDDCB9C85BAE71C679C0BF /* TabBarScreen.swift */; };
|
||||
2EE4D94530F6BF39B26FB4D4 /* DayScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 427CD9C91D43AB6A0302B4DD /* DayScreen.swift */; };
|
||||
A371ED1B0784315F96FFC6BD /* EntryDetailScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E35564DEA72EB6F8447CDAA /* EntryDetailScreen.swift */; };
|
||||
92C1523E0398F866DB4CA027 /* SettingsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 881CA8B21231D67DED575502 /* SettingsScreen.swift */; };
|
||||
AA11110011111100AAAAAAAA /* AppLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA11111111111111AAAAAAAA /* AppLaunchTests.swift */; };
|
||||
BB22220022222200BBBBBBBB /* MoodLoggingEmptyStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB22222222222222BBBBBBBB /* MoodLoggingEmptyStateTests.swift */; };
|
||||
CC33330033333300CCCCCCCC /* MoodLoggingWithDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC33333333333333CCCCCCCC /* MoodLoggingWithDataTests.swift */; };
|
||||
DD44440044444400DDDDDDDD /* EntryDetailTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD44444444444444DDDDDDDD /* EntryDetailTests.swift */; };
|
||||
EE55550055555500EEEEEEEE /* SettingsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE55555555555555EEEEEEEE /* SettingsTests.swift */; };
|
||||
FF66660066666600FFFFFFFF /* SecondaryTabTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF66666666666666FFFFFFFF /* SecondaryTabTests.swift */; };
|
||||
A1B2C3D400000000C9D0E1F2 /* NoteEditorScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3D4E5F6A7B8C9D0E1F2 /* NoteEditorScreen.swift */; };
|
||||
B2C3D4E500000000D0E1F2A3 /* CustomizeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2C3D4E5F6A7B8C9D0E1F2A3 /* CustomizeScreen.swift */; };
|
||||
C3D4E500000000E1F2A3B4C5 /* OnboardingScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D4E5F6A7B8C9D0E1F2A3B4 /* OnboardingScreen.swift */; };
|
||||
D4E5F6A700000000F2A3B4C5 /* MoodReplacementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4E5F6A7B8C9D0E1F2A3B4C5 /* MoodReplacementTests.swift */; };
|
||||
E5F6A7B800000000A3B4C5D6 /* EmptyStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5F6A7B8C9D0E1F2A3B4C5D6 /* EmptyStateTests.swift */; };
|
||||
F6A7B8C900000000B4C5D6E7 /* EntryDeleteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6A7B8C9D0E1F2A3B4C5D6E7 /* EntryDeleteTests.swift */; };
|
||||
A7B8C9D000000000C5D6E7F8 /* NotesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7B8C9D0E1F2A3B4C5D6E7F8 /* NotesTests.swift */; };
|
||||
F75470AA2BA1E9EFF8F5265A /* LocalizationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DC4C498A1185DC831F4593 /* LocalizationTests.swift */; };
|
||||
E3482DB0421C12E11517BDC8 /* TrialBannerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21CD463209E0909393545D62 /* TrialBannerTests.swift */; };
|
||||
A4B459F8CE7F5534DE4FADCA /* DarkModeStylesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8114D2CE12EC5392371BB415 /* DarkModeStylesTests.swift */; };
|
||||
1AB245144C89927264D16645 /* InsightsEmptyStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6988985985DE9C29CFDFA96 /* InsightsEmptyStateTests.swift */; };
|
||||
756B9857B0657D2DB2D6D4E2 /* AppResumeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0359E1D32D936859E5A0C9F3 /* AppResumeTests.swift */; };
|
||||
6F9C9C4B50CF8C1769171FF9 /* NoteEditTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 469470483072085BE9E04E12 /* NoteEditTests.swift */; };
|
||||
B8C9D0E100000000D6E7F8A9 /* MonthViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8C9D0E1F2A3B4C5D6E7F8A9 /* MonthViewTests.swift */; };
|
||||
C9D0E1F200000000E7F8A9B0 /* SettingsActionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D0E1F2A3B4C5D6E7F8A9B0 /* SettingsActionTests.swift */; };
|
||||
D0E1F2A300000000F8A9B0C1 /* CustomizationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E1F2A3B4C5D6E7F8A9B0C1 /* CustomizationTests.swift */; };
|
||||
E1F2A3B400000000A9B0C1D2 /* OnboardingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1F2A3B4C5D6E7F8A9B0C1D2 /* OnboardingTests.swift */; };
|
||||
F2A3B400000000B0C1D2E3F4 /* StabilityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2A3B4C5D6E7F8A9B0C1D2E3 /* StabilityTests.swift */; };
|
||||
756B9857B0657D2DB2D6D4E2 /* AppResumeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0359E1D32D936859E5A0C9F3 /* AppResumeTests.swift */; };
|
||||
92C1523E0398F866DB4CA027 /* SettingsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 881CA8B21231D67DED575502 /* SettingsScreen.swift */; };
|
||||
9559409B5AEEAB40EBCB6AF9 /* VoteLogicsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD717F91BD65382B7DDFE3C4 /* VoteLogicsTests.swift */; };
|
||||
A018FE95582C04ED0F1806DC /* BaseUITestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29CE4110A0D8FBBAD7F92BDF /* BaseUITestCase.swift */; };
|
||||
A1B2C3D400000000C9D0E1F2 /* NoteEditorScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3D4E5F6A7B8C9D0E1F2 /* NoteEditorScreen.swift */; };
|
||||
A1B2C3D4E5F607080910ABCD /* DayViewViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4E5F60708091011ABCDE001 /* DayViewViewModelTests.swift */; };
|
||||
A371ED1B0784315F96FFC6BD /* EntryDetailScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E35564DEA72EB6F8447CDAA /* EntryDetailScreen.swift */; };
|
||||
A3B4C5D600000000C1D2E3F4 /* DataPersistenceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3B4C5D6E7F8A9B0C1D2E3F4 /* DataPersistenceTests.swift */; };
|
||||
B4C5D6E700000000D2E3F4A5 /* PaywallGateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4C5D6E7F8A9B0C1D2E3F4A5 /* PaywallGateTests.swift */; };
|
||||
C5D6E7F800000000E3F4A5B6 /* AppThemeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5D6E7F8A9B0C1D2E3F4A5B6 /* AppThemeTests.swift */; };
|
||||
D6E7F8A900000000F4A5B6C7 /* IconPackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E7F8A9B0C1D2E3F4A5B6C7 /* IconPackTests.swift */; };
|
||||
E7F8A9B000000000A5B6C7D8 /* PremiumCustomizationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7F8A9B0C1D2E3F4A5B6C7D8 /* PremiumCustomizationTests.swift */; };
|
||||
F8A9B0C100000000B6C7D8E9 /* HeaderMoodLoggingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8A9B0C1D2E3F4A5B6C7D8E9 /* HeaderMoodLoggingTests.swift */; };
|
||||
A4B459F8CE7F5534DE4FADCA /* DarkModeStylesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8114D2CE12EC5392371BB415 /* DarkModeStylesTests.swift */; };
|
||||
A7B8C9D000000000C5D6E7F8 /* NotesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7B8C9D0E1F2A3B4C5D6E7F8 /* NotesTests.swift */; };
|
||||
A9B0C1D200000000C7D8E9FA /* DayViewGroupingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9B0C1D2E3F4A5B6C7D8E9FA /* DayViewGroupingTests.swift */; };
|
||||
AA11110011111100AAAAAAAA /* AppLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA11111111111111AAAAAAAA /* AppLaunchTests.swift */; };
|
||||
B0C1D2E300000000D8E9FA0B /* AllDayViewStylesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0C1D2E3F4A5B6C7D8E9FA0B /* AllDayViewStylesTests.swift */; };
|
||||
B2C3D4E500000000D0E1F2A3 /* CustomizeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2C3D4E5F6A7B8C9D0E1F2A3 /* CustomizeScreen.swift */; };
|
||||
B4C5D6E700000000D2E3F4A5 /* PaywallGateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4C5D6E7F8A9B0C1D2E3F4A5 /* PaywallGateTests.swift */; };
|
||||
B8C9D0E100000000D6E7F8A9 /* MonthViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8C9D0E1F2A3B4C5D6E7F8A9 /* MonthViewTests.swift */; };
|
||||
BB22220022222200BBBBBBBB /* MoodLoggingEmptyStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB22222222222222BBBBBBBB /* MoodLoggingEmptyStateTests.swift */; };
|
||||
C1D2E3F400000000E9FA0B1C /* MonthViewInteractionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1D2E3F4A5B6C7D8E9FA0B1C /* MonthViewInteractionTests.swift */; };
|
||||
C26D40397E1AA24816FB3751 /* TabBarScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7CDDCB9C85BAE71C679C0BF /* TabBarScreen.swift */; };
|
||||
C3D4E500000000E1F2A3B4C5 /* OnboardingScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D4E5F6A7B8C9D0E1F2A3B4 /* OnboardingScreen.swift */; };
|
||||
C5D6E7F800000000E3F4A5B6 /* AppThemeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5D6E7F8A9B0C1D2E3F4A5B6 /* AppThemeTests.swift */; };
|
||||
C9D0E1F200000000E7F8A9B0 /* SettingsActionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D0E1F2A3B4C5D6E7F8A9B0 /* SettingsActionTests.swift */; };
|
||||
CC33330033333300CCCCCCCC /* MoodLoggingWithDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC33333333333333CCCCCCCC /* MoodLoggingWithDataTests.swift */; };
|
||||
D0E1F2A300000000F8A9B0C1 /* CustomizationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E1F2A3B4C5D6E7F8A9B0C1 /* CustomizationTests.swift */; };
|
||||
D1AD0A0469EADFB1446E9B09 /* YearViewDisplayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0246E9F406F872E5DEEB7269 /* YearViewDisplayTests.swift */; };
|
||||
D4E5F6A700000000F2A3B4C5 /* MoodReplacementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4E5F6A7B8C9D0E1F2A3B4C5 /* MoodReplacementTests.swift */; };
|
||||
D6E7F8A900000000F4A5B6C7 /* IconPackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E7F8A9B0C1D2E3F4A5B6C7 /* IconPackTests.swift */; };
|
||||
DD44440044444400DDDDDDDD /* EntryDetailTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD44444444444444DDDDDDDD /* EntryDetailTests.swift */; };
|
||||
E0579E66FFBBF124AC625ACD /* WaitHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5354C23DD5FC67C1C97482F2 /* WaitHelpers.swift */; };
|
||||
E1F2A3B400000000A9B0C1D2 /* OnboardingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1F2A3B4C5D6E7F8A9B0C1D2 /* OnboardingTests.swift */; };
|
||||
E3482DB0421C12E11517BDC8 /* TrialBannerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21CD463209E0909393545D62 /* TrialBannerTests.swift */; };
|
||||
E5F6A7B800000000A3B4C5D6 /* EmptyStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5F6A7B8C9D0E1F2A3B4C5D6 /* EmptyStateTests.swift */; };
|
||||
E7F8A9B000000000A5B6C7D8 /* PremiumCustomizationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7F8A9B0C1D2E3F4A5B6C7D8 /* PremiumCustomizationTests.swift */; };
|
||||
EE55550055555500EEEEEEEE /* SettingsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE55555555555555EEEEEEEE /* SettingsTests.swift */; };
|
||||
EEB21B1CAA8EAEB497BD9FB3 /* DataControllerCRUDTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5566271983AEDF1D33C34FE6 /* DataControllerCRUDTests.swift */; };
|
||||
F2A3B400000000B0C1D2E3F4 /* StabilityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2A3B4C5D6E7F8A9B0C1D2E3 /* StabilityTests.swift */; };
|
||||
F6A7B8C900000000B4C5D6E7 /* EntryDeleteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6A7B8C9D0E1F2A3B4C5D6E7 /* EntryDeleteTests.swift */; };
|
||||
F75470AA2BA1E9EFF8F5265A /* LocalizationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DC4C498A1185DC831F4593 /* LocalizationTests.swift */; };
|
||||
F8A9B0C100000000B6C7D8E9 /* HeaderMoodLoggingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8A9B0C1D2E3F4A5B6C7D8E9 /* HeaderMoodLoggingTests.swift */; };
|
||||
FD30D4508D4C61AB10AC1E71 /* SettingsOnboardingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFDAD20AE6C6914EDD87DCBC /* SettingsOnboardingTests.swift */; };
|
||||
FF66660066666600FFFFFFFF /* SecondaryTabTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF66666666666666FFFFFFFF /* SecondaryTabTests.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -117,7 +119,10 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
1C0DAB50279DB0FB003B1F21 /* Feels/Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Feels/Localizable.xcstrings; sourceTree = "<group>"; };
|
||||
0246E9F406F872E5DEEB7269 /* YearViewDisplayTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = YearViewDisplayTests.swift; sourceTree = "<group>"; };
|
||||
0359E1D32D936859E5A0C9F3 /* AppResumeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppResumeTests.swift; sourceTree = "<group>"; };
|
||||
17DC4C498A1185DC831F4593 /* LocalizationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizationTests.swift; sourceTree = "<group>"; };
|
||||
1C0DAB50279DB0FB003B1F21 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Feels/Localizable.xcstrings; sourceTree = "<group>"; };
|
||||
1CB4D09F28787D8A00902A56 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.5.sdk/System/Library/Frameworks/StoreKit.framework; sourceTree = DEVELOPER_DIR; };
|
||||
1CD90AF5278C7DE0001C4FEA /* Feels.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Feels.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
1CD90AFB278C7DE0001C4FEA /* Feels.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Feels.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -139,58 +144,57 @@
|
||||
1CD90B70278C8000001C4FEA /* Feels (iOS)Dev.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = "Feels (iOS)Dev.entitlements"; sourceTree = "<group>"; };
|
||||
1CDEFBBE2F3B8736006AE6A1 /* Configuration.storekit */ = {isa = PBXFileReference; lastKnownFileType = text; path = Configuration.storekit; sourceTree = "<group>"; };
|
||||
1E594AEAB5F046E3B3ED7C47 /* Feels Watch App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Feels Watch App.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
29E2A2FC314F88244CA946BF /* StreakTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StreakTests.swift; sourceTree = "<group>"; };
|
||||
5566271983AEDF1D33C34FE6 /* DataControllerCRUDTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DataControllerCRUDTests.swift; sourceTree = "<group>"; };
|
||||
9CFAE86F485C853DB3239DD9 /* IntegrationTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = IntegrationTests.swift; sourceTree = "<group>"; };
|
||||
D4E5F60708091011ABCDE001 /* DayViewViewModelTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DayViewViewModelTests.swift; sourceTree = "<group>"; };
|
||||
B60015D02A064FF582E232FD /* Feels Watch App/Feels Watch AppDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Feels Watch App/Feels Watch AppDebug.entitlements"; sourceTree = "<group>"; };
|
||||
B8AB4CD73C2B4DC89C6FE84D /* Feels Watch App/Feels Watch App.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Feels Watch App/Feels Watch App.entitlements"; sourceTree = "<group>"; };
|
||||
DA0D74ACDD741CFA1F14F50F /* FeelsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FeelsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DD717F91BD65382B7DDFE3C4 /* VoteLogicsTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = VoteLogicsTests.swift; sourceTree = "<group>"; };
|
||||
F4D304CD05CC7C662CCD7DCB /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
|
||||
29CE4110A0D8FBBAD7F92BDF /* BaseUITestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseUITestCase.swift; sourceTree = "<group>"; };
|
||||
5354C23DD5FC67C1C97482F2 /* WaitHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitHelpers.swift; sourceTree = "<group>"; };
|
||||
C7CDDCB9C85BAE71C679C0BF /* TabBarScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarScreen.swift; sourceTree = "<group>"; };
|
||||
427CD9C91D43AB6A0302B4DD /* DayScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DayScreen.swift; sourceTree = "<group>"; };
|
||||
7E35564DEA72EB6F8447CDAA /* EntryDetailScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntryDetailScreen.swift; sourceTree = "<group>"; };
|
||||
881CA8B21231D67DED575502 /* SettingsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreen.swift; sourceTree = "<group>"; };
|
||||
AA11111111111111AAAAAAAA /* AppLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLaunchTests.swift; sourceTree = "<group>"; };
|
||||
BB22222222222222BBBBBBBB /* MoodLoggingEmptyStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoodLoggingEmptyStateTests.swift; sourceTree = "<group>"; };
|
||||
CC33333333333333CCCCCCCC /* MoodLoggingWithDataTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoodLoggingWithDataTests.swift; sourceTree = "<group>"; };
|
||||
DD44444444444444DDDDDDDD /* EntryDetailTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntryDetailTests.swift; sourceTree = "<group>"; };
|
||||
EE55555555555555EEEEEEEE /* SettingsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTests.swift; sourceTree = "<group>"; };
|
||||
FF66666666666666FFFFFFFF /* SecondaryTabTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondaryTabTests.swift; sourceTree = "<group>"; };
|
||||
A1B2C3D4E5F6A7B8C9D0E1F2 /* NoteEditorScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteEditorScreen.swift; sourceTree = "<group>"; };
|
||||
B2C3D4E5F6A7B8C9D0E1F2A3 /* CustomizeScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomizeScreen.swift; sourceTree = "<group>"; };
|
||||
C3D4E5F6A7B8C9D0E1F2A3B4 /* OnboardingScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingScreen.swift; sourceTree = "<group>"; };
|
||||
D4E5F6A7B8C9D0E1F2A3B4C5 /* MoodReplacementTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoodReplacementTests.swift; sourceTree = "<group>"; };
|
||||
E5F6A7B8C9D0E1F2A3B4C5D6 /* EmptyStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyStateTests.swift; sourceTree = "<group>"; };
|
||||
F6A7B8C9D0E1F2A3B4C5D6E7 /* EntryDeleteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntryDeleteTests.swift; sourceTree = "<group>"; };
|
||||
A7B8C9D0E1F2A3B4C5D6E7F8 /* NotesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotesTests.swift; sourceTree = "<group>"; };
|
||||
17DC4C498A1185DC831F4593 /* LocalizationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizationTests.swift; sourceTree = "<group>"; };
|
||||
21CD463209E0909393545D62 /* TrialBannerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrialBannerTests.swift; sourceTree = "<group>"; };
|
||||
8114D2CE12EC5392371BB415 /* DarkModeStylesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DarkModeStylesTests.swift; sourceTree = "<group>"; };
|
||||
A6988985985DE9C29CFDFA96 /* InsightsEmptyStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsightsEmptyStateTests.swift; sourceTree = "<group>"; };
|
||||
0359E1D32D936859E5A0C9F3 /* AppResumeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppResumeTests.swift; sourceTree = "<group>"; };
|
||||
29CE4110A0D8FBBAD7F92BDF /* BaseUITestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseUITestCase.swift; sourceTree = "<group>"; };
|
||||
29E2A2FC314F88244CA946BF /* StreakTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StreakTests.swift; sourceTree = "<group>"; };
|
||||
427CD9C91D43AB6A0302B4DD /* DayScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DayScreen.swift; sourceTree = "<group>"; };
|
||||
469470483072085BE9E04E12 /* NoteEditTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteEditTests.swift; sourceTree = "<group>"; };
|
||||
B8C9D0E1F2A3B4C5D6E7F8A9 /* MonthViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MonthViewTests.swift; sourceTree = "<group>"; };
|
||||
C9D0E1F2A3B4C5D6E7F8A9B0 /* SettingsActionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsActionTests.swift; sourceTree = "<group>"; };
|
||||
D0E1F2A3B4C5D6E7F8A9B0C1 /* CustomizationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomizationTests.swift; sourceTree = "<group>"; };
|
||||
E1F2A3B4C5D6E7F8A9B0C1D2 /* OnboardingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingTests.swift; sourceTree = "<group>"; };
|
||||
F2A3B4C5D6E7F8A9B0C1D2E3 /* StabilityTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StabilityTests.swift; sourceTree = "<group>"; };
|
||||
5354C23DD5FC67C1C97482F2 /* WaitHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitHelpers.swift; sourceTree = "<group>"; };
|
||||
5566271983AEDF1D33C34FE6 /* DataControllerCRUDTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DataControllerCRUDTests.swift; sourceTree = "<group>"; };
|
||||
7E35564DEA72EB6F8447CDAA /* EntryDetailScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntryDetailScreen.swift; sourceTree = "<group>"; };
|
||||
8114D2CE12EC5392371BB415 /* DarkModeStylesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DarkModeStylesTests.swift; sourceTree = "<group>"; };
|
||||
881CA8B21231D67DED575502 /* SettingsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreen.swift; sourceTree = "<group>"; };
|
||||
9CFAE86F485C853DB3239DD9 /* IntegrationTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = IntegrationTests.swift; sourceTree = "<group>"; };
|
||||
A1B2C3D4E5F6A7B8C9D0E1F2 /* NoteEditorScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteEditorScreen.swift; sourceTree = "<group>"; };
|
||||
A3B4C5D6E7F8A9B0C1D2E3F4 /* DataPersistenceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataPersistenceTests.swift; sourceTree = "<group>"; };
|
||||
B4C5D6E7F8A9B0C1D2E3F4A5 /* PaywallGateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaywallGateTests.swift; sourceTree = "<group>"; };
|
||||
C5D6E7F8A9B0C1D2E3F4A5B6 /* AppThemeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppThemeTests.swift; sourceTree = "<group>"; };
|
||||
D6E7F8A9B0C1D2E3F4A5B6C7 /* IconPackTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconPackTests.swift; sourceTree = "<group>"; };
|
||||
E7F8A9B0C1D2E3F4A5B6C7D8 /* PremiumCustomizationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PremiumCustomizationTests.swift; sourceTree = "<group>"; };
|
||||
F8A9B0C1D2E3F4A5B6C7D8E9 /* HeaderMoodLoggingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderMoodLoggingTests.swift; sourceTree = "<group>"; };
|
||||
A6988985985DE9C29CFDFA96 /* InsightsEmptyStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsightsEmptyStateTests.swift; sourceTree = "<group>"; };
|
||||
A7B8C9D0E1F2A3B4C5D6E7F8 /* NotesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotesTests.swift; sourceTree = "<group>"; };
|
||||
A9B0C1D2E3F4A5B6C7D8E9FA /* DayViewGroupingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DayViewGroupingTests.swift; sourceTree = "<group>"; };
|
||||
AA11111111111111AAAAAAAA /* AppLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLaunchTests.swift; sourceTree = "<group>"; };
|
||||
B0C1D2E3F4A5B6C7D8E9FA0B /* AllDayViewStylesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllDayViewStylesTests.swift; sourceTree = "<group>"; };
|
||||
B2C3D4E5F6A7B8C9D0E1F2A3 /* CustomizeScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomizeScreen.swift; sourceTree = "<group>"; };
|
||||
B4C5D6E7F8A9B0C1D2E3F4A5 /* PaywallGateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaywallGateTests.swift; sourceTree = "<group>"; };
|
||||
B60015D02A064FF582E232FD /* Feels Watch AppDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Feels Watch App/Feels Watch AppDebug.entitlements"; sourceTree = "<group>"; };
|
||||
B8AB4CD73C2B4DC89C6FE84D /* Feels Watch App.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Feels Watch App/Feels Watch App.entitlements"; sourceTree = "<group>"; };
|
||||
B8C9D0E1F2A3B4C5D6E7F8A9 /* MonthViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MonthViewTests.swift; sourceTree = "<group>"; };
|
||||
BB22222222222222BBBBBBBB /* MoodLoggingEmptyStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoodLoggingEmptyStateTests.swift; sourceTree = "<group>"; };
|
||||
C1D2E3F4A5B6C7D8E9FA0B1C /* MonthViewInteractionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MonthViewInteractionTests.swift; sourceTree = "<group>"; };
|
||||
C3D4E5F6A7B8C9D0E1F2A3B4 /* OnboardingScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingScreen.swift; sourceTree = "<group>"; };
|
||||
C5D6E7F8A9B0C1D2E3F4A5B6 /* AppThemeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppThemeTests.swift; sourceTree = "<group>"; };
|
||||
C7CDDCB9C85BAE71C679C0BF /* TabBarScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarScreen.swift; sourceTree = "<group>"; };
|
||||
C9D0E1F2A3B4C5D6E7F8A9B0 /* SettingsActionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsActionTests.swift; sourceTree = "<group>"; };
|
||||
CC33333333333333CCCCCCCC /* MoodLoggingWithDataTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoodLoggingWithDataTests.swift; sourceTree = "<group>"; };
|
||||
D0E1F2A3B4C5D6E7F8A9B0C1 /* CustomizationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomizationTests.swift; sourceTree = "<group>"; };
|
||||
D4E5F60708091011ABCDE001 /* DayViewViewModelTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DayViewViewModelTests.swift; sourceTree = "<group>"; };
|
||||
D4E5F6A7B8C9D0E1F2A3B4C5 /* MoodReplacementTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoodReplacementTests.swift; sourceTree = "<group>"; };
|
||||
D6E7F8A9B0C1D2E3F4A5B6C7 /* IconPackTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconPackTests.swift; sourceTree = "<group>"; };
|
||||
DA0D74ACDD741CFA1F14F50F /* FeelsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FeelsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DD44444444444444DDDDDDDD /* EntryDetailTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntryDetailTests.swift; sourceTree = "<group>"; };
|
||||
DD717F91BD65382B7DDFE3C4 /* VoteLogicsTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = VoteLogicsTests.swift; sourceTree = "<group>"; };
|
||||
DFDAD20AE6C6914EDD87DCBC /* SettingsOnboardingTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SettingsOnboardingTests.swift; sourceTree = "<group>"; };
|
||||
E1F2A3B4C5D6E7F8A9B0C1D2 /* OnboardingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingTests.swift; sourceTree = "<group>"; };
|
||||
E5F6A7B8C9D0E1F2A3B4C5D6 /* EmptyStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyStateTests.swift; sourceTree = "<group>"; };
|
||||
E7F8A9B0C1D2E3F4A5B6C7D8 /* PremiumCustomizationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PremiumCustomizationTests.swift; sourceTree = "<group>"; };
|
||||
EE55555555555555EEEEEEEE /* SettingsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTests.swift; sourceTree = "<group>"; };
|
||||
F2A3B4C5D6E7F8A9B0C1D2E3 /* StabilityTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StabilityTests.swift; sourceTree = "<group>"; };
|
||||
F4D304CD05CC7C662CCD7DCB /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
|
||||
F6A7B8C9D0E1F2A3B4C5D6E7 /* EntryDeleteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntryDeleteTests.swift; sourceTree = "<group>"; };
|
||||
F8A9B0C1D2E3F4A5B6C7D8E9 /* HeaderMoodLoggingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderMoodLoggingTests.swift; sourceTree = "<group>"; };
|
||||
FF66666666666666FFFFFFFF /* SecondaryTabTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondaryTabTests.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||
1C000C162EE93AE3009C9ED5 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
|
||||
1C000C162EE93AE3009C9ED5 /* Exceptions for "Shared" folder in "FeelsWidgetExtension" target */ = {
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
AccessibilityIdentifiers.swift,
|
||||
@@ -221,7 +225,7 @@
|
||||
);
|
||||
target = 1CD90B44278C7E7A001C4FEA /* FeelsWidgetExtension */;
|
||||
};
|
||||
2166CE8AA7264FC2B4BFAAAC /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
|
||||
2166CE8AA7264FC2B4BFAAAC /* Exceptions for "Shared" folder in "Feels Watch App" target */ = {
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
Models/Mood.swift,
|
||||
@@ -236,9 +240,41 @@
|
||||
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||
1C00073D2EE9388A009C9ED5 /* Shared */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (2166CE8AA7264FC2B4BFAAAC /* PBXFileSystemSynchronizedBuildFileExceptionSet */, 1C000C162EE93AE3009C9ED5 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = Shared; sourceTree = "<group>"; };
|
||||
1C0009922EE938FC009C9ED5 /* FeelsWidget2 */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = FeelsWidget2; sourceTree = "<group>"; };
|
||||
579031D619ED4B989145EEB1 /* Feels Watch App */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = "Feels Watch App"; sourceTree = "<group>"; };
|
||||
1C00073D2EE9388A009C9ED5 /* Shared */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
2166CE8AA7264FC2B4BFAAAC /* Exceptions for "Shared" folder in "Feels Watch App" target */,
|
||||
1C000C162EE93AE3009C9ED5 /* Exceptions for "Shared" folder in "FeelsWidgetExtension" target */,
|
||||
);
|
||||
explicitFileTypes = {
|
||||
};
|
||||
explicitFolders = (
|
||||
);
|
||||
path = Shared;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1C0009922EE938FC009C9ED5 /* FeelsWidget2 */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
);
|
||||
explicitFileTypes = {
|
||||
};
|
||||
explicitFolders = (
|
||||
);
|
||||
path = FeelsWidget2;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
579031D619ED4B989145EEB1 /* Feels Watch App */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
);
|
||||
explicitFileTypes = {
|
||||
};
|
||||
explicitFolders = (
|
||||
);
|
||||
path = "Feels Watch App";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXFileSystemSynchronizedRootGroup section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -306,9 +342,9 @@
|
||||
1CD90AE5278C7DDF001C4FEA = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B8AB4CD73C2B4DC89C6FE84D /* Feels Watch App/Feels Watch App.entitlements */,
|
||||
B60015D02A064FF582E232FD /* Feels Watch App/Feels Watch AppDebug.entitlements */,
|
||||
1C0DAB50279DB0FB003B1F21 /* Feels/Localizable.xcstrings */,
|
||||
B8AB4CD73C2B4DC89C6FE84D /* Feels Watch App.entitlements */,
|
||||
B60015D02A064FF582E232FD /* Feels Watch AppDebug.entitlements */,
|
||||
1C0DAB50279DB0FB003B1F21 /* Localizable.xcstrings */,
|
||||
1CDEFBBE2F3B8736006AE6A1 /* Configuration.storekit */,
|
||||
1CD90B6A278C7F75001C4FEA /* Feels (iOS).entitlements */,
|
||||
1CD90B70278C8000001C4FEA /* Feels (iOS)Dev.entitlements */,
|
||||
@@ -386,33 +422,12 @@
|
||||
A9B0C1D2E3F4A5B6C7D8E9FA /* DayViewGroupingTests.swift */,
|
||||
B0C1D2E3F4A5B6C7D8E9FA0B /* AllDayViewStylesTests.swift */,
|
||||
C1D2E3F4A5B6C7D8E9FA0B1C /* MonthViewInteractionTests.swift */,
|
||||
0246E9F406F872E5DEEB7269 /* YearViewDisplayTests.swift */,
|
||||
DFDAD20AE6C6914EDD87DCBC /* SettingsOnboardingTests.swift */,
|
||||
);
|
||||
path = "Tests iOS";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3A62ED77167DA212DE1CCB7D /* Helpers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
29CE4110A0D8FBBAD7F92BDF /* BaseUITestCase.swift */,
|
||||
5354C23DD5FC67C1C97482F2 /* WaitHelpers.swift */,
|
||||
);
|
||||
path = Helpers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B697A2092711045D69109EA1 /* Screens */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C7CDDCB9C85BAE71C679C0BF /* TabBarScreen.swift */,
|
||||
427CD9C91D43AB6A0302B4DD /* DayScreen.swift */,
|
||||
7E35564DEA72EB6F8447CDAA /* EntryDetailScreen.swift */,
|
||||
881CA8B21231D67DED575502 /* SettingsScreen.swift */,
|
||||
A1B2C3D4E5F6A7B8C9D0E1F2 /* NoteEditorScreen.swift */,
|
||||
B2C3D4E5F6A7B8C9D0E1F2A3 /* CustomizeScreen.swift */,
|
||||
C3D4E5F6A7B8C9D0E1F2A3B4 /* OnboardingScreen.swift */,
|
||||
);
|
||||
path = Screens;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1CD90B11278C7DE0001C4FEA /* Tests macOS */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -446,6 +461,15 @@
|
||||
path = FeelsTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3A62ED77167DA212DE1CCB7D /* Helpers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
29CE4110A0D8FBBAD7F92BDF /* BaseUITestCase.swift */,
|
||||
5354C23DD5FC67C1C97482F2 /* WaitHelpers.swift */,
|
||||
);
|
||||
path = Helpers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
88F4C25CA0D11FB136B0B8A6 /* iOS */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -454,6 +478,20 @@
|
||||
name = iOS;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B697A2092711045D69109EA1 /* Screens */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C7CDDCB9C85BAE71C679C0BF /* TabBarScreen.swift */,
|
||||
427CD9C91D43AB6A0302B4DD /* DayScreen.swift */,
|
||||
7E35564DEA72EB6F8447CDAA /* EntryDetailScreen.swift */,
|
||||
881CA8B21231D67DED575502 /* SettingsScreen.swift */,
|
||||
A1B2C3D4E5F6A7B8C9D0E1F2 /* NoteEditorScreen.swift */,
|
||||
B2C3D4E5F6A7B8C9D0E1F2A3 /* CustomizeScreen.swift */,
|
||||
C3D4E5F6A7B8C9D0E1F2A3B4 /* OnboardingScreen.swift */,
|
||||
);
|
||||
path = Screens;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@@ -676,7 +714,7 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
1C0DAB51279DB0FB003B1F21 /* Feels/Localizable.xcstrings in Resources */,
|
||||
1C0DAB51279DB0FB003B1F21 /* Localizable.xcstrings in Resources */,
|
||||
1CDEFBBF2F3B8736006AE6A1 /* Configuration.storekit in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -707,7 +745,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
1CDEFBC02F3B8736006AE6A1 /* Configuration.storekit in Resources */,
|
||||
1C0DAB52279DB0FB003B1F22 /* Feels/Localizable.xcstrings in Resources */,
|
||||
1C0DAB52279DB0FB003B1F22 /* Localizable.xcstrings in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -787,6 +825,8 @@
|
||||
A9B0C1D200000000C7D8E9FA /* DayViewGroupingTests.swift in Sources */,
|
||||
B0C1D2E300000000D8E9FA0B /* AllDayViewStylesTests.swift in Sources */,
|
||||
C1D2E3F400000000E9FA0B1C /* MonthViewInteractionTests.swift in Sources */,
|
||||
D1AD0A0469EADFB1446E9B09 /* YearViewDisplayTests.swift in Sources */,
|
||||
FD30D4508D4C61AB10AC1E71 /* SettingsOnboardingTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -125,6 +125,11 @@ enum AccessibilityID {
|
||||
// MARK: - Year View
|
||||
enum YearView {
|
||||
static let heatmap = "year_heatmap"
|
||||
static let donutChart = "year_donut_chart"
|
||||
static let barChart = "year_bar_chart"
|
||||
static let statsSection = "year_stats_section"
|
||||
static func cardHeader(year: Int) -> String { "year_card_header_\(year)" }
|
||||
static let shareButton = "year_share_button"
|
||||
}
|
||||
|
||||
// MARK: - Onboarding
|
||||
|
||||
@@ -25,15 +25,6 @@ struct OnboardingDay: View {
|
||||
@ObservedObject var onboardingData: OnboardingData
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
// Gradient background
|
||||
LinearGradient(
|
||||
colors: [Color(hex: "4facfe"), Color(hex: "00f2fe")],
|
||||
startPoint: .topLeading,
|
||||
endPoint: .bottomTrailing
|
||||
)
|
||||
.ignoresSafeArea()
|
||||
|
||||
VStack(spacing: 0) {
|
||||
Spacer()
|
||||
|
||||
@@ -104,7 +95,14 @@ struct OnboardingDay: View {
|
||||
.padding(.horizontal, 30)
|
||||
.padding(.bottom, 80)
|
||||
}
|
||||
}
|
||||
.background(
|
||||
LinearGradient(
|
||||
colors: [Color(hex: "4facfe"), Color(hex: "00f2fe")],
|
||||
startPoint: .topLeading,
|
||||
endPoint: .bottomTrailing
|
||||
)
|
||||
.ignoresSafeArea()
|
||||
)
|
||||
.accessibilityIdentifier(AccessibilityID.Onboarding.dayScreen)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,16 +12,6 @@ struct OnboardingStyle: View {
|
||||
@State private var selectedTheme: AppTheme = .celestial
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
// Gradient background that updates with theme
|
||||
LinearGradient(
|
||||
colors: selectedTheme.previewColors,
|
||||
startPoint: .topLeading,
|
||||
endPoint: .bottomTrailing
|
||||
)
|
||||
.ignoresSafeArea()
|
||||
.animation(.easeInOut(duration: 0.4), value: selectedTheme)
|
||||
|
||||
ScrollView(showsIndicators: false) {
|
||||
VStack(spacing: 0) {
|
||||
// Icon
|
||||
@@ -86,7 +76,15 @@ struct OnboardingStyle: View {
|
||||
.padding(.bottom, 80)
|
||||
}
|
||||
}
|
||||
}
|
||||
.background(
|
||||
LinearGradient(
|
||||
colors: selectedTheme.previewColors,
|
||||
startPoint: .topLeading,
|
||||
endPoint: .bottomTrailing
|
||||
)
|
||||
.ignoresSafeArea()
|
||||
.animation(.easeInOut(duration: 0.4), value: selectedTheme)
|
||||
)
|
||||
.onAppear {
|
||||
// Apply default theme on appear
|
||||
selectedTheme.apply()
|
||||
|
||||
@@ -15,15 +15,6 @@ struct OnboardingSubscription: View {
|
||||
let completionClosure: ((OnboardingData) -> Void)
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
// Gradient background
|
||||
LinearGradient(
|
||||
colors: [Color(hex: "11998e"), Color(hex: "38ef7d")],
|
||||
startPoint: .topLeading,
|
||||
endPoint: .bottomTrailing
|
||||
)
|
||||
.ignoresSafeArea()
|
||||
|
||||
VStack(spacing: 0) {
|
||||
Spacer()
|
||||
|
||||
@@ -138,7 +129,14 @@ struct OnboardingSubscription: View {
|
||||
.padding(.horizontal, 24)
|
||||
.padding(.bottom, 50)
|
||||
}
|
||||
}
|
||||
.background(
|
||||
LinearGradient(
|
||||
colors: [Color(hex: "11998e"), Color(hex: "38ef7d")],
|
||||
startPoint: .topLeading,
|
||||
endPoint: .bottomTrailing
|
||||
)
|
||||
.ignoresSafeArea()
|
||||
)
|
||||
.accessibilityIdentifier(AccessibilityID.Onboarding.subscriptionScreen)
|
||||
.sheet(isPresented: $showSubscriptionStore, onDismiss: {
|
||||
// After subscription store closes, complete onboarding
|
||||
|
||||
@@ -16,15 +16,6 @@ struct OnboardingTitle: View {
|
||||
@ObservedObject var onboardingData: OnboardingData
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
|
||||
Image("average", bundle: .main)
|
||||
.foregroundColor(Color(UIColor.darkText))
|
||||
.opacity(0.04)
|
||||
.scaleEffect(1.2)
|
||||
.padding(.bottom, 55)
|
||||
.accessibilityHidden(true)
|
||||
|
||||
ScrollView {
|
||||
VStack{
|
||||
Text(String(localized: "onboarding_title_title"))
|
||||
@@ -67,8 +58,17 @@ struct OnboardingTitle: View {
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
.background {
|
||||
ZStack {
|
||||
Color.orange
|
||||
Image("average", bundle: .main)
|
||||
.foregroundColor(Color(UIColor.darkText))
|
||||
.opacity(0.04)
|
||||
.scaleEffect(1.2)
|
||||
.padding(.bottom, 55)
|
||||
.accessibilityHidden(true)
|
||||
}
|
||||
}
|
||||
.background(.orange)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,18 +19,7 @@ struct OnboardingWrapup: View {
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
GeometryReader { geometry in
|
||||
VStack {
|
||||
Spacer()
|
||||
Image("great", bundle: .main)
|
||||
.foregroundColor(Color(UIColor.darkText))
|
||||
.opacity(0.04)
|
||||
.scaleEffect(1.2, anchor: .trailing)
|
||||
.accessibilityHidden(true)
|
||||
Spacer()
|
||||
}
|
||||
|
||||
VStack {
|
||||
ScrollView {
|
||||
|
||||
@@ -77,8 +66,20 @@ struct OnboardingWrapup: View {
|
||||
}
|
||||
.frame(maxWidth: geometry.size.width)
|
||||
}
|
||||
.background {
|
||||
ZStack {
|
||||
Color(hex: "31d158")
|
||||
VStack {
|
||||
Spacer()
|
||||
Image("great", bundle: .main)
|
||||
.foregroundColor(Color(UIColor.darkText))
|
||||
.opacity(0.04)
|
||||
.scaleEffect(1.2, anchor: .trailing)
|
||||
.accessibilityHidden(true)
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
}
|
||||
.background(Color(hex: "31d158"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,8 +41,6 @@ struct AddMoodHeaderView: View {
|
||||
Text(String(imagePack.rawValue))
|
||||
.hidden()
|
||||
|
||||
theme.currentTheme.secondaryBGColor
|
||||
|
||||
VStack(spacing: 16) {
|
||||
Text(ShowBasedOnVoteLogics.getVotingTitle(onboardingData: onboardingData))
|
||||
.font(.title2.bold())
|
||||
@@ -66,6 +64,7 @@ struct AddMoodHeaderView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.accessibilityIdentifier(AccessibilityID.DayView.moodHeader)
|
||||
|
||||
@@ -24,16 +24,16 @@ struct CustomizeContentView: View {
|
||||
Button(action: { showThemePicker = true }) {
|
||||
HStack(spacing: 16) {
|
||||
// Emoji preview
|
||||
ZStack {
|
||||
Text("🎨")
|
||||
.font(.title)
|
||||
.frame(width: 56, height: 56)
|
||||
.background(
|
||||
LinearGradient(
|
||||
colors: [.purple.opacity(0.8), .blue.opacity(0.8), .cyan.opacity(0.8)],
|
||||
startPoint: .topLeading,
|
||||
endPoint: .bottomTrailing
|
||||
)
|
||||
Text("🎨")
|
||||
.font(.title)
|
||||
}
|
||||
.frame(width: 56, height: 56)
|
||||
)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 12))
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
|
||||
@@ -259,14 +259,6 @@ struct AppThemePreviewSheet: View {
|
||||
}
|
||||
|
||||
private var heroSection: some View {
|
||||
ZStack {
|
||||
// Gradient background
|
||||
LinearGradient(
|
||||
colors: theme.previewColors + [theme.previewColors[0].opacity(0.5)],
|
||||
startPoint: .topLeading,
|
||||
endPoint: .bottomTrailing
|
||||
)
|
||||
|
||||
VStack(spacing: 16) {
|
||||
Text(theme.emoji)
|
||||
.font(.system(size: 72))
|
||||
@@ -277,8 +269,15 @@ struct AppThemePreviewSheet: View {
|
||||
.foregroundColor(.white)
|
||||
.shadow(color: .black.opacity(0.3), radius: 4, x: 0, y: 2)
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: 200)
|
||||
.background(
|
||||
LinearGradient(
|
||||
colors: theme.previewColors + [theme.previewColors[0].opacity(0.5)],
|
||||
startPoint: .topLeading,
|
||||
endPoint: .bottomTrailing
|
||||
)
|
||||
)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 20))
|
||||
.padding(.horizontal, 20)
|
||||
.padding(.top, 16)
|
||||
|
||||
@@ -22,9 +22,6 @@ struct DayFilterPickerView: View {
|
||||
(Calendar.current.shortWeekdaySymbols[6], 7)]
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
|
||||
VStack {
|
||||
HStack {
|
||||
ForEach(weekdays.indices, id: \.self) { dayIdx in
|
||||
@@ -55,7 +52,7 @@ struct DayFilterPickerView: View {
|
||||
.foregroundColor(textColor)
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
@@ -50,8 +50,6 @@ struct IconPickerView: View {
|
||||
]
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
VStack {
|
||||
ScrollView(.horizontal) {
|
||||
HStack {
|
||||
@@ -90,7 +88,7 @@ struct IconPickerView: View {
|
||||
.padding()
|
||||
.cornerRadius(10)
|
||||
}
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@ struct PersonalityPackPickerView: View {
|
||||
private var textColor: Color { theme.currentTheme.labelColor }
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
VStack {
|
||||
ForEach(PersonalityPack.allCases, id: \.self) { aPack in
|
||||
VStack(spacing: 10) {
|
||||
@@ -67,7 +65,7 @@ struct PersonalityPackPickerView: View {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
@@ -15,8 +15,6 @@ struct ThemePickerView: View {
|
||||
private var textColor: Color { selectedTheme.currentTheme.labelColor }
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
selectedTheme.currentTheme.secondaryBGColor
|
||||
VStack {
|
||||
HStack(spacing: 0) {
|
||||
themeButton(for: .system)
|
||||
@@ -27,7 +25,7 @@ struct ThemePickerView: View {
|
||||
.padding(.top)
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.background(selectedTheme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
.onAppear {
|
||||
|
||||
@@ -18,9 +18,6 @@ struct VotingLayoutPickerView: View {
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
Text("Voting Layout")
|
||||
.font(.headline)
|
||||
@@ -68,7 +65,7 @@ struct VotingLayoutPickerView: View {
|
||||
}
|
||||
.padding(.bottom)
|
||||
}
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
@@ -118,8 +118,6 @@ struct SettingsContentView: View {
|
||||
// MARK: - Reminder Time Button
|
||||
|
||||
private var reminderTimeButton: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
AnalyticsManager.shared.track(.reminderTimeTapped)
|
||||
showReminderTimePicker = true
|
||||
@@ -150,7 +148,7 @@ struct SettingsContentView: View {
|
||||
.accessibilityLabel(String(localized: "Reminder Time"))
|
||||
.accessibilityValue(formattedReminderTime)
|
||||
.accessibilityHint(String(localized: "Opens time picker to change reminder time"))
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
@@ -217,8 +215,6 @@ struct SettingsContentView: View {
|
||||
}
|
||||
|
||||
private var bypassSubscriptionToggle: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
HStack(spacing: 12) {
|
||||
Image(systemName: "lock.open.fill")
|
||||
.font(.title2)
|
||||
@@ -240,14 +236,12 @@ struct SettingsContentView: View {
|
||||
.labelsHidden()
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var trialDateButton: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
VStack(spacing: 12) {
|
||||
HStack(spacing: 12) {
|
||||
Image(systemName: "calendar.badge.clock")
|
||||
@@ -273,7 +267,7 @@ struct SettingsContentView: View {
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
.sheet(isPresented: $showTrialDatePicker) {
|
||||
@@ -308,8 +302,6 @@ struct SettingsContentView: View {
|
||||
@State private var showTipsPreview = false
|
||||
|
||||
private var animationLabButton: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button {
|
||||
showAnimationLab = true
|
||||
} label: {
|
||||
@@ -336,7 +328,7 @@ struct SettingsContentView: View {
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
.sheet(isPresented: $showAnimationLab) {
|
||||
@@ -347,8 +339,6 @@ struct SettingsContentView: View {
|
||||
}
|
||||
|
||||
private var paywallPreviewButton: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button {
|
||||
showPaywallPreview = true
|
||||
} label: {
|
||||
@@ -381,7 +371,7 @@ struct SettingsContentView: View {
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
.sheet(isPresented: $showPaywallPreview) {
|
||||
@@ -392,8 +382,6 @@ struct SettingsContentView: View {
|
||||
}
|
||||
|
||||
private var tipsPreviewButton: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button {
|
||||
showTipsPreview = true
|
||||
} label: {
|
||||
@@ -426,7 +414,7 @@ struct SettingsContentView: View {
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
.sheet(isPresented: $showTipsPreview) {
|
||||
@@ -437,8 +425,6 @@ struct SettingsContentView: View {
|
||||
}
|
||||
|
||||
private var testNotificationsButton: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button {
|
||||
LocalNotification.sendAllPersonalityNotificationsForScreenshot()
|
||||
} label: {
|
||||
@@ -465,14 +451,12 @@ struct SettingsContentView: View {
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var exportWidgetsButton: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button {
|
||||
isExportingWidgets = true
|
||||
Task {
|
||||
@@ -519,14 +503,12 @@ struct SettingsContentView: View {
|
||||
.padding()
|
||||
}
|
||||
.disabled(isExportingWidgets)
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var exportVotingLayoutsButton: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button {
|
||||
isExportingVotingLayouts = true
|
||||
Task {
|
||||
@@ -573,14 +555,12 @@ struct SettingsContentView: View {
|
||||
.padding()
|
||||
}
|
||||
.disabled(isExportingVotingLayouts)
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var exportWatchViewsButton: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button {
|
||||
isExportingWatchViews = true
|
||||
Task {
|
||||
@@ -627,14 +607,12 @@ struct SettingsContentView: View {
|
||||
.padding()
|
||||
}
|
||||
.disabled(isExportingWatchViews)
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var exportInsightsButton: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button {
|
||||
isExportingInsights = true
|
||||
Task {
|
||||
@@ -687,14 +665,12 @@ struct SettingsContentView: View {
|
||||
.padding()
|
||||
}
|
||||
.disabled(isExportingInsights)
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var generateAndExportButton: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button {
|
||||
isGeneratingScreenshots = true
|
||||
Task {
|
||||
@@ -748,14 +724,12 @@ struct SettingsContentView: View {
|
||||
.padding()
|
||||
}
|
||||
.disabled(isGeneratingScreenshots)
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var deleteHealthKitDataButton: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button {
|
||||
isDeletingHealthKitData = true
|
||||
healthKitDeleteResult = nil
|
||||
@@ -800,14 +774,12 @@ struct SettingsContentView: View {
|
||||
.padding()
|
||||
}
|
||||
.disabled(isDeletingHealthKitData)
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var clearDataButton: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button {
|
||||
MoodLogger.shared.deleteAllData()
|
||||
} label: {
|
||||
@@ -830,7 +802,7 @@ struct SettingsContentView: View {
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.clearDataButton)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
@@ -842,8 +814,6 @@ struct SettingsContentView: View {
|
||||
@ViewBuilder
|
||||
private var privacyLockToggle: some View {
|
||||
if authManager.canUseBiometrics {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
HStack(spacing: 12) {
|
||||
Image(systemName: authManager.biometricIcon)
|
||||
.font(.title2)
|
||||
@@ -881,7 +851,7 @@ struct SettingsContentView: View {
|
||||
.accessibilityHint(String(localized: "Require biometric authentication to open app"))
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
@@ -892,8 +862,6 @@ struct SettingsContentView: View {
|
||||
@ObservedObject private var healthKitManager = HealthKitManager.shared
|
||||
|
||||
private var addTestDataButton: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button {
|
||||
DataController.shared.populateTestData()
|
||||
} label: {
|
||||
@@ -916,7 +884,7 @@ struct SettingsContentView: View {
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
@@ -1031,8 +999,6 @@ struct SettingsContentView: View {
|
||||
// MARK: - Export Data Button
|
||||
|
||||
private var exportDataButton: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
AnalyticsManager.shared.track(.exportTapped)
|
||||
showExportView = true
|
||||
@@ -1062,14 +1028,12 @@ struct SettingsContentView: View {
|
||||
})
|
||||
.accessibilityLabel(String(localized: "Export Data"))
|
||||
.accessibilityHint(String(localized: "Export your mood data as CSV or PDF"))
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var showOnboardingButton: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
AnalyticsManager.shared.track(.onboardingReshown)
|
||||
showOnboarding.toggle()
|
||||
@@ -1080,14 +1044,13 @@ struct SettingsContentView: View {
|
||||
.accessibilityHint(String(localized: "View the app introduction again"))
|
||||
.accessibilityIdentifier(AccessibilityID.Settings.showOnboardingButton)
|
||||
.padding()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var canDelete: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
VStack {
|
||||
Toggle(String(localized: "settings_use_delete_enable"),
|
||||
isOn: $deleteEnabled)
|
||||
@@ -1098,14 +1061,12 @@ struct SettingsContentView: View {
|
||||
.accessibilityHint(String(localized: "Allow deleting mood entries by swiping"))
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var eulaButton: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
AnalyticsManager.shared.track(.eulaViewed)
|
||||
if let url = URL(string: "https://feels.88oakapps.com/eula.html") {
|
||||
@@ -1117,14 +1078,13 @@ struct SettingsContentView: View {
|
||||
})
|
||||
.accessibilityHint(String(localized: "Opens End User License Agreement in browser"))
|
||||
.padding()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var privacyButton: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
AnalyticsManager.shared.track(.privacyPolicyViewed)
|
||||
if let url = URL(string: "https://feels.88oakapps.com/privacy.html") {
|
||||
@@ -1136,7 +1096,8 @@ struct SettingsContentView: View {
|
||||
})
|
||||
.accessibilityHint(String(localized: "Opens Privacy Policy in browser"))
|
||||
.padding()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
@@ -1144,8 +1105,6 @@ struct SettingsContentView: View {
|
||||
// MARK: - Analytics Toggle
|
||||
|
||||
private var analyticsToggle: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
HStack(spacing: 12) {
|
||||
Image(systemName: "chart.bar.xaxis")
|
||||
.font(.title2)
|
||||
@@ -1179,7 +1138,7 @@ struct SettingsContentView: View {
|
||||
.accessibilityHint("Toggle anonymous usage analytics")
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
@@ -1458,8 +1417,6 @@ struct SettingsView: View {
|
||||
@ViewBuilder
|
||||
private var privacyLockToggle: some View {
|
||||
if authManager.canUseBiometrics {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
HStack(spacing: 12) {
|
||||
Image(systemName: authManager.biometricIcon)
|
||||
.font(.title2)
|
||||
@@ -1495,7 +1452,7 @@ struct SettingsView: View {
|
||||
.labelsHidden()
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
@@ -1607,8 +1564,6 @@ struct SettingsView: View {
|
||||
// MARK: - Export Data Button
|
||||
|
||||
private var exportDataButton: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
AnalyticsManager.shared.track(.exportTapped)
|
||||
showExportView = true
|
||||
@@ -1636,7 +1591,7 @@ struct SettingsView: View {
|
||||
}
|
||||
.padding()
|
||||
})
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
@@ -1656,8 +1611,6 @@ struct SettingsView: View {
|
||||
}
|
||||
|
||||
private var specialThanksCell: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
VStack {
|
||||
Button(action: {
|
||||
AnalyticsManager.shared.track(.specialThanksViewed)
|
||||
@@ -1683,14 +1636,12 @@ struct SettingsView: View {
|
||||
.padding(.bottom)
|
||||
}
|
||||
}
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var addTestDataCell: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
DataController.shared.populateTestData()
|
||||
}, label: {
|
||||
@@ -1698,14 +1649,13 @@ struct SettingsView: View {
|
||||
.foregroundColor(textColor)
|
||||
})
|
||||
.padding()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var editFirstLaunchDatePast: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
HStack(spacing: 12) {
|
||||
Image(systemName: "calendar.badge.clock")
|
||||
.font(.title2)
|
||||
@@ -1729,7 +1679,7 @@ struct SettingsView: View {
|
||||
.font(.subheadline.weight(.medium))
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
.sheet(isPresented: $showTrialDatePicker) {
|
||||
@@ -1760,8 +1710,6 @@ struct SettingsView: View {
|
||||
}
|
||||
|
||||
private var resetLaunchDate: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
firstLaunchDate = Date()
|
||||
Task {
|
||||
@@ -1772,14 +1720,13 @@ struct SettingsView: View {
|
||||
.foregroundColor(textColor)
|
||||
})
|
||||
.padding()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var clearDB: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
MoodLogger.shared.deleteAllData()
|
||||
}, label: {
|
||||
@@ -1787,14 +1734,13 @@ struct SettingsView: View {
|
||||
.foregroundColor(textColor)
|
||||
})
|
||||
.padding()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var fixWeekday: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
DataController.shared.fixWrongWeekdays()
|
||||
}, label: {
|
||||
@@ -1802,14 +1748,13 @@ struct SettingsView: View {
|
||||
.foregroundColor(textColor)
|
||||
})
|
||||
.padding()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var whyBackgroundMode: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
VStack {
|
||||
Button(action: {
|
||||
withAnimation{
|
||||
@@ -1826,14 +1771,12 @@ struct SettingsView: View {
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var showOnboardingButton: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
AnalyticsManager.shared.track(.onboardingReshown)
|
||||
showOnboarding.toggle()
|
||||
@@ -1842,14 +1785,13 @@ struct SettingsView: View {
|
||||
.foregroundColor(textColor)
|
||||
})
|
||||
.padding()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var eulaButton: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
AnalyticsManager.shared.track(.eulaViewed)
|
||||
openURL(URL(string: "https://feels.88oakapps.com/eula.html")!)
|
||||
@@ -1858,14 +1800,13 @@ struct SettingsView: View {
|
||||
.foregroundColor(textColor)
|
||||
})
|
||||
.padding()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var privacyButton: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
AnalyticsManager.shared.track(.privacyPolicyViewed)
|
||||
openURL(URL(string: "https://feels.88oakapps.com/privacy.html")!)
|
||||
@@ -1874,14 +1815,13 @@ struct SettingsView: View {
|
||||
.foregroundColor(textColor)
|
||||
})
|
||||
.padding()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var analyticsToggle: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
HStack(spacing: 12) {
|
||||
Image(systemName: "chart.bar.xaxis")
|
||||
.font(.title2)
|
||||
@@ -1915,14 +1855,12 @@ struct SettingsView: View {
|
||||
.accessibilityHint("Toggle anonymous usage analytics")
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var canDelete: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
VStack {
|
||||
Toggle(String(localized: "settings_use_delete_enable"),
|
||||
isOn: $deleteEnabled)
|
||||
@@ -1932,14 +1870,12 @@ struct SettingsView: View {
|
||||
.foregroundColor(textColor)
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var exportData: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
showingExporter.toggle()
|
||||
AnalyticsManager.shared.track(.exportTapped)
|
||||
@@ -1948,14 +1884,13 @@ struct SettingsView: View {
|
||||
.foregroundColor(textColor)
|
||||
})
|
||||
.padding()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var importData: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
showingImporter.toggle()
|
||||
AnalyticsManager.shared.track(.importTapped)
|
||||
@@ -1964,14 +1899,13 @@ struct SettingsView: View {
|
||||
.foregroundColor(textColor)
|
||||
})
|
||||
.padding()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var randomIcons: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
var iconViews = [UIImage]()
|
||||
|
||||
@@ -2095,7 +2029,8 @@ struct SettingsView: View {
|
||||
.foregroundColor(textColor)
|
||||
})
|
||||
.padding()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
@@ -522,6 +522,7 @@ struct YearCard: View, Equatable {
|
||||
}
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityIdentifier(AccessibilityID.YearView.cardHeader(year: year))
|
||||
|
||||
Spacer()
|
||||
|
||||
@@ -533,6 +534,7 @@ struct YearCard: View, Equatable {
|
||||
.foregroundColor(textColor.opacity(0.6))
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityIdentifier(AccessibilityID.YearView.shareButton)
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.vertical, 12)
|
||||
@@ -543,6 +545,7 @@ struct YearCard: View, Equatable {
|
||||
// Donut Chart
|
||||
MoodDonutChart(metrics: animatedMetrics, moodTint: moodTint)
|
||||
.frame(width: 100, height: 100)
|
||||
.accessibilityIdentifier(AccessibilityID.YearView.donutChart)
|
||||
|
||||
// Bar Chart
|
||||
VStack(spacing: 6) {
|
||||
@@ -574,10 +577,12 @@ struct YearCard: View, Equatable {
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.accessibilityIdentifier(AccessibilityID.YearView.barChart)
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.bottom, 12)
|
||||
.transition(.opacity.combined(with: .move(edge: .top)))
|
||||
.accessibilityIdentifier(AccessibilityID.YearView.statsSection)
|
||||
}
|
||||
|
||||
Divider()
|
||||
|
||||
@@ -82,6 +82,14 @@ enum UITestID {
|
||||
static let header = "insights_header"
|
||||
}
|
||||
|
||||
enum Year {
|
||||
static let donutChart = "year_donut_chart"
|
||||
static let barChart = "year_bar_chart"
|
||||
static let statsSection = "year_stats_section"
|
||||
static func cardHeader(year: Int) -> String { "year_card_header_\(year)" }
|
||||
static let shareButton = "year_share_button"
|
||||
}
|
||||
|
||||
enum Month {
|
||||
static let grid = "month_grid"
|
||||
}
|
||||
|
||||
48
Tests iOS/SettingsOnboardingTests.swift
Normal file
48
Tests iOS/SettingsOnboardingTests.swift
Normal file
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// SettingsOnboardingTests.swift
|
||||
// Tests iOS
|
||||
//
|
||||
// TC-124: Show onboarding from Settings.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
final class SettingsOnboardingTests: BaseUITestCase {
|
||||
override var seedFixture: String? { "empty" }
|
||||
override var bypassSubscription: Bool { true }
|
||||
|
||||
/// TC-124: Tapping Show Onboarding in Settings replays the onboarding flow.
|
||||
func testSettings_ShowOnboarding_OpensOnboardingFlow() {
|
||||
let tabBar = TabBarScreen(app: app)
|
||||
let settingsScreen = tabBar.tapSettings()
|
||||
settingsScreen.assertVisible()
|
||||
|
||||
// Switch to the Settings sub-tab (not Customize)
|
||||
settingsScreen.tapSettingsTab()
|
||||
|
||||
captureScreenshot(name: "settings_before_show_onboarding")
|
||||
|
||||
// Scroll to and tap "Show Onboarding" button
|
||||
let showOnboardingBtn = app.element("settings_show_onboarding")
|
||||
guard showOnboardingBtn.waitForExistence(timeout: 2) ||
|
||||
app.swipeUntilExists(showOnboardingBtn, direction: .up, maxSwipes: 8) else {
|
||||
captureScreenshot(name: "settings_show_onboarding_not_found")
|
||||
XCTFail("Show Onboarding button not found in Settings")
|
||||
return
|
||||
}
|
||||
showOnboardingBtn.tapWhenReady()
|
||||
|
||||
// The sheet may take a moment to animate in.
|
||||
// Look for the onboarding welcome screen or any text unique to onboarding.
|
||||
let welcomeScreen = app.element(UITestID.Onboarding.welcome)
|
||||
let welcomeText = app.staticTexts["Welcome to Feels"]
|
||||
let found = welcomeScreen.waitForExistence(timeout: 8) ||
|
||||
welcomeText.waitForExistence(timeout: 3)
|
||||
|
||||
captureScreenshot(name: "settings_show_onboarding_result")
|
||||
|
||||
XCTAssertTrue(found,
|
||||
"Onboarding should appear after tapping Show Onboarding"
|
||||
)
|
||||
}
|
||||
}
|
||||
51
Tests iOS/YearViewDisplayTests.swift
Normal file
51
Tests iOS/YearViewDisplayTests.swift
Normal file
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// YearViewDisplayTests.swift
|
||||
// Tests iOS
|
||||
//
|
||||
// Year View display tests: donut chart, bar chart.
|
||||
// TC-035, TC-036
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
final class YearViewDisplayTests: BaseUITestCase {
|
||||
override var seedFixture: String? { "week_of_moods" }
|
||||
override var bypassSubscription: Bool { true }
|
||||
|
||||
/// TC-035: Year View shows donut chart with mood distribution.
|
||||
func testYearView_DonutChartVisible() {
|
||||
let tabBar = TabBarScreen(app: app)
|
||||
tabBar.tapYear()
|
||||
|
||||
// Wait for Year tab to be selected and content to load
|
||||
XCTAssertTrue(tabBar.yearTab.isSelected, "Year tab should be selected")
|
||||
|
||||
captureScreenshot(name: "year_view_loaded")
|
||||
|
||||
// The donut chart is inside the stats section of the first YearCard.
|
||||
// Try finding by accessibility identifier first, then fall back to presence of "days" text.
|
||||
let donutChart = app.element(UITestID.Year.donutChart)
|
||||
let found = donutChart.waitForExistence(timeout: 8) ||
|
||||
app.swipeUntilExists(donutChart, direction: .up, maxSwipes: 3, timeoutPerTry: 1.0)
|
||||
|
||||
captureScreenshot(name: "year_donut_chart")
|
||||
|
||||
XCTAssertTrue(found, "Donut chart should be visible in Year View")
|
||||
}
|
||||
|
||||
/// TC-036: Year View shows bar chart with mood percentages.
|
||||
func testYearView_BarChartVisible() {
|
||||
let tabBar = TabBarScreen(app: app)
|
||||
tabBar.tapYear()
|
||||
|
||||
XCTAssertTrue(tabBar.yearTab.isSelected, "Year tab should be selected")
|
||||
|
||||
let barChart = app.element(UITestID.Year.barChart)
|
||||
let found = barChart.waitForExistence(timeout: 8) ||
|
||||
app.swipeUntilExists(barChart, direction: .up, maxSwipes: 3, timeoutPerTry: 1.0)
|
||||
|
||||
captureScreenshot(name: "year_bar_chart")
|
||||
|
||||
XCTAssertTrue(found, "Bar chart should be visible in Year View")
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -1,53 +1,71 @@
|
||||
# UI Test Prompt Template
|
||||
# UI Test Prompt Template (QA Plan Driven)
|
||||
|
||||
Copy/paste this prompt into Codex or Claude and replace the placeholders.
|
||||
Copy/paste this into Claude (or Codex), then replace placeholders.
|
||||
|
||||
```md
|
||||
Create an iOS UI test for this behavior:
|
||||
Task:
|
||||
Create 3 solid iOS UI tests from the QA plan that compile and run reliably using the existing test architecture.
|
||||
|
||||
<DESCRIBE USER FLOW / EXPECTED BEHAVIOR>
|
||||
Project:
|
||||
- Root: /Users/treyt/Desktop/code/Feels
|
||||
- QA source: /Users/treyt/Desktop/code/Feels/docs/Feels_QA_Test_Plan.xlsx
|
||||
|
||||
Repository context:
|
||||
- Project root: /Users/treyt/Desktop/code/Feels
|
||||
- Follow these files strictly:
|
||||
Optional explicit test IDs/names from me (if provided, prioritize these):
|
||||
<PASTE_TEST_IDS_AND_NAMES_HERE_OR_LEAVE_EMPTY>
|
||||
|
||||
Mandatory references (read before coding):
|
||||
- /Users/treyt/Desktop/code/Feels/docs/XCUITest-Authoring.md
|
||||
- /Users/treyt/Desktop/code/Feels/AGENTS.md
|
||||
- /Users/treyt/Desktop/code/Feels/Tests iOS/README.md
|
||||
- /Users/treyt/Desktop/code/Feels/Tests iOS/Helpers/BaseUITestCase.swift
|
||||
- /Users/treyt/Desktop/code/Feels/Tests iOS/Helpers/WaitHelpers.swift
|
||||
- /Users/treyt/Desktop/code/Feels/Shared/AccessibilityIdentifiers.swift
|
||||
- Existing suites in /Users/treyt/Desktop/code/Feels/Tests iOS/ (use them for style/patterns)
|
||||
|
||||
Implementation requirements:
|
||||
1. Use the established pattern:
|
||||
Selection rules:
|
||||
1. If I pasted specific QA IDs/names, use those first.
|
||||
2. If fewer than 3 are provided, choose remaining from the spreadsheet.
|
||||
3. Pick the easiest automatable tests (low setup complexity, deterministic UI state, no external dependencies).
|
||||
4. Skip cases likely to be flaky or blocked (network dependency, unstable animation-only behavior, uncertain app hooks).
|
||||
5. Briefly justify why each selected test is “easy + stable”.
|
||||
|
||||
Implementation rules (do not reinvent):
|
||||
1. Reuse existing architecture only:
|
||||
- `BaseUITestCase`
|
||||
- `UITestID` / accessibility identifier selectors first
|
||||
- screen objects in `Tests iOS/Screens/`
|
||||
- wait helpers (`tapWhenReady`, `waitForExistence`, `waitForDisappearance`)
|
||||
2. Do NOT use `sleep(...)`.
|
||||
3. Do NOT rely on localized/raw text selectors as primary selectors.
|
||||
4. If needed, add missing accessibility IDs in app code and wire them into tests.
|
||||
5. Keep the test deterministic using fixture + launch flags from `BaseUITestCase`.
|
||||
6. Add screenshots at meaningful checkpoints for triage.
|
||||
- `UITestID` and accessibility identifiers
|
||||
- screen objects under `Tests iOS/Screens/`
|
||||
- wait helpers (`tapWhenReady`, `waitForExistence`, `waitForDisappearance`, etc.)
|
||||
2. No `sleep(...)`.
|
||||
3. No raw/localized text selectors as primary locators.
|
||||
4. Add missing accessibility IDs only when required, then wire them through current helper patterns.
|
||||
5. Keep tests deterministic with fixtures and launch flags from `BaseUITestCase`.
|
||||
6. Follow existing naming/style conventions from current passing tests.
|
||||
7. Add screenshots at meaningful checkpoints for triage.
|
||||
|
||||
Test setup choices:
|
||||
- Suggested suite file: `Tests iOS/<SUITE_NAME>Tests.swift`
|
||||
- Suggested test method: `test<FEATURE>_<BEHAVIOR>()`
|
||||
- Fixture to use: `<empty | single_mood | week_of_moods>`
|
||||
- Launch overrides if needed:
|
||||
- `skipOnboarding = <true/false>`
|
||||
- `bypassSubscription = <true/false>`
|
||||
- `expireTrial = <true/false>`
|
||||
Flake-resistance checklist (must satisfy):
|
||||
- Each test has deterministic starting state (fixture + launch args).
|
||||
- No arbitrary timing waits.
|
||||
- Assertions target stable identifiers.
|
||||
- Test does not depend on current date text formatting unless already stabilized by existing helpers.
|
||||
- If a new selector is needed, add app-side accessibility identifier first.
|
||||
|
||||
Validation requirements:
|
||||
1. Run targeted suite:
|
||||
- `xcodebuild -project Feels.xcodeproj -scheme "Feels (iOS)" -destination 'platform=iOS Simulator,name=iPhone 16 Pro' -only-testing:"Tests iOS/<SUITE_NAME>" test`
|
||||
2. Report pass/fail summary.
|
||||
3. If failures occur, fix and rerun until green.
|
||||
Deliverable shape:
|
||||
- Prefer one suite file with 3 test methods, unless existing suite placement is clearly better.
|
||||
- Method naming: `test<Feature>_<Behavior>()`.
|
||||
- Keep helper logic in screen objects/helpers instead of duplicating in test body.
|
||||
|
||||
Validation gates (required before done):
|
||||
1. Run only the 3 new tests (not full suite), e.g.:
|
||||
- `xcodebuild -project Feels.xcodeproj -scheme "Feels (iOS)" -destination 'platform=iOS Simulator,name=iPhone 16 Pro' -only-testing:"Tests iOS/<SuiteName>/testA" -only-testing:"Tests iOS/<SuiteName>/testB" -only-testing:"Tests iOS/<SuiteName>/testC" test`
|
||||
2. If failures occur, fix and rerun until green.
|
||||
3. Run the same targeted command a second time to check flakiness.
|
||||
4. Only mark complete if both runs pass.
|
||||
|
||||
Output format:
|
||||
1. Files changed
|
||||
2. Why each change was needed
|
||||
3. Test run summary
|
||||
4. Any follow-up risks/gaps
|
||||
1. Selected QA test IDs/names with short reason for selection.
|
||||
2. Files changed.
|
||||
3. Key architecture decisions (how existing patterns were reused).
|
||||
4. Exact test command(s) executed.
|
||||
5. Run results for pass #1 and pass #2.
|
||||
6. Any residual risk/gaps.
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user