diff --git a/Tickmate/Tickmate/Controllers/TrackController.swift b/Tickmate/Tickmate/Controllers/TrackController.swift index 28d725b..9e7ea0e 100644 --- a/Tickmate/Tickmate/Controllers/TrackController.swift +++ b/Tickmate/Tickmate/Controllers/TrackController.swift @@ -201,18 +201,39 @@ class TrackController: NSObject, ObservableObject { return (weekday, dateFormatter.string(from: date)) } - func weekend(day: Int) -> Bool { + func isWeekEnd(day: Int) -> Bool { // The Swift % operator doesn't calculate // the modulo from negative numbers, // so we're adding 7 and %ing again. (weekday - day % 7 + 7) % 7 + 1 == weekStartDay } + private func isWeekStart(day: Int) -> Bool { + (weekday - day % 7 + 6) % 7 + 1 == weekStartDay + } + func insets(day: Int) -> Edge.Set? { - weekend(day: day) - ? .bottom - : (weekday - day % 7 + 6) % 7 + 1 == weekStartDay - ? .top : nil + let todayAtTop = UserDefaults(suiteName: groupID)?.bool(forKey: Defaults.todayAtTop.rawValue) ?? false + var after: Edge.Set { todayAtTop ? .top : .bottom } + var before: Edge.Set { todayAtTop ? .bottom : .top } + + if isWeekEnd(day: day) { + return after + } else if isWeekStart(day: day) { + return before + } else { + return .none + } + } + + func shouldShowSeparatorBelow(day: Int) -> Bool { + let todayAtTop = UserDefaults(suiteName: groupID)?.bool(forKey: Defaults.todayAtTop.rawValue) ?? false + + if todayAtTop { + return isWeekStart(day: day) + } else { + return isWeekEnd(day: day) + } } //MARK: Track CRUD @@ -300,7 +321,7 @@ class TrackController: NSObject, ObservableObject { } } - // TODO: Update this to instead save _now_, but prevent a second save from happening for 5 seconds (or whatever interval) + // TODO: Update this and the below to instead save _now_, but prevent a second save from happening for 5 seconds (or whatever interval) /// Schedule a Core Data save on the current view context. /// /// Call this function when you want to save a small change when other small changes may happen soon after. diff --git a/Tickmate/Tickmate/Model/Defaults.swift b/Tickmate/Tickmate/Model/Defaults.swift index f5b4d02..7288dad 100644 --- a/Tickmate/Tickmate/Model/Defaults.swift +++ b/Tickmate/Tickmate/Model/Defaults.swift @@ -2,7 +2,7 @@ // Defaults.swift // Tickmate // -// Created by Isaac Lyons on 3/9/21. +// Created by Elaine Lyons on 3/9/21. // import Foundation @@ -23,4 +23,5 @@ enum Defaults: String { case appGroupDatabaseMigration // Bool case userDefaultsMigration // Bool App Group case lastUpdateTime // String App Group + case todayAtTop // Bool App Group } diff --git a/Tickmate/Tickmate/TickmateApp.swift b/Tickmate/Tickmate/TickmateApp.swift index 7fb4974..5f1a9df 100644 --- a/Tickmate/Tickmate/TickmateApp.swift +++ b/Tickmate/Tickmate/TickmateApp.swift @@ -2,7 +2,7 @@ // TickmateApp.swift // Tickmate // -// Created by Isaac Lyons on 2/19/21. +// Created by Elaine Lyons on 2/19/21. // import SwiftUI diff --git a/Tickmate/Tickmate/Views/SettingsView.swift b/Tickmate/Tickmate/Views/SettingsView.swift index 9bfdfe9..51e4834 100644 --- a/Tickmate/Tickmate/Views/SettingsView.swift +++ b/Tickmate/Tickmate/Views/SettingsView.swift @@ -17,6 +17,9 @@ struct SettingsView: View { @AppStorage(Defaults.weekStartDay.rawValue, store: UserDefaults(suiteName: groupID)) private var weekStartDay = 2 + @AppStorage(Defaults.todayAtTop.rawValue, store: UserDefaults(suiteName: groupID)) + private var todayAtTop = false + @AppStorage(Defaults.weekSeparatorSpaces.rawValue) private var weekSeparatorSpaces: Bool = true @AppStorage(Defaults.weekSeparatorLines.rawValue) private var weekSeparatorLines: Bool = true @AppStorage(Defaults.relativeDates.rawValue) private var relativeDates = true @@ -50,6 +53,15 @@ struct SettingsView: View { } } + Section { + Picker("Put today at the", selection: $todayAtTop) { + Text("top") + .tag(true) + Text("bottom") + .tag(false) + } + } + Section { Toggle(isOn: $relativeDates) { TextWithCaption(text: "Use relative dates", caption: "Today, Yesterday") @@ -167,6 +179,9 @@ struct SettingsView: View { } .onChange(of: customDayStart, perform: updateCustomDayStart) .onChange(of: timeOffset, perform: updateCustomDayStart) + .onChange(of: todayAtTop) { _ in + trackController.scheduleTimelineRefresh() + } .onChange(of: weekStartDay) { value in trackController.weekStartDay = value } diff --git a/Tickmate/Tickmate/Views/TickView.swift b/Tickmate/Tickmate/Views/TickView.swift index 53a3d3e..25cf022 100644 --- a/Tickmate/Tickmate/Views/TickView.swift +++ b/Tickmate/Tickmate/Views/TickView.swift @@ -34,8 +34,8 @@ struct DayRow: View where C.Element == Track { } @ViewBuilder - private var backgroud: some View { - if lines && trackController.weekend(day: day) { + private var background: some View { + if lines && trackController.shouldShowSeparatorBelow(day: day) { VStack { Spacer() Capsule() @@ -70,7 +70,7 @@ struct DayRow: View where C.Element == Track { .opacity(0) } } - .listRowBackground(backgroud) + .listRowBackground(background) .id(day) } } diff --git a/Tickmate/Tickmate/Views/TicksView.swift b/Tickmate/Tickmate/Views/TicksView.swift index 4bfaba2..08b7288 100644 --- a/Tickmate/Tickmate/Views/TicksView.swift +++ b/Tickmate/Tickmate/Views/TicksView.swift @@ -22,6 +22,8 @@ struct TicksView: View { fetchRequest.wrappedValue } + @AppStorage(Defaults.todayAtTop.rawValue, store: UserDefaults(suiteName: groupID)) + private var todayAtTop = false @AppStorage(Defaults.weekSeparatorLines.rawValue) private var weekSeparatorLines: Bool = true @AppStorage(Defaults.weekSeparatorSpaces.rawValue) private var weekSeparatorSpaces: Bool = true @@ -122,24 +124,31 @@ struct TicksView: View { ScrollViewReader { proxy in List { - Button("Go to bottom") { - proxy.scrollTo(0) + if !todayAtTop { + Button("Go to bottom") { + proxy.scrollTo(0) + } } - ForEach(0..<365) { dayComplement in - DayRow(364 - dayComplement, tracks: tracks, spaces: weekSeparatorSpaces, lines: weekSeparatorLines) - .listRowInsets(.init(top: 4, leading: 0, bottom: 4, trailing: 0)) - #if os(iOS) - .padding(.horizontal) - #endif + ForEach(0..<365) { row in + DayRow( + todayAtTop ? row : 364 - row, + tracks: tracks, + spaces: weekSeparatorSpaces, + lines: weekSeparatorLines + ) + .listRowInsets(.init(top: 4, leading: 0, bottom: 4, trailing: 0)) + #if os(iOS) + .padding(.horizontal) + #endif } } .listStyle(PlainListStyle()) .introspect(.list, on: .iOS(.v14, .v15)) { tableView in - tableView.scrollsToTop = false + tableView.scrollsToTop = todayAtTop } .introspect(.list, on: .iOS(.v16, .v17)) { collectionView in - collectionView.scrollsToTop = false + collectionView.scrollsToTop = todayAtTop } .padding(0) .onAppear { diff --git a/Tickmate/TicksWidget/TicksWidget.swift b/Tickmate/TicksWidget/TicksWidget.swift index 216c66c..72cf7f2 100644 --- a/Tickmate/TicksWidget/TicksWidget.swift +++ b/Tickmate/TicksWidget/TicksWidget.swift @@ -172,6 +172,9 @@ struct TicksWidgetEntryView : View { @Environment(\.colorScheme) private var colorScheme @Environment(\.widgetFamily) private var widgetFamily + @AppStorage(Defaults.todayAtTop.rawValue, store: UserDefaults(suiteName: groupID)) + private var todayAtTop = false + //MARK: Properties var entry: Provider.Entry @@ -206,6 +209,14 @@ struct TicksWidgetEntryView : View { : min(entry.configuration.numDays?.intValue ?? defaultNumDays, maxNumDays) } + struct Row: Identifiable { + var id: Int { value } + var value: Int + } + var rows: [Row] { + (0..