This commit is contained in:
Trey t
2025-12-09 23:37:04 -06:00
parent 3a10b4b8d6
commit f2565678be
1587 changed files with 7747 additions and 647 deletions

View File

@@ -0,0 +1,31 @@
//
// DaysFilterClass.swift
// Feels
//
// Created by Trey Tartt on 3/31/22.
//
import SwiftUI
class DaysFilterClass: ObservableObject {
static let shared = DaysFilterClass()
@Published public var currentFilters = [Int]()
init() {
let storedDays = UserDefaultsStore.getDaysFilter()
currentFilters = storedDays
}
func addFilter(newFilter: Int) {
currentFilters.append(newFilter)
currentFilters = UserDefaultsStore.saveDaysFilter(days: currentFilters)
}
func removeFilter(filter: Int) {
if let index = currentFilters.firstIndex(of: filter) {
currentFilters.remove(at: index)
}
currentFilters = UserDefaultsStore.saveDaysFilter(days: currentFilters)
}
}

View File

@@ -0,0 +1,31 @@
//
// DiamondView.swift
// Feels
//
// Created by Trey Tartt on 3/20/22.
//
import SwiftUI
struct Diamond:Shape {
func path(in rect: CGRect) -> Path {
var path = Path()
// get the center of the rect
let center = CGPoint(x: rect.midX, y: rect.midY)
// get the starting of our drawing the right side of our diamond
let startingPoint = CGPoint(x: rect.maxX, y: center.y)
// move our start of drawing to the beggining point
path.move(to: startingPoint)
// distance / 2 is our height
// create all our points
let secondPoint = CGPoint(x: center.x, y: rect.maxY)
let thirdPoint = CGPoint(x: rect.minX , y: center.y)
let fourthPoint = CGPoint(x: center.x, y: rect.minY)
path.addLine(to: secondPoint)
path.addLine(to: thirdPoint)
path.addLine(to: fourthPoint)
path.addLine(to: startingPoint)
return path
}
}

87
Shared/Models/Mood.swift Normal file
View File

@@ -0,0 +1,87 @@
//
// Mood.swift
// Feels
//
// Created by Trey Tartt on 1/5/22.
//
import Foundation
import SwiftUI
enum Mood: Int {
case horrible
case bad
case average
case good
case great
case missing
case placeholder
var next: Mood {
var moodValue = self.rawValue
moodValue -= 1
if moodValue < 0 {
moodValue = 4
}
return Mood.init(rawValue: moodValue) ?? Mood.horrible
}
var strValue: String {
switch self {
case .horrible:
return String(localized: "mood_value_horrible")
case .bad:
return String(localized: "mood_value_bad")
case .average:
return String(localized: "mood_value_average")
case .good:
return String(localized: "mood_value_good")
case .great:
return String(localized: "mood_value_great")
case .missing:
return String(localized: "mood_value_missing")
case .placeholder:
return String("placeholder")
}
}
var color: Color {
let moodTint: MoodTintable.Type = UserDefaultsStore.moodTintable()
return moodTint.color(forMood: self)
}
static var allValues: [Mood] {
return [Mood.horrible, Mood.bad, Mood.average, Mood.good, Mood.great].reversed()
}
var icon: Image {
let moodImages: MoodImagable.Type = UserDefaultsStore.moodMoodImagable()
return moodImages.icon(forMood: self)
}
var graphic: Image {
switch self {
case .horrible:
return Image("HorribleGraphic", bundle: .main)
case .bad:
return Image("BadGraphic", bundle: .main)
case .average:
return Image("AverageGraphic", bundle: .main)
case .good:
return Image("GoodGraphic", bundle: .main)
case .great:
return Image("GreatGraphic", bundle: .main)
case .missing:
return Image("MissingGraphic", bundle: .main)
case .placeholder:
return Image("MissingGraphic", bundle: .main)
}
}
}
extension Mood: Identifiable {
var id: Int {
rawValue
}
}

View File

@@ -0,0 +1,26 @@
//
// MoodEntryExtension.swift
// Feels
//
// Created by Trey Tartt on 1/5/22.
//
import Foundation
enum EntryType: Int {
case notification
case header
case listView
case filledInMissing
case widget
}
extension MoodEntry {
var moodString: String {
return Mood.init(rawValue: Int(self.moodValue))?.strValue ?? "NA"
}
var mood: Mood {
return Mood.init(rawValue: Int(self.moodValue))!
}
}

