everything changed
This commit is contained in:
@@ -7,12 +7,27 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1C02589C27B9677A00EB91AC /* CreateIconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C02589B27B9677A00EB91AC /* CreateIconView.swift */; };
|
||||
1C02589E27B9821700EB91AC /* CenterTiledImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C02589D27B9821700EB91AC /* CenterTiledImage.swift */; };
|
||||
1C02589C27B9677A00EB91AC /* CreateWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C02589B27B9677A00EB91AC /* CreateWidgetView.swift */; };
|
||||
1C04488727C1C81D00D22444 /* PersonalityPackable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C04488627C1C81D00D22444 /* PersonalityPackable.swift */; };
|
||||
1C04488827C1CD8C00D22444 /* PersonalityPackable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C04488627C1C81D00D22444 /* PersonalityPackable.swift */; };
|
||||
1C04488A27C2ABD500D22444 /* IconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C04488927C2ABD500D22444 /* IconView.swift */; };
|
||||
1C04488B27C2ABDE00D22444 /* IconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C04488927C2ABD500D22444 /* IconView.swift */; };
|
||||
1C04488D27C2ADDB00D22444 /* IconViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C04488C27C2ADDB00D22444 /* IconViewModel.swift */; };
|
||||
1C04488E27C2AE5200D22444 /* IconViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C04488C27C2ADDB00D22444 /* IconViewModel.swift */; };
|
||||
1C04489627C2DB0100D22444 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C358FAC27ADD0C3002C83A6 /* Theme.swift */; };
|
||||
1C04489727C2DB9B00D22444 /* BGView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CAD603127A5C1C800C520BD /* BGView.swift */; };
|
||||
1C0DAB45279DB0FB003B1F21 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1C0DAB47279DB0FB003B1F21 /* Localizable.strings */; };
|
||||
1C10E24E27A1AB110047948B /* UserDefaultsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C5F4977279C945E0092F1B4 /* UserDefaultsStore.swift */; };
|
||||
1C10E25027A1AB220047948B /* OnboardingDay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CA03774279A294800D26164 /* OnboardingDay.swift */; };
|
||||
1C10E25127A1AB320047948B /* OnboardingTitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CA03776279A295600D26164 /* OnboardingTitle.swift */; };
|
||||
1C2162EB27C14EFA004353D1 /* Date+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C2162EA27C14EFA004353D1 /* Date+Extensions.swift */; };
|
||||
1C2162EC27C14FC5004353D1 /* Date+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C2162EA27C14EFA004353D1 /* Date+Extensions.swift */; };
|
||||
1C2162EE27C15191004353D1 /* MoodEntryFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C2162ED27C15191004353D1 /* MoodEntryFunctions.swift */; };
|
||||
1C2162F227C156E6004353D1 /* CustomizeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C2162F127C156E6004353D1 /* CustomizeView.swift */; };
|
||||
1C2162F427C1602D004353D1 /* MoodImagable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C2162F327C1602D004353D1 /* MoodImagable.swift */; };
|
||||
1C2162F527C16061004353D1 /* MoodImagable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C2162F327C1602D004353D1 /* MoodImagable.swift */; };
|
||||
1C2162F727C16D11004353D1 /* MoodTintable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C2162F627C16D11004353D1 /* MoodTintable.swift */; };
|
||||
1C2162F827C16E3C004353D1 /* MoodTintable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C2162F627C16D11004353D1 /* MoodTintable.swift */; };
|
||||
1C2618FA2795E41D00FDC148 /* Charts in Frameworks */ = {isa = PBXBuildFile; productRef = 1C2618F92795E41D00FDC148 /* Charts */; };
|
||||
1C2618FE27960A4F00FDC148 /* FilterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C2618FD27960A4F00FDC148 /* FilterViewModel.swift */; };
|
||||
1C26190327960CE500FDC148 /* ChartDataBuildable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C26190227960CE500FDC148 /* ChartDataBuildable.swift */; };
|
||||
@@ -52,7 +67,7 @@
|
||||
1C683FCC2792281400745862 /* Stats.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C683FC92792281400745862 /* Stats.swift */; };
|
||||
1C744F2C278CE15600953A57 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C744F2B278CE15600953A57 /* AppDelegate.swift */; };
|
||||
1C747CC9279F06EB00762CBD /* CloudKitSyncMonitor in Frameworks */ = {isa = PBXBuildFile; productRef = 1C747CC8279F06EB00762CBD /* CloudKitSyncMonitor */; };
|
||||
1CA037702799FFA600D26164 /* ContentModeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CA0376F2799FFA600D26164 /* ContentModeViewModel.swift */; };
|
||||
1CA037702799FFA600D26164 /* HomeViewViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CA0376F2799FFA600D26164 /* HomeViewViewModel.swift */; };
|
||||
1CA03773279A293D00D26164 /* OnboardingTime.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CA03772279A293D00D26164 /* OnboardingTime.swift */; };
|
||||
1CA03775279A294800D26164 /* OnboardingDay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CA03774279A294800D26164 /* OnboardingDay.swift */; };
|
||||
1CA03777279A295600D26164 /* OnboardingTitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CA03776279A295600D26164 /* OnboardingTitle.swift */; };
|
||||
@@ -104,10 +119,10 @@
|
||||
1CD90B6E278C7F8B001C4FEA /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1CD90B6B278C7F78001C4FEA /* CloudKit.framework */; };
|
||||
1CD90B71278C80CA001C4FEA /* Feels.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 1CD90AEB278C7DDF001C4FEA /* Feels.xcdatamodeld */; };
|
||||
1CD90B76278C8119001C4FEA /* LocalNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CD90B75278C8119001C4FEA /* LocalNotification.swift */; };
|
||||
1CEC966F27B9C29300CC8688 /* IconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CEC966E27B9C29300CC8688 /* IconView.swift */; };
|
||||
1CEC967127B9C2BB00CC8688 /* CustomIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CEC967027B9C2BB00CC8688 /* CustomIcon.swift */; };
|
||||
1CEC967227B9C9FB00CC8688 /* IconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CEC966E27B9C29300CC8688 /* IconView.swift */; };
|
||||
1CEC967327B9CA0C00CC8688 /* CustomIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CEC967027B9C2BB00CC8688 /* CustomIcon.swift */; };
|
||||
1CEC966F27B9C29300CC8688 /* CustomWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CEC966E27B9C29300CC8688 /* CustomWidgetView.swift */; };
|
||||
1CEC967127B9C2BB00CC8688 /* CustomWidgetModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CEC967027B9C2BB00CC8688 /* CustomWidgetModel.swift */; };
|
||||
1CEC967227B9C9FB00CC8688 /* CustomWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CEC966E27B9C29300CC8688 /* CustomWidgetView.swift */; };
|
||||
1CEC967327B9CA0C00CC8688 /* CustomWidgetModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CEC967027B9C2BB00CC8688 /* CustomWidgetModel.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -149,10 +164,17 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
1C02589B27B9677A00EB91AC /* CreateIconView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateIconView.swift; sourceTree = "<group>"; };
|
||||
1C02589D27B9821700EB91AC /* CenterTiledImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CenterTiledImage.swift; sourceTree = "<group>"; };
|
||||
1C02589B27B9677A00EB91AC /* CreateWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = CreateWidgetView.swift; path = ../CustomIcon/CreateWidgetView.swift; sourceTree = "<group>"; };
|
||||
1C04488627C1C81D00D22444 /* PersonalityPackable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersonalityPackable.swift; sourceTree = "<group>"; };
|
||||
1C04488927C2ABD500D22444 /* IconView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconView.swift; sourceTree = "<group>"; };
|
||||
1C04488C27C2ADDB00D22444 /* IconViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconViewModel.swift; sourceTree = "<group>"; };
|
||||
1C0DAB46279DB0FB003B1F21 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
1C0DAB48279DB116003B1F21 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
1C2162EA27C14EFA004353D1 /* Date+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Extensions.swift"; sourceTree = "<group>"; };
|
||||
1C2162ED27C15191004353D1 /* MoodEntryFunctions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoodEntryFunctions.swift; sourceTree = "<group>"; };
|
||||
1C2162F127C156E6004353D1 /* CustomizeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomizeView.swift; sourceTree = "<group>"; };
|
||||
1C2162F327C1602D004353D1 /* MoodImagable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoodImagable.swift; sourceTree = "<group>"; };
|
||||
1C2162F627C16D11004353D1 /* MoodTintable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoodTintable.swift; sourceTree = "<group>"; };
|
||||
1C2618FD27960A4F00FDC148 /* FilterViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterViewModel.swift; sourceTree = "<group>"; };
|
||||
1C26190227960CE500FDC148 /* ChartDataBuildable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartDataBuildable.swift; sourceTree = "<group>"; };
|
||||
1C26190627960DC900FDC148 /* ChartViewItemBuildable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartViewItemBuildable.swift; sourceTree = "<group>"; };
|
||||
@@ -179,7 +201,7 @@
|
||||
1C658D7627C0744D003231EE /* PersistenceUPDATE.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistenceUPDATE.swift; sourceTree = "<group>"; };
|
||||
1C683FC92792281400745862 /* Stats.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stats.swift; sourceTree = "<group>"; };
|
||||
1C744F2B278CE15600953A57 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
1CA0376F2799FFA600D26164 /* ContentModeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentModeViewModel.swift; sourceTree = "<group>"; };
|
||||
1CA0376F2799FFA600D26164 /* HomeViewViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewViewModel.swift; sourceTree = "<group>"; };
|
||||
1CA03772279A293D00D26164 /* OnboardingTime.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingTime.swift; sourceTree = "<group>"; };
|
||||
1CA03774279A294800D26164 /* OnboardingDay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingDay.swift; sourceTree = "<group>"; };
|
||||
1CA03776279A295600D26164 /* OnboardingTitle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingTitle.swift; sourceTree = "<group>"; };
|
||||
@@ -230,8 +252,8 @@
|
||||
1CD90B6F278C8000001C4FEA /* FeelsWidgetExtensionDev.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = FeelsWidgetExtensionDev.entitlements; sourceTree = "<group>"; };
|
||||
1CD90B70278C8000001C4FEA /* Feels (iOS)Dev.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = "Feels (iOS)Dev.entitlements"; sourceTree = "<group>"; };
|
||||
1CD90B75278C8119001C4FEA /* LocalNotification.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalNotification.swift; sourceTree = "<group>"; };
|
||||
1CEC966E27B9C29300CC8688 /* IconView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconView.swift; sourceTree = "<group>"; };
|
||||
1CEC967027B9C2BB00CC8688 /* CustomIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomIcon.swift; sourceTree = "<group>"; };
|
||||
1CEC966E27B9C29300CC8688 /* CustomWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomWidgetView.swift; sourceTree = "<group>"; };
|
||||
1CEC967027B9C2BB00CC8688 /* CustomWidgetModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomWidgetModel.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -279,6 +301,68 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
1C04488F27C2CA9C00D22444 /* HomeView */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1CAD603227A5C1C800C520BD /* HomeView.swift */,
|
||||
1CA0376F2799FFA600D26164 /* HomeViewViewModel.swift */,
|
||||
1C361F1827C046E400E832FC /* HomeViewTwo */,
|
||||
);
|
||||
path = HomeView;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1C04489027C2CAAC00D22444 /* CustomIcon */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1C04488927C2ABD500D22444 /* IconView.swift */,
|
||||
1C04488C27C2ADDB00D22444 /* IconViewModel.swift */,
|
||||
);
|
||||
path = CustomIcon;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1C04489127C2CAB100D22444 /* CustomWidget */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1CEC966E27B9C29300CC8688 /* CustomWidgetView.swift */,
|
||||
1C02589B27B9677A00EB91AC /* CreateWidgetView.swift */,
|
||||
1CEC967027B9C2BB00CC8688 /* CustomWidgetModel.swift */,
|
||||
);
|
||||
path = CustomWidget;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1C04489227C2CAB700D22444 /* CustomizeView */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1C2162F127C156E6004353D1 /* CustomizeView.swift */,
|
||||
);
|
||||
path = CustomizeView;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1C04489327C2CABF00D22444 /* SettingsView */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1CAD602C27A5C1C800C520BD /* SettingsView.swift */,
|
||||
);
|
||||
path = SettingsView;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1C04489427C2CAD100D22444 /* FilterView */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1C2618FD27960A4F00FDC148 /* FilterViewModel.swift */,
|
||||
1CAD602E27A5C1C800C520BD /* FilterView.swift */,
|
||||
);
|
||||
path = FilterView;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1C04489527C2CB1A00D22444 /* Sharing */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1C358FB027B0AD87002C83A6 /* SharingListView.swift */,
|
||||
);
|
||||
path = Sharing;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1C26190127960CDA00FDC148 /* Protocols */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -317,8 +401,8 @@
|
||||
1C4FF3C627BEE09E00BE8F34 /* PersistenceADD.swift */,
|
||||
1C4FF3C227BEE07200BE8F34 /* PersistenceDELETE.swift */,
|
||||
1C4FF3BF27BEE06900BE8F34 /* PersistenceGET.swift */,
|
||||
1C4FF3BD27BEDF9100BE8F34 /* PersistenceHelper.swift */,
|
||||
1C658D7627C0744D003231EE /* PersistenceUPDATE.swift */,
|
||||
1C4FF3BD27BEDF9100BE8F34 /* PersistenceHelper.swift */,
|
||||
);
|
||||
path = Persisence;
|
||||
sourceTree = "<group>";
|
||||
@@ -350,18 +434,19 @@
|
||||
1C358FB927B35252002C83A6 /* ActivityViewController.swift */,
|
||||
1CAD602F27A5C1C800C520BD /* AddMoodHeaderView.swift */,
|
||||
1CAD603127A5C1C800C520BD /* BGView.swift */,
|
||||
1C02589B27B9677A00EB91AC /* CreateIconView.swift */,
|
||||
1C04489027C2CAAC00D22444 /* CustomIcon */,
|
||||
1C04489227C2CAB700D22444 /* CustomizeView */,
|
||||
1C04489127C2CAB100D22444 /* CustomWidget */,
|
||||
1CC469AB27907D48003E0C6E /* DayChartView.swift */,
|
||||
1CB101C427B62A2D00D1C033 /* EmptyView.swift */,
|
||||
1CAD602E27A5C1C800C520BD /* FilterView.swift */,
|
||||
1C04489427C2CAD100D22444 /* FilterView */,
|
||||
1CAD602D27A5C1C800C520BD /* GraphView.swift */,
|
||||
1CAD603027A5C1C800C520BD /* HeaderPercView.swift */,
|
||||
1CAD603327A5C1C800C520BD /* HeaderStatsView.swift */,
|
||||
1CAD603227A5C1C800C520BD /* HomeView.swift */,
|
||||
1C361F1827C046E400E832FC /* HomeViewTwo */,
|
||||
1CEC966E27B9C29300CC8688 /* IconView.swift */,
|
||||
1C04488F27C2CA9C00D22444 /* HomeView */,
|
||||
1C361F0B27C0356B00E832FC /* MainTabView.swift */,
|
||||
1CAD602C27A5C1C800C520BD /* SettingsView.swift */,
|
||||
1C358FB027B0AD87002C83A6 /* SharingListView.swift */,
|
||||
1C04489327C2CABF00D22444 /* SettingsView */,
|
||||
1C04489527C2CB1A00D22444 /* Sharing */,
|
||||
1C358FB427B0ADF3002C83A6 /* SharingTemplates */,
|
||||
1CAD602B27A5C1C800C520BD /* SmallRollUpHeaderView.swift */,
|
||||
1CAD603D27A6ECCD00C520BD /* SwitchableView.swift */,
|
||||
@@ -397,6 +482,8 @@
|
||||
1CD90B75278C8119001C4FEA /* LocalNotification.swift */,
|
||||
1C4FF3C527BEE07800BE8F34 /* Persisence */,
|
||||
1CD90B5C278C7EAD001C4FEA /* Random.swift */,
|
||||
1C2162EA27C14EFA004353D1 /* Date+Extensions.swift */,
|
||||
1C2162ED27C15191004353D1 /* MoodEntryFunctions.swift */,
|
||||
1C683FC92792281400745862 /* Stats.swift */,
|
||||
1C4FF3BA27BEDDF000BE8F34 /* ShowBasedOnVoteLogics.swift */,
|
||||
1CA03771279A291F00D26164 /* Onboarding */,
|
||||
@@ -471,15 +558,13 @@
|
||||
1CD90B60278C7EBA001C4FEA /* Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1C02589D27B9821700EB91AC /* CenterTiledImage.swift */,
|
||||
1CA0376F2799FFA600D26164 /* ContentModeViewModel.swift */,
|
||||
1CEC967027B9C2BB00CC8688 /* CustomIcon.swift */,
|
||||
1CC469AB27907D48003E0C6E /* DayChartView.swift */,
|
||||
1C2618FD27960A4F00FDC148 /* FilterViewModel.swift */,
|
||||
1CD90B61278C7EBA001C4FEA /* Mood.swift */,
|
||||
1CD90B62278C7EBA001C4FEA /* MoodEntryExtension.swift */,
|
||||
1C2162F327C1602D004353D1 /* MoodImagable.swift */,
|
||||
1CB101C627B81CAC00D1C033 /* MoodMetrics.swift */,
|
||||
1C2162F627C16D11004353D1 /* MoodTintable.swift */,
|
||||
1C361F1327C03C8600E832FC /* OnboardingDataDataManager.swift */,
|
||||
1C04488627C1C81D00D22444 /* PersonalityPackable.swift */,
|
||||
1C358FAC27ADD0C3002C83A6 /* Theme.swift */,
|
||||
1C5F4977279C945E0092F1B4 /* UserDefaultsStore.swift */,
|
||||
);
|
||||
@@ -685,7 +770,7 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
1CA037702799FFA600D26164 /* ContentModeViewModel.swift in Sources */,
|
||||
1CA037702799FFA600D26164 /* HomeViewViewModel.swift in Sources */,
|
||||
1CA03773279A293D00D26164 /* OnboardingTime.swift in Sources */,
|
||||
1CAD603927A5C1C800C520BD /* HeaderPercView.swift in Sources */,
|
||||
1CAD603C27A5C1C800C520BD /* HeaderStatsView.swift in Sources */,
|
||||
@@ -694,11 +779,14 @@
|
||||
1C4FF3C327BEE07200BE8F34 /* PersistenceDELETE.swift in Sources */,
|
||||
1CA03775279A294800D26164 /* OnboardingDay.swift in Sources */,
|
||||
1CAD603727A5C1C800C520BD /* FilterView.swift in Sources */,
|
||||
1C04488D27C2ADDB00D22444 /* IconViewModel.swift in Sources */,
|
||||
1C2162F227C156E6004353D1 /* CustomizeView.swift in Sources */,
|
||||
1C683FCA2792281400745862 /* Stats.swift in Sources */,
|
||||
1CAD603E27A6ECCD00C520BD /* SwitchableView.swift in Sources */,
|
||||
1CD90B76278C8119001C4FEA /* LocalNotification.swift in Sources */,
|
||||
1C358FB627B0AE15002C83A6 /* AllMoodsTotalTemplate.swift in Sources */,
|
||||
1CD90B16278C7DE0001C4FEA /* Feels.xcdatamodeld in Sources */,
|
||||
1C04488727C1C81D00D22444 /* PersonalityPackable.swift in Sources */,
|
||||
1C4FF3BE27BEDF9100BE8F34 /* PersistenceHelper.swift in Sources */,
|
||||
1CC469AA278F30A0003E0C6E /* BGTask.swift in Sources */,
|
||||
1CAD603B27A5C1C800C520BD /* HomeView.swift in Sources */,
|
||||
@@ -707,7 +795,6 @@
|
||||
1CAD603A27A5C1C800C520BD /* BGView.swift in Sources */,
|
||||
1C26190727960DC900FDC148 /* ChartViewItemBuildable.swift in Sources */,
|
||||
1CD90B5D278C7EAD001C4FEA /* Random.swift in Sources */,
|
||||
1C02589E27B9821700EB91AC /* CenterTiledImage.swift in Sources */,
|
||||
1C2618FE27960A4F00FDC148 /* FilterViewModel.swift in Sources */,
|
||||
1C744F2C278CE15600953A57 /* AppDelegate.swift in Sources */,
|
||||
1CD90B63278C7EBA001C4FEA /* Mood.swift in Sources */,
|
||||
@@ -720,7 +807,9 @@
|
||||
1C26190327960CE500FDC148 /* ChartDataBuildable.swift in Sources */,
|
||||
1CB101C527B62A2D00D1C033 /* EmptyView.swift in Sources */,
|
||||
1CB101C727B81CAC00D1C033 /* MoodMetrics.swift in Sources */,
|
||||
1C2162F427C1602D004353D1 /* MoodImagable.swift in Sources */,
|
||||
1CAD603627A5C1C800C520BD /* GraphView.swift in Sources */,
|
||||
1C2162F727C16D11004353D1 /* MoodTintable.swift in Sources */,
|
||||
1C361F1727C046D800E832FC /* MonthDetailView.swift in Sources */,
|
||||
1CD90B66278C7EBA001C4FEA /* MoodEntryExtension.swift in Sources */,
|
||||
1C658D7727C0744D003231EE /* PersistenceUPDATE.swift in Sources */,
|
||||
@@ -728,7 +817,7 @@
|
||||
1C358FB827B0AEE3002C83A6 /* LongestStreakTemplate.swift in Sources */,
|
||||
1C358FB127B0AD87002C83A6 /* SharingListView.swift in Sources */,
|
||||
1CD90B1C278C7DE0001C4FEA /* Persistence.swift in Sources */,
|
||||
1CEC966F27B9C29300CC8688 /* IconView.swift in Sources */,
|
||||
1CEC966F27B9C29300CC8688 /* CustomWidgetView.swift in Sources */,
|
||||
1CA0377A279A296E00D26164 /* OnboardingMain.swift in Sources */,
|
||||
1C358FBA27B35252002C83A6 /* ActivityViewController.swift in Sources */,
|
||||
1C5F4978279C945E0092F1B4 /* UserDefaultsStore.swift in Sources */,
|
||||
@@ -736,12 +825,15 @@
|
||||
1C358FC027B4D20C002C83A6 /* MonthTotalTemplate.swift in Sources */,
|
||||
1CA03777279A295600D26164 /* OnboardingTitle.swift in Sources */,
|
||||
1C4FF3C027BEE06900BE8F34 /* PersistenceGET.swift in Sources */,
|
||||
1C04488A27C2ABD500D22444 /* IconView.swift in Sources */,
|
||||
1C361F0C27C0356B00E832FC /* MainTabView.swift in Sources */,
|
||||
1CEC967127B9C2BB00CC8688 /* CustomIcon.swift in Sources */,
|
||||
1CEC967127B9C2BB00CC8688 /* CustomWidgetModel.swift in Sources */,
|
||||
1C2162EE27C15191004353D1 /* MoodEntryFunctions.swift in Sources */,
|
||||
1C361F0A27C0356000E832FC /* HomeViewTwo.swift in Sources */,
|
||||
1C361F1427C03C8600E832FC /* OnboardingDataDataManager.swift in Sources */,
|
||||
1C358FAD27ADD0C3002C83A6 /* Theme.swift in Sources */,
|
||||
1C02589C27B9677A00EB91AC /* CreateIconView.swift in Sources */,
|
||||
1C2162EB27C14EFA004353D1 /* Date+Extensions.swift in Sources */,
|
||||
1C02589C27B9677A00EB91AC /* CreateWidgetView.swift in Sources */,
|
||||
1C358FC227B4D227002C83A6 /* WeekTotalTemplate.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -781,8 +873,10 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
1CD90B65278C7EBA001C4FEA /* Mood.swift in Sources */,
|
||||
1C04488B27C2ABDE00D22444 /* IconView.swift in Sources */,
|
||||
1C361F1127C03C3D00E832FC /* OnboardingTime.swift in Sources */,
|
||||
1CEC967227B9C9FB00CC8688 /* IconView.swift in Sources */,
|
||||
1CEC967227B9C9FB00CC8688 /* CustomWidgetView.swift in Sources */,
|
||||
1C2162F827C16E3C004353D1 /* MoodTintable.swift in Sources */,
|
||||
1C4FF3BC27BEDF6600BE8F34 /* ShowBasedOnVoteLogics.swift in Sources */,
|
||||
1C4FF3C927BEE0C300BE8F34 /* PersistenceHelper.swift in Sources */,
|
||||
1CA2662D2793908700C0E12C /* Persistence.swift in Sources */,
|
||||
@@ -791,16 +885,22 @@
|
||||
1CD90B71278C80CA001C4FEA /* Feels.xcdatamodeld in Sources */,
|
||||
1C658D7827C0744D003231EE /* PersistenceUPDATE.swift in Sources */,
|
||||
1C10E25127A1AB320047948B /* OnboardingTitle.swift in Sources */,
|
||||
1C04488E27C2AE5200D22444 /* IconViewModel.swift in Sources */,
|
||||
1C04489727C2DB9B00D22444 /* BGView.swift in Sources */,
|
||||
1CB101C827B81CAC00D1C033 /* MoodMetrics.swift in Sources */,
|
||||
1C683FCB2792281400745862 /* Stats.swift in Sources */,
|
||||
1CEC967327B9CA0C00CC8688 /* CustomIcon.swift in Sources */,
|
||||
1CEC967327B9CA0C00CC8688 /* CustomWidgetModel.swift in Sources */,
|
||||
1C10E25027A1AB220047948B /* OnboardingDay.swift in Sources */,
|
||||
1C04488827C1CD8C00D22444 /* PersonalityPackable.swift in Sources */,
|
||||
1C4FF3C427BEE07200BE8F34 /* PersistenceDELETE.swift in Sources */,
|
||||
1C4FF3C827BEE09E00BE8F34 /* PersistenceADD.swift in Sources */,
|
||||
1C2162F527C16061004353D1 /* MoodImagable.swift in Sources */,
|
||||
1C2162EC27C14FC5004353D1 /* Date+Extensions.swift in Sources */,
|
||||
1C4FF3C127BEE06900BE8F34 /* PersistenceGET.swift in Sources */,
|
||||
1C361F0D27C03BDF00E832FC /* OnboardingData.swift in Sources */,
|
||||
1CD90B52278C7E7A001C4FEA /* FeelsWidget.intentdefinition in Sources */,
|
||||
1CD90B4D278C7E7A001C4FEA /* FeelsWidget.swift in Sources */,
|
||||
1C04489627C2DB0100D22444 /* Theme.swift in Sources */,
|
||||
1C361F0F27C03C0E00E832FC /* LocalNotification.swift in Sources */,
|
||||
1C10E24E27A1AB110047948B /* UserDefaultsStore.swift in Sources */,
|
||||
);
|
||||
|
||||
@@ -16,12 +16,14 @@ class WatchTimelineView: Identifiable {
|
||||
let graphic: Image
|
||||
let date: Date
|
||||
let color: Color
|
||||
let secondaryColor: Color
|
||||
|
||||
init(image: Image, date: Date, color: Color, graphic: Image) {
|
||||
init(image: Image, graphic: Image, date: Date, color: Color, secondaryColor: Color) {
|
||||
self.image = image
|
||||
self.date = date
|
||||
self.color = color
|
||||
self.graphic = graphic
|
||||
self.secondaryColor = secondaryColor
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,17 +41,21 @@ struct TimeLineCreator {
|
||||
|
||||
let dayStart = Calendar.current.startOfDay(for: day)
|
||||
let dayEnd = Calendar.current.date(bySettingHour: 23, minute: 59, second: 59, of: dayStart)!
|
||||
let moodTint: MoodTintable.Type = UserDefaultsStore.moodTintable()
|
||||
let moodImages: MoodImagable.Type = UserDefaultsStore.moodMoodImagable()
|
||||
|
||||
if let todayEntry = PersistenceController.shared.getData(startDate: dayStart, endDate: dayEnd, includedDays: []).first {
|
||||
timeLineView.append(WatchTimelineView(image: todayEntry.mood.icon,
|
||||
date: dayStart,
|
||||
color: todayEntry.mood.color,
|
||||
graphic: todayEntry.mood.graphic))
|
||||
timeLineView.append(WatchTimelineView(image: moodImages.icon(forMood: todayEntry.mood),
|
||||
graphic: moodImages.icon(forMood: todayEntry.mood),
|
||||
date: dayStart,
|
||||
color: moodTint.color(forMood: todayEntry.mood),
|
||||
secondaryColor: moodTint.secondary(forMood: todayEntry.mood)))
|
||||
} else {
|
||||
timeLineView.append(WatchTimelineView(image: Mood.missing.icon,
|
||||
date: dayStart,
|
||||
color: Mood.missing.color,
|
||||
graphic: Mood.missing.graphic))
|
||||
timeLineView.append(WatchTimelineView(image: moodImages.icon(forMood: .missing),
|
||||
graphic: moodImages.icon(forMood: .missing),
|
||||
date: Date(),
|
||||
color: moodTint.color(forMood: .missing),
|
||||
secondaryColor: moodTint.secondary(forMood: .missing)))
|
||||
}
|
||||
}
|
||||
timeLineView = timeLineView.sorted(by: { $0.date > $1.date })
|
||||
@@ -72,7 +78,7 @@ struct Provider: IntentTimelineProvider {
|
||||
|
||||
func getSnapshot(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) {
|
||||
let entry = SimpleEntry(date: Date(),
|
||||
configuration: ConfigurationIntent(),
|
||||
configuration: ConfigurationIntent(),
|
||||
timeLineViews: Array(TimeLineCreator.createViews(daysBack: 11).prefix(10)))
|
||||
completion(entry)
|
||||
}
|
||||
@@ -83,8 +89,8 @@ struct Provider: IntentTimelineProvider {
|
||||
timeLineViews: nil)
|
||||
|
||||
let midNightEntry = SimpleEntry(date: Calendar.current.date(bySettingHour: 23, minute: 59, second: 59, of: Date())!,
|
||||
configuration: ConfigurationIntent(),
|
||||
timeLineViews: nil)
|
||||
configuration: ConfigurationIntent(),
|
||||
timeLineViews: nil)
|
||||
|
||||
let date = Calendar.current.date(byAdding: .second, value: 10, to: Date())!
|
||||
let timeline = Timeline(entries: [entry, midNightEntry], policy: .after(date))
|
||||
@@ -164,7 +170,7 @@ struct SmallWidgetView: View {
|
||||
struct MediumWidgetView: View {
|
||||
var entry: Provider.Entry
|
||||
var timeLineView = [WatchTimelineView]()
|
||||
|
||||
|
||||
init(entry: Provider.Entry) {
|
||||
self.entry = entry
|
||||
timeLineView = Array(TimeLineCreator.createViews(daysBack: 6).prefix(5))
|
||||
@@ -191,7 +197,7 @@ struct MediumWidgetView: View {
|
||||
struct LargeWidgetView: View {
|
||||
var entry: Provider.Entry
|
||||
var timeLineView = [WatchTimelineView]()
|
||||
|
||||
|
||||
init(entry: Provider.Entry) {
|
||||
self.entry = entry
|
||||
timeLineView = Array(TimeLineCreator.createViews(daysBack: 11).prefix(10))
|
||||
@@ -241,26 +247,31 @@ struct FeelsGraphicWidgetEntryView : View {
|
||||
var body: some View {
|
||||
SmallGraphicWidgetView(entry: entry)
|
||||
.onReceive(NotificationCenter.default.publisher(for: .NSPersistentStoreRemoteChange)) { _ in
|
||||
// make sure you don't call this too often
|
||||
WidgetCenter.shared.reloadAllTimelines()
|
||||
}
|
||||
// make sure you don't call this too often
|
||||
WidgetCenter.shared.reloadAllTimelines()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SmallGraphicWidgetView: View {
|
||||
var entry: Provider.Entry
|
||||
var timeLineView = [WatchTimelineView]()
|
||||
var timeLineView: [WatchTimelineView]
|
||||
|
||||
init(entry: Provider.Entry) {
|
||||
self.entry = entry
|
||||
timeLineView = [TimeLineCreator.createViews(daysBack: 2).first!]
|
||||
timeLineView = TimeLineCreator.createViews(daysBack: 2)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
GeometryReader { geo in
|
||||
timeLineView.first!.graphic
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
if let first = timeLineView.first {
|
||||
IconView(iconViewModel: IconViewModel(backgroundImage: first.graphic,
|
||||
bgColor: first.color,
|
||||
bgOverlayColor: first.secondaryColor,
|
||||
centerImage: first.graphic),
|
||||
isPreview: true)
|
||||
} else {
|
||||
IconView(iconViewModel: IconViewModel.great,
|
||||
isPreview: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -407,23 +418,49 @@ struct FeelsGraphicWidget: Widget {
|
||||
struct FeelsWidget_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
// FeelsWidgetEntryView(entry: SimpleEntry(date: Date(),
|
||||
// configuration: ConfigurationIntent(),
|
||||
// timeLineViews: FeelsWidget_Previews.data))
|
||||
// .previewContext(WidgetPreviewContext(family: .systemSmall))
|
||||
// .environment(\.sizeCategory, .small)
|
||||
//
|
||||
// FeelsWidgetEntryView(entry: SimpleEntry(date: Date(),
|
||||
// configuration: ConfigurationIntent(),
|
||||
// timeLineViews: FeelsWidget_Previews.data))
|
||||
// .previewContext(WidgetPreviewContext(family: .systemMedium))
|
||||
// .environment(\.sizeCategory, .medium)
|
||||
//
|
||||
// FeelsWidgetEntryView(entry: SimpleEntry(date: Date(),
|
||||
// configuration: ConfigurationIntent(),
|
||||
// timeLineViews: FeelsWidget_Previews.data))
|
||||
// .previewContext(WidgetPreviewContext(family: .systemLarge))
|
||||
// .environment(\.sizeCategory, .large)
|
||||
FeelsGraphicWidgetEntryView(entry: SimpleEntry(date: Date(),
|
||||
configuration: ConfigurationIntent(),
|
||||
timeLineViews: [WatchTimelineView(image: HandEmojiMoodImages.icon(forMood: .great),
|
||||
graphic: HandEmojiMoodImages.icon(forMood: .great),
|
||||
date: Date(),
|
||||
color: MoodTints.Neon.color(forMood: .great),
|
||||
|
||||
secondaryColor: .white),
|
||||
WatchTimelineView(image: HandEmojiMoodImages.icon(forMood: .great),
|
||||
graphic: HandEmojiMoodImages.icon(forMood: .great),
|
||||
date: Date(),
|
||||
color: MoodTints.Neon.color(forMood: .great),
|
||||
|
||||
secondaryColor: .white)]))
|
||||
.previewContext(WidgetPreviewContext(family: .systemSmall))
|
||||
|
||||
FeelsGraphicWidgetEntryView(entry: SimpleEntry(date: Date(),
|
||||
configuration: ConfigurationIntent(),
|
||||
timeLineViews: [WatchTimelineView(image: HandEmojiMoodImages.icon(forMood: .horrible),
|
||||
graphic: HandEmojiMoodImages.icon(forMood: .horrible),
|
||||
date: Date(),
|
||||
color: MoodTints.Neon.color(forMood: .horrible),
|
||||
|
||||
secondaryColor: .white),
|
||||
WatchTimelineView(image: HandEmojiMoodImages.icon(forMood: .horrible),
|
||||
graphic: HandEmojiMoodImages.icon(forMood: .horrible),
|
||||
date: Date(),
|
||||
color: MoodTints.Neon.color(forMood: .horrible),
|
||||
|
||||
secondaryColor: .white)]))
|
||||
.previewContext(WidgetPreviewContext(family: .systemSmall))
|
||||
|
||||
// FeelsWidgetEntryView(entry: SimpleEntry(date: Date(),
|
||||
// configuration: ConfigurationIntent(),
|
||||
// timeLineViews: FeelsWidget_Previews.data))
|
||||
// .previewContext(WidgetPreviewContext(family: .systemMedium))
|
||||
// .environment(\.sizeCategory, .medium)
|
||||
//
|
||||
// FeelsWidgetEntryView(entry: SimpleEntry(date: Date(),
|
||||
// configuration: ConfigurationIntent(),
|
||||
// timeLineViews: FeelsWidget_Previews.data))
|
||||
// .previewContext(WidgetPreviewContext(family: .systemLarge))
|
||||
// .environment(\.sizeCategory, .large)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,20 @@ class AppDelegate: NSObject, UIApplicationDelegate {
|
||||
// PersistenceController.shared.clearDB()
|
||||
PersistenceController.shared.fillInMissingDates()
|
||||
UNUserNotificationCenter.current().delegate = self
|
||||
|
||||
let theme = UserDefaultsStore.theme()
|
||||
UIPageControl.appearance().currentPageIndicatorTintColor = UIColor.label
|
||||
UIPageControl.appearance().pageIndicatorTintColor = UIColor.systemGray
|
||||
UITabBar.appearance().backgroundColor = UIColor(cgColor: theme.currentTheme.secondaryBGColor.cgColor ?? UIColor.secondarySystemBackground.cgColor)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func applicationWillEnterForeground(_ application: UIApplication) {
|
||||
PersistenceController.shared.fillInMissingDates()
|
||||
|
||||
// reschedule notifications so there's a new title next notification
|
||||
LocalNotification.rescheduleNotifiations()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
87
Shared/Date+Extensions.swift
Normal file
87
Shared/Date+Extensions.swift
Normal file
@@ -0,0 +1,87 @@
|
||||
//
|
||||
// Date+Extensions.swift
|
||||
// Feels (iOS)
|
||||
//
|
||||
// Created by Trey Tartt on 2/19/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Date: RawRepresentable {
|
||||
public var rawValue: String {
|
||||
self.timeIntervalSinceReferenceDate.description
|
||||
}
|
||||
|
||||
public init?(rawValue: String) {
|
||||
self = Date(timeIntervalSinceReferenceDate: Double(rawValue) ?? 0.0)
|
||||
}
|
||||
|
||||
var startOfDay: Date {
|
||||
return Calendar.current.startOfDay(for: self)
|
||||
}
|
||||
|
||||
var startOfMonth: Date {
|
||||
|
||||
let calendar = Calendar(identifier: .gregorian)
|
||||
let components = calendar.dateComponents([.year, .month], from: self)
|
||||
|
||||
return calendar.date(from: components)!
|
||||
}
|
||||
|
||||
var endOfDay: Date {
|
||||
var components = DateComponents()
|
||||
components.day = 1
|
||||
components.second = -1
|
||||
return Calendar.current.date(byAdding: components, to: startOfDay)!
|
||||
}
|
||||
|
||||
var endOfMonth: Date {
|
||||
var components = DateComponents()
|
||||
components.month = 1
|
||||
components.second = -1
|
||||
return Calendar(identifier: .gregorian).date(byAdding: components, to: startOfMonth)!
|
||||
}
|
||||
|
||||
func toLocalTime() -> Date {
|
||||
let timezone = TimeZone.current
|
||||
let seconds = TimeInterval(timezone.secondsFromGMT(for: self))
|
||||
return Date(timeInterval: seconds, since: self)
|
||||
}
|
||||
|
||||
var weekday: Int {
|
||||
Calendar.current.component(.weekday, from: self)
|
||||
}
|
||||
|
||||
var firstDayOfTheMonth: Date {
|
||||
Calendar.current.dateComponents([.calendar, .year,.month], from: self).date!
|
||||
}
|
||||
|
||||
static func dates(from fromDate: Date, to toDate: Date) -> [Date] {
|
||||
var dates: [Date] = []
|
||||
var date = fromDate
|
||||
|
||||
while date <= toDate {
|
||||
dates.append(date)
|
||||
guard let newDate = Calendar.current.date(byAdding: .day, value: 1, to: date) else { break }
|
||||
date = newDate
|
||||
}
|
||||
return dates
|
||||
}
|
||||
|
||||
static func dateRange(monthInt: Int, yearInt: Int) -> (startDate: Date, endDate: Date) {
|
||||
var dateComponents = DateComponents()
|
||||
dateComponents.year = yearInt
|
||||
dateComponents.month = monthInt
|
||||
dateComponents.day = 3
|
||||
dateComponents.hour = 12
|
||||
var userCalendar = Calendar(identifier: .gregorian)
|
||||
userCalendar.timeZone = TimeZone(secondsFromGMT: 0)!
|
||||
let someDateTime = userCalendar.date(from: dateComponents)!
|
||||
|
||||
let startDate = someDateTime.startOfMonth
|
||||
var endDate = someDateTime.endOfMonth
|
||||
endDate = Calendar.current.date(byAdding: .hour, value: -8, to: endDate)!
|
||||
|
||||
return (startDate, endDate)
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,14 @@ class LocalNotification {
|
||||
}
|
||||
}
|
||||
|
||||
public class func rescheduleNotifiations() {
|
||||
if let data = GroupUserDefaults.groupDefaults.object(forKey: UserDefaultsStore.Keys.savedOnboardingData.rawValue) as? Data,
|
||||
let model = try? JSONDecoder().decode(OnboardingData.self, from: data) {
|
||||
LocalNotification.scheduleReminder(atTime: model.date,
|
||||
withTitle: model.title)
|
||||
}
|
||||
}
|
||||
|
||||
public class func scheduleReminder(atTime time: Date, withTitle title: String) {
|
||||
self.removeNotificaiton()
|
||||
|
||||
@@ -37,7 +45,7 @@ class LocalNotification {
|
||||
let _ = LocalNotification.createNotificationCategory()
|
||||
|
||||
let notificationContent = UNMutableNotificationContent()
|
||||
notificationContent.title = title
|
||||
notificationContent.title = UserDefaultsStore.personalityPackable().randomPushNotificationTitle()
|
||||
|
||||
notificationContent.badge = NSNumber(value: 1)
|
||||
notificationContent.sound = .default
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
//
|
||||
// CenterTiledImage.swift
|
||||
// Feels (iOS)
|
||||
//
|
||||
// Created by Trey Tartt on 2/13/22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct CenterTiledImage: View {
|
||||
let imageName: String
|
||||
let imageSize: CGSize
|
||||
|
||||
var body: some View {
|
||||
GeometryReader { geoReader in
|
||||
let horizontalTilesNeeded = ceil(geoReader.size.width / imageSize.width / 2) * 2 + 1
|
||||
let verticalTilesNeeded = ceil(geoReader.size.height / imageSize.height / 2) * 2 + 1
|
||||
|
||||
Image(imageName)
|
||||
.resizable(resizingMode: .tile)
|
||||
.frame(
|
||||
width: horizontalTilesNeeded * imageSize.width,
|
||||
height: verticalTilesNeeded * imageSize.height
|
||||
)
|
||||
.position(x: geoReader.size.width * 0.5, y: geoReader.size.height * 0.5)
|
||||
}
|
||||
}
|
||||
|
||||
init?(imageName: String) {
|
||||
guard let imageSize = UIImage(named: imageName)?.size else {
|
||||
return nil
|
||||
}
|
||||
|
||||
self.imageName = imageName
|
||||
self.imageSize = imageSize
|
||||
}
|
||||
}
|
||||
@@ -37,22 +37,8 @@ enum Mood: Int {
|
||||
}
|
||||
|
||||
var color: Color {
|
||||
switch self {
|
||||
case .horrible:
|
||||
return .red
|
||||
case .bad:
|
||||
return .orange
|
||||
case .average:
|
||||
return .blue
|
||||
case .good:
|
||||
return .yellow
|
||||
case .great:
|
||||
return .green
|
||||
case .missing:
|
||||
return Color(uiColor: UIColor.systemGray2)
|
||||
case .placeholder:
|
||||
return .clear
|
||||
}
|
||||
let moodTint: MoodTintable.Type = UserDefaultsStore.moodTintable()
|
||||
return moodTint.color(forMood: self)
|
||||
}
|
||||
|
||||
static var allValues: [Mood] {
|
||||
@@ -60,23 +46,8 @@ enum Mood: Int {
|
||||
}
|
||||
|
||||
var icon: Image {
|
||||
switch self {
|
||||
|
||||
case .horrible:
|
||||
return Image("horrible", bundle: .main)
|
||||
case .bad:
|
||||
return Image("bad", bundle: .main)
|
||||
case .average:
|
||||
return Image("average", bundle: .main)
|
||||
case .good:
|
||||
return Image("good", bundle: .main)
|
||||
case .great:
|
||||
return Image("great", bundle: .main)
|
||||
case .missing:
|
||||
return Image("missing", bundle: .main)
|
||||
case .placeholder:
|
||||
return Image("missing", bundle: .main)
|
||||
}
|
||||
let moodImages: MoodImagable.Type = UserDefaultsStore.moodMoodImagable()
|
||||
return moodImages.icon(forMood: self)
|
||||
}
|
||||
|
||||
var graphic: Image {
|
||||
|
||||
104
Shared/Models/MoodImagable.swift
Normal file
104
Shared/Models/MoodImagable.swift
Normal file
@@ -0,0 +1,104 @@
|
||||
//
|
||||
// MoodImagable.swift
|
||||
// Feels (iOS)
|
||||
//
|
||||
// Created by Trey Tartt on 2/19/22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
protocol MoodImagable {
|
||||
static func icon(forMood mood: Mood) -> Image
|
||||
}
|
||||
|
||||
enum MoodImages: Int, CaseIterable {
|
||||
case FontAwesome
|
||||
case Emoji
|
||||
case HandEmjoi
|
||||
|
||||
func icon(forMood mood: Mood) -> Image {
|
||||
switch self {
|
||||
|
||||
case .FontAwesome:
|
||||
return FontAwesomeMoodImages.icon(forMood: mood)
|
||||
case .Emoji:
|
||||
return EmojiMoodImages.icon(forMood: mood)
|
||||
case .HandEmjoi:
|
||||
return HandEmojiMoodImages.icon(forMood: mood)
|
||||
}
|
||||
}
|
||||
|
||||
var moodImages: MoodImagable.Type {
|
||||
switch self {
|
||||
case .FontAwesome:
|
||||
return FontAwesomeMoodImages.self
|
||||
case .Emoji:
|
||||
return EmojiMoodImages.self
|
||||
case .HandEmjoi:
|
||||
return HandEmojiMoodImages.self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class FontAwesomeMoodImages: MoodImagable {
|
||||
static func icon(forMood mood: Mood) -> Image {
|
||||
switch mood {
|
||||
case .horrible:
|
||||
return Image("horrible", bundle: .main)
|
||||
case .bad:
|
||||
return Image("bad", bundle: .main)
|
||||
case .average:
|
||||
return Image("average", bundle: .main)
|
||||
case .good:
|
||||
return Image("good", bundle: .main)
|
||||
case .great:
|
||||
return Image("great", bundle: .main)
|
||||
case .missing:
|
||||
return Image("missing", bundle: .main)
|
||||
case .placeholder:
|
||||
return Image("missing", bundle: .main)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class EmojiMoodImages: MoodImagable {
|
||||
static func icon(forMood mood: Mood) -> Image {
|
||||
switch mood {
|
||||
case .horrible:
|
||||
return Image(uiImage: "💩".textToImage()!)
|
||||
case .bad:
|
||||
return Image(uiImage: "😕".textToImage()!)
|
||||
case .average:
|
||||
return Image(uiImage: "😑".textToImage()!)
|
||||
case .good:
|
||||
return Image(uiImage: "🙂".textToImage()!)
|
||||
case .great:
|
||||
return Image(uiImage: "😀".textToImage()!)
|
||||
case .missing:
|
||||
return Image(uiImage: "x".textToImage()!)
|
||||
case .placeholder:
|
||||
return Image(uiImage: "x".textToImage()!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class HandEmojiMoodImages: MoodImagable {
|
||||
static func icon(forMood mood: Mood) -> Image {
|
||||
switch mood {
|
||||
case .horrible:
|
||||
return Image(uiImage: "🖕".textToImage()!)
|
||||
case .bad:
|
||||
return Image(uiImage: "👎".textToImage()!)
|
||||
case .average:
|
||||
return Image(uiImage: "🖖".textToImage()!)
|
||||
case .good:
|
||||
return Image(uiImage: "👍".textToImage()!)
|
||||
case .great:
|
||||
return Image(uiImage: "🙏".textToImage()!)
|
||||
case .missing:
|
||||
return Image(uiImage: "x".textToImage()!)
|
||||
case .placeholder:
|
||||
return Image(uiImage: "x".textToImage()!)
|
||||
}
|
||||
}
|
||||
}
|
||||
266
Shared/Models/MoodTintable.swift
Normal file
266
Shared/Models/MoodTintable.swift
Normal file
@@ -0,0 +1,266 @@
|
||||
//
|
||||
// MoodTintable.swift
|
||||
// Feels (iOS)
|
||||
//
|
||||
// Created by Trey Tartt on 2/19/22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
protocol MoodTintable {
|
||||
static func color(forMood mood: Mood) -> Color
|
||||
static func secondary(forMood mood: Mood) -> Color
|
||||
}
|
||||
|
||||
enum MoodTints: Int, CaseIterable {
|
||||
case Default
|
||||
case AllRed
|
||||
case Neon
|
||||
case MonoChrome
|
||||
case Pastel
|
||||
|
||||
func color(forMood mood: Mood) -> Color {
|
||||
switch self {
|
||||
case .Default:
|
||||
return DefaultMoodTint.color(forMood: mood)
|
||||
case .AllRed:
|
||||
return AllRedMoodTint.color(forMood: mood)
|
||||
case .Neon:
|
||||
return NeonMoodTint.color(forMood: mood)
|
||||
case .MonoChrome:
|
||||
return MonoChromeTint.color(forMood: mood)
|
||||
case .Pastel:
|
||||
return PastelTint.color(forMood: mood)
|
||||
}
|
||||
}
|
||||
|
||||
func secondary(forMood mood: Mood) -> Color {
|
||||
switch self {
|
||||
case .Default:
|
||||
return DefaultMoodTint.secondary(forMood: mood)
|
||||
case .AllRed:
|
||||
return AllRedMoodTint.secondary(forMood: mood)
|
||||
case .Neon:
|
||||
return NeonMoodTint.secondary(forMood: mood)
|
||||
case .MonoChrome:
|
||||
return MonoChromeTint.secondary(forMood: mood)
|
||||
case .Pastel:
|
||||
return PastelTint.secondary(forMood: mood)
|
||||
}
|
||||
}
|
||||
|
||||
var moodTints: MoodTintable.Type {
|
||||
switch self {
|
||||
case .Default:
|
||||
return DefaultMoodTint.self
|
||||
case .AllRed:
|
||||
return AllRedMoodTint.self
|
||||
case .Neon:
|
||||
return NeonMoodTint.self
|
||||
case .MonoChrome:
|
||||
return MonoChromeTint.self
|
||||
case .Pastel:
|
||||
return PastelTint.self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class DefaultMoodTint: MoodTintable {
|
||||
static func color(forMood mood: Mood) -> Color {
|
||||
switch mood {
|
||||
case .horrible:
|
||||
return Color(hex: "ff453a")
|
||||
case .bad:
|
||||
return Color(hex: "ff9e0b")
|
||||
case .average:
|
||||
return Color(hex: "0b84ff")
|
||||
case .good:
|
||||
return Color(hex: "ffd709")
|
||||
case .great:
|
||||
return Color(hex: "31d158")
|
||||
case .missing:
|
||||
return Color(uiColor: UIColor.systemGray4)
|
||||
case .placeholder:
|
||||
return Color(uiColor: UIColor.systemGray4)
|
||||
}
|
||||
}
|
||||
|
||||
static func secondary(forMood mood: Mood) -> Color {
|
||||
switch mood {
|
||||
case .horrible:
|
||||
return Color(hex: "a92b26")
|
||||
case .bad:
|
||||
return Color(hex: "a06407")
|
||||
case .average:
|
||||
return Color(hex: "074f9a")
|
||||
case .good:
|
||||
return Color(hex: "9d8405")
|
||||
case .great:
|
||||
return Color(hex: "208939")
|
||||
case .missing:
|
||||
return Color(uiColor: UIColor.label)
|
||||
case .placeholder:
|
||||
return Color(uiColor: UIColor.label)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class AllRedMoodTint: MoodTintable {
|
||||
static func color(forMood mood: Mood) -> Color {
|
||||
switch mood {
|
||||
case .horrible:
|
||||
return .red
|
||||
case .bad:
|
||||
return .red
|
||||
case .average:
|
||||
return .red
|
||||
case .good:
|
||||
return .red
|
||||
case .great:
|
||||
return .red
|
||||
case .missing:
|
||||
return Color(uiColor: UIColor.systemGray2)
|
||||
case .placeholder:
|
||||
return Color(uiColor: UIColor.systemGray2)
|
||||
}
|
||||
}
|
||||
|
||||
static func secondary(forMood mood: Mood) -> Color {
|
||||
switch mood {
|
||||
case .horrible:
|
||||
return .red
|
||||
case .bad:
|
||||
return .red
|
||||
case .average:
|
||||
return .red
|
||||
case .good:
|
||||
return .red
|
||||
case .great:
|
||||
return .red
|
||||
case .missing:
|
||||
return Color(uiColor: UIColor.label)
|
||||
case .placeholder:
|
||||
return Color(uiColor: UIColor.label)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class NeonMoodTint: MoodTintable {
|
||||
static func color(forMood mood: Mood) -> Color {
|
||||
switch mood {
|
||||
case .horrible:
|
||||
return Color(hex: "#ff1818")
|
||||
case .bad:
|
||||
return Color(hex: "#FF5F1F")
|
||||
case .average:
|
||||
return Color(hex: "#1F51FF")
|
||||
case .good:
|
||||
return Color(hex: "#FFF01F")
|
||||
case .great:
|
||||
return Color(hex: "#39FF14")
|
||||
case .missing:
|
||||
return Color(uiColor: UIColor.systemGray2)
|
||||
case .placeholder:
|
||||
return Color(uiColor: UIColor.systemGray2)
|
||||
}
|
||||
}
|
||||
|
||||
static func secondary(forMood mood: Mood) -> Color {
|
||||
switch mood {
|
||||
case .horrible:
|
||||
return Color(hex: "#8b1113")
|
||||
case .bad:
|
||||
return Color(hex: "#893315")
|
||||
case .average:
|
||||
return Color(hex: "#0f2a85")
|
||||
case .good:
|
||||
return Color(hex: "#807a18")
|
||||
case .great:
|
||||
return Color(hex: "#218116")
|
||||
case .missing:
|
||||
return Color(uiColor: UIColor.label)
|
||||
case .placeholder:
|
||||
return Color(uiColor: UIColor.label)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class MonoChromeTint: MoodTintable {
|
||||
static func color(forMood mood: Mood) -> Color {
|
||||
switch mood {
|
||||
case .horrible:
|
||||
return .black
|
||||
case .bad:
|
||||
return Color(uiColor: UIColor.systemGray)
|
||||
case .average:
|
||||
return Color(uiColor: UIColor.systemGray)
|
||||
case .good:
|
||||
return Color(uiColor: UIColor.systemGray2)
|
||||
case .great:
|
||||
return Color(uiColor: UIColor.systemGray3)
|
||||
case .missing:
|
||||
return Color(uiColor: UIColor.systemGray2)
|
||||
case .placeholder:
|
||||
return Color(uiColor: UIColor.systemGray4)
|
||||
}
|
||||
}
|
||||
|
||||
static func secondary(forMood mood: Mood) -> Color {
|
||||
switch mood {
|
||||
case .horrible:
|
||||
return .black
|
||||
case .bad:
|
||||
return Color(uiColor: UIColor.systemGray)
|
||||
case .average:
|
||||
return Color(uiColor: UIColor.systemGray)
|
||||
case .good:
|
||||
return Color(uiColor: UIColor.systemGray2)
|
||||
case .great:
|
||||
return Color(uiColor: UIColor.systemGray3)
|
||||
case .missing:
|
||||
return Color(uiColor: UIColor.systemGray2)
|
||||
case .placeholder:
|
||||
return Color(uiColor: UIColor.systemGray4)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class PastelTint: MoodTintable {
|
||||
static func color(forMood mood: Mood) -> Color {
|
||||
switch mood {
|
||||
case .horrible:
|
||||
return Color(hex: "#FF6961")
|
||||
case .bad:
|
||||
return Color(hex: "#ffb347")
|
||||
case .average:
|
||||
return Color(hex: "#A7C7E7")
|
||||
case .good:
|
||||
return Color(hex: "#fdfd96")
|
||||
case .great:
|
||||
return Color(hex: "#C1E1C1")
|
||||
case .missing:
|
||||
return Color(uiColor: UIColor.systemGray2)
|
||||
case .placeholder:
|
||||
return Color(uiColor: UIColor.systemGray4)
|
||||
}
|
||||
}
|
||||
|
||||
static func secondary(forMood mood: Mood) -> Color {
|
||||
switch mood {
|
||||
case .horrible:
|
||||
return Color(hex: "#893734")
|
||||
case .bad:
|
||||
return Color(hex: "#855d28")
|
||||
case .average:
|
||||
return Color(hex: "#5d6e83")
|
||||
case .good:
|
||||
return Color(hex: "#7f804f")
|
||||
case .great:
|
||||
return Color(hex: "#6b7e6d")
|
||||
case .missing:
|
||||
return Color(uiColor: UIColor.systemGray2)
|
||||
case .placeholder:
|
||||
return Color(uiColor: UIColor.systemGray4)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,13 +7,14 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
final class OnboardingDataDataManager {
|
||||
final class OnboardingDataDataManager: ObservableObject {
|
||||
static let shared = OnboardingDataDataManager()
|
||||
|
||||
@Published public private(set) var savedOnboardingData = UserDefaultsStore.getOnboarding()
|
||||
|
||||
|
||||
public func updateOnboardingData(onboardingData: OnboardingData) {
|
||||
let onboardingData = UserDefaultsStore.saveOnboarding(onboardingData: onboardingData)
|
||||
savedOnboardingData = onboardingData
|
||||
LocalNotification.scheduleReminder(atTime: onboardingData.date, withTitle: onboardingData.title)
|
||||
}
|
||||
}
|
||||
|
||||
91
Shared/Models/PersonalityPackable.swift
Normal file
91
Shared/Models/PersonalityPackable.swift
Normal file
@@ -0,0 +1,91 @@
|
||||
//
|
||||
// NotificationTitles.swift
|
||||
// Feels (iOS)
|
||||
//
|
||||
// Created by Trey Tartt on 2/19/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
protocol PersonalityPackable {
|
||||
static var notificationTitlesToday: [String] { get }
|
||||
static var notificationTitlesYesterday: [String] { get }
|
||||
static var notificationTitlesTwoDaysAgo: [String] { get }
|
||||
|
||||
static var title: String { get }
|
||||
}
|
||||
|
||||
enum PersonalityPack: Int, CaseIterable {
|
||||
case Default
|
||||
case Rude
|
||||
|
||||
func randomPushNotificationTitle() -> String {
|
||||
switch self {
|
||||
case .Default:
|
||||
return DefaultTitles.notificationTitlesToday.randomElement()!
|
||||
case .Rude:
|
||||
return RudeTitles.notificationTitlesToday.randomElement()!
|
||||
}
|
||||
}
|
||||
|
||||
func title() -> String {
|
||||
switch self {
|
||||
case .Default:
|
||||
return DefaultTitles.title
|
||||
case .Rude:
|
||||
return RudeTitles.title
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class DefaultTitles: PersonalityPackable {
|
||||
static var title = "Nice"
|
||||
|
||||
static var notificationTitlesToday: [String] {
|
||||
[
|
||||
"How was your day",
|
||||
"Don't forget to rate your day",
|
||||
"Please rate your day"
|
||||
]
|
||||
}
|
||||
|
||||
static var notificationTitlesYesterday: [String] {
|
||||
[
|
||||
"How was your day",
|
||||
"Don't forget to rate your day"
|
||||
]
|
||||
}
|
||||
|
||||
static var notificationTitlesTwoDaysAgo: [String] {
|
||||
[
|
||||
"How was your day",
|
||||
"Don't forget to rate your day"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
final class RudeTitles: PersonalityPackable {
|
||||
static var title = "Rude"
|
||||
|
||||
static var notificationTitlesToday: [String] {
|
||||
[
|
||||
"How the fuck was your day",
|
||||
"Hey asshat, tell me how your day was",
|
||||
"Hey, lazy dickbag, rate your day"
|
||||
]
|
||||
}
|
||||
|
||||
static var notificationTitlesYesterday: [String] {
|
||||
[
|
||||
"How was your day",
|
||||
"Don't forget to rate your day"
|
||||
]
|
||||
}
|
||||
|
||||
static var notificationTitlesTwoDaysAgo: [String] {
|
||||
[
|
||||
"How was your day",
|
||||
"Don't forget to rate your day"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,8 @@ struct ThemeConstants {
|
||||
enum Theme: Int, CaseIterable {
|
||||
case system
|
||||
case iFeel
|
||||
case dark
|
||||
case light
|
||||
|
||||
var title: String {
|
||||
switch self {
|
||||
@@ -21,6 +23,10 @@ enum Theme: Int, CaseIterable {
|
||||
return SystemTheme.title
|
||||
case .iFeel:
|
||||
return IFeelTheme.title
|
||||
case .dark:
|
||||
return AlwaysDark.title
|
||||
case .light:
|
||||
return AlwaysLight.title
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,24 +37,33 @@ enum Theme: Int, CaseIterable {
|
||||
return SystemTheme()
|
||||
case .iFeel:
|
||||
return IFeelTheme()
|
||||
case .dark:
|
||||
return AlwaysDark()
|
||||
case .light:
|
||||
return AlwaysLight()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protocol Themeable {
|
||||
static var title: String { get }
|
||||
var secondaryBGColor: UIColor { get }
|
||||
var secondaryBGColor: Color { get }
|
||||
var bg: AnyView { get }
|
||||
var preview: AnyView { get }
|
||||
var labelColor: Color { get }
|
||||
}
|
||||
|
||||
struct IFeelTheme: Themeable {
|
||||
static var title: String {
|
||||
return "iFeel Theme"
|
||||
var labelColor: Color {
|
||||
return Color(uiColor: UIColor.label)
|
||||
}
|
||||
|
||||
var secondaryBGColor: UIColor {
|
||||
return UIColor.systemBackground
|
||||
static var title: String {
|
||||
return "iFeel"
|
||||
}
|
||||
|
||||
var secondaryBGColor: Color {
|
||||
return Color(uiColor: UIColor.systemBackground)
|
||||
}
|
||||
|
||||
var bg: AnyView {
|
||||
@@ -69,12 +84,16 @@ struct IFeelTheme: Themeable {
|
||||
}
|
||||
|
||||
struct SystemTheme: Themeable {
|
||||
var labelColor: Color {
|
||||
return Color(uiColor: UIColor.label)
|
||||
}
|
||||
|
||||
static var title: String {
|
||||
return "System"
|
||||
}
|
||||
|
||||
var secondaryBGColor: UIColor {
|
||||
return UIColor.secondarySystemBackground
|
||||
var secondaryBGColor: Color {
|
||||
return Color(uiColor: UIColor.secondarySystemBackground)
|
||||
}
|
||||
|
||||
var bg: AnyView {
|
||||
@@ -97,3 +116,71 @@ struct SystemTheme: Themeable {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct AlwaysDark: Themeable {
|
||||
var labelColor: Color {
|
||||
return .white
|
||||
}
|
||||
|
||||
static var title: String {
|
||||
return "Dark"
|
||||
}
|
||||
|
||||
var secondaryBGColor: Color {
|
||||
return Color(uiColor: UIColor.secondarySystemBackground.resolvedColor(with: .init(userInterfaceStyle: .dark)))
|
||||
}
|
||||
|
||||
var bg: AnyView {
|
||||
return AnyView(
|
||||
ZStack {
|
||||
Rectangle()
|
||||
.fill(Color(UIColor.systemBackground.resolvedColor(with: .init(userInterfaceStyle: .dark))))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
var preview: AnyView {
|
||||
return AnyView(
|
||||
ZStack {
|
||||
Rectangle()
|
||||
.fill(Color(UIColor.secondarySystemBackground.resolvedColor(with: .init(userInterfaceStyle: .dark))))
|
||||
.frame(width: ThemeConstants.iconSize, height: ThemeConstants.iconSize)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 25, style: .continuous))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct AlwaysLight: Themeable {
|
||||
var labelColor: Color {
|
||||
return .black
|
||||
}
|
||||
|
||||
static var title: String {
|
||||
return "Light"
|
||||
}
|
||||
|
||||
var secondaryBGColor: Color {
|
||||
return Color(uiColor: UIColor.secondarySystemBackground.resolvedColor(with: .init(userInterfaceStyle: .light)))
|
||||
}
|
||||
|
||||
var bg: AnyView {
|
||||
return AnyView(
|
||||
ZStack {
|
||||
Rectangle()
|
||||
.fill(Color(UIColor.systemBackground.resolvedColor(with: .init(userInterfaceStyle: .light))))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
var preview: AnyView {
|
||||
return AnyView(
|
||||
ZStack {
|
||||
Rectangle()
|
||||
.fill(Color(UIColor.secondarySystemBackground.resolvedColor(with: .init(userInterfaceStyle: .light))))
|
||||
.frame(width: ThemeConstants.iconSize, height: ThemeConstants.iconSize)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 25, style: .continuous))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,9 @@ class UserDefaultsStore {
|
||||
case deleteEnable
|
||||
case mainViewTopHeaderIndex
|
||||
case theme
|
||||
|
||||
case moodImages
|
||||
case moodTint
|
||||
case personalityPack
|
||||
case customIcon
|
||||
|
||||
case contentViewCurrentSelectedHeaderViewBackDays
|
||||
@@ -43,4 +45,41 @@ class UserDefaultsStore {
|
||||
fatalError("error saving")
|
||||
}
|
||||
}
|
||||
|
||||
static func moodMoodImagable() -> MoodImagable.Type {
|
||||
if let data = GroupUserDefaults.groupDefaults.object(forKey: UserDefaultsStore.Keys.moodImages.rawValue) as? Int,
|
||||
let model = MoodImages.init(rawValue: data) {
|
||||
return model.moodImages
|
||||
} else {
|
||||
return MoodImages.FontAwesome.moodImages
|
||||
}
|
||||
}
|
||||
|
||||
static func moodTintable() -> MoodTintable.Type {
|
||||
if let data = GroupUserDefaults.groupDefaults.object(forKey: UserDefaultsStore.Keys.moodTint.rawValue) as? Int,
|
||||
let model = MoodTints.init(rawValue: data) {
|
||||
return model.moodTints
|
||||
} else {
|
||||
return MoodTints.Default.moodTints
|
||||
}
|
||||
}
|
||||
|
||||
static func personalityPackable() -> PersonalityPack {
|
||||
if let data = GroupUserDefaults.groupDefaults.object(forKey: UserDefaultsStore.Keys.personalityPack.rawValue) as? Int,
|
||||
let model = PersonalityPack.init(rawValue: data) {
|
||||
return model
|
||||
} else {
|
||||
return PersonalityPack.Default
|
||||
}
|
||||
}
|
||||
|
||||
static func theme() -> Theme {
|
||||
if let data = GroupUserDefaults.groupDefaults.object(forKey: UserDefaultsStore.Keys.theme.rawValue) as? Int,
|
||||
let model = Theme.init(rawValue: data) {
|
||||
return model
|
||||
} else {
|
||||
return Theme.system
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
66
Shared/MoodEntryFunctions.swift
Normal file
66
Shared/MoodEntryFunctions.swift
Normal file
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// MoodEntryFunctions.swift
|
||||
// Feels (iOS)
|
||||
//
|
||||
// Created by Trey Tartt on 2/19/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class MoodEntryFunctions {
|
||||
static func padMoodEntriesForCalendar(entries grouped: [Int: [Int: [MoodEntry]]]) -> [Int: [Int: [MoodEntry]]] {
|
||||
var newGrouped = [Int: [Int: [MoodEntry]]]()
|
||||
|
||||
let allYears = grouped.keys.sorted(by: > )
|
||||
for year in allYears {
|
||||
var newMonth = [Int: [MoodEntry]]()
|
||||
|
||||
let oldMonths = grouped[year]!
|
||||
let monthKeys = oldMonths.keys.sorted(by: > )
|
||||
for key in monthKeys {
|
||||
if let entries = oldMonths[key] {
|
||||
newMonth[key] = MoodEntryFunctions.padMoodEntriesMonth(monthEntries: entries)
|
||||
}
|
||||
newGrouped[year] = newMonth
|
||||
}
|
||||
}
|
||||
return newGrouped
|
||||
}
|
||||
|
||||
static func padMoodEntriesMonth(monthEntries entries: [MoodEntry]) -> [MoodEntry] {
|
||||
let sortedEntries = entries.sorted(by: { $0.forDate! < $1.forDate! })
|
||||
var mutableEntries = sortedEntries
|
||||
|
||||
if let firstDate = sortedEntries.first {
|
||||
let date = firstDate.forDate!
|
||||
|
||||
// if the first entry for a month is in the middle of the month we
|
||||
// need to add in the missing entries, as placeholders, to the beignning to get
|
||||
// the entries on the right day. think user downloads in the middle of the month
|
||||
// and entry is on the 13th ... this needs to show on the 13th entry spot
|
||||
var startOfMonth = date.startOfMonth
|
||||
startOfMonth = Calendar.current.date(byAdding: .hour, value: 9, to: startOfMonth)!
|
||||
let lastMissingDate = mutableEntries.first?.forDate ?? date.endOfMonth
|
||||
var missingDates = Date.dates(from: startOfMonth, to: lastMissingDate)
|
||||
missingDates = missingDates.dropLast()
|
||||
|
||||
for date in missingDates {
|
||||
mutableEntries.insert(PersistenceController.shared.generateObjectNotInArray(forDate: date, withMood: .placeholder), at: 0)
|
||||
}
|
||||
|
||||
mutableEntries = mutableEntries.sorted(by: {
|
||||
$0.forDate! < $1.forDate!
|
||||
})
|
||||
|
||||
// fill in calendar day offset .. if month starts on wed we need to
|
||||
// pad the beginning sun, mon, tues
|
||||
if let firstDate = mutableEntries.first?.forDate {
|
||||
let weekday = Int16(Calendar.current.component(.weekday, from: firstDate))
|
||||
for _ in 1..<weekday {
|
||||
mutableEntries.insert(PersistenceController.shared.generateObjectNotInArray(withMood: .placeholder), at: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
return mutableEntries
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,8 @@ extension PersistenceController {
|
||||
}
|
||||
|
||||
func fillInMissingDates() {
|
||||
let endDate = ShowBasedOnVoteLogics.getLastDateVoteShouldExist()
|
||||
let currentOnboarding = UserDefaultsStore.getOnboarding()
|
||||
let endDate = ShowBasedOnVoteLogics.getLastDateVoteShouldExist(onboardingData: currentOnboarding)
|
||||
|
||||
let fetchRequest = NSFetchRequest<MoodEntry>(entityName: "MoodEntry")
|
||||
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "forDate", ascending: false)]
|
||||
|
||||
@@ -73,13 +73,12 @@ extension PersistenceController {
|
||||
var components = DateComponents()
|
||||
components.month = month
|
||||
components.year = year
|
||||
components.day = 1
|
||||
let startDateOfMonth = Calendar.current.date(from: components)!
|
||||
|
||||
let items = data.filter({ entry in
|
||||
let components = calendar.dateComponents([.month, .year], from: startDateOfMonth)
|
||||
let entryComponents = calendar.dateComponents([.month, .year], from: entry.forDate!)
|
||||
return (components.month == entryComponents.month && components.year == entryComponents.year)
|
||||
})
|
||||
let items = PersistenceController.shared.getData(startDate: startDateOfMonth,
|
||||
endDate: startDateOfMonth.endOfMonth,
|
||||
includedDays: [1,2,3,4,5,6,7])
|
||||
if !items.isEmpty {
|
||||
allMonths[month] = items
|
||||
}
|
||||
|
||||
@@ -51,11 +51,11 @@ extension PersistenceController {
|
||||
}
|
||||
}
|
||||
|
||||
func generateObjectNotInArray() -> MoodEntry {
|
||||
func generateObjectNotInArray(forDate date: Date = Date(), withMood mood: Mood = .placeholder) -> MoodEntry {
|
||||
let newItem = MoodEntry(context: childContext)
|
||||
newItem.timestamp = Date()
|
||||
newItem.moodValue = Int16(Mood.placeholder.rawValue)
|
||||
newItem.forDate = Date()
|
||||
newItem.moodValue = Int16(mood.rawValue)
|
||||
newItem.forDate = date
|
||||
newItem.weekDay = Int16(Calendar.current.component(.weekday, from: Date()))
|
||||
newItem.canEdit = false
|
||||
newItem.canDelete = false
|
||||
|
||||
@@ -77,7 +77,9 @@ extension ChartDataBuildable {
|
||||
let date = components.day
|
||||
return day == date
|
||||
}).first {
|
||||
let view = ChartType(color: item.mood.color,
|
||||
let moodTint: MoodTintable.Type = UserDefaultsStore.moodTintable()
|
||||
|
||||
let view = ChartType(color: moodTint.color(forMood: item.mood),
|
||||
weekDay: Int(item.weekDay),
|
||||
viewType: .square)
|
||||
filledOutArray.append(view)
|
||||
|
||||
@@ -18,8 +18,6 @@ struct GroupUserDefaults {
|
||||
}
|
||||
}
|
||||
|
||||
typealias MoodGroupingMetrics = (mood: Mood, total: Int, percent: Float)
|
||||
|
||||
class Random {
|
||||
static var tomorrowMidnightThirty: Date {
|
||||
let components = DateComponents(hour: 0, minute: 30, second: 0)
|
||||
@@ -52,61 +50,29 @@ class Random {
|
||||
return formatter.string(from: NSNumber(integerLiteral: day)) ?? ""
|
||||
}
|
||||
|
||||
static func createTotalPerc(fromEntries entries: [MoodEntry]) -> [MoodGroupingMetrics] {
|
||||
var returnData = [MoodGroupingMetrics]()
|
||||
static func createTotalPerc(fromEntries entries: [MoodEntry]) -> [MoodMetrics] {
|
||||
let filteredEntries = entries.filter({
|
||||
return ![.missing, .placeholder].contains($0.mood)
|
||||
})
|
||||
var returnData = [MoodMetrics]()
|
||||
|
||||
for (_, mood) in Mood.allValues.enumerated() {
|
||||
let moodEntries = entries.filter({
|
||||
let moodEntries = filteredEntries.filter({
|
||||
Int($0.moodValue) == mood.rawValue
|
||||
})
|
||||
let total = moodEntries.count
|
||||
let perc = (Float(total) / Float(entries.count)) * 100
|
||||
returnData.append((mood, total, perc))
|
||||
let perc = (Float(total) / Float(filteredEntries.count)) * 100
|
||||
returnData.append(MoodMetrics(mood: mood, total: total, percent: perc))
|
||||
}
|
||||
|
||||
returnData = returnData.sorted(by: {
|
||||
$0.0.rawValue > $1.0.rawValue
|
||||
$0.mood.rawValue > $1.mood.rawValue
|
||||
})
|
||||
|
||||
return returnData
|
||||
}
|
||||
}
|
||||
|
||||
extension Date: RawRepresentable {
|
||||
public var rawValue: String {
|
||||
self.timeIntervalSinceReferenceDate.description
|
||||
}
|
||||
|
||||
public init?(rawValue: String) {
|
||||
self = Date(timeIntervalSinceReferenceDate: Double(rawValue) ?? 0.0)
|
||||
}
|
||||
|
||||
func startOfMonth() -> Date {
|
||||
let interval = Calendar.current.dateInterval(of: .month, for: self)
|
||||
return (interval?.start.toLocalTime())! // Without toLocalTime it give last months last date
|
||||
}
|
||||
|
||||
func endOfMonth() -> Date {
|
||||
let interval = Calendar.current.dateInterval(of: .month, for: self)
|
||||
return interval!.end
|
||||
}
|
||||
|
||||
func toLocalTime() -> Date {
|
||||
let timezone = TimeZone.current
|
||||
let seconds = TimeInterval(timezone.secondsFromGMT(for: self))
|
||||
return Date(timeInterval: seconds, since: self)
|
||||
}
|
||||
|
||||
var weekday: Int {
|
||||
Calendar.current.component(.weekday, from: self)
|
||||
}
|
||||
|
||||
var firstDayOfTheMonth: Date {
|
||||
Calendar.current.dateComponents([.calendar, .year,.month], from: self).date!
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct RoundedCorner: Shape {
|
||||
|
||||
var radius: CGFloat = .infinity
|
||||
@@ -153,20 +119,6 @@ extension UIView {
|
||||
}
|
||||
}
|
||||
|
||||
extension Date {
|
||||
static func dates(from fromDate: Date, to toDate: Date) -> [Date] {
|
||||
var dates: [Date] = []
|
||||
var date = fromDate
|
||||
|
||||
while date <= toDate {
|
||||
dates.append(date)
|
||||
guard let newDate = Calendar.current.date(byAdding: .day, value: 1, to: date) else { break }
|
||||
date = newDate
|
||||
}
|
||||
return dates
|
||||
}
|
||||
}
|
||||
|
||||
extension Color {
|
||||
static func random() -> Self {
|
||||
Self(
|
||||
@@ -175,4 +127,47 @@ extension Color {
|
||||
blue: .random(in: 0...1)
|
||||
)
|
||||
}
|
||||
|
||||
init(hex: String) {
|
||||
let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
|
||||
var int: UInt64 = 0
|
||||
Scanner(string: hex).scanHexInt64(&int)
|
||||
let a, r, g, b: UInt64
|
||||
switch hex.count {
|
||||
case 3: // RGB (12-bit)
|
||||
(a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
|
||||
case 6: // RGB (24-bit)
|
||||
(a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
|
||||
case 8: // ARGB (32-bit)
|
||||
(a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
|
||||
default:
|
||||
(a, r, g, b) = (1, 1, 1, 0)
|
||||
}
|
||||
|
||||
self.init(
|
||||
.sRGB,
|
||||
red: Double(r) / 255,
|
||||
green: Double(g) / 255,
|
||||
blue: Double(b) / 255,
|
||||
opacity: Double(a) / 255
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
func textToImage() -> UIImage? {
|
||||
let nsString = (self as NSString)
|
||||
let font = UIFont.systemFont(ofSize: 100) // you can change your font size here
|
||||
let stringAttributes = [NSAttributedString.Key.font: font]
|
||||
let imageSize = nsString.size(withAttributes: stringAttributes)
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(imageSize, false, 0) // begin image context
|
||||
UIColor.clear.set() // clear background
|
||||
UIRectFill(CGRect(origin: CGPoint(), size: imageSize)) // set rect size
|
||||
nsString.draw(at: CGPoint.zero, withAttributes: stringAttributes) // draw text within rect
|
||||
let image = UIGraphicsGetImageFromCurrentImageContext() // create image from context
|
||||
UIGraphicsEndImageContext() // end image context
|
||||
|
||||
return image ?? UIImage()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,17 +18,13 @@ import SwiftUI
|
||||
// today at 11 am -> How as 2 days ago
|
||||
// today at 1 pm -> How was yesterday
|
||||
class ShowBasedOnVoteLogics {
|
||||
private static var currentVoting: (passTimeToVote: Bool, dayOptions: DayOptions) {
|
||||
let passedTimeToVote = UserDefaultsStore.getOnboarding().ableToVoteBasedOnCurentTime()
|
||||
let inputDay = UserDefaultsStore.getOnboarding().inputDay
|
||||
static func isMissingCurrentVote(onboardingData: OnboardingData) -> Bool {
|
||||
let passedTimeToVote = onboardingData.ableToVoteBasedOnCurentTime()
|
||||
let inputDay = onboardingData.inputDay
|
||||
|
||||
return (passedTimeToVote, inputDay)
|
||||
}
|
||||
|
||||
static func isMissingCurrentVote() -> Bool {
|
||||
var startDate: Date?
|
||||
|
||||
switch (currentVoting.passTimeToVote, currentVoting.dayOptions) {
|
||||
|
||||
switch (passedTimeToVote, inputDay) {
|
||||
case (true, .Previous):
|
||||
// if we're passed time to vote and the voting type is previous - last vote should be -1
|
||||
startDate = Calendar.current.date(byAdding: .day, value: -1, to: Date())!
|
||||
@@ -57,8 +53,11 @@ class ShowBasedOnVoteLogics {
|
||||
return entries < 1
|
||||
}
|
||||
|
||||
static func getVotingTitle() -> String {
|
||||
switch (currentVoting.passTimeToVote, currentVoting.dayOptions) {
|
||||
static func getVotingTitle(onboardingData: OnboardingData) -> String {
|
||||
let passedTimeToVote = onboardingData.ableToVoteBasedOnCurentTime()
|
||||
let inputDay = onboardingData.inputDay
|
||||
|
||||
switch (passedTimeToVote, inputDay) {
|
||||
case (true, .Previous):
|
||||
// if we're passed time to vote and the voting type is previous - last vote should be -1
|
||||
return "how was yesterday"
|
||||
@@ -67,7 +66,7 @@ class ShowBasedOnVoteLogics {
|
||||
return "how is today"
|
||||
case (false, .Previous):
|
||||
// if we're passed time to vote and the voting type is previous - last vote should be -2
|
||||
let lastDayVoteShouldExist = ShowBasedOnVoteLogics.getLastDateVoteShouldExist()
|
||||
let lastDayVoteShouldExist = ShowBasedOnVoteLogics.getLastDateVoteShouldExist(onboardingData: onboardingData)
|
||||
return "how was \(Random.weekdayName(fromDate: lastDayVoteShouldExist))"
|
||||
case (false, .Today):
|
||||
// if we're passed time to vote and the voting type is previous - last vote should be -1
|
||||
@@ -75,10 +74,13 @@ class ShowBasedOnVoteLogics {
|
||||
}
|
||||
}
|
||||
|
||||
static func dateForHeaderVote() -> Date? {
|
||||
static func dateForHeaderVote(onboardingData: OnboardingData) -> Date? {
|
||||
let passedTimeToVote = onboardingData.ableToVoteBasedOnCurentTime()
|
||||
let inputDay = onboardingData.inputDay
|
||||
|
||||
var date: Date?
|
||||
|
||||
switch (currentVoting.passTimeToVote, currentVoting.dayOptions) {
|
||||
switch (passedTimeToVote, inputDay) {
|
||||
case (true, .Previous):
|
||||
// if we're passed time to vote and the voting type is previous - last vote should be -1
|
||||
date = Calendar.current.date(byAdding: .day, value: -1, to: Date())
|
||||
@@ -100,10 +102,13 @@ class ShowBasedOnVoteLogics {
|
||||
return nil
|
||||
}
|
||||
|
||||
static func getLastDateVoteShouldExist() -> Date {
|
||||
static func getLastDateVoteShouldExist(onboardingData: OnboardingData) -> Date {
|
||||
let passedTimeToVote = onboardingData.ableToVoteBasedOnCurentTime()
|
||||
let inputDay = onboardingData.inputDay
|
||||
|
||||
var endDate: Date?
|
||||
|
||||
switch (currentVoting.passTimeToVote, currentVoting.dayOptions) {
|
||||
switch (passedTimeToVote, inputDay) {
|
||||
case (true, .Previous):
|
||||
// if we're passed time to vote and the voting type is previous - last vote should -1
|
||||
endDate = Calendar.current.date(byAdding: .day, value: -1, to: Date())!
|
||||
|
||||
@@ -11,8 +11,10 @@ import SwiftUI
|
||||
import CoreData
|
||||
|
||||
struct AddMoodHeaderView: View {
|
||||
private let savedOnboardingData = UserDefaultsStore.getOnboarding()
|
||||
@AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system
|
||||
@AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults) private var moodTint: MoodTints = .Default
|
||||
|
||||
@State var onboardingData = OnboardingDataDataManager.shared.savedOnboardingData
|
||||
|
||||
let addItemHeaderClosure: ((Mood, Date) -> Void)
|
||||
|
||||
@@ -22,12 +24,12 @@ struct AddMoodHeaderView: View {
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
theme.currentTheme.secondaryBGColor
|
||||
|
||||
VStack {
|
||||
Text(ShowBasedOnVoteLogics.getVotingTitle())
|
||||
Text(ShowBasedOnVoteLogics.getVotingTitle(onboardingData: onboardingData))
|
||||
.font(.title)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
.padding()
|
||||
HStack{
|
||||
ForEach(Mood.allValues) { mood in
|
||||
@@ -38,7 +40,7 @@ struct AddMoodHeaderView: View {
|
||||
mood.icon
|
||||
.resizable()
|
||||
.frame(width: CGFloat(50), height: CGFloat(50), alignment: .center)
|
||||
.foregroundColor(mood.color)
|
||||
.foregroundColor(moodTint.color(forMood: mood))
|
||||
})
|
||||
|
||||
//Text(mood.strValue)
|
||||
@@ -49,7 +51,7 @@ struct AddMoodHeaderView: View {
|
||||
.padding([.leading, .trailing, .bottom])
|
||||
}
|
||||
.background(
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
theme.currentTheme.secondaryBGColor
|
||||
)
|
||||
.cornerRadius(10, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
.frame(minHeight: 88, maxHeight: 150)
|
||||
@@ -57,7 +59,7 @@ struct AddMoodHeaderView: View {
|
||||
}
|
||||
|
||||
private func addItem(withMood mood: Mood) {
|
||||
if let date = ShowBasedOnVoteLogics.dateForHeaderVote() {
|
||||
if let date = ShowBasedOnVoteLogics.dateForHeaderVote(onboardingData: onboardingData) {
|
||||
addItemHeaderClosure(mood, date)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,14 +8,16 @@
|
||||
import SwiftUI
|
||||
|
||||
struct BGViewItem: View {
|
||||
@AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults) private var moodTint: MoodTints = .Default
|
||||
|
||||
let mood: Mood
|
||||
let size: CGSize
|
||||
var color: Color
|
||||
let animate: Bool
|
||||
let yRowPosition: Float
|
||||
|
||||
init(mood: Mood, size: CGSize, animate: Bool, yRowPosition: Float) {
|
||||
color = mood.color
|
||||
init(mood: Mood, size: CGSize, animate: Bool, yRowPosition: Float, color: Color) {
|
||||
self.color = color
|
||||
self.mood = mood
|
||||
self.size = size
|
||||
self.yRowPosition = yRowPosition
|
||||
@@ -23,16 +25,18 @@ struct BGViewItem: View {
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Mood.allValues.randomElement()?.icon
|
||||
FontAwesomeMoodImages.icon(forMood: mood)
|
||||
.resizable()
|
||||
.frame(width: size.width, height: size.height)
|
||||
.foregroundColor(color)
|
||||
// .blur(radius: 3)
|
||||
.foregroundColor(DefaultMoodTint.color(forMood: mood))
|
||||
// .blur(radius: 3)
|
||||
.opacity(0.1)
|
||||
}
|
||||
}
|
||||
|
||||
struct BGView: View, Equatable {
|
||||
@AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults) private var moodTint: MoodTints = .Default
|
||||
|
||||
var numAcross: Int
|
||||
var numDown: Int
|
||||
let iconSize = 35
|
||||
@@ -45,15 +49,22 @@ struct BGView: View, Equatable {
|
||||
numDown = Int(screenHeight)/iconSize
|
||||
}
|
||||
|
||||
var randomMood: Mood? {
|
||||
return Mood.allValues.randomElement()
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
ForEach(0...numDown, id: \.self) { row in
|
||||
HStack {
|
||||
ForEach(0...numAcross, id: \.self) { _ in
|
||||
BGViewItem(mood: Mood.allValues.randomElement()!,
|
||||
size: .init(width: iconSize,height: iconSize),
|
||||
animate: false,
|
||||
yRowPosition: Float(row)/Float(numDown))
|
||||
if let randomMood = randomMood {
|
||||
BGViewItem(mood: randomMood,
|
||||
size: .init(width: iconSize,height: iconSize),
|
||||
animate: false,
|
||||
yRowPosition: Float(row)/Float(numDown),
|
||||
color: moodTint.color(forMood:randomMood))
|
||||
}
|
||||
}.frame(minWidth: 0, maxWidth: .infinity)
|
||||
.padding([.trailing, .leading], 13.5)
|
||||
}
|
||||
|
||||
@@ -7,47 +7,47 @@
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct CreateIconView: View {
|
||||
struct CreateWidgetView: View {
|
||||
@AppStorage(UserDefaultsStore.Keys.customIcon.rawValue, store: GroupUserDefaults.groupDefaults) private var savedCustomIcon = Data()
|
||||
|
||||
@AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system
|
||||
|
||||
static var iconViewBGs: [(BackGroundOptions, UUID)] = {
|
||||
var blah = [(BackGroundOptions, UUID)]()
|
||||
static var iconViewBGs: [(CustomWidgetBackGroundOptions, UUID)] = {
|
||||
var blah = [(CustomWidgetBackGroundOptions, UUID)]()
|
||||
for _ in 0...99 {
|
||||
blah.append((BackGroundOptions.selectable.randomElement()!, UUID()))
|
||||
blah.append((CustomWidgetBackGroundOptions.selectable.randomElement()!, UUID()))
|
||||
}
|
||||
return blah
|
||||
}()
|
||||
|
||||
@State private var mouth: MouthOptions = MouthOptions.defaultOption
|
||||
@StateObject private var customIcon = CustomIcon(leftEye: EyeOptions.defaultOption,
|
||||
rightEye: EyeOptions.defaultOption,
|
||||
mouth: MouthOptions.defaultOption,
|
||||
background: CreateIconView.iconViewBGs,
|
||||
bgColor: .red,
|
||||
innerColor: .green,
|
||||
bgOverlayColor: .black,
|
||||
rightEyeColor: .orange,
|
||||
leftEyeColor: .yellow,
|
||||
mouthColor: .purple,
|
||||
circleStrokeColor: .pink)
|
||||
@State private var mouth: CustomWidgetMouthOptions = CustomWidgetMouthOptions.defaultOption
|
||||
@StateObject private var customIcon = CustomWidgetModel(leftEye: CustomWidgetEyeOptions.defaultOption,
|
||||
rightEye: CustomWidgetEyeOptions.defaultOption,
|
||||
mouth: CustomWidgetMouthOptions.defaultOption,
|
||||
background: CreateWidgetView.iconViewBGs,
|
||||
bgColor: .red,
|
||||
innerColor: .green,
|
||||
bgOverlayColor: .black,
|
||||
rightEyeColor: .orange,
|
||||
leftEyeColor: .yellow,
|
||||
mouthColor: .purple,
|
||||
circleStrokeColor: .pink)
|
||||
private var randomElements: [AnyView] = [
|
||||
AnyView(Image(BackGroundOptions.selectable.randomElement()!.rawValue)
|
||||
AnyView(Image(CustomWidgetBackGroundOptions.selectable.randomElement()!.rawValue)
|
||||
.resizable()
|
||||
.frame(width: 20, height: 20)),
|
||||
AnyView(Image(BackGroundOptions.selectable.randomElement()!.rawValue)
|
||||
AnyView(Image(CustomWidgetBackGroundOptions.selectable.randomElement()!.rawValue)
|
||||
.resizable()
|
||||
.frame(width: 20, height: 20)),
|
||||
AnyView(Image(BackGroundOptions.selectable.randomElement()!.rawValue)
|
||||
AnyView(Image(CustomWidgetBackGroundOptions.selectable.randomElement()!.rawValue)
|
||||
.resizable()
|
||||
.frame(width: 20, height: 20)),
|
||||
AnyView(Image(BackGroundOptions.selectable.randomElement()!.rawValue)
|
||||
AnyView(Image(CustomWidgetBackGroundOptions.selectable.randomElement()!.rawValue)
|
||||
.resizable()
|
||||
.frame(width: 20, height: 20))
|
||||
]
|
||||
|
||||
func update(eye: Eyes, eyeOption: EyeOptions) {
|
||||
func update(eye: CustomWidgetEyes, eyeOption: CustomWidgetEyeOptions) {
|
||||
switch eye {
|
||||
case .left:
|
||||
customIcon.leftEye = eyeOption
|
||||
@@ -65,27 +65,27 @@ struct CreateIconView: View {
|
||||
customIcon.rightEyeColor = Color.random()
|
||||
customIcon.mouthColor = Color.random()
|
||||
|
||||
update(eye: .left, eyeOption: EyeOptions.allCases.randomElement()!)
|
||||
update(eye: .right, eyeOption: EyeOptions.allCases.randomElement()!)
|
||||
update(mouthOption: MouthOptions.allCases.randomElement()!)
|
||||
update(eye: .left, eyeOption: CustomWidgetEyeOptions.allCases.randomElement()!)
|
||||
update(eye: .right, eyeOption: CustomWidgetEyeOptions.allCases.randomElement()!)
|
||||
update(mouthOption: CustomWidgetMouthOptions.allCases.randomElement()!)
|
||||
|
||||
update(background: BackGroundOptions.allCases.randomElement()!)
|
||||
update(background: CustomWidgetBackGroundOptions.allCases.randomElement()!)
|
||||
}
|
||||
|
||||
func update(mouthOption: MouthOptions) {
|
||||
func update(mouthOption: CustomWidgetMouthOptions) {
|
||||
customIcon.mouth = mouthOption
|
||||
}
|
||||
|
||||
func update(background: BackGroundOptions) {
|
||||
func update(background: CustomWidgetBackGroundOptions) {
|
||||
customIcon.background.removeAll()
|
||||
|
||||
if background == .random {
|
||||
for _ in 0...CustomIcon.numberOfBGItems {
|
||||
customIcon.background.append((BackGroundOptions.selectable.randomElement()!, UUID()))
|
||||
for _ in 0...CustomWidgetModel.numberOfBGItems {
|
||||
customIcon.background.append((CustomWidgetBackGroundOptions.selectable.randomElement()!, UUID()))
|
||||
}
|
||||
return
|
||||
}
|
||||
for _ in 0...CustomIcon.numberOfBGItems {
|
||||
for _ in 0...CustomWidgetModel.numberOfBGItems {
|
||||
customIcon.background.append((background, UUID()))
|
||||
}
|
||||
}
|
||||
@@ -103,16 +103,16 @@ struct CreateIconView: View {
|
||||
}
|
||||
}
|
||||
|
||||
var iconView: some View {
|
||||
IconView(customIcon: customIcon, isPreview: true)
|
||||
var widgetView: some View {
|
||||
CustomWidgetView(customWidgetModel: customIcon)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
iconView
|
||||
.frame(width: 256, height: 256)
|
||||
widgetView
|
||||
// .frame(width: 256, height: 256)
|
||||
.cornerRadius(10)
|
||||
.padding(.top)
|
||||
.padding()
|
||||
|
||||
Spacer()
|
||||
|
||||
@@ -123,7 +123,7 @@ struct CreateIconView: View {
|
||||
Spacer()
|
||||
VStack(alignment: .center) {
|
||||
Menu("Left Eye") {
|
||||
ForEach(EyeOptions.allCases, id: \.self) { option in
|
||||
ForEach(CustomWidgetEyeOptions.allCases, id: \.self) { option in
|
||||
Button(action: {
|
||||
update(eye: .left, eyeOption: option)
|
||||
}, label: {
|
||||
@@ -131,12 +131,12 @@ struct CreateIconView: View {
|
||||
})
|
||||
}
|
||||
}
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
}
|
||||
Spacer()
|
||||
VStack(alignment: .center) {
|
||||
Menu("Right Eye") {
|
||||
ForEach(EyeOptions.allCases, id: \.self) { option in
|
||||
ForEach(CustomWidgetEyeOptions.allCases, id: \.self) { option in
|
||||
Button(action: {
|
||||
update(eye: .right, eyeOption: option)
|
||||
}, label: {
|
||||
@@ -144,12 +144,12 @@ struct CreateIconView: View {
|
||||
})
|
||||
}
|
||||
}
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
}
|
||||
Spacer()
|
||||
VStack(alignment: .center) {
|
||||
Menu("Mouth") {
|
||||
ForEach(MouthOptions.allCases, id: \.self) { option in
|
||||
ForEach(CustomWidgetMouthOptions.allCases, id: \.self) { option in
|
||||
Button(action: {
|
||||
update(mouthOption: option)
|
||||
}, label: {
|
||||
@@ -157,13 +157,13 @@ struct CreateIconView: View {
|
||||
})
|
||||
}
|
||||
}
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
.background(
|
||||
Color(uiColor: theme.currentTheme.secondaryBGColor)
|
||||
theme.currentTheme.secondaryBGColor
|
||||
)
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ struct CreateIconView: View {
|
||||
|
||||
Group {
|
||||
HStack {
|
||||
ForEach(BackGroundOptions.selectable, id: \.self) { bg in
|
||||
ForEach(CustomWidgetBackGroundOptions.selectable, id: \.self) { bg in
|
||||
Image(bg.rawValue, bundle: .main)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
@@ -191,7 +191,7 @@ struct CreateIconView: View {
|
||||
}
|
||||
.padding()
|
||||
.background(
|
||||
Color(uiColor: theme.currentTheme.secondaryBGColor)
|
||||
theme.currentTheme.secondaryBGColor
|
||||
)
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@ struct CreateIconView: View {
|
||||
}
|
||||
.padding()
|
||||
.background(
|
||||
Color(uiColor: theme.currentTheme.secondaryBGColor)
|
||||
theme.currentTheme.secondaryBGColor
|
||||
)
|
||||
}
|
||||
|
||||
@@ -269,7 +269,7 @@ struct CreateIconView: View {
|
||||
.background(.blue)
|
||||
|
||||
Button(action: {
|
||||
let bigIconView = IconView(customIcon: customIcon, isPreview: false)
|
||||
let bigIconView = CustomWidgetView(customWidgetModel: customIcon)
|
||||
.frame(width: 512, height: 512, alignment: .center)
|
||||
.aspectRatio(contentMode: .fill)
|
||||
let icon = bigIconView.snapshot()
|
||||
@@ -297,9 +297,9 @@ struct CreateIconView: View {
|
||||
struct CreateIconView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
CreateIconView()
|
||||
CreateWidgetView()
|
||||
|
||||
CreateIconView()
|
||||
CreateWidgetView()
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
}
|
||||
124
Shared/views/CustomIcon/IconView.swift
Normal file
124
Shared/views/CustomIcon/IconView.swift
Normal file
@@ -0,0 +1,124 @@
|
||||
//
|
||||
// IconView.swift
|
||||
// Feels (iOS)
|
||||
//
|
||||
// Created by Trey Tartt on 2/20/22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct IconView: View {
|
||||
@State public var iconViewModel: IconViewModel
|
||||
|
||||
private let facePercSize = 0.6
|
||||
public let isPreview: Bool
|
||||
|
||||
private var gridXOffset: CGFloat {
|
||||
if isPreview {
|
||||
return CGFloat(0)
|
||||
}
|
||||
return CGFloat(6)
|
||||
}
|
||||
|
||||
private var gridYOffset: CGFloat {
|
||||
if isPreview {
|
||||
return CGFloat(0)
|
||||
}
|
||||
return CGFloat(-8)
|
||||
}
|
||||
|
||||
private var entireFuckingViewOffset: CGFloat {
|
||||
if isPreview {
|
||||
return CGFloat(0)
|
||||
}
|
||||
return CGFloat(25)
|
||||
}
|
||||
|
||||
let columns = [
|
||||
GridItem(.flexible(minimum: 1, maximum: 100), spacing: 1),
|
||||
GridItem(.flexible(minimum: 1, maximum: 100), spacing: 1),
|
||||
GridItem(.flexible(minimum: 1, maximum: 100), spacing: 1),
|
||||
GridItem(.flexible(minimum: 1, maximum: 100), spacing: 1),
|
||||
GridItem(.flexible(minimum: 1, maximum: 100), spacing: 1),
|
||||
GridItem(.flexible(minimum: 1, maximum: 100), spacing: 1),
|
||||
GridItem(.flexible(minimum: 1, maximum: 100), spacing: 1),
|
||||
GridItem(.flexible(minimum: 1, maximum: 100), spacing: 1),
|
||||
GridItem(.flexible(minimum: 1, maximum: 100), spacing: 1),
|
||||
GridItem(.flexible(minimum: 1, maximum: 100), spacing: 1)
|
||||
]
|
||||
|
||||
var body: some View {
|
||||
GeometryReader { geo in
|
||||
ZStack {
|
||||
Rectangle()
|
||||
.fill(
|
||||
iconViewModel.bgColor
|
||||
)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
|
||||
LazyVGrid(columns: columns, alignment: .leading, spacing: 0) {
|
||||
ForEach(iconViewModel.background, id: \.self.1) { (bgOption, uuid) in
|
||||
bgOption
|
||||
.resizable()
|
||||
.aspectRatio(1, contentMode: .fill)
|
||||
.foregroundColor(iconViewModel.bgOverlayColor)
|
||||
}
|
||||
}
|
||||
.scaleEffect(1.1)
|
||||
.clipped()
|
||||
.background(
|
||||
.clear
|
||||
)
|
||||
|
||||
Circle()
|
||||
.strokeBorder(iconViewModel.bgColor, lineWidth: geo.size.width * 0.045)
|
||||
.background(Circle().fill(iconViewModel.bgColor))
|
||||
.frame(width: geo.size.width*facePercSize,
|
||||
height: geo.size.height*facePercSize,
|
||||
alignment: .center)
|
||||
.position(x: geo.size.width/2, y: geo.size.height/2)
|
||||
|
||||
iconViewModel.centerImage
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(width: geo.size.width*facePercSize,
|
||||
height: geo.size.height*facePercSize,
|
||||
alignment: .center)
|
||||
.foregroundColor(iconViewModel.bgOverlayColor)
|
||||
.position(x: geo.size.width/2, y: geo.size.height/2)
|
||||
|
||||
}
|
||||
.position(x: geo.size.width/2,
|
||||
y: geo.size.height/2 - entireFuckingViewOffset)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct IconView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
IconView(iconViewModel: IconViewModel.great, isPreview: false)
|
||||
.frame(width: 256, height: 256, alignment: .center)
|
||||
|
||||
// IconView(iconViewModel: IconViewModel.good, isPreview: true)
|
||||
// .frame(width: 256, height: 256, alignment: .center)
|
||||
//
|
||||
// IconView(iconViewModel: IconViewModel.average, isPreview: true)
|
||||
// .frame(width: 256, height: 256, alignment: .center)
|
||||
//
|
||||
// IconView(iconViewModel: IconViewModel.bad, isPreview: true)
|
||||
// .frame(width: 256, height: 256, alignment: .center)
|
||||
//
|
||||
// IconView(iconViewModel: IconViewModel.horrible, isPreview: true)
|
||||
// .frame(width: 256, height: 256, alignment: .center)
|
||||
//
|
||||
// IconView(iconViewModel: IconViewModel(backgroundImage: EmojiMoodImages.icon(forMood: .horrible),
|
||||
// bgColor: MoodTints.Neon.color(forMood: .horrible),
|
||||
// bgOverlayColor: MoodTints.Neon.color(forMood: .horrible),
|
||||
// centerImage: EmojiMoodImages.icon(forMood: .horrible)),
|
||||
// isPreview: true)
|
||||
// .frame(width: 256, height: 256, alignment: .center)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
80
Shared/views/CustomIcon/IconViewModel.swift
Normal file
80
Shared/views/CustomIcon/IconViewModel.swift
Normal file
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// CustomIcon.swift
|
||||
// Feels (iOS)
|
||||
//
|
||||
// Created by Trey Tartt on 2/20/22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
class IconViewModel: ObservableObject {
|
||||
static let numberOfBGItems = 109
|
||||
|
||||
static let great = IconViewModel(backgroundImage: MoodImages.FontAwesome.icon(forMood: .great),
|
||||
bgColor: Color(hex: "31d158"),
|
||||
bgOverlayColor: Color(hex: "208939"),
|
||||
centerImage: MoodImages.FontAwesome.icon(forMood: .great))
|
||||
|
||||
static let good = IconViewModel(backgroundImage: MoodImages.FontAwesome.icon(forMood: .good),
|
||||
bgColor: Color(hex: "ffd709"),
|
||||
bgOverlayColor: Color(hex: "9d8405"),
|
||||
centerImage: MoodImages.FontAwesome.icon(forMood: .good))
|
||||
|
||||
static let average = IconViewModel(backgroundImage: MoodImages.FontAwesome.icon(forMood: .average),
|
||||
bgColor: Color(hex: "0b84ff"),
|
||||
bgOverlayColor: Color(hex: "074f9a"),
|
||||
centerImage: MoodImages.FontAwesome.icon(forMood: .average))
|
||||
|
||||
static let bad = IconViewModel(backgroundImage: MoodImages.FontAwesome.icon(forMood: .bad),
|
||||
bgColor: Color(hex: "ff9f0b"),
|
||||
bgOverlayColor: Color(hex: "a06407"),
|
||||
centerImage: MoodImages.FontAwesome.icon(forMood: .bad))
|
||||
|
||||
static let horrible = IconViewModel(backgroundImage: MoodImages.FontAwesome.icon(forMood: .horrible),
|
||||
bgColor: Color(hex: "fe5257"),
|
||||
bgOverlayColor: Color(hex: "a92b26"),
|
||||
centerImage: MoodImages.FontAwesome.icon(forMood: .horrible))
|
||||
|
||||
init(backgroundImage: Image,
|
||||
bgColor: Color,
|
||||
bgOverlayColor: Color,
|
||||
centerImage: Image
|
||||
) {
|
||||
|
||||
var blah = [(Image, UUID)]()
|
||||
for _ in 0...IconViewModel.numberOfBGItems {
|
||||
blah.append((backgroundImage, UUID()))
|
||||
}
|
||||
|
||||
self.background = blah
|
||||
self.bgColor = bgColor
|
||||
self.bgOverlayColor = bgOverlayColor
|
||||
self.centerImage = centerImage
|
||||
}
|
||||
|
||||
@Published var background: [(Image, UUID)]
|
||||
@Published var bgColor: Color
|
||||
@Published var bgOverlayColor: Color
|
||||
@Published var centerImage: Image
|
||||
}
|
||||
|
||||
enum CustomIconBackGroundOptions: String, CaseIterable, Codable {
|
||||
case horrible
|
||||
case bad
|
||||
case average
|
||||
case good
|
||||
case great
|
||||
case random
|
||||
|
||||
static var selectable: [CustomIconBackGroundOptions] {
|
||||
return [.great, .good, .average, .bad, .horrible]
|
||||
}
|
||||
|
||||
static public var defaultOption: CustomIconBackGroundOptions {
|
||||
CustomIconBackGroundOptions.random
|
||||
}
|
||||
|
||||
public var image: Image {
|
||||
return Image(self.rawValue, bundle: .main)
|
||||
}
|
||||
}
|
||||
@@ -7,26 +7,26 @@
|
||||
|
||||
import SwiftUI
|
||||
|
||||
class CustomIcon: ObservableObject {
|
||||
static let numberOfBGItems = 99
|
||||
class CustomWidgetModel: ObservableObject {
|
||||
static let numberOfBGItems = 109
|
||||
|
||||
static let defaultCustomIcon = CustomIcon(leftEye: EyeOptions.defaultOption,
|
||||
rightEye: EyeOptions.defaultOption,
|
||||
mouth: MouthOptions.defaultOption,
|
||||
background: IconView_Previews.backgrounds,
|
||||
bgColor: .red,
|
||||
innerColor: .green,
|
||||
bgOverlayColor: .orange,
|
||||
rightEyeColor: .orange,
|
||||
leftEyeColor: .yellow,
|
||||
mouthColor: .green,
|
||||
circleStrokeColor: .pink)
|
||||
static let defaultCustomIcon = CustomWidgetModel(leftEye: CustomWidgetEyeOptions.defaultOption,
|
||||
rightEye: CustomWidgetEyeOptions.defaultOption,
|
||||
mouth: CustomWidgetMouthOptions.defaultOption,
|
||||
background: WidgetView_Previews.backgrounds,
|
||||
bgColor: .red,
|
||||
innerColor: .green,
|
||||
bgOverlayColor: .orange,
|
||||
rightEyeColor: .orange,
|
||||
leftEyeColor: .yellow,
|
||||
mouthColor: .green,
|
||||
circleStrokeColor: .pink)
|
||||
|
||||
|
||||
init(leftEye: EyeOptions,
|
||||
rightEye: EyeOptions,
|
||||
mouth: MouthOptions,
|
||||
background: [(BackGroundOptions, UUID)],
|
||||
init(leftEye: CustomWidgetEyeOptions,
|
||||
rightEye: CustomWidgetEyeOptions,
|
||||
mouth: CustomWidgetMouthOptions,
|
||||
background: [(CustomWidgetBackGroundOptions, UUID)],
|
||||
bgColor: Color,
|
||||
innerColor: Color,
|
||||
bgOverlayColor: Color,
|
||||
@@ -48,11 +48,11 @@ class CustomIcon: ObservableObject {
|
||||
self.circleStrokeColor = circleStrokeColor
|
||||
}
|
||||
|
||||
@Published var leftEye: EyeOptions
|
||||
@Published var rightEye: EyeOptions
|
||||
@Published var mouth: MouthOptions
|
||||
@Published var leftEye: CustomWidgetEyeOptions
|
||||
@Published var rightEye: CustomWidgetEyeOptions
|
||||
@Published var mouth: CustomWidgetMouthOptions
|
||||
|
||||
@Published var background: [(BackGroundOptions, UUID)]
|
||||
@Published var background: [(CustomWidgetBackGroundOptions, UUID)]
|
||||
@Published var bgColor: Color
|
||||
@Published var innerColor: Color
|
||||
@Published var bgOverlayColor: Color
|
||||
@@ -64,7 +64,7 @@ class CustomIcon: ObservableObject {
|
||||
@Published var circleStrokeColor: Color
|
||||
}
|
||||
|
||||
enum BackGroundOptions: String, CaseIterable, Codable {
|
||||
enum CustomWidgetBackGroundOptions: String, CaseIterable, Codable {
|
||||
case horrible
|
||||
case bad
|
||||
case average
|
||||
@@ -72,12 +72,12 @@ enum BackGroundOptions: String, CaseIterable, Codable {
|
||||
case great
|
||||
case random
|
||||
|
||||
static var selectable: [BackGroundOptions] {
|
||||
static var selectable: [CustomWidgetBackGroundOptions] {
|
||||
return [.great, .good, .average, .bad, .horrible]
|
||||
}
|
||||
|
||||
static public var defaultOption: BackGroundOptions {
|
||||
BackGroundOptions.random
|
||||
static public var defaultOption: CustomWidgetBackGroundOptions {
|
||||
CustomWidgetBackGroundOptions.random
|
||||
}
|
||||
|
||||
public var image: Image {
|
||||
@@ -85,12 +85,12 @@ enum BackGroundOptions: String, CaseIterable, Codable {
|
||||
}
|
||||
}
|
||||
|
||||
enum Eyes: String, Codable {
|
||||
enum CustomWidgetEyes: String, Codable {
|
||||
case left
|
||||
case right
|
||||
}
|
||||
|
||||
enum EyeOptions: String, CaseIterable, Codable {
|
||||
enum CustomWidgetEyeOptions: String, CaseIterable, Codable {
|
||||
case fire = "fire"
|
||||
case bolt = "bolt2"
|
||||
case dollar = "dollar"
|
||||
@@ -109,8 +109,8 @@ enum EyeOptions: String, CaseIterable, Codable {
|
||||
case skull2 = "skull2"
|
||||
case poo = "poo"
|
||||
|
||||
static public var defaultOption: EyeOptions {
|
||||
EyeOptions.fire
|
||||
static public var defaultOption: CustomWidgetEyeOptions {
|
||||
CustomWidgetEyeOptions.fire
|
||||
}
|
||||
|
||||
public var image: Image {
|
||||
@@ -118,7 +118,7 @@ enum EyeOptions: String, CaseIterable, Codable {
|
||||
}
|
||||
}
|
||||
|
||||
enum MouthOptions: String, CaseIterable, Codable {
|
||||
enum CustomWidgetMouthOptions: String, CaseIterable, Codable {
|
||||
case fire = "fire"
|
||||
case bolt = "bolt2"
|
||||
case dollar = "dollar"
|
||||
@@ -137,8 +137,8 @@ enum MouthOptions: String, CaseIterable, Codable {
|
||||
case skull2 = "skull2"
|
||||
case poo = "poo"
|
||||
|
||||
static public var defaultOption: MouthOptions {
|
||||
MouthOptions.bomb
|
||||
static public var defaultOption: CustomWidgetMouthOptions {
|
||||
CustomWidgetMouthOptions.bomb
|
||||
}
|
||||
|
||||
public var image: Image {
|
||||
@@ -7,32 +7,31 @@
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct IconView: View {
|
||||
@State public var customIcon: CustomIcon
|
||||
struct CustomWidgetView: View {
|
||||
@State public var customWidgetModel: CustomWidgetModel
|
||||
|
||||
private let facePercSize = 0.6
|
||||
public let isPreview: Bool
|
||||
|
||||
private var gridXOffset: CGFloat {
|
||||
if isPreview {
|
||||
return CGFloat(0)
|
||||
}
|
||||
return CGFloat(6)
|
||||
}
|
||||
|
||||
private var gridYOffset: CGFloat {
|
||||
if isPreview {
|
||||
return CGFloat(0)
|
||||
}
|
||||
return CGFloat(-8)
|
||||
}
|
||||
|
||||
private var entireFuckingViewOffset: CGFloat {
|
||||
if isPreview {
|
||||
return CGFloat(0)
|
||||
}
|
||||
return CGFloat(25)
|
||||
}
|
||||
// private var gridXOffset: CGFloat {
|
||||
// if isPreview {
|
||||
// return CGFloat(0)
|
||||
// }
|
||||
// return CGFloat(6)
|
||||
// }
|
||||
//
|
||||
// private var gridYOffset: CGFloat {
|
||||
// if isPreview {
|
||||
// return CGFloat(0)
|
||||
// }
|
||||
// return CGFloat(-8)
|
||||
// }
|
||||
//
|
||||
// private var entireFuckingViewOffset: CGFloat {
|
||||
// if isPreview {
|
||||
// return CGFloat(0)
|
||||
// }
|
||||
// return CGFloat(25)
|
||||
// }
|
||||
|
||||
let columns = [
|
||||
GridItem(.flexible(minimum: 1, maximum: 100), spacing: 1),
|
||||
@@ -52,32 +51,33 @@ struct IconView: View {
|
||||
ZStack {
|
||||
Rectangle()
|
||||
.fill(
|
||||
customIcon.bgColor
|
||||
customWidgetModel.bgColor
|
||||
)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
|
||||
LazyVGrid(columns: columns, alignment: .leading, spacing: 0) {
|
||||
ForEach(customIcon.background, id: \.self.1) { (bgOption, uuid) in
|
||||
ForEach(customWidgetModel.background, id: \.self.1) { (bgOption, uuid) in
|
||||
bgOption.image
|
||||
.resizable()
|
||||
.aspectRatio(1, contentMode: .fill)
|
||||
.foregroundColor(customIcon.bgOverlayColor)
|
||||
.foregroundColor(customWidgetModel.bgOverlayColor)
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.scaleEffect(1.1)
|
||||
.clipped()
|
||||
.background(
|
||||
.clear
|
||||
)
|
||||
|
||||
Circle()
|
||||
.strokeBorder(customIcon.circleStrokeColor, lineWidth: geo.size.width * 0.045)
|
||||
.background(Circle().fill(customIcon.innerColor))
|
||||
.strokeBorder(customWidgetModel.circleStrokeColor, lineWidth: geo.size.width * 0.045)
|
||||
.background(Circle().fill(customWidgetModel.innerColor))
|
||||
.frame(width: geo.size.width*facePercSize,
|
||||
height: geo.size.height*facePercSize,
|
||||
alignment: .center)
|
||||
.position(x: geo.size.width/2, y: geo.size.height/2)
|
||||
|
||||
customIcon.leftEye.image
|
||||
customWidgetModel.leftEye.image
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: geo.size.width*0.12,
|
||||
@@ -85,9 +85,9 @@ struct IconView: View {
|
||||
alignment: .center)
|
||||
.position(x: geo.size.width*0.4,
|
||||
y: geo.size.height*0.4)
|
||||
.foregroundColor(customIcon.leftEyeColor)
|
||||
.foregroundColor(customWidgetModel.leftEyeColor)
|
||||
|
||||
customIcon.rightEye.image
|
||||
customWidgetModel.rightEye.image
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: geo.size.width*0.12,
|
||||
@@ -95,9 +95,9 @@ struct IconView: View {
|
||||
alignment: .center)
|
||||
.position(x: geo.size.width*0.6,
|
||||
y: geo.size.height*0.4)
|
||||
.foregroundColor(customIcon.rightEyeColor)
|
||||
.foregroundColor(customWidgetModel.rightEyeColor)
|
||||
|
||||
customIcon.mouth.image
|
||||
customWidgetModel.mouth.image
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: geo.size.width*0.12,
|
||||
@@ -105,26 +105,25 @@ struct IconView: View {
|
||||
alignment: .center)
|
||||
.position(x: geo.size.width*0.5,
|
||||
y: geo.size.height*0.59)
|
||||
.foregroundColor(customIcon.mouthColor)
|
||||
.foregroundColor(customWidgetModel.mouthColor)
|
||||
}
|
||||
.position(x: geo.size.width/2,
|
||||
y: geo.size.height/2 - entireFuckingViewOffset)
|
||||
y: geo.size.height/2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct IconView_Previews: PreviewProvider {
|
||||
static var backgrounds: [(BackGroundOptions, UUID)] = {
|
||||
var blah = [(BackGroundOptions, UUID)]()
|
||||
for _ in 0...CustomIcon.numberOfBGItems {
|
||||
blah.append((BackGroundOptions.selectable.randomElement()!, UUID()))
|
||||
struct WidgetView_Previews: PreviewProvider {
|
||||
static var backgrounds: [(CustomWidgetBackGroundOptions, UUID)] = {
|
||||
var blah = [(CustomWidgetBackGroundOptions, UUID)]()
|
||||
for _ in 0...CustomWidgetModel.numberOfBGItems {
|
||||
blah.append((CustomWidgetBackGroundOptions.selectable.randomElement()!, UUID()))
|
||||
}
|
||||
return blah
|
||||
}()
|
||||
|
||||
static var previews: some View {
|
||||
IconView(customIcon: CustomIcon.defaultCustomIcon,
|
||||
isPreview: true)
|
||||
CustomWidgetView(customWidgetModel: CustomWidgetModel.defaultCustomIcon)
|
||||
.frame(width: 256, height: 256, alignment: .center)
|
||||
|
||||
}
|
||||
239
Shared/views/CustomizeView/CustomizeView.swift
Normal file
239
Shared/views/CustomizeView/CustomizeView.swift
Normal file
@@ -0,0 +1,239 @@
|
||||
//
|
||||
// CustomizeView.swift
|
||||
// Feels (iOS)
|
||||
//
|
||||
// Created by Trey Tartt on 2/19/22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct CustomizeView: View {
|
||||
@AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system
|
||||
@AppStorage(UserDefaultsStore.Keys.moodImages.rawValue, store: GroupUserDefaults.groupDefaults) private var imagePack: MoodImages = .FontAwesome
|
||||
@AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults) private var moodTint: MoodTints = .Default
|
||||
@AppStorage(UserDefaultsStore.Keys.personalityPack.rawValue, store: GroupUserDefaults.groupDefaults) private var personalityPack: PersonalityPack = .Default
|
||||
|
||||
@State private var showCreateCustomWidget = false
|
||||
|
||||
let iconSets: [(String,String)] = [
|
||||
("PurpleFeelsAppIcon", "PurpleAppIcon"),
|
||||
("RedFeelsAppIcon", "RedAppIcon")
|
||||
]
|
||||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
VStack {
|
||||
Text(String(localized: "customize_view_title"))
|
||||
.font(.title)
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
.padding([.trailing, .leading], 55)
|
||||
.padding([.top], 15)
|
||||
|
||||
createCustomWidget
|
||||
changeIcon
|
||||
themePicker
|
||||
pickMoodImagePack
|
||||
pickMoodTintPack
|
||||
pickPeronsalityPack
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.sheet(isPresented: $showCreateCustomWidget) {
|
||||
CreateWidgetView()
|
||||
}
|
||||
.background(
|
||||
theme.currentTheme.bg
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
)
|
||||
}
|
||||
|
||||
private var changeIcon: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
VStack {
|
||||
Text(String(localized: "settings_view_change_icon"))
|
||||
HStack {
|
||||
|
||||
Button(action: {
|
||||
UIApplication.shared.setAlternateIconName(nil)
|
||||
}, label: {
|
||||
Image("FeelsAppIcon", bundle: .main)
|
||||
.resizable()
|
||||
.frame(width: 50, height:50)
|
||||
.cornerRadius(10)
|
||||
})
|
||||
.padding()
|
||||
|
||||
ForEach(iconSets, id: \.self.0){ iconSet in
|
||||
Button(action: {
|
||||
UIApplication.shared.setAlternateIconName(iconSet.1) { (error) in
|
||||
// FIXME: Handle error
|
||||
}
|
||||
}, label: {
|
||||
Image(iconSet.0, bundle: .main)
|
||||
.resizable()
|
||||
.frame(width: 50, height:50)
|
||||
.cornerRadius(10)
|
||||
})
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(10, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var themePicker: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
VStack {
|
||||
Text(String(localized: "settings_background_title"))
|
||||
HStack {
|
||||
Spacer()
|
||||
ForEach(Theme.allCases, id:\.rawValue) { aTheme in
|
||||
Button(action: {
|
||||
theme = aTheme
|
||||
}, label: {
|
||||
VStack {
|
||||
aTheme.currentTheme.preview
|
||||
.overlay(
|
||||
Circle()
|
||||
.stroke(Color(UIColor.systemGray), style: StrokeStyle(lineWidth: 2))
|
||||
)
|
||||
Text(aTheme.title)
|
||||
}
|
||||
})
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
.padding(.top)
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(10, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var createCustomWidget: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
showCreateCustomWidget = true
|
||||
}, label: {
|
||||
Text("Create Custom Widget")
|
||||
})
|
||||
.padding()
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(10, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var pickMoodImagePack: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
VStack {
|
||||
ForEach(MoodImages.allCases, id: \.rawValue) { images in
|
||||
HStack {
|
||||
ForEach(Mood.allValues, id: \.self) { mood in
|
||||
images.icon(forMood: mood)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 35, height: 35)
|
||||
.foregroundColor(
|
||||
moodTint.color(forMood: mood)
|
||||
)
|
||||
}
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
.onTapGesture {
|
||||
let impactMed = UIImpactFeedbackGenerator(style: .heavy)
|
||||
impactMed.impactOccurred()
|
||||
imagePack = images
|
||||
}
|
||||
}
|
||||
if images.rawValue != (MoodImages.allCases.sorted(by: { $0.rawValue > $1.rawValue }).first?.rawValue) ?? 0 {
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(10, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var pickMoodTintPack: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
VStack {
|
||||
ForEach(MoodTints.allCases, id: \.rawValue) { tint in
|
||||
HStack {
|
||||
ForEach(Mood.allValues, id: \.self) { mood in
|
||||
Circle()
|
||||
.frame(width: 35, height: 35)
|
||||
.foregroundColor(
|
||||
tint.color(forMood: mood)
|
||||
)
|
||||
}
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
.onTapGesture {
|
||||
let impactMed = UIImpactFeedbackGenerator(style: .heavy)
|
||||
impactMed.impactOccurred()
|
||||
moodTint = tint
|
||||
}
|
||||
}
|
||||
if tint.rawValue != (MoodTints.allCases.sorted(by: { $0.rawValue > $1.rawValue }).first?.rawValue) ?? 0 {
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(10, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var pickPeronsalityPack: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
VStack {
|
||||
ForEach(PersonalityPack.allCases, id: \.self) { aPack in
|
||||
VStack(spacing: 10) {
|
||||
Text(String(aPack.title()))
|
||||
.font(.title)
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
|
||||
|
||||
Text(aPack.randomPushNotificationTitle())
|
||||
.font(.body)
|
||||
.foregroundColor(Color(UIColor.systemGray))
|
||||
}
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
.padding()
|
||||
.onTapGesture {
|
||||
let impactMed = UIImpactFeedbackGenerator(style: .heavy)
|
||||
impactMed.impactOccurred()
|
||||
personalityPack = aPack
|
||||
LocalNotification.rescheduleNotifiations()
|
||||
|
||||
UITabBar.appearance().backgroundColor = UIColor(cgColor: theme.currentTheme.secondaryBGColor.cgColor ?? UIColor.secondarySystemBackground.cgColor)
|
||||
}
|
||||
if aPack.rawValue != (PersonalityPack.allCases.sorted(by: { $0.rawValue > $1.rawValue }).first?.rawValue) ?? 0 {
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(10, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
}
|
||||
|
||||
struct CustomizeView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
CustomizeView()
|
||||
}
|
||||
}
|
||||
@@ -10,21 +10,21 @@ import SwiftUI
|
||||
struct EmptyHomeView: View {
|
||||
@AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system
|
||||
|
||||
let viewModel: ContentModeViewModel
|
||||
let viewModel: HomeViewViewModel
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
theme.currentTheme.secondaryBGColor
|
||||
|
||||
VStack {
|
||||
Text(String(localized: "content_view_empty_title"))
|
||||
.font(.title)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
.padding()
|
||||
|
||||
Text(String(localized: "content_view_empty_title"))
|
||||
.font(.body)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
.padding()
|
||||
AddMoodHeaderView(addItemHeaderClosure: { (mood, date) in
|
||||
withAnimation {
|
||||
@@ -40,6 +40,6 @@ struct EmptyHomeView: View {
|
||||
|
||||
struct EmptyHomeView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
EmptyHomeView(viewModel: ContentModeViewModel(addMonthStartWeekdayPadding: false))
|
||||
EmptyHomeView(viewModel: HomeViewViewModel(addMonthStartWeekdayPadding: false))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,8 @@ struct FilterView: View {
|
||||
private var items: FetchedResults<MoodEntry>
|
||||
|
||||
@AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system
|
||||
|
||||
@AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults) private var moodTint: MoodTints = .Default
|
||||
|
||||
@StateObject private var viewModel = FilterViewModel()
|
||||
//[
|
||||
// 2001: [0: [], 1: [], 2: []],
|
||||
@@ -54,6 +55,7 @@ struct FilterView: View {
|
||||
|
||||
Text(String(localized: "filter_view_total") + ": \(self.viewModel.numberOfRatings)")
|
||||
.font(.title2)
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
|
||||
if showFilter {
|
||||
filterView
|
||||
@@ -80,13 +82,16 @@ struct FilterView: View {
|
||||
Text(showFilter ? String(localized: "filter_view_hide_filters") : String(localized: "filter_view_show_filters"))
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: 44)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
.background(Color(theme.currentTheme.secondaryBGColor))
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
.background(theme.currentTheme.secondaryBGColor)
|
||||
.cornerRadius(10)
|
||||
}).frame(maxWidth: .infinity)
|
||||
}
|
||||
|
||||
struct StatsSubView: View {
|
||||
@AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults) private var moodTint: MoodTints = .Default
|
||||
@AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system
|
||||
|
||||
let data: [MoodEntry]
|
||||
let mood: Mood
|
||||
|
||||
@@ -95,15 +100,16 @@ struct FilterView: View {
|
||||
Text(String(Stats.getCountFor(moodType: mood,
|
||||
inData: data)))
|
||||
.font(.title)
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
Text(mood.strValue)
|
||||
.foregroundColor(mood.color)
|
||||
.foregroundColor(moodTint.color(forMood: mood))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var statsView: some View {
|
||||
ZStack {
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
theme.currentTheme.secondaryBGColor
|
||||
|
||||
HStack {
|
||||
Spacer()
|
||||
@@ -120,7 +126,7 @@ struct FilterView: View {
|
||||
VStack {
|
||||
VStack {
|
||||
ZStack {
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
theme.currentTheme.secondaryBGColor
|
||||
DatePicker(
|
||||
String(localized: "filter_view_begin_date"),
|
||||
selection: $viewModel.entryStartDate,
|
||||
@@ -133,9 +139,10 @@ struct FilterView: View {
|
||||
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 44, maxHeight: 44)
|
||||
.cornerRadius(10)
|
||||
.padding([.leading, .trailing])
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
|
||||
ZStack {
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
theme.currentTheme.secondaryBGColor
|
||||
DatePicker(
|
||||
String(localized: "filter_view_end_date"),
|
||||
selection: $viewModel.entryEndDate,
|
||||
@@ -148,9 +155,10 @@ struct FilterView: View {
|
||||
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 44, maxHeight: 44)
|
||||
.cornerRadius(10)
|
||||
.padding([.leading, .trailing])
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
|
||||
ZStack {
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
theme.currentTheme.secondaryBGColor
|
||||
HStack {
|
||||
Spacer()
|
||||
ForEach(weekdays.indices, id: \.self) { dayIdx in
|
||||
@@ -186,6 +194,7 @@ struct FilterView: View {
|
||||
ForEach(months, id: \.self.0) { item in
|
||||
Text(item.1)
|
||||
.textCase(.uppercase)
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
}
|
||||
}.padding([.leading, .trailing, .top])
|
||||
}
|
||||
@@ -202,9 +211,10 @@ struct FilterView: View {
|
||||
let yearData = self.viewModel.data[yearKey]!
|
||||
Text(String(yearKey))
|
||||
.font(.title)
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
yearGridView(yearData: yearData, columns: columns)
|
||||
.background(
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
theme.currentTheme.secondaryBGColor
|
||||
)
|
||||
.cornerRadius(10)
|
||||
}
|
||||
@@ -13,8 +13,9 @@ enum PercViewType {
|
||||
}
|
||||
|
||||
struct HeaderPercView: View {
|
||||
typealias model = (mood: Mood, total: Int, percent: Float)
|
||||
var entries = [model]()
|
||||
@AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults) private var moodTint: MoodTints = .Default
|
||||
|
||||
var entries = [MoodMetrics]()
|
||||
let backDays: Int
|
||||
let type: PercViewType
|
||||
|
||||
@@ -32,44 +33,34 @@ struct HeaderPercView: View {
|
||||
moodEntries = PersistenceController.shared.getData(startDate: daysAgo, endDate: Date(), includedDays: [1,2,3,4,5,6,7])
|
||||
}
|
||||
|
||||
let totalEntryCount = moodEntries?.count ?? 0
|
||||
|
||||
if let moodEntries = moodEntries {
|
||||
for (_, mood) in Mood.allValues.enumerated() {
|
||||
|
||||
let moodEntries = moodEntries.filter({
|
||||
Int($0.moodValue) == mood.rawValue
|
||||
})
|
||||
let total = moodEntries.count
|
||||
let perc = (Float(total) / Float(totalEntryCount)) * 100
|
||||
entries.append((mood, total, perc))
|
||||
}
|
||||
entries = Random.createTotalPerc(fromEntries: moodEntries)
|
||||
|
||||
entries = entries.sorted(by: {
|
||||
$0.mood.rawValue > $1.mood.rawValue
|
||||
})
|
||||
}
|
||||
|
||||
entries = entries.sorted(by: {
|
||||
$0.0.rawValue > $1.0.rawValue
|
||||
})
|
||||
}
|
||||
|
||||
private var textViews: some View {
|
||||
VStack {
|
||||
Spacer()
|
||||
HStack {
|
||||
ForEach(entries.prefix(3), id: \.0) { model in
|
||||
ForEach(entries.prefix(3), id: \.id) { model in
|
||||
Text("\(model.percent, specifier: "%.0f")%")
|
||||
.font(.title)
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(model.mood.color)
|
||||
.foregroundColor(moodTint.color(forMood: model.mood))
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
HStack {
|
||||
ForEach(entries.suffix(2), id: \.0) { model in
|
||||
ForEach(entries.suffix(2), id: \.id) { model in
|
||||
Text("\(model.percent, specifier: "%.0f")%")
|
||||
.font(.title)
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(model.mood.color)
|
||||
.foregroundColor(moodTint.color(forMood: model.mood))
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
}
|
||||
@@ -81,27 +72,27 @@ struct HeaderPercView: View {
|
||||
VStack {
|
||||
Spacer()
|
||||
HStack {
|
||||
ForEach(entries.prefix(3), id: \.0) { model in
|
||||
ForEach(entries.prefix(3), id: \.id) { model in
|
||||
Text("\(model.percent, specifier: "%.0f")%")
|
||||
.font(.title2)
|
||||
.fontWeight(.bold)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding()
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(Circle().fill(model.mood.color))
|
||||
.background(Circle().fill(moodTint.color(forMood: model.mood)))
|
||||
.foregroundColor(Color(UIColor.white))
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
HStack {
|
||||
ForEach(entries.suffix(2), id: \.0) { model in
|
||||
ForEach(entries.suffix(2), id: \.id) { model in
|
||||
Text("\(model.percent, specifier: "%.0f")%")
|
||||
.font(.title2)
|
||||
.fontWeight(.bold)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding()
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(Circle().fill(model.mood.color))
|
||||
.background(Circle().fill(moodTint.color(forMood: model.mood)))
|
||||
.foregroundColor(Color(UIColor.white))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,10 @@ import Charts
|
||||
struct HeaderStatsView : UIViewRepresentable {
|
||||
//Bar chart accepts data as array of BarChartDataEntry objects
|
||||
var entries : [BarChartDataEntry]
|
||||
var moodTint: MoodTints
|
||||
|
||||
init(fakeData: Bool, backDays: Int) {
|
||||
init(fakeData: Bool, backDays: Int, moodTint: MoodTints) {
|
||||
self.moodTint = moodTint
|
||||
entries = [BarChartDataEntry]()
|
||||
|
||||
var moodEntries: [MoodEntry]?
|
||||
@@ -96,7 +98,7 @@ struct HeaderStatsView : UIViewRepresentable {
|
||||
let dataSet = BarChartDataSet(entries: entries)
|
||||
|
||||
// change bars color to green
|
||||
dataSet.colors = Mood.allValues.map({ NSUIColor( $0.color ) })
|
||||
dataSet.colors = Mood.allValues.map({ NSUIColor( moodTint.color(forMood: $0) ) })
|
||||
dataSet.secondaryTextColor = UIColor.systemGray
|
||||
dataSet.valueColors = [.white]
|
||||
dataSet.highlightAlpha = 0.0
|
||||
@@ -120,6 +122,6 @@ struct HeaderStatsView : UIViewRepresentable {
|
||||
|
||||
struct HeaderStatsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
HeaderStatsView(fakeData: true, backDays: 30).frame(minHeight: 85, maxHeight: 90)
|
||||
HeaderStatsView(fakeData: true, backDays: 30, moodTint: .Default).frame(minHeight: 85, maxHeight: 90)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,10 @@ struct HomeView: View {
|
||||
@AppStorage(UserDefaultsStore.Keys.deleteEnable.rawValue, store: GroupUserDefaults.groupDefaults) private var deleteEnabled = true
|
||||
|
||||
@AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system
|
||||
|
||||
|
||||
@AppStorage(UserDefaultsStore.Keys.moodImages.rawValue, store: GroupUserDefaults.groupDefaults) private var imagePack: MoodImages = .FontAwesome
|
||||
@AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults) private var moodTint: MoodTints = .Default
|
||||
|
||||
// MARK: top header storage
|
||||
@AppStorage(UserDefaultsStore.Keys.contentViewCurrentSelectedHeaderViewBackDays.rawValue, store: GroupUserDefaults.groupDefaults) private var currentSelectedHeaderViewBackDays: Int = 30
|
||||
@AppStorage(UserDefaultsStore.Keys.contentViewHeaderTagViewOneViewType.rawValue, store: GroupUserDefaults.groupDefaults) private var firstSwichableHeaderViewType: MainSwitchableViewType = .total
|
||||
@@ -37,6 +40,7 @@ struct HomeView: View {
|
||||
// MARK: ?? properties
|
||||
@State private var showTodayInput = true
|
||||
@State private var showUpdateEntryAlert = false
|
||||
@StateObject private var onboardingData = OnboardingDataDataManager.shared
|
||||
|
||||
// MARK: header properties
|
||||
@State private var headerHeight: CGFloat = HomeViewConstants.maxHeaderHeight
|
||||
@@ -44,17 +48,11 @@ struct HomeView: View {
|
||||
@State private var headerOpacity: Double = 1.0
|
||||
//
|
||||
|
||||
@ObservedObject var viewModel = ContentModeViewModel(addMonthStartWeekdayPadding: false)
|
||||
|
||||
init(){
|
||||
UIPageControl.appearance().currentPageIndicatorTintColor = UIColor.label
|
||||
UIPageControl.appearance().pageIndicatorTintColor = UIColor.systemGray
|
||||
UITabBar.appearance().backgroundColor = UIColor.secondarySystemBackground
|
||||
}
|
||||
|
||||
@ObservedObject var viewModel = HomeViewViewModel(addMonthStartWeekdayPadding: false)
|
||||
|
||||
var body: some View {
|
||||
mainView
|
||||
.alert(ContentModeViewModel.updateTitleHeader(forEntry: selectedEntry),
|
||||
.alert(HomeViewViewModel.updateTitleHeader(forEntry: selectedEntry),
|
||||
isPresented: $showUpdateEntryAlert) {
|
||||
ForEach(Mood.allValues) { mood in
|
||||
Button(mood.strValue, action: {
|
||||
@@ -130,11 +128,12 @@ struct HomeView: View {
|
||||
VStack {
|
||||
SmallRollUpHeaderView(entries: getBackEntries(),
|
||||
viewType: $currentSelectedHeaderViewViewType)
|
||||
.frame(height: HomeViewConstants.minHeaderHeight)
|
||||
.padding([.trailing, .leading])
|
||||
.background(
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
theme.currentTheme.secondaryBGColor
|
||||
)
|
||||
.cornerRadius(10, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
.padding([.top, .bottom], 5)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
@@ -173,8 +172,6 @@ struct HomeView: View {
|
||||
withAnimation{
|
||||
viewModel.updateData()
|
||||
}
|
||||
}, updateBoardingDataClosure: { onboardingData in
|
||||
OnboardingDataDataManager.shared.updateOnboardingData(onboardingData: onboardingData)
|
||||
})
|
||||
}.padding(.trailing)
|
||||
}
|
||||
@@ -182,7 +179,7 @@ struct HomeView: View {
|
||||
|
||||
private var headerView: some View {
|
||||
VStack {
|
||||
if ShowBasedOnVoteLogics.isMissingCurrentVote() {
|
||||
if ShowBasedOnVoteLogics.isMissingCurrentVote(onboardingData: onboardingData.savedOnboardingData) {
|
||||
AddMoodHeaderView(addItemHeaderClosure: { (mood, date) in
|
||||
withAnimation {
|
||||
viewModel.add(mood: mood, forDate: date, entryType: .header)
|
||||
@@ -255,7 +252,7 @@ struct HomeView: View {
|
||||
)
|
||||
}
|
||||
.background(
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
theme.currentTheme.secondaryBGColor
|
||||
)
|
||||
.coordinateSpace(name: "scroll")
|
||||
.onPreferenceChange(ViewOffsetKey.self) { value in
|
||||
@@ -281,11 +278,11 @@ extension HomeView {
|
||||
private func SectionHeaderView(month: Int, year: Int) -> some View {
|
||||
Text("\(Random.monthName(fromMonthInt: month)) \(String(year))")
|
||||
.font(.title)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding()
|
||||
.background(
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
theme.currentTheme.secondaryBGColor
|
||||
)
|
||||
}
|
||||
|
||||
@@ -307,23 +304,23 @@ extension HomeView {
|
||||
|
||||
private func entryListView(entry: MoodEntry) -> some View {
|
||||
HStack {
|
||||
entry.mood.icon
|
||||
imagePack.icon(forMood: entry.mood)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 40, height: 40, alignment: .center)
|
||||
.foregroundColor(entry.mood.color)
|
||||
.foregroundColor(moodTint.color(forMood: entry.mood))
|
||||
.padding(.leading, 5)
|
||||
|
||||
VStack {
|
||||
HStack {
|
||||
Text(Random.weekdayName(fromDate:entry.forDate!))
|
||||
.font(.title3)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
Text(" - ")
|
||||
.padding([.leading, .trailing], -10)
|
||||
Text(Random.dayFormat(fromDate:entry.forDate!))
|
||||
.font(.title3)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
Spacer()
|
||||
}
|
||||
.multilineTextAlignment(.leading)
|
||||
170
Shared/views/HomeView/HomeViewTwo/HomeViewTwo.swift
Normal file
170
Shared/views/HomeView/HomeViewTwo/HomeViewTwo.swift
Normal file
@@ -0,0 +1,170 @@
|
||||
//
|
||||
// HomeViewTwo.swift
|
||||
// Feels (iOS)
|
||||
//
|
||||
// Created by Trey Tartt on 2/18/22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct HomeViewTwo: View {
|
||||
@AppStorage(UserDefaultsStore.Keys.needsOnboarding.rawValue, store: GroupUserDefaults.groupDefaults) private var needsOnboarding = true
|
||||
|
||||
@AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system
|
||||
@AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults) private var moodTint: MoodTints = .Default
|
||||
|
||||
@ObservedObject var viewModel = HomeViewViewModel(addMonthStartWeekdayPadding: true)
|
||||
|
||||
@StateObject private var selectedDetail = StupidAssDetailViewObservableObject()
|
||||
@State private var showingSheet = false
|
||||
@StateObject private var onboardingData = OnboardingDataDataManager.shared
|
||||
|
||||
class StupidAssDetailViewObservableObject: ObservableObject {
|
||||
@Published var fuckingWrapped: MonthDetailView? = nil
|
||||
@Published var showFuckingSheet = false
|
||||
}
|
||||
|
||||
let columns = [
|
||||
GridItem(.flexible(minimum: 5, maximum: 400)),
|
||||
GridItem(.flexible(minimum: 5, maximum: 400)),
|
||||
GridItem(.flexible(minimum: 5, maximum: 400)),
|
||||
GridItem(.flexible(minimum: 5, maximum: 400)),
|
||||
GridItem(.flexible(minimum: 5, maximum: 400)),
|
||||
GridItem(.flexible(minimum: 5, maximum: 400)),
|
||||
GridItem(.flexible(minimum: 5, maximum: 400))
|
||||
]
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
if viewModel.hasNoData {
|
||||
settingsButtonView
|
||||
VStack {
|
||||
Spacer()
|
||||
EmptyHomeView(viewModel: viewModel)
|
||||
.padding()
|
||||
Spacer()
|
||||
}
|
||||
} else {
|
||||
ScrollView {
|
||||
ZStack {
|
||||
topView
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.frame(height: 250)
|
||||
.background(
|
||||
.blue
|
||||
)
|
||||
settingsButtonView
|
||||
}
|
||||
LazyVStack(spacing: 5, pinnedViews: [.sectionHeaders]) {
|
||||
ForEach(viewModel.grouped.sorted(by: { $0.key > $1.key }), id: \.key) { year, months in
|
||||
|
||||
// for reach month
|
||||
ForEach(months.sorted(by: { $0.key > $1.key }), id: \.key) { month, entries in
|
||||
Section() {
|
||||
homeViewTwoMonthListView(month: month, year: year, entries: entries)
|
||||
}
|
||||
}
|
||||
.padding(.bottom)
|
||||
}
|
||||
.padding()
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 10)
|
||||
.foregroundColor(
|
||||
theme.currentTheme.secondaryBGColor
|
||||
)
|
||||
)
|
||||
}
|
||||
.padding([.leading, .trailing])
|
||||
}.sheet(isPresented: $selectedDetail.showFuckingSheet,
|
||||
onDismiss: didDismiss) {
|
||||
selectedDetail.fuckingWrapped
|
||||
}
|
||||
.edgesIgnoringSafeArea(.top)
|
||||
}
|
||||
}
|
||||
.background(
|
||||
theme.currentTheme.bg
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
func didDismiss() {
|
||||
selectedDetail.showFuckingSheet = false
|
||||
selectedDetail.fuckingWrapped = nil
|
||||
}
|
||||
}
|
||||
|
||||
extension HomeViewTwo {
|
||||
private var topView: some View {
|
||||
VStack {
|
||||
if ShowBasedOnVoteLogics.isMissingCurrentVote(onboardingData: onboardingData.savedOnboardingData) {
|
||||
Text("Vote")
|
||||
}
|
||||
Text("dis top")
|
||||
}
|
||||
}
|
||||
|
||||
private var settingsButtonView: some View {
|
||||
HStack {
|
||||
Spacer()
|
||||
VStack {
|
||||
Button(action: {
|
||||
showingSheet.toggle()
|
||||
}, label: {
|
||||
Image(systemName: "gear")
|
||||
.foregroundColor(Color(UIColor.darkGray))
|
||||
.font(.system(size: 20))
|
||||
}).sheet(isPresented: $showingSheet) {
|
||||
SettingsView(editedDataClosure: {
|
||||
withAnimation{
|
||||
viewModel.updateData()
|
||||
}
|
||||
})
|
||||
}
|
||||
.padding(.top, 60)
|
||||
.padding(.trailing)
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// view that make up the list body
|
||||
extension HomeViewTwo {
|
||||
private func homeViewTwoSectionHeaderView(month: Int, year: Int) -> some View {
|
||||
Text("\(Random.monthName(fromMonthInt: month)) \(String(year))")
|
||||
.font(.body)
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
|
||||
private func homeViewTwoMonthListView(month: Int, year: Int, entries: [MoodEntry]) -> some View {
|
||||
VStack {
|
||||
homeViewTwoSectionHeaderView(month: month, year: year)
|
||||
Divider()
|
||||
LazyVGrid(columns: columns, spacing: 15) {
|
||||
ForEach(entries, id: \.self) { entry in
|
||||
Circle()
|
||||
.foregroundColor(moodTint.color(forMood: entry.mood))
|
||||
.frame(minHeight: 5, idealHeight: 20, maxHeight: 50, alignment: .center)
|
||||
}
|
||||
}
|
||||
}
|
||||
.onTapGesture{
|
||||
let deailView = MonthDetailView(monthInt: month,
|
||||
yearInt: year,
|
||||
entries: entries,
|
||||
parentViewModel: viewModel)
|
||||
|
||||
selectedDetail.fuckingWrapped = deailView
|
||||
selectedDetail.showFuckingSheet = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct HomeViewTwo_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
HomeViewTwo()
|
||||
}
|
||||
}
|
||||
171
Shared/views/HomeView/HomeViewTwo/MonthDetailView.swift
Normal file
171
Shared/views/HomeView/HomeViewTwo/MonthDetailView.swift
Normal file
@@ -0,0 +1,171 @@
|
||||
//
|
||||
// MonthDetailView.swift
|
||||
// Feels (iOS)
|
||||
//
|
||||
// Created by Trey Tartt on 2/18/22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct MonthDetailView: View {
|
||||
@AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system
|
||||
@AppStorage(UserDefaultsStore.Keys.deleteEnable.rawValue, store: GroupUserDefaults.groupDefaults) private var deleteEnabled = true
|
||||
@AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults) private var moodTint: MoodTints = .Default
|
||||
|
||||
@State private var showingSheet = false
|
||||
@State private var selectedEntry: MoodEntry?
|
||||
@State private var showingUpdateEntryAlert = false
|
||||
@State private var showUpdateEntryAlert = false
|
||||
|
||||
let monthInt: Int
|
||||
let yearInt: Int
|
||||
@State var entries: [MoodEntry]
|
||||
var parentViewModel: HomeViewViewModel
|
||||
|
||||
let columns = [
|
||||
GridItem(.flexible(minimum: 5, maximum: 50)),
|
||||
GridItem(.flexible(minimum: 5, maximum: 50)),
|
||||
GridItem(.flexible(minimum: 5, maximum: 50)),
|
||||
GridItem(.flexible(minimum: 5, maximum: 50)),
|
||||
GridItem(.flexible(minimum: 5, maximum: 50)),
|
||||
GridItem(.flexible(minimum: 5, maximum: 50)),
|
||||
GridItem(.flexible(minimum: 5, maximum: 50))
|
||||
]
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Text("\(Random.monthName(fromMonthInt: monthInt)) \(String(yearInt))")
|
||||
.font(.title)
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding()
|
||||
.background(
|
||||
theme.currentTheme.secondaryBGColor
|
||||
)
|
||||
|
||||
createListView()
|
||||
.padding([.leading, .trailing])
|
||||
.background(
|
||||
theme.currentTheme.bg
|
||||
)
|
||||
|
||||
monthDetails
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.background(
|
||||
theme.currentTheme.secondaryBGColor
|
||||
)
|
||||
}
|
||||
.alert(HomeViewViewModel.updateTitleHeader(forEntry: selectedEntry),
|
||||
isPresented: $showUpdateEntryAlert) {
|
||||
ForEach(Mood.allValues) { mood in
|
||||
Button(mood.strValue, action: {
|
||||
if let selectedEntry = selectedEntry {
|
||||
PersistenceController.shared.update(entryDate: selectedEntry.forDate!, withModd: mood)
|
||||
}
|
||||
updateEntries()
|
||||
showUpdateEntryAlert = false
|
||||
selectedEntry = nil
|
||||
})
|
||||
}
|
||||
|
||||
if let selectedEntry = selectedEntry,
|
||||
deleteEnabled,
|
||||
selectedEntry.mood != .missing {
|
||||
Button(String(localized: "content_view_delete_entry"), action: {
|
||||
updateEntries()
|
||||
PersistenceController.shared.update(entryDate: selectedEntry.forDate!, withModd: .missing)
|
||||
showUpdateEntryAlert = false
|
||||
})
|
||||
}
|
||||
|
||||
Button(String(localized: "content_view_fill_in_missing_entry_cancel"), role: .cancel, action: {
|
||||
updateEntries()
|
||||
selectedEntry = nil
|
||||
showUpdateEntryAlert = false
|
||||
})
|
||||
}
|
||||
.background(
|
||||
theme.currentTheme.bg
|
||||
)
|
||||
}
|
||||
|
||||
private func createListView() -> some View {
|
||||
ScrollView {
|
||||
LazyVGrid(columns: columns, spacing: 25) {
|
||||
ForEach(entries, id: \.self) { entry in
|
||||
listViewEntry(forEntry: entry)
|
||||
.onTapGesture(perform: {
|
||||
if entry.canEdit {
|
||||
selectedEntry = entry
|
||||
showUpdateEntryAlert = true
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func listViewEntry(forEntry entry: MoodEntry) -> some View {
|
||||
VStack {
|
||||
if entry.mood == .placeholder {
|
||||
Text(" ")
|
||||
.font(.title3)
|
||||
.foregroundColor(Mood.placeholder.color)
|
||||
} else {
|
||||
Text(entry.forDate!,
|
||||
format: Date.FormatStyle().day())
|
||||
.font(.title3)
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
}
|
||||
|
||||
if entry.mood == .placeholder {
|
||||
Circle()
|
||||
.frame(minWidth: 5,
|
||||
maxWidth: 50,
|
||||
minHeight: 5,
|
||||
maxHeight: 50,
|
||||
alignment: .center)
|
||||
.foregroundColor(moodTint.color(forMood: entry.mood))
|
||||
} else {
|
||||
entry.mood.icon
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(minWidth: 5,
|
||||
maxWidth: 50,
|
||||
minHeight: 5,
|
||||
maxHeight: 50,
|
||||
alignment: .center)
|
||||
.foregroundColor(moodTint.color(forMood: entry.mood))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func updateEntries() {
|
||||
parentViewModel.updateData()
|
||||
let (startDate, endDate) = Date.dateRange(monthInt: monthInt, yearInt: yearInt)
|
||||
let updatedEntries = PersistenceController.shared.getData(startDate: startDate, endDate: endDate, includedDays: [1,2,3,4,5,6,7])
|
||||
let padded = MoodEntryFunctions.padMoodEntriesMonth(monthEntries: updatedEntries)
|
||||
entries = padded
|
||||
}
|
||||
|
||||
private var monthDetails: some View {
|
||||
VStack {
|
||||
SmallRollUpHeaderView(entries: entries,
|
||||
viewType: .constant(.total))
|
||||
|
||||
SmallRollUpHeaderView(entries: entries,
|
||||
viewType: .constant(.percentageCircle))
|
||||
.padding(.top, -20)
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
|
||||
struct MonthDetailView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
MonthDetailView(monthInt: 5, yearInt: 2022, entries:
|
||||
PersistenceController.shared.randomEntries(count: 30).sorted(by: {
|
||||
$0.forDate! < $1.forDate!
|
||||
}), parentViewModel: HomeViewViewModel(addMonthStartWeekdayPadding: true))
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
import SwiftUI
|
||||
import CoreData
|
||||
|
||||
class ContentModeViewModel: ObservableObject {
|
||||
class HomeViewViewModel: ObservableObject {
|
||||
@Published var grouped = [Int: [Int: [MoodEntry]]]()
|
||||
@Published var numberOfItems = 0
|
||||
|
||||
@@ -50,33 +50,7 @@ class ContentModeViewModel: ObservableObject {
|
||||
grouped = PersistenceController.shared.splitIntoYearMonth()
|
||||
|
||||
if addMonthStartWeekdayPadding {
|
||||
var newGrouped = [Int: [Int: [MoodEntry]]]()
|
||||
|
||||
let allYears = grouped.keys.sorted(by: > )
|
||||
for year in allYears {
|
||||
var newMonth = [Int: [MoodEntry]]()
|
||||
|
||||
let oldMonths = grouped[year]!
|
||||
let monthKeys = oldMonths.keys.sorted(by: > )
|
||||
for key in monthKeys {
|
||||
if let entries = oldMonths[key] {
|
||||
let sortedEntries = entries.sorted(by: { $0.forDate! < $1.forDate! })
|
||||
var mutableEntries = sortedEntries
|
||||
|
||||
if let firstDate = sortedEntries.first {
|
||||
let date = firstDate.forDate!
|
||||
let weekday = Int16(Calendar.current.component(.weekday, from: date))
|
||||
for _ in 1..<weekday {
|
||||
mutableEntries.insert(PersistenceController.shared.generateObjectNotInArray(), at: 0)
|
||||
}
|
||||
}
|
||||
|
||||
newMonth[key] = mutableEntries
|
||||
}
|
||||
newGrouped[year] = newMonth
|
||||
}
|
||||
}
|
||||
grouped = newGrouped
|
||||
grouped = MoodEntryFunctions.padMoodEntriesForCalendar(entries: grouped)
|
||||
}
|
||||
|
||||
numberOfItems = numberOfEntries
|
||||
@@ -1,110 +0,0 @@
|
||||
//
|
||||
// HomeViewTwo.swift
|
||||
// Feels (iOS)
|
||||
//
|
||||
// Created by Trey Tartt on 2/18/22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct HomeViewTwo: View {
|
||||
@AppStorage(UserDefaultsStore.Keys.needsOnboarding.rawValue, store: GroupUserDefaults.groupDefaults) private var needsOnboarding = true
|
||||
|
||||
@AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system
|
||||
|
||||
@ObservedObject var viewModel = ContentModeViewModel(addMonthStartWeekdayPadding: true)
|
||||
|
||||
@StateObject private var selectedDetail = StupidAssDetailViewObservableObject()
|
||||
|
||||
class StupidAssDetailViewObservableObject: ObservableObject {
|
||||
@Published var fuckingWrapped: MonthDetailView? = nil
|
||||
@Published var showFuckingSheet = false
|
||||
}
|
||||
|
||||
let columns = [
|
||||
GridItem(.flexible(minimum: 5, maximum: 400)),
|
||||
GridItem(.flexible(minimum: 5, maximum: 400)),
|
||||
GridItem(.flexible(minimum: 5, maximum: 400)),
|
||||
GridItem(.flexible(minimum: 5, maximum: 400)),
|
||||
GridItem(.flexible(minimum: 5, maximum: 400)),
|
||||
GridItem(.flexible(minimum: 5, maximum: 400)),
|
||||
GridItem(.flexible(minimum: 5, maximum: 400))
|
||||
]
|
||||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
topView
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.frame(height: 200)
|
||||
.background(
|
||||
.blue
|
||||
)
|
||||
LazyVStack(spacing: 5, pinnedViews: [.sectionHeaders]) {
|
||||
ForEach(viewModel.grouped.sorted(by: { $0.key > $1.key }), id: \.key) { year, months in
|
||||
|
||||
// for reach month
|
||||
ForEach(months.sorted(by: { $0.key > $1.key }), id: \.key) { month, entries in
|
||||
Section(header: homeViewTwoSectionHeaderView(month: month, year: year)) {
|
||||
homeViewTwoMonthListView(month: month, year: year, entries: entries)
|
||||
}
|
||||
.onTapGesture{
|
||||
let deailView = MonthDetailView(monthInt: month,
|
||||
yearInt: year,
|
||||
entries: entries)
|
||||
|
||||
selectedDetail.fuckingWrapped = deailView
|
||||
selectedDetail.showFuckingSheet = true
|
||||
}
|
||||
}
|
||||
.padding(.bottom)
|
||||
}
|
||||
}
|
||||
.padding([.leading, .trailing])
|
||||
}.sheet(isPresented: $selectedDetail.showFuckingSheet,
|
||||
onDismiss: didDismiss) {
|
||||
selectedDetail.fuckingWrapped
|
||||
}
|
||||
}
|
||||
|
||||
func didDismiss() {
|
||||
selectedDetail.showFuckingSheet = false
|
||||
selectedDetail.fuckingWrapped = nil
|
||||
}
|
||||
}
|
||||
|
||||
extension HomeViewTwo {
|
||||
private var topView: some View {
|
||||
HStack {
|
||||
Text("dis top")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// view that make up the list body
|
||||
extension HomeViewTwo {
|
||||
private func homeViewTwoSectionHeaderView(month: Int, year: Int) -> some View {
|
||||
Text("\(Random.monthName(fromMonthInt: month)) \(String(year))")
|
||||
.font(.body)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.background(
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
)
|
||||
}
|
||||
|
||||
private func homeViewTwoMonthListView(month: Int, year: Int, entries: [MoodEntry]) -> some View {
|
||||
LazyVGrid(columns: columns, spacing: 15) {
|
||||
ForEach(entries, id: \.self) { entry in
|
||||
Circle()
|
||||
.foregroundColor(entry.mood.color)
|
||||
.frame(minHeight: 5, idealHeight: 20, maxHeight: 50, alignment: .center)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct HomeViewTwo_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
HomeViewTwo()
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
//
|
||||
// MonthDetailView.swift
|
||||
// Feels (iOS)
|
||||
//
|
||||
// Created by Trey Tartt on 2/18/22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct MonthDetailView: View {
|
||||
@AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system
|
||||
@AppStorage(UserDefaultsStore.Keys.deleteEnable.rawValue, store: GroupUserDefaults.groupDefaults) private var deleteEnabled = true
|
||||
|
||||
@State private var showingUpdateEntryAlert = false
|
||||
|
||||
let monthInt: Int
|
||||
let yearInt: Int
|
||||
let entries: [MoodEntry]
|
||||
|
||||
lazy var dateFormatter: DateFormatter = {
|
||||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.dateFormat = "dd"
|
||||
return dateFormatter
|
||||
}()
|
||||
|
||||
let columns = [
|
||||
GridItem(.flexible(minimum: 5, maximum: 50)),
|
||||
GridItem(.flexible(minimum: 5, maximum: 50)),
|
||||
GridItem(.flexible(minimum: 5, maximum: 50)),
|
||||
GridItem(.flexible(minimum: 5, maximum: 50)),
|
||||
GridItem(.flexible(minimum: 5, maximum: 50)),
|
||||
GridItem(.flexible(minimum: 5, maximum: 50)),
|
||||
GridItem(.flexible(minimum: 5, maximum: 50))
|
||||
]
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Text("\(Random.monthName(fromMonthInt: monthInt)) \(String(yearInt))")
|
||||
.font(.title)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding()
|
||||
.background(
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
)
|
||||
|
||||
ScrollView {
|
||||
LazyVGrid(columns: columns, spacing: 25) {
|
||||
ForEach(entries, id: \.self) { entry in
|
||||
VStack {
|
||||
if entry.mood != .placeholder {
|
||||
Text(entry.forDate!,
|
||||
format: Date.FormatStyle().day())
|
||||
.font(.title3)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
|
||||
entry.mood.icon
|
||||
.resizable()
|
||||
.frame(minWidth: 5,
|
||||
maxWidth: 50,
|
||||
minHeight: 5,
|
||||
maxHeight: 50,
|
||||
alignment: .center)
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.foregroundColor(entry.mood.color)
|
||||
}
|
||||
}
|
||||
.alert(ContentModeViewModel.updateTitleHeader(forEntry: entry),
|
||||
isPresented: $showingUpdateEntryAlert) {
|
||||
ForEach(Mood.allValues) { mood in
|
||||
Button(mood.strValue, action: {
|
||||
PersistenceController.shared.update(entryDate: entry.forDate!, withModd: mood)
|
||||
// viewModel.update(entry: selectedEntry, toMood: mood)
|
||||
})
|
||||
}
|
||||
|
||||
if deleteEnabled,
|
||||
entry.mood != .missing {
|
||||
Button(String(localized: "content_view_delete_entry"), action: {
|
||||
PersistenceController.shared.update(entryDate: entry.forDate!, withModd: Mood.missing)
|
||||
// viewModel.update(entry: selectedEntry, toMood: Mood.missing)
|
||||
})
|
||||
}
|
||||
|
||||
Button(String(localized: "content_view_fill_in_missing_entry_cancel"), role: .cancel, action: {
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding([.leading, .trailing])
|
||||
|
||||
monthDetails
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.background(
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private var monthDetails: some View {
|
||||
VStack {
|
||||
SmallRollUpHeaderView(entries: entries,
|
||||
viewType: .constant(.total))
|
||||
|
||||
SmallRollUpHeaderView(entries: entries,
|
||||
viewType: .constant(.percentageCircle))
|
||||
.padding(.top, -20)
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
|
||||
struct MonthDetailView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
MonthDetailView(monthInt: 5, yearInt: 2022, entries:
|
||||
PersistenceController.shared.randomEntries(count: 30).sorted(by: {
|
||||
$0.forDate! < $1.forDate!
|
||||
}))
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ struct MainTabView: View {
|
||||
TabView {
|
||||
HomeViewTwo()
|
||||
.tabItem {
|
||||
Label(String(localized: "content_view_tab_main"), systemImage: "list.dash")
|
||||
Label(String(localized: "content_view_tab_main"), systemImage: "calendar")
|
||||
}
|
||||
|
||||
HomeView()
|
||||
@@ -26,13 +26,18 @@ struct MainTabView: View {
|
||||
|
||||
FilterView()
|
||||
.tabItem {
|
||||
Label(String(localized: "content_view_tab_filter"), systemImage: "calendar.circle")
|
||||
Label(String(localized: "content_view_tab_filter"), systemImage: "line.3.horizontal.decrease.circle")
|
||||
}
|
||||
|
||||
SharingListView()
|
||||
.tabItem {
|
||||
Label(String(localized: "content_view_tab_share"), systemImage: "square.and.arrow.up")
|
||||
}
|
||||
|
||||
CustomizeView()
|
||||
.tabItem {
|
||||
Label(String(localized: "content_view_tab_customize"), systemImage: "pencil")
|
||||
}
|
||||
}.sheet(isPresented: $needsOnboarding, onDismiss: {
|
||||
|
||||
}, content: {
|
||||
|
||||
@@ -12,13 +12,11 @@ struct SettingsView: View {
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
let editedDataClosure: (() -> Void)
|
||||
let updateBoardingDataClosure: ((OnboardingData) -> Void)
|
||||
|
||||
@State private var showOnboarding = false
|
||||
|
||||
@State private var showSpecialThanks = false
|
||||
@State private var showWhyBGMode = false
|
||||
@State private var showCreateCustomWidget = false
|
||||
@ObservedObject var syncMonitor = SyncMonitor.shared
|
||||
|
||||
@AppStorage(UserDefaultsStore.Keys.useCloudKit.rawValue, store: GroupUserDefaults.groupDefaults) private var useCloudKit = false
|
||||
@@ -34,9 +32,6 @@ struct SettingsView: View {
|
||||
|
||||
cloudKitEnable
|
||||
canDelete
|
||||
changeIcon
|
||||
themePicker
|
||||
createCustomWidget
|
||||
showOnboardingButton
|
||||
whyBackgroundMode
|
||||
specialThanksCell
|
||||
@@ -56,13 +51,10 @@ struct SettingsView: View {
|
||||
}.sheet(isPresented: $showOnboarding) {
|
||||
OnboardingMain(onboardingData: UserDefaultsStore.getOnboarding(),
|
||||
updateBoardingDataClosure: { onboardingData in
|
||||
updateBoardingDataClosure(onboardingData)
|
||||
OnboardingDataDataManager.shared.updateOnboardingData(onboardingData: onboardingData)
|
||||
showOnboarding = false
|
||||
})
|
||||
}
|
||||
.sheet(isPresented: $showCreateCustomWidget) {
|
||||
CreateIconView()
|
||||
}
|
||||
.background(
|
||||
theme.currentTheme.bg
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
@@ -84,7 +76,7 @@ struct SettingsView: View {
|
||||
|
||||
private var specialThanksCell: some View {
|
||||
ZStack {
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
theme.currentTheme.secondaryBGColor
|
||||
VStack {
|
||||
Button(action: {
|
||||
withAnimation{
|
||||
@@ -107,7 +99,7 @@ struct SettingsView: View {
|
||||
|
||||
private var addTestDataCell: some View {
|
||||
ZStack {
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
PersistenceController.shared.populateTestData()
|
||||
editedDataClosure()
|
||||
@@ -122,7 +114,7 @@ struct SettingsView: View {
|
||||
|
||||
private var clearDB: some View {
|
||||
ZStack {
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
PersistenceController.shared.clearDB()
|
||||
editedDataClosure()
|
||||
@@ -137,7 +129,7 @@ struct SettingsView: View {
|
||||
|
||||
private var whyBackgroundMode: some View {
|
||||
ZStack {
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
theme.currentTheme.secondaryBGColor
|
||||
VStack {
|
||||
Button(action: {
|
||||
withAnimation{
|
||||
@@ -157,51 +149,13 @@ struct SettingsView: View {
|
||||
.cornerRadius(10, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
let iconSets: [(String,String)] = [
|
||||
("PurpleFeelsAppIcon", "PurpleAppIcon"),
|
||||
("RedFeelsAppIcon", "RedAppIcon")
|
||||
]
|
||||
|
||||
|
||||
|
||||
private var changeIcon: some View {
|
||||
ZStack {
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
VStack {
|
||||
Text(String(localized: "settings_view_change_icon"))
|
||||
HStack {
|
||||
|
||||
Button(action: {
|
||||
UIApplication.shared.setAlternateIconName(nil)
|
||||
}, label: {
|
||||
Image("FeelsAppIcon", bundle: .main)
|
||||
.resizable()
|
||||
.frame(width: 50, height:50)
|
||||
.cornerRadius(10)
|
||||
})
|
||||
.padding()
|
||||
|
||||
ForEach(iconSets, id: \.self.0){ iconSet in
|
||||
Button(action: {
|
||||
UIApplication.shared.setAlternateIconName(iconSet.1) { (error) in
|
||||
// FIXME: Handle error
|
||||
}
|
||||
}, label: {
|
||||
Image(iconSet.0, bundle: .main)
|
||||
.resizable()
|
||||
.frame(width: 50, height:50)
|
||||
.cornerRadius(10)
|
||||
})
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(10, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var showOnboardingButton: some View {
|
||||
ZStack {
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
showOnboarding.toggle()
|
||||
}, label: {
|
||||
@@ -215,7 +169,7 @@ struct SettingsView: View {
|
||||
|
||||
private var cloudKitEnable: some View {
|
||||
ZStack {
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
theme.currentTheme.secondaryBGColor
|
||||
VStack {
|
||||
Toggle(String(localized: "settings_use_cloudkit_title"),
|
||||
isOn: $useCloudKit)
|
||||
@@ -233,7 +187,7 @@ struct SettingsView: View {
|
||||
|
||||
private var cloudKitStatus: some View {
|
||||
ZStack {
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
theme.currentTheme.secondaryBGColor
|
||||
VStack {
|
||||
Image(systemName: syncMonitor.syncStateSummary.symbolName)
|
||||
.foregroundColor(syncMonitor.syncStateSummary.symbolColor)
|
||||
@@ -247,7 +201,7 @@ struct SettingsView: View {
|
||||
|
||||
private var canDelete: some View {
|
||||
ZStack {
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
theme.currentTheme.secondaryBGColor
|
||||
VStack {
|
||||
Toggle(String(localized: "settings_use_delete_enable"),
|
||||
isOn: $deleteEnabled)
|
||||
@@ -257,65 +211,16 @@ struct SettingsView: View {
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(10, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var themePicker: some View {
|
||||
ZStack {
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
VStack {
|
||||
Text(String(localized: "settings_background_title"))
|
||||
HStack {
|
||||
Spacer()
|
||||
ForEach(Theme.allCases, id:\.rawValue) { aTheme in
|
||||
Button(action: {
|
||||
theme = aTheme
|
||||
}, label: {
|
||||
VStack {
|
||||
aTheme.currentTheme.preview
|
||||
.overlay(
|
||||
Circle()
|
||||
.stroke(Color(UIColor.systemGray), style: StrokeStyle(lineWidth: 2))
|
||||
)
|
||||
Text(aTheme.title)
|
||||
}
|
||||
})
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
.padding(.top)
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(10, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var createCustomWidget: some View {
|
||||
ZStack {
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
Button(action: {
|
||||
showCreateCustomWidget = true
|
||||
}, label: {
|
||||
Text("Create Custom Widget")
|
||||
})
|
||||
.padding()
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(10, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
}
|
||||
|
||||
struct SettingsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
SettingsView(editedDataClosure: {
|
||||
|
||||
}, updateBoardingDataClosure: { _ in
|
||||
|
||||
})
|
||||
|
||||
SettingsView(editedDataClosure: {
|
||||
|
||||
}, updateBoardingDataClosure: { _ in
|
||||
|
||||
})
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
@@ -71,13 +71,13 @@ struct SharingListView: View {
|
||||
//////////////////////////////////////////////////////////
|
||||
WrappedSharable(preview: AnyView(
|
||||
MonthTotalTemplate(isPreview: true,
|
||||
startDate: Date().startOfMonth(),
|
||||
endDate: Date().endOfMonth(),
|
||||
startDate: Date().startOfMonth,
|
||||
endDate: Date().endOfMonth,
|
||||
fakeData: false)
|
||||
), destination: AnyView(
|
||||
MonthTotalTemplate(isPreview: false,
|
||||
startDate: Date().startOfMonth(),
|
||||
endDate: Date().endOfMonth(),
|
||||
startDate: Date().startOfMonth,
|
||||
endDate: Date().endOfMonth,
|
||||
fakeData: false)
|
||||
), description: MonthTotalTemplate.description),
|
||||
//////////////////////////////////////////////////////////
|
||||
@@ -93,7 +93,7 @@ struct SharingListView: View {
|
||||
Text(String(format: String(localized: "Share your shit")))
|
||||
.font(.title)
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
.padding([.top, .leading])
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
@@ -104,7 +104,7 @@ struct SharingListView: View {
|
||||
selectedShare.showFuckingSheet = true
|
||||
}, label: {
|
||||
ZStack {
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
theme.currentTheme.secondaryBGColor
|
||||
|
||||
item.preview
|
||||
.frame(height: 88)
|
||||
@@ -113,7 +113,7 @@ struct SharingListView: View {
|
||||
Spacer()
|
||||
Text(item.description)
|
||||
.font(.title)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
.fontWeight(.bold)
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
.frame(height: 44)
|
||||
@@ -19,6 +19,8 @@ struct AllMoodsTotalTemplate: View, SharingTemplate {
|
||||
|
||||
@State var showSharingTemplate = false
|
||||
@Environment(\.presentationMode) var presentationMode
|
||||
@AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults) private var moodTint: MoodTints = .Default
|
||||
@AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system
|
||||
|
||||
private var entries = [MoodMetrics]()
|
||||
|
||||
@@ -41,16 +43,7 @@ struct AllMoodsTotalTemplate: View, SharingTemplate {
|
||||
totalEntryCount = moodEntries?.count ?? 0
|
||||
|
||||
if let moodEntries = moodEntries {
|
||||
for (_, mood) in Mood.allValues.enumerated() {
|
||||
|
||||
let moodEntries = moodEntries.filter({
|
||||
Int($0.moodValue) == mood.rawValue
|
||||
})
|
||||
let total = moodEntries.count
|
||||
let perc = (Float(total) / Float(totalEntryCount)) * 100
|
||||
entries.append(MoodMetrics(mood: mood, total: total, percent: perc))
|
||||
}
|
||||
|
||||
entries = Random.createTotalPerc(fromEntries: moodEntries)
|
||||
entries = entries.sorted(by: {
|
||||
$0.percent > $1.percent
|
||||
})
|
||||
@@ -78,7 +71,7 @@ struct AllMoodsTotalTemplate: View, SharingTemplate {
|
||||
mood.icon
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.foregroundColor(mood.color)
|
||||
.foregroundColor(moodTint.color(forMood: mood))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +79,7 @@ struct AllMoodsTotalTemplate: View, SharingTemplate {
|
||||
HStack {
|
||||
ForEach(entries.prefix(2), id: \.mood) { model in
|
||||
ZStack {
|
||||
Circle().fill(model.mood.color)
|
||||
Circle().fill(moodTint.color(forMood: model.mood))
|
||||
|
||||
Text("\(model.percent, specifier: "%.0f")%")
|
||||
.font(.title)
|
||||
@@ -104,7 +97,7 @@ struct AllMoodsTotalTemplate: View, SharingTemplate {
|
||||
HStack {
|
||||
ForEach(entries.suffix(3), id: \.mood) { model in
|
||||
ZStack {
|
||||
Circle().fill(model.mood.color)
|
||||
Circle().fill(moodTint.color(forMood: model.mood))
|
||||
|
||||
Text("\(model.percent, specifier: "%.0f")%")
|
||||
.font(.title)
|
||||
@@ -124,7 +117,7 @@ struct AllMoodsTotalTemplate: View, SharingTemplate {
|
||||
HStack {
|
||||
ForEach(entries, id: \.mood) { model in
|
||||
ZStack {
|
||||
Circle().fill(model.mood.color)
|
||||
Circle().fill(moodTint.color(forMood: model.mood))
|
||||
|
||||
Text("\(model.total)")
|
||||
.font(.title)
|
||||
@@ -144,7 +137,7 @@ struct AllMoodsTotalTemplate: View, SharingTemplate {
|
||||
VStack {
|
||||
Text(String(format: String(localized: "share_view_all_moods_total_template_title"), totalEntryCount))
|
||||
.font(.title)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.padding()
|
||||
|
||||
@@ -203,7 +196,7 @@ struct AllMoodsTotalTemplate: View, SharingTemplate {
|
||||
.padding([.leading, .trailing], -20)
|
||||
} else {
|
||||
mainView
|
||||
.padding([.leading, .trailing])
|
||||
.padding([.leading, .trailing, .top])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@ struct CurrentStreakTemplate: View, SharingTemplate {
|
||||
|
||||
@State var showSharingTemplate = false
|
||||
@Environment(\.presentationMode) var presentationMode
|
||||
|
||||
@AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults) private var moodTint: MoodTints = .Default
|
||||
@AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system
|
||||
|
||||
let columns = [
|
||||
GridItem(.flexible(minimum: 5, maximum: .infinity), alignment: .center),
|
||||
@@ -60,7 +61,7 @@ struct CurrentStreakTemplate: View, SharingTemplate {
|
||||
entry.mood.icon
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.foregroundColor(entry.mood.color)
|
||||
.foregroundColor(moodTint.color(forMood: entry.mood))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,7 +73,7 @@ struct CurrentStreakTemplate: View, SharingTemplate {
|
||||
VStack {
|
||||
Text(String(format: String(localized: "share_view_current_streak_template_title")))
|
||||
.font(.title)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.padding(.top)
|
||||
|
||||
@@ -83,7 +84,7 @@ struct CurrentStreakTemplate: View, SharingTemplate {
|
||||
entry.mood.icon
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.foregroundColor(entry.mood.color)
|
||||
.foregroundColor(moodTint.color(forMood: entry.mood))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,7 +142,8 @@ struct CurrentStreakTemplate: View, SharingTemplate {
|
||||
.padding([.leading, .trailing], -20)
|
||||
} else {
|
||||
mainView
|
||||
.padding([.leading, .trailing])
|
||||
.padding([.leading, .trailing, .top])
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,8 @@ struct LongestStreakTemplate: View, SharingTemplate {
|
||||
|
||||
@State var showSharingTemplate = false
|
||||
@Environment(\.presentationMode) var presentationMode
|
||||
|
||||
@AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults) private var moodTint: MoodTints = .Default
|
||||
@AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system
|
||||
|
||||
let columns = [
|
||||
GridItem(.flexible(minimum: 5, maximum: .infinity), alignment: .center),
|
||||
@@ -96,7 +97,7 @@ struct LongestStreakTemplate: View, SharingTemplate {
|
||||
entry.mood.icon
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.foregroundColor(entry.mood.color)
|
||||
.foregroundColor(moodTint.color(forMood: entry.mood))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,26 +113,26 @@ struct LongestStreakTemplate: View, SharingTemplate {
|
||||
VStack {
|
||||
Text(String(format: String(localized: "share_view_longest_streak_template_title"), self.selectedMood.strValue))
|
||||
.font(.title)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.padding()
|
||||
|
||||
HStack {
|
||||
Text(self.moodEntries.first?.forDate ?? Date(), formatter: itemFormatter)
|
||||
.font(.title)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.padding(.top, 1)
|
||||
|
||||
Text("-")
|
||||
.font(.title)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.padding(.top, 1)
|
||||
|
||||
Text(self.moodEntries.last?.forDate ?? Date(), formatter: itemFormatter)
|
||||
.font(.title)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.padding(.top, 1)
|
||||
}
|
||||
@@ -144,7 +145,7 @@ struct LongestStreakTemplate: View, SharingTemplate {
|
||||
entry.mood.icon
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.foregroundColor(entry.mood.color)
|
||||
.foregroundColor(moodTint.color(forMood: entry.mood))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -224,7 +225,8 @@ struct LongestStreakTemplate: View, SharingTemplate {
|
||||
.padding([.leading, .trailing], -20)
|
||||
} else {
|
||||
mainView
|
||||
.padding([.leading, .trailing])
|
||||
.padding([.leading, .trailing, .top])
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ struct MonthTotalTemplate: View, SharingTemplate {
|
||||
|
||||
@State var showSharingTemplate = false
|
||||
@Environment(\.presentationMode) var presentationMode
|
||||
@AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults) private var moodTint: MoodTints = .Default
|
||||
@AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system
|
||||
|
||||
private var moodMetrics = [MoodMetrics]()
|
||||
private var moodEntries = [MoodEntry]()
|
||||
@@ -59,16 +61,7 @@ struct MonthTotalTemplate: View, SharingTemplate {
|
||||
moodEntries = _moodEntries ?? [MoodEntry]()
|
||||
|
||||
totalEntryCount = moodEntries.count
|
||||
|
||||
for (_, mood) in Mood.allValues.enumerated() {
|
||||
let moodEntries = moodEntries.filter({
|
||||
Int($0.moodValue) == mood.rawValue
|
||||
})
|
||||
let total = moodEntries.count
|
||||
let perc = (Float(total) / Float(totalEntryCount)) * 100
|
||||
moodMetrics.append(MoodMetrics(mood: mood, total: total, percent: perc))
|
||||
}
|
||||
|
||||
moodMetrics = Random.createTotalPerc(fromEntries: moodEntries)
|
||||
moodMetrics = moodMetrics.sorted(by: {
|
||||
$0.mood.rawValue > $1.mood.rawValue
|
||||
})
|
||||
@@ -89,7 +82,7 @@ struct MonthTotalTemplate: View, SharingTemplate {
|
||||
HStack {
|
||||
ForEach(moodMetrics, id: \.mood) { model in
|
||||
ZStack {
|
||||
Circle().fill(model.mood.color)
|
||||
Circle().fill(moodTint.color(forMood: model.mood))
|
||||
|
||||
Text("\(model.percent, specifier: "%.0f")%")
|
||||
.font(.title)
|
||||
@@ -109,7 +102,7 @@ struct MonthTotalTemplate: View, SharingTemplate {
|
||||
VStack {
|
||||
Text(String(format: String(localized: "share_view_month_moods_total_template_title"), Random.monthName(fromMonthInt: month), moodEntries.count))
|
||||
.font(.title)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
.foregroundColor(theme.currentTheme.labelColor)
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.padding()
|
||||
|
||||
@@ -119,7 +112,7 @@ struct MonthTotalTemplate: View, SharingTemplate {
|
||||
entry.mood.icon
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.foregroundColor(entry.mood.color)
|
||||
.foregroundColor(moodTint.color(forMood: entry.mood))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -179,15 +172,15 @@ struct MonthTotalTemplate: View, SharingTemplate {
|
||||
.padding([.leading, .trailing], -20)
|
||||
} else {
|
||||
mainView
|
||||
.padding([.leading, .trailing])
|
||||
.padding([.leading, .trailing, .top])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MonthTotalTemplate_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
MonthTotalTemplate(isPreview: true, startDate: Date().startOfMonth(), endDate: Date().endOfMonth(), fakeData: true)
|
||||
MonthTotalTemplate(isPreview: true, startDate: Date().startOfMonth, endDate: Date().endOfMonth, fakeData: true)
|
||||
|
||||
MonthTotalTemplate(isPreview: false, startDate: Date().startOfMonth(), endDate: Date().endOfMonth(), fakeData: true)
|
||||
MonthTotalTemplate(isPreview: false, startDate: Date().startOfMonth, endDate: Date().endOfMonth, fakeData: true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,10 @@ import SwiftUI
|
||||
|
||||
struct SmallRollUpHeaderView: View {
|
||||
@Binding var viewType: MainSwitchableViewType
|
||||
|
||||
@AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults) private var moodTint: MoodTints = .Default
|
||||
|
||||
let entries: [MoodEntry]
|
||||
private var moodMetrics = [MoodGroupingMetrics]()
|
||||
private var moodMetrics = [MoodMetrics]()
|
||||
|
||||
init(entries: [MoodEntry], viewType: Binding<MainSwitchableViewType>) {
|
||||
self.entries = entries
|
||||
@@ -20,7 +21,7 @@ struct SmallRollUpHeaderView: View {
|
||||
moodMetrics = Random.createTotalPerc(fromEntries: entries)
|
||||
}
|
||||
|
||||
private func textView(forModel model: MoodGroupingMetrics) -> Text {
|
||||
private func textView(forModel model: MoodMetrics) -> Text {
|
||||
switch viewType {
|
||||
case .total:
|
||||
return Text(String(model.total))
|
||||
@@ -32,24 +33,25 @@ struct SmallRollUpHeaderView: View {
|
||||
}
|
||||
|
||||
private var textViews: some View {
|
||||
HStack {
|
||||
ForEach(moodMetrics, id: \.0) { model in
|
||||
HStack() {
|
||||
ForEach(moodMetrics, id: \.id) { model in
|
||||
textView(forModel: model)
|
||||
.font(.title2)
|
||||
.fontWeight(.bold)
|
||||
.lineLimit(1)
|
||||
.foregroundColor(model.mood.color)
|
||||
.frame(width: 70, height: 70)
|
||||
.foregroundColor(moodTint.color(forMood: model.mood))
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding([.top, .bottom])
|
||||
}
|
||||
|
||||
private var circularViews: some View {
|
||||
HStack {
|
||||
ForEach(moodMetrics, id: \.0) { model in
|
||||
ForEach(moodMetrics, id: \.id) { model in
|
||||
ZStack {
|
||||
Circle().fill(model.mood.color)
|
||||
Circle().fill(moodTint.color(forMood: model.mood))
|
||||
.frame(minWidth: 5,
|
||||
maxWidth: 70,
|
||||
minHeight: 5,
|
||||
@@ -60,9 +62,9 @@ struct SmallRollUpHeaderView: View {
|
||||
.font(.title3)
|
||||
.fontWeight(.bold)
|
||||
.lineLimit(1)
|
||||
.clipShape(ContainerRelativeShape()).padding()
|
||||
.clipShape(ContainerRelativeShape())
|
||||
.foregroundColor(Color(UIColor.white))
|
||||
.minimumScaleFactor(0.1)
|
||||
.minimumScaleFactor(0.7)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -94,8 +96,13 @@ struct SmallHeaderView_Previews: PreviewProvider {
|
||||
viewType: .constant(.total))
|
||||
|
||||
SmallRollUpHeaderView(entries: PersistenceController.shared.randomEntries(count: 10),
|
||||
viewType: .constant(.total))
|
||||
.frame(height: 20)
|
||||
viewType: .constant(.percentageCircle))
|
||||
.background(.gray)
|
||||
|
||||
SmallRollUpHeaderView(entries: PersistenceController.shared.randomEntries(count: 10),
|
||||
viewType: .constant(.percentage))
|
||||
|
||||
.background(.gray)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,8 @@ struct SwitchableView: View {
|
||||
let daysBack: Int
|
||||
|
||||
@AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system
|
||||
|
||||
@AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults) private var moodTint: MoodTints = .Default
|
||||
|
||||
init(daysBack: Int, viewType: Binding<MainSwitchableViewType>, headerTypeChanged: @escaping ((MainSwitchableViewType) -> Void)) {
|
||||
self.daysBack = daysBack
|
||||
self.headerTypeChanged = headerTypeChanged
|
||||
@@ -40,7 +41,7 @@ struct SwitchableView: View {
|
||||
ZStack {
|
||||
switch viewType {
|
||||
case .total:
|
||||
HeaderStatsView(fakeData: false, backDays: daysBack)
|
||||
HeaderStatsView(fakeData: false, backDays: daysBack, moodTint: moodTint)
|
||||
.padding([.leading, .trailing], -15)
|
||||
.padding([.top, .bottom], 8)
|
||||
.allowsHitTesting(false)
|
||||
@@ -75,7 +76,7 @@ struct SwitchableView: View {
|
||||
.padding(.top, -12)
|
||||
}
|
||||
.background(
|
||||
Color(theme.currentTheme.secondaryBGColor)
|
||||
theme.currentTheme.secondaryBGColor
|
||||
)
|
||||
.contentShape(Rectangle())
|
||||
.cornerRadius(10, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
"content_view_tab_main" = "Main";
|
||||
"content_view_tab_filter" = "Filter";
|
||||
"content_view_tab_share" = "Share";
|
||||
"content_view_tab_customize" = "Customize";
|
||||
"content_view_fill_in_missing_entry" = "Update %@";
|
||||
"content_view_fill_in_missing_entry_cancel" = "Cancel";
|
||||
"content_view_delete_entry" = "Delete this entry";
|
||||
@@ -70,3 +71,5 @@
|
||||
"share_view_month_moods_total_template_title" = "Total Entries for %@ - %d";
|
||||
"share_view_current_streak_template_title" = "Last 10 Days";
|
||||
"share_view_longest_streak_template_title" = "Longest consecutive days I was %@";
|
||||
|
||||
"customize_view_title" = "Make ifeel yours!!!";
|
||||
|
||||
Reference in New Issue
Block a user