everything changed
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
147
Shared/views/CustomWidget/CustomWidgetModel.swift
Normal file
147
Shared/views/CustomWidget/CustomWidgetModel.swift
Normal file
@@ -0,0 +1,147 @@
|
||||
//
|
||||
// CustomIcon.swift
|
||||
// Feels (iOS)
|
||||
//
|
||||
// Created by Trey Tartt on 2/13/22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
class CustomWidgetModel: ObservableObject {
|
||||
static let numberOfBGItems = 109
|
||||
|
||||
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: CustomWidgetEyeOptions,
|
||||
rightEye: CustomWidgetEyeOptions,
|
||||
mouth: CustomWidgetMouthOptions,
|
||||
background: [(CustomWidgetBackGroundOptions, UUID)],
|
||||
bgColor: Color,
|
||||
innerColor: Color,
|
||||
bgOverlayColor: Color,
|
||||
rightEyeColor: Color,
|
||||
leftEyeColor: Color,
|
||||
mouthColor: Color,
|
||||
circleStrokeColor: Color
|
||||
) {
|
||||
self.leftEye = leftEye
|
||||
self.rightEye = rightEye
|
||||
self.mouth = mouth
|
||||
self.background = background
|
||||
self.bgColor = bgColor
|
||||
self.innerColor = innerColor
|
||||
self.bgOverlayColor = bgOverlayColor
|
||||
self.rightEyeColor = rightEyeColor
|
||||
self.leftEyeColor = leftEyeColor
|
||||
self.mouthColor = mouthColor
|
||||
self.circleStrokeColor = circleStrokeColor
|
||||
}
|
||||
|
||||
@Published var leftEye: CustomWidgetEyeOptions
|
||||
@Published var rightEye: CustomWidgetEyeOptions
|
||||
@Published var mouth: CustomWidgetMouthOptions
|
||||
|
||||
@Published var background: [(CustomWidgetBackGroundOptions, UUID)]
|
||||
@Published var bgColor: Color
|
||||
@Published var innerColor: Color
|
||||
@Published var bgOverlayColor: Color
|
||||
|
||||
@Published var leftEyeColor: Color
|
||||
@Published var rightEyeColor: Color
|
||||
@Published var mouthColor: Color
|
||||
|
||||
@Published var circleStrokeColor: Color
|
||||
}
|
||||
|
||||
enum CustomWidgetBackGroundOptions: String, CaseIterable, Codable {
|
||||
case horrible
|
||||
case bad
|
||||
case average
|
||||
case good
|
||||
case great
|
||||
case random
|
||||
|
||||
static var selectable: [CustomWidgetBackGroundOptions] {
|
||||
return [.great, .good, .average, .bad, .horrible]
|
||||
}
|
||||
|
||||
static public var defaultOption: CustomWidgetBackGroundOptions {
|
||||
CustomWidgetBackGroundOptions.random
|
||||
}
|
||||
|
||||
public var image: Image {
|
||||
return Image(self.rawValue, bundle: .main)
|
||||
}
|
||||
}
|
||||
|
||||
enum CustomWidgetEyes: String, Codable {
|
||||
case left
|
||||
case right
|
||||
}
|
||||
|
||||
enum CustomWidgetEyeOptions: String, CaseIterable, Codable {
|
||||
case fire = "fire"
|
||||
case bolt = "bolt2"
|
||||
case dollar = "dollar"
|
||||
case bell = "bell"
|
||||
case btc = "btc"
|
||||
case code = "code"
|
||||
case crown = "crown"
|
||||
case divide = "divide"
|
||||
case exclamation = "exclamation"
|
||||
case fan = "fan"
|
||||
case floppy = "floppy"
|
||||
case x = "x"
|
||||
case skull = "skull"
|
||||
case covid = "covid"
|
||||
case bomb = "bomb"
|
||||
case skull2 = "skull2"
|
||||
case poo = "poo"
|
||||
|
||||
static public var defaultOption: CustomWidgetEyeOptions {
|
||||
CustomWidgetEyeOptions.fire
|
||||
}
|
||||
|
||||
public var image: Image {
|
||||
return Image(self.rawValue, bundle: .main)
|
||||
}
|
||||
}
|
||||
|
||||
enum CustomWidgetMouthOptions: String, CaseIterable, Codable {
|
||||
case fire = "fire"
|
||||
case bolt = "bolt2"
|
||||
case dollar = "dollar"
|
||||
case bell = "bell"
|
||||
case btc = "btc"
|
||||
case code = "code"
|
||||
case crown = "crown"
|
||||
case divide = "divide"
|
||||
case exclamation = "exclamation"
|
||||
case fan = "fan"
|
||||
case floppy = "floppy"
|
||||
case x = "x"
|
||||
case skull = "skull"
|
||||
case covid = "covid"
|
||||
case bomb = "bomb"
|
||||
case skull2 = "skull2"
|
||||
case poo = "poo"
|
||||
|
||||
static public var defaultOption: CustomWidgetMouthOptions {
|
||||
CustomWidgetMouthOptions.bomb
|
||||
}
|
||||
|
||||
public var image: Image {
|
||||
return Image(self.rawValue, bundle: .main)
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
33
Shared/views/DayChartView.swift
Normal file
33
Shared/views/DayChartView.swift
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// CircleView.swift
|
||||
// Feels (iOS)
|
||||
//
|
||||
// Created by Trey Tartt on 1/13/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
struct DayChartView: ChartViewItemBuildable, View, Hashable {
|
||||
var color: Color
|
||||
var weekDay: Int
|
||||
var viewType: ViewType
|
||||
|
||||
var body: some View {
|
||||
switch viewType {
|
||||
case .cicle:
|
||||
Circle()
|
||||
.fill(color)
|
||||
.frame(minWidth: 5, idealWidth: 50, maxWidth: 50, minHeight: 5, idealHeight: 20, maxHeight: 50, alignment: .center)
|
||||
.opacity(color == Mood.missing.color ? 0.5 : 1.0)
|
||||
case .square:
|
||||
Rectangle()
|
||||
.fill(color)
|
||||
.frame(minWidth: 5, idealWidth: 50, maxWidth: 50, minHeight: 5, idealHeight: 20, maxHeight: 50, alignment: .center)
|
||||
case .text(let value):
|
||||
Text(value)
|
||||
.font(.footnote)
|
||||
.frame(minWidth: 5, idealWidth: 50, maxWidth: 50, minHeight: 5, idealHeight: 20, maxHeight: 50, alignment: .center)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
46
Shared/views/FilterView/FilterViewModel.swift
Normal file
46
Shared/views/FilterView/FilterViewModel.swift
Normal file
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// FilterViewModel.swift
|
||||
// Feels
|
||||
//
|
||||
// Created by Trey Tartt on 1/17/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class FilterViewModel: ObservableObject {
|
||||
@Published public var entryStartDate: Date = Date()
|
||||
@Published public var entryEndDate: Date = Date()
|
||||
@Published var selectedDays = [Int]()
|
||||
|
||||
// year, month, items
|
||||
@Published public private(set) var data = [Int: [Int: [DayChartView]]]()
|
||||
@Published public private(set) var numberOfRatings: Int = 0
|
||||
public private(set) var uncategorizedData = [MoodEntry]() {
|
||||
didSet {
|
||||
self.numberOfRatings = uncategorizedData.count
|
||||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
let filteredEntries = PersistenceController.shared.getData(startDate: Date(timeIntervalSince1970: 0),
|
||||
endDate: Date(),
|
||||
includedDays: selectedDays)
|
||||
|
||||
if let fuckingDAte = filteredEntries.sorted(by: { $0.forDate! < $1.forDate! }).first?.forDate {
|
||||
self.entryStartDate = fuckingDAte
|
||||
}
|
||||
self.entryEndDate = Date()
|
||||
}
|
||||
|
||||
private let chartViewBuilder = DayChartViewChartBuilder()
|
||||
|
||||
public func filterEntries(startDate: Date, endDate: Date) {
|
||||
let filteredEntries = PersistenceController.shared.getData(startDate: startDate,
|
||||
endDate: endDate,
|
||||
includedDays: selectedDays)
|
||||
data.removeAll()
|
||||
let filledOutData = chartViewBuilder.buildGridData(withData: filteredEntries)
|
||||
data = filledOutData
|
||||
uncategorizedData = filteredEntries
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
127
Shared/views/HomeView/HomeViewViewModel.swift
Normal file
127
Shared/views/HomeView/HomeViewViewModel.swift
Normal file
@@ -0,0 +1,127 @@
|
||||
//
|
||||
// ContentModeViewModel.swift
|
||||
// Feels (iOS)
|
||||
//
|
||||
// Created by Trey Tartt on 1/20/22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import CoreData
|
||||
|
||||
class HomeViewViewModel: ObservableObject {
|
||||
@Published var grouped = [Int: [Int: [MoodEntry]]]()
|
||||
@Published var numberOfItems = 0
|
||||
|
||||
let addMonthStartWeekdayPadding: Bool
|
||||
|
||||
var hasNoData: Bool {
|
||||
grouped.isEmpty
|
||||
}
|
||||
|
||||
private var numberOfEntries: Int {
|
||||
var num = 0
|
||||
grouped.keys.forEach({
|
||||
let year = grouped[$0]
|
||||
let monthKeys = year?.keys
|
||||
monthKeys?.forEach({
|
||||
num += year![$0]!.count
|
||||
})
|
||||
})
|
||||
return num
|
||||
|
||||
// grouped.keys.map{
|
||||
// grouped[$0]!.values.reduce(0) { sum, array in
|
||||
// sum + array.count
|
||||
// }
|
||||
// }.reduce(0, +)
|
||||
}
|
||||
|
||||
init(addMonthStartWeekdayPadding: Bool) {
|
||||
self.addMonthStartWeekdayPadding = addMonthStartWeekdayPadding
|
||||
|
||||
PersistenceController.shared.switchContainerListeners.append {
|
||||
self.getGroupedData(addMonthStartWeekdayPadding: self.addMonthStartWeekdayPadding)
|
||||
|
||||
}
|
||||
updateData()
|
||||
}
|
||||
|
||||
private func getGroupedData(addMonthStartWeekdayPadding: Bool) {
|
||||
grouped = PersistenceController.shared.splitIntoYearMonth()
|
||||
|
||||
if addMonthStartWeekdayPadding {
|
||||
grouped = MoodEntryFunctions.padMoodEntriesForCalendar(entries: grouped)
|
||||
}
|
||||
|
||||
numberOfItems = numberOfEntries
|
||||
}
|
||||
|
||||
|
||||
|
||||
public func updateData() {
|
||||
getGroupedData(addMonthStartWeekdayPadding: self.addMonthStartWeekdayPadding)
|
||||
}
|
||||
|
||||
public func add(mood: Mood, forDate date: Date, entryType: EntryType) {
|
||||
PersistenceController.shared.add(mood: mood, forDate: date, entryType: entryType)
|
||||
updateData()
|
||||
}
|
||||
|
||||
public func update(entry: MoodEntry, toMood mood: Mood) {
|
||||
if PersistenceController.shared.update(entryDate: entry.forDate!, withModd: mood) {
|
||||
updateData()
|
||||
}
|
||||
}
|
||||
|
||||
public func delete(offsets: IndexSet, inMonth month: Int, inYear year: Int) {
|
||||
if let monthEntries = grouped[year],
|
||||
let entries = monthEntries[month] {
|
||||
var mutableEntries = entries.sorted(by: {
|
||||
$0.forDate! > $1.forDate!
|
||||
})
|
||||
var entriesToDelete = [MoodEntry]()
|
||||
for idx in offsets {
|
||||
let obj = mutableEntries.remove(at: idx)
|
||||
entriesToDelete.append(obj)
|
||||
}
|
||||
entriesToDelete.forEach({ entry in
|
||||
let entryDate = entry.forDate!
|
||||
PersistenceController.shared.viewContext.delete(entry)
|
||||
self.add(mood: .missing, forDate: entryDate, entryType: .listView)
|
||||
})
|
||||
}
|
||||
|
||||
do {
|
||||
try PersistenceController.shared.viewContext.save()
|
||||
updateData()
|
||||
} catch {
|
||||
// Replace this implementation with code to handle the error appropriately.
|
||||
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
|
||||
let nsError = error as NSError
|
||||
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
|
||||
}
|
||||
}
|
||||
|
||||
static func updateTitleHeader(forEntry entry: MoodEntry?) -> String {
|
||||
guard let entry = entry else {
|
||||
return ""
|
||||
}
|
||||
|
||||
guard let forDate = entry.forDate else {
|
||||
return ""
|
||||
}
|
||||
|
||||
let components = Calendar.current.dateComponents([.day, .month, .year], from: forDate)
|
||||
// let day = components.day!
|
||||
let month = components.month!
|
||||
let year = components.year!
|
||||
|
||||
let monthName = Random.monthName(fromMonthInt: month)
|
||||
let weekday = Random.weekdayName(fromDate:entry.forDate!)
|
||||
let dayz = Random.dayFormat(fromDate:entry.forDate!)
|
||||
|
||||
let string = weekday + " " + monthName + " " + dayz + " " + String(year)
|
||||
|
||||
return String(format: String(localized: "content_view_fill_in_missing_entry"), string)
|
||||
}
|
||||
}
|
||||
@@ -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])
|
||||
|
||||
Reference in New Issue
Block a user