View 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("xmark-solid", bundle: .main)
case .placeholder:
return Image("xmark-solid", 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("xmark-solid", bundle: .main)
case .placeholder:
return Image("xmark-solid", bundle: .main)
}
}
}
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("xmark-solid", bundle: .main)
case .placeholder:
return Image("xmark-solid", bundle: .main)
}
}
}

View File

@@ -0,0 +1,15 @@
//
// MoodMetrics.swift
// Feels
//
// Created by Trey Tartt on 2/12/22.
//
import Foundation
struct MoodMetrics: Identifiable {
let id = UUID()
let mood: Mood
let total: Int
let percent: Float
}

View File

@@ -0,0 +1,347 @@
//
// MoodTintable.swift
// Feels (iOS)
//
// Created by Trey Tartt on 2/19/22.
//
import SwiftUI
struct DefaultTextColor {
static var textColor: Color {
Color(UIColor.label)
}
}
protocol MoodTintable {
static func color(forMood mood: Mood) -> Color
static func secondary(forMood mood: Mood) -> Color
}
enum MoodTints: Int, CaseIterable {
case Default
case Neon
case Pastel
case Custom
static var defaultOptions: [MoodTints] {
return [Default, Neon, Pastel]
}
func color(forMood mood: Mood) -> Color {
switch self {
case .Default:
return DefaultMoodTint.color(forMood: mood)
case .Custom:
return CustomMoodTint.color(forMood: mood)
case .Neon:
return NeonMoodTint.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 .Custom:
return CustomMoodTint.secondary(forMood: mood)
case .Neon:
return NeonMoodTint.secondary(forMood: mood)
case .Pastel:
return PastelTint.secondary(forMood: mood)
}
}
var moodTints: MoodTintable.Type {
switch self {
case .Default:
return DefaultMoodTint.self
case .Custom:
return CustomMoodTint.self
case .Neon:
return NeonMoodTint.self
case .Pastel:
return PastelTint.self
}
}
}
final class SavedMoodTint: NSObject, ObservableObject, Codable {
@Published var colorOne: Color
@Published var colorTwo: Color
@Published var colorThree: Color
@Published var colorFour: Color
@Published var colorFive: Color
override init() {
colorOne = Color(hex: "a92b26")
colorTwo = Color(hex: "a92b26")
colorThree = Color(hex: "a92b26")
colorFour = Color(hex: "a92b26")
colorFive = Color(hex: "a92b26")
}
enum CodingKeys: CodingKey {
case colorOne, colorTwo, colorThree, colorFour, colorFive
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
colorOne = try container.decode(Color.self, forKey: .colorOne)
colorTwo = try container.decode(Color.self, forKey: .colorTwo)
colorThree = try container.decode(Color.self, forKey: .colorThree)
colorFour = try container.decode(Color.self, forKey: .colorFour)
colorFive = try container.decode(Color.self, forKey: .colorFive)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(colorOne, forKey: .colorOne)
try container.encode(colorTwo, forKey: .colorTwo)
try container.encode(colorThree, forKey: .colorThree)
try container.encode(colorFour, forKey: .colorFour)
try container.encode(colorFive, forKey: .colorFive)
}
}
final class CustomMoodTint: MoodTintable {
static func color(forMood mood: Mood) -> Color {
switch mood {
case .horrible:
return UserDefaultsStore.getCustomMoodTint().colorFive
case .bad:
return UserDefaultsStore.getCustomMoodTint().colorFour
case .average:
return UserDefaultsStore.getCustomMoodTint().colorThree
case .good:
return UserDefaultsStore.getCustomMoodTint().colorTwo
case .great:
return UserDefaultsStore.getCustomMoodTint().colorOne
case .missing:
return Color(uiColor: UIColor.lightGray)
case .placeholder:
return Color(uiColor: UIColor.lightGray)
}
}
static func secondary(forMood mood: Mood) -> Color {
switch mood {
case .horrible:
return UserDefaultsStore.getCustomMoodTint().colorFive.darker(by: 40)
case .bad:
return UserDefaultsStore.getCustomMoodTint().colorFour.darker(by: 40)
case .average:
return UserDefaultsStore.getCustomMoodTint().colorThree.darker(by: 40)
case .good:
return UserDefaultsStore.getCustomMoodTint().colorTwo.darker(by: 40)
case .great:
return UserDefaultsStore.getCustomMoodTint().colorOne.darker(by: 40)
case .missing:
return Color(uiColor: UIColor.lightGray).darker(by: 40)
case .placeholder:
return Color(uiColor: UIColor.lightGray).darker(by: 40)
}
}
}
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.systemGray2)
case .placeholder:
return Color(uiColor: UIColor.systemGray2)
}
}
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 Color(hex: "#000000")
case .bad:
return Color(hex: "#47474a")
case .average:
return Color(hex: "#7b7b81")
case .good:
return Color(hex: "#a3a3ab")
case .great:
return Color(hex: "#c2c1cb")
case .missing:
return Color(hex: "#ff0000")
case .placeholder:
return Color(hex: "#efeffb")
}
}
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.systemGray2)
}
}
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.label)
case .placeholder:
return Color(uiColor: UIColor.label)
}
}
}

View File

@@ -0,0 +1,20 @@
//
// OnboardingDataDataManager.swift
// Feels (iOS)
//
// Created by Trey Tartt on 2/18/22.
//
import Foundation
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)
}
}

View File

@@ -0,0 +1,108 @@
//
// NotificationTitles.swift
// Feels (iOS)
//
// Created by Trey Tartt on 2/19/22.
//
import Foundation
protocol PersonalityPackable {
static var notificationTitles: [String] { get }
static var notificationBodyToday: [String] { get }
static var notificationBodyYesterday: [String] { get }
static var title: String { get }
}
enum PersonalityPack: Int, CaseIterable {
case Default
case Rude
func randomPushNotificationStrings() -> (title: String, body: String) {
let onboarding = UserDefaultsStore.getOnboarding()
switch (self, onboarding.inputDay) {
case (.Default, .Today):
return (DefaultTitles.notificationTitles.randomElement()!,
DefaultTitles.notificationBodyToday.randomElement()!)
case (.Default, .Previous):
return (DefaultTitles.notificationTitles.randomElement()!,
DefaultTitles.notificationBodyYesterday.randomElement()!)
case (.Rude, .Today):
return (RudeTitles.notificationTitles.randomElement()!,
RudeTitles.notificationBodyToday.randomElement()!)
case (.Rude, .Previous):
return (RudeTitles.notificationTitles.randomElement()!,
RudeTitles.notificationBodyYesterday.randomElement()!)
}
}
func title() -> String {
switch self {
case .Default:
return DefaultTitles.title
case .Rude:
return RudeTitles.title
}
}
}
final class DefaultTitles: PersonalityPackable {
static var title = String(localized: "nice")
static var notificationTitles: [String] {
[
String(localized: "default_notif_title_one"),
String(localized: "default_notif_title_two"),
String(localized: "default_notif_title_three")
]
}
static var notificationBodyToday: [String] {
[
String(localized: "default_notif_body_today_one"),
String(localized: "default_notif_body_today_two"),
String(localized: "default_notif_body_today_three"),
String(localized: "default_notif_body_today_four")
]
}
static var notificationBodyYesterday: [String] {
[
String(localized: "default_notif_body_yesterday_one"),
String(localized: "default_notif_body_yesterday_two"),
String(localized: "default_notif_body_yesterday_three"),
String(localized: "default_notif_body_yesterday_four")
]
}
}
final class RudeTitles: PersonalityPackable {
static var title = String(localized: "rude")
static var notificationTitles: [String] {
[
String(localized: "rude_notif_title_one"),
String(localized: "rude_notif_title_two"),
String(localized: "rude_notif_title_three"),
String(localized: "rude_notif_title_four")
]
}
static var notificationBodyToday: [String] {
[
String(localized: "rude_notif_body_today_one"),
String(localized: "rude_notif_body_today_two"),
String(localized: "rude_notif_body_today_three")
]
}
static var notificationBodyYesterday: [String] {
[
String(localized: "rude_notif_body_yesterday_one"),
String(localized: "rude_notif_body_yesterday_two"),
String(localized: "rude_notif_body_yesterday_three")
]
}
}

View File

@@ -0,0 +1,95 @@
//
// Shapes.swift
// Feels
//
// Created by Trey Tartt on 3/20/22.
//
import SwiftUI
enum BGShape: Int, CaseIterable {
case circle
case diamond
case rectangle
case roundedRectangle
func view(withText text: Text, bgColor: Color, textColor: Color) -> some View{
return AnyView(
ZStack {
switch self {
case .circle:
Circle()
.fill(bgColor)
.frame(minWidth: 5,
maxWidth: 500,
minHeight: 5,
maxHeight: 500,
alignment: .center)
.overlay(
text
.font(.title2)
.fontWeight(.bold)
.lineLimit(1)
.foregroundColor(textColor)
.minimumScaleFactor(0.2)
.padding(10)
.frame(maxWidth: .infinity, alignment: .center)
)
case .diamond:
Diamond()
.fill(bgColor)
.frame(minWidth: 5,
maxWidth: 500,
minHeight: 5,
maxHeight: 500)
.aspectRatio(contentMode: .fit)
.overlay(
text
.font(.title2)
.fontWeight(.bold)
.lineLimit(1)
.foregroundColor(textColor)
.minimumScaleFactor(0.2)
.padding(10)
.frame(maxWidth: .infinity, alignment: .center)
)
case .rectangle:
Rectangle()
.fill(bgColor)
.frame(minWidth: 5,
maxWidth: 500,
minHeight: 5,
maxHeight: 500,
alignment: .center)
.overlay(
text
.font(.title2)
.fontWeight(.bold)
.lineLimit(1)
.foregroundColor(textColor)
.minimumScaleFactor(0.2)
.padding(10)
.frame(maxWidth: .infinity, alignment: .center)
)
case .roundedRectangle:
RoundedRectangle(cornerRadius: 8, style: .continuous)
.fill(bgColor)
.frame(minWidth: 5,
maxWidth: 500,
minHeight: 5,
maxHeight: 500,
alignment: .center)
.overlay(
text
.font(.title2)
.fontWeight(.bold)
.lineLimit(1)
.foregroundColor(textColor)
.minimumScaleFactor(0.2)
.padding(10)
.frame(maxWidth: .infinity, alignment: .center)
)
}
})
}
}

View File

@@ -0,0 +1,59 @@
//
// SharingImageModels.swift
// Feels
//
// Created by Trey Tartt on 2/24/22.
//
import SwiftUI
import LinkPresentation
class StupidAssShareObservableObject: ObservableObject {
@Published var fuckingWrappedShrable: UIImage? = nil
@Published var showFuckingSheet = false
}
class ShareActivityItemSource: NSObject, UIActivityItemSource {
var shareText: String
var shareImage: UIImage
var linkMetaData = LPLinkMetadata()
init(shareText: String, shareImage: UIImage) {
self.shareText = shareText
self.shareImage = shareImage
linkMetaData.title = shareText
super.init()
}
func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
return UIImage(named: "AppIcon") as Any
}
func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
return nil
}
func activityViewControllerLinkMetadata(_ activityViewController: UIActivityViewController) -> LPLinkMetadata? {
return linkMetaData
}
}
struct ShareSheet: UIViewControllerRepresentable {
let photo: UIImage
func makeUIViewController(context: Context) -> UIActivityViewController {
let text = "ifeel"
let itemSource = ShareActivityItemSource(shareText: text, shareImage: photo)
let activityItems: [Any] = [photo, text, itemSource]
let controller = UIActivityViewController(
activityItems: activityItems,
applicationActivities: nil)
return controller
}
func updateUIViewController(_ vc: UIActivityViewController, context: Context) {
}
}

View File

@@ -0,0 +1,13 @@
//
// StupidAssCustomWidgetObservableObject.swift
// Feels
//
// Created by Trey Tartt on 3/31/22.
//
import Foundation
class StupidAssCustomWidgetObservableObject: ObservableObject {
@Published var fuckingWrapped: CustomWidgetModel? = nil
@Published var showFuckingSheet = false
}

203
Shared/Models/Theme.swift Normal file
View File

@@ -0,0 +1,203 @@
//
// theme.currentTheme.swift
// Feels (iOS)
//
// Created by Trey Tartt on 2/4/22.
//
import SwiftUI
struct ThemeConstants {
static let iconSize: CGFloat = 50
}
enum Theme: Int, CaseIterable {
case system
case iFeel
case dark
case light
var title: String {
switch self {
case .system:
return SystemTheme.title
case .iFeel:
return IFeelTheme.title
case .dark:
return AlwaysDark.title
case .light:
return AlwaysLight.title
}
}
var currentTheme: Themeable {
switch self {
case .system:
return SystemTheme()
case .iFeel:
return IFeelTheme()
case .dark:
return AlwaysDark()
case .light:
return AlwaysLight()
}
}
}
protocol Themeable {
static var title: String { get }
var secondaryBGColor: Color { get }
var bgColor: Color { get }
var bg: AnyView { get }
var preview: AnyView { get }
var labelColor: Color { get }
}
struct IFeelTheme: Themeable {
var bgColor: Color {
return Color(uiColor: UIColor.systemBackground)
}
var labelColor: Color {
return Color(uiColor: UIColor.label)
}
static var title: String {
return "iFeel"
}
var secondaryBGColor: Color {
return Color(uiColor: UIColor.secondarySystemBackground)
}
var bg: AnyView {
return AnyView(
BGView().equatable()
)
}
var preview: AnyView {
return AnyView(
ZStack {
BGView().equatable()
.frame(width: ThemeConstants.iconSize, height: ThemeConstants.iconSize)
.clipShape(RoundedRectangle(cornerRadius: 25, style: .continuous))
}
)
}
}
struct SystemTheme: Themeable {
var bgColor: Color {
return Color(uiColor: UIColor.systemBackground)
}
var labelColor: Color {
return Color(uiColor: UIColor.label)
}
static var title: String {
return "System"
}
var secondaryBGColor: Color {
return Color(uiColor: UIColor.secondarySystemBackground)
}
var bg: AnyView {
return AnyView(
ZStack {
Rectangle()
.fill(Color(UIColor.systemBackground))
}
)
}
var preview: AnyView {
return AnyView(
ZStack {
Rectangle()
.fill(Color(UIColor.secondarySystemBackground))
.frame(width: ThemeConstants.iconSize, height: ThemeConstants.iconSize)
.clipShape(RoundedRectangle(cornerRadius: 25, style: .continuous))
}
)
}
}
struct AlwaysDark: Themeable {
var bgColor: Color {
return Color(uiColor: UIColor.systemBackground.resolvedColor(with: .init(userInterfaceStyle: .dark)))
}
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 bgColor: Color {
return Color(uiColor: UIColor.systemBackground)
}
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))
}
)
}
}

View File

@@ -0,0 +1,233 @@
//
// UserDefaultsStore.swift
// Feels (iOS)
//
// Created by Trey Tartt on 1/22/22.
//
import Foundation
class UserDefaultsStore {
enum Keys: String {
case savedOnboardingData
case needsOnboarding
case useCloudKit
case deleteEnable
case mainViewTopHeaderIndex
case theme
case moodImages
case moodTint
case personalityPack
case customWidget
case customMoodTint
case customMoodTintUpdateNumber
case textColor
case showNSFW
case shape
case daysFilter
case firstLaunchDate
case hasActiveSubscription
case lastVotedDate
case contentViewCurrentSelectedHeaderViewBackDays
case contentViewHeaderTag
case contentViewHeaderTagViewOneViewType
case contentViewHeaderTagViewTwoViewType
case currentSelectedHeaderViewViewType
}
static func getOnboarding() -> OnboardingData {
if let data = GroupUserDefaults.groupDefaults.object(forKey: UserDefaultsStore.Keys.savedOnboardingData.rawValue) as? Data,
let model = try? JSONDecoder().decode(OnboardingData.self, from: data) {
return model
} else {
return OnboardingData()
}
}
static func saveOnboarding(onboardingData: OnboardingData) -> OnboardingData {
do {
let data = try JSONEncoder().encode(onboardingData)
GroupUserDefaults.groupDefaults.set(data, forKey: UserDefaultsStore.Keys.savedOnboardingData.rawValue)
return UserDefaultsStore.getOnboarding()
} catch {
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
}
}
static func getCustomWidgets() -> [CustomWidgetModel] {
if let data = GroupUserDefaults.groupDefaults.object(forKey: UserDefaultsStore.Keys.customWidget.rawValue) as? Data,
let model = try? JSONDecoder().decode([CustomWidgetModel].self, from: data) {
return model
} else {
GroupUserDefaults.groupDefaults.removeObject(forKey: UserDefaultsStore.Keys.customWidget.rawValue)
let widget = CustomWidgetModel.randomWidget
widget.isSaved = true
let widgets = [widget]
let data = try! JSONEncoder().encode(widgets)
GroupUserDefaults.groupDefaults.set(data, forKey: UserDefaultsStore.Keys.customWidget.rawValue)
if let data = GroupUserDefaults.groupDefaults.object(forKey: UserDefaultsStore.Keys.customWidget.rawValue) as? Data,
let models = try? JSONDecoder().decode([CustomWidgetModel].self, from: data) {
let sorted = models.sorted(by: {
$0.createdDate < $1.createdDate
})
return sorted
} else {
fatalError("error getting widgets")
}
}
}
@discardableResult
static func saveCustomWidget(widgetModel: CustomWidgetModel, inUse: Bool) -> [CustomWidgetModel] {
do {
var existingWidgets = getCustomWidgets()
if let exisitingWidget = existingWidgets.firstIndex(where: {
$0.uuid == widgetModel.uuid
}) {
existingWidgets.remove(at: exisitingWidget)
// give it differnet uuid so the view updates
widgetModel.uuid = UUID().uuidString
}
if inUse {
existingWidgets.forEach({
$0.inUse = false
})
widgetModel.inUse = true
}
existingWidgets.append(widgetModel)
existingWidgets.forEach({
$0.isSaved = true
})
let data = try JSONEncoder().encode(existingWidgets)
GroupUserDefaults.groupDefaults.set(data, forKey: UserDefaultsStore.Keys.customWidget.rawValue)
return UserDefaultsStore.getCustomWidgets()
} catch {
fatalError("error saving")
}
}
@discardableResult
static func deleteCustomWidget(withUUID uuid: String) -> [CustomWidgetModel] {
do {
var existingWidgets = getCustomWidgets()
if let exisitingWidget = existingWidgets.firstIndex(where: {
$0.uuid == uuid
}) {
existingWidgets.remove(at: exisitingWidget)
}
if existingWidgets.count == 0 {
let widget = CustomWidgetModel.randomWidget
widget.isSaved = true
widget.inUse = true
existingWidgets.append(widget)
}
if let _ = existingWidgets.first(where: {
$0.inUse == true
}) {} else {
if let first = existingWidgets.first {
first.inUse = true
}
}
let data = try JSONEncoder().encode(existingWidgets)
GroupUserDefaults.groupDefaults.set(data, forKey: UserDefaultsStore.Keys.customWidget.rawValue)
return UserDefaultsStore.getCustomWidgets()
} catch {
fatalError("error saving")
}
}
static func getCustomMoodTint() -> SavedMoodTint {
if let data = GroupUserDefaults.groupDefaults.object(forKey: UserDefaultsStore.Keys.customMoodTint.rawValue) as? Data{
do {
let model = try JSONDecoder().decode(SavedMoodTint.self, from: data)
return model
} catch {
print(error)
}
}
return SavedMoodTint()
}
static func getCustomBGShape() -> BGShape {
if let data = GroupUserDefaults.groupDefaults.object(forKey: UserDefaultsStore.Keys.shape.rawValue) as? Int,
let model = BGShape.init(rawValue: data) {
return model
} else {
return BGShape.circle
}
}
@discardableResult
static func saveCustomMoodTint(customTint: SavedMoodTint) -> SavedMoodTint {
do {
let data = try JSONEncoder().encode(customTint)
GroupUserDefaults.groupDefaults.set(data, forKey: UserDefaultsStore.Keys.customMoodTint.rawValue)
return UserDefaultsStore.getCustomMoodTint()
} catch {
print(error)
fatalError("error saving")
}
}
@discardableResult
static func saveDaysFilter(days: [Int]) -> [Int] {
GroupUserDefaults.groupDefaults.set(days, forKey: UserDefaultsStore.Keys.daysFilter.rawValue)
return UserDefaultsStore.getDaysFilter()
}
static func getDaysFilter() -> [Int] {
if let data = GroupUserDefaults.groupDefaults.object(forKey: UserDefaultsStore.Keys.daysFilter.rawValue) as? [Int] {
return data
} else {
return [1,2,3,4,5,6,7]
}
}
}