Skip to content

Commit 8d5d6cb

Browse files
authored
Merge pull request #292 from aapis/feature/1.11/move-date-selector-to-appnav
Replaced DateSelectorWidget
2 parents 766dfa3 + 8a95a33 commit 8d5d6cb

File tree

7 files changed

+224
-95
lines changed

7 files changed

+224
-95
lines changed

KWCore/Sources/Helpers/DateHelper.swift

+8-3
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,15 @@ final public class DateHelper {
7676

7777
return entries
7878
}
79-
80-
static public func todayShort(_ date: Date? = Date()) -> String {
79+
80+
/// Format today's date
81+
/// - Parameters:
82+
/// - date: Date
83+
/// - format: String
84+
/// - Returns: Void
85+
static public func todayShort(_ date: Date? = Date(), format: String = "yyyy-MM-dd") -> String {
8186
let formatter = DateFormatter()
82-
formatter.dateFormat = "yyyy-MM-dd"
87+
formatter.dateFormat = format
8388
formatter.timeZone = TimeZone.autoupdatingCurrent
8489
formatter.locale = NSLocale.current
8590

KWCore/Sources/UI/WidgetLibrary/WidgetLibrary.UI.swift

+198-47
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ extension WidgetLibrary {
2323
public struct Buttons {
2424
public enum UIButtonType {
2525
case resetUserChoices, createNote, createTask, createRecord, createPerson, createCompany, createProject,
26-
createJob, createTerm, createDefinition, historyPrevious, settings, CLIMode
26+
createJob, createTerm, createDefinition, historyPrevious, settings, CLIMode, CLIFilter
2727
}
2828

2929
struct ResetUserChoices: View {
@@ -223,6 +223,7 @@ extension WidgetLibrary {
223223
public var onAction: (() -> Void)? = {}
224224
@State private var isHighlighted: Bool = false
225225
@State private var selectedPage: Page = .dashboard
226+
private var isEmpty: Bool { self.state.history.recent.count == 0 }
226227

227228
var body: some View {
228229
Button {
@@ -242,9 +243,10 @@ extension WidgetLibrary {
242243
.clipShape(.rect(cornerRadius: 5))
243244
.padding([.top, .bottom], 10)
244245
}
246+
.disabled(self.isEmpty)
245247
.keyboardShortcut(KeyEquivalent.leftArrow, modifiers: [.command])
246248
.buttonStyle(.plain)
247-
.useDefaultHover({ hover in self.isHighlighted = hover})
249+
.useDefaultHover({ hover in !self.isEmpty ? self.isHighlighted = hover : nil})
248250
}
249251
}
250252

@@ -272,25 +274,49 @@ extension WidgetLibrary {
272274

273275
struct CLIMode: View {
274276
@EnvironmentObject public var state: Navigation
277+
@AppStorage("general.experimental.cli") private var cliEnabled: Bool = false
275278
@AppStorage("today.commandLineMode") private var commandLineMode: Bool = false
276-
@AppStorage("general.experimental.cli") private var allowCLIMode: Bool = false
277279
public var onAction: (() -> Void)? = {}
278280
@State private var isHighlighted: Bool = false
279281
@State private var selectedPage: Page = .dashboard
280282

281283
var body: some View {
282-
FancyButtonv2(
283-
text: "Command line mode",
284-
action: {commandLineMode.toggle() ; self.onAction?()},
285-
icon: self.commandLineMode ? "apple.terminal.fill" : "apple.terminal",
286-
iconWhenHighlighted: self.commandLineMode ? "apple.terminal" : "apple.terminal.fill",
287-
showLabel: false,
288-
size: .small,
289-
type: .clear,
290-
font: .title
291-
)
292-
.help("Enter CLI mode")
293-
.frame(width: 25)
284+
if self.cliEnabled {
285+
FancyButtonv2(
286+
text: "Command line mode",
287+
action: {self.commandLineMode.toggle() ; self.onAction?()},
288+
icon: self.commandLineMode ? "apple.terminal.fill" : "apple.terminal",
289+
iconWhenHighlighted: self.commandLineMode ? "apple.terminal" : "apple.terminal.fill",
290+
showLabel: false,
291+
size: .small,
292+
type: .clear,
293+
font: .title
294+
)
295+
.help(self.commandLineMode ? "Exit CLI mode" : "Enter CLI mode")
296+
.frame(width: 25)
297+
}
298+
}
299+
}
300+
301+
struct CLIFilter: View {
302+
@EnvironmentObject public var state: Navigation
303+
@AppStorage("general.experimental.cli") private var cliEnabled: Bool = false
304+
@AppStorage("today.commandLineMode") private var commandLineMode: Bool = false
305+
@AppStorage("today.cli.showFilter") private var showCLIFilter: Bool = false
306+
307+
var body: some View {
308+
if self.cliEnabled && self.commandLineMode {
309+
FancyButtonv2(
310+
text: "Filter",
311+
action: {self.showCLIFilter.toggle()},
312+
icon: "line.3.horizontal.decrease",
313+
bgColour: self.state.session.appPage.primaryColour.opacity(0.2),
314+
showLabel: false,
315+
size: .small,
316+
type: .clear
317+
)
318+
.mask(Circle())
319+
}
294320
}
295321
}
296322
}
@@ -393,48 +419,173 @@ extension WidgetLibrary {
393419
@EnvironmentObject public var state: Navigation
394420

395421
var body: some View {
396-
if self.state.history.recent.count > 0 {
397-
ZStack {
398-
Theme.toolbarColour
399-
LinearGradient(colors: [Theme.base, .clear], startPoint: .bottom, endPoint: .top)
400-
.opacity(0.6)
401-
.blendMode(.softLight)
402-
403-
VStack(alignment: .leading, spacing: 0) {
404-
HStack {
405-
Buttons.HistoryPrevious()
406-
Spacer()
407-
ForEach(self.state.navButtons, id: \.self) { type in
408-
switch type {
409-
case .CLIMode: Buttons.CLIMode()
410-
case .historyPrevious: Buttons.HistoryPrevious()
411-
case .resetUserChoices: Buttons.ResetUserChoices()
412-
case .settings: Buttons.Settings()
413-
case .createJob: Buttons.CreateJob()
414-
case .createNote: Buttons.CreateNote()
422+
ZStack {
423+
Theme.toolbarColour
424+
LinearGradient(colors: [Theme.base, .clear], startPoint: .bottom, endPoint: .top)
425+
.opacity(0.6)
426+
.blendMode(.softLight)
427+
428+
VStack(alignment: .leading, spacing: 0) {
429+
HStack {
430+
Buttons.HistoryPrevious()
431+
Spacer()
432+
SimpleDateSelector()
433+
Spacer()
434+
ForEach(self.state.navButtons, id: \.self) { type in
435+
switch type {
436+
case .CLIMode: Buttons.CLIMode()
437+
case .CLIFilter: Buttons.CLIFilter()
438+
case .historyPrevious: Buttons.HistoryPrevious()
439+
case .resetUserChoices: Buttons.ResetUserChoices()
440+
case .settings: Buttons.Settings()
441+
case .createJob: Buttons.CreateJob()
442+
case .createNote: Buttons.CreateNote()
415443
// case .createTask: Buttons.CreateTask()
416-
case .createTerm: Buttons.CreateTerm()
417-
case .createPerson: Buttons.CreatePerson()
418-
case .createRecord: Buttons.CreateRecord()
419-
case .createCompany: Buttons.CreateCompany()
420-
case .createProject: Buttons.CreateProject()
421-
case .createDefinition: Buttons.CreateDefinition()
422-
default: EmptyView()
444+
case .createTerm: Buttons.CreateTerm()
445+
case .createPerson: Buttons.CreatePerson()
446+
case .createRecord: Buttons.CreateRecord()
447+
case .createCompany: Buttons.CreateCompany()
448+
case .createProject: Buttons.CreateProject()
449+
case .createDefinition: Buttons.CreateDefinition()
450+
default: EmptyView()
451+
}
452+
}
453+
}
454+
.padding([.leading, .trailing])
455+
Divider()
456+
}
457+
}
458+
.frame(height: 55)
459+
}
460+
}
461+
462+
struct SimpleDateSelector: View {
463+
@EnvironmentObject private var state: Navigation
464+
@AppStorage("today.numPastDates") public var numPastDates: Int = 20
465+
@AppStorage("isDatePickerPresented") public var isDatePickerPresented: Bool = false
466+
@State private var isToday: Bool = false
467+
@State private var isHighlighted: Bool = false
468+
@State private var date: String = ""
469+
@State private var showDateOverlay: Bool = false
470+
@State private var sDate: Date = Date()
471+
472+
var body: some View {
473+
HStack(alignment: .center) {
474+
FancyButtonv2(
475+
text: "Previous day",
476+
action: self.actionPreviousDay,
477+
icon: "chevron.left",
478+
fgColour: .gray,
479+
highlightColour: .white,
480+
showLabel: false,
481+
size: .titleLink,
482+
type: .titleLink
483+
)
484+
.help("Previous day")
485+
.frame(height: 20)
486+
487+
Button {
488+
self.showDateOverlay.toggle()
489+
} label: {
490+
HStack(alignment: .center) {
491+
ZStack {
492+
RoundedRectangle(cornerRadius: 5)
493+
.strokeBorder(self.isToday ? .yellow.opacity(0.6) : .gray, lineWidth: 1)
494+
.fill(.white.opacity(self.isHighlighted ? 0.2 : 0.1))
495+
if !self.showDateOverlay {
496+
HStack {
497+
Image(systemName: "calendar")
498+
.foregroundStyle(.gray)
499+
Text(self.date)
423500
}
424501
}
425-
// Buttons.Settings()
426-
// Buttons.CLIMode()
427-
// Buttons.ResetUserChoices(onActionClear: {})
428502
}
429-
.padding([.leading, .trailing])
430-
Divider()
503+
.frame(width: 200)
504+
}
505+
}
506+
.foregroundStyle(self.isHighlighted ? .white : self.isToday ? .yellow.opacity(0.6) : .gray)
507+
.buttonStyle(.plain)
508+
.useDefaultHover({ hover in self.isHighlighted = hover})
509+
.overlay {
510+
if self.showDateOverlay {
511+
HStack {
512+
DatePicker("", selection: $sDate)
513+
Image(systemName: "xmark")
514+
}
431515
}
432516
}
433-
.frame(height: 55)
517+
518+
FancyButtonv2(
519+
text: "Next day",
520+
action: self.actionNextDay,
521+
icon: "chevron.right",
522+
fgColour: .gray,
523+
showLabel: false,
524+
size: .titleLink,
525+
type: .titleLink
526+
)
527+
.help("Next day")
528+
.frame(height: 20)
529+
}
530+
.padding(12)
531+
.onAppear(perform: self.actionOnAppear)
532+
.onChange(of: self.state.session.date) { self.actionOnChangeDate() }
533+
.onChange(of: self.sDate) { self.state.session.date = self.sDate }
534+
}
535+
}
536+
}
537+
}
538+
539+
extension WidgetLibrary.UI.SimpleDateSelector {
540+
/// Onload handler. Sets up a timer to advance to the next day and sets view state
541+
/// - Returns: Void
542+
private func actionOnAppear() -> Void {
543+
self.actionOnChangeDate()
544+
545+
// Auto-advance date to tomorrow when the clock strikes midnight
546+
Timer.scheduledTimer(withTimeInterval: 3600, repeats: true) { timer in
547+
let components = Calendar.autoupdatingCurrent.dateComponents([.hour], from: Date())
548+
549+
if let hour = components.hour {
550+
if hour == 24 {
551+
self.actionNextDay()
434552
}
435553
}
436554
}
437555
}
556+
557+
/// Fires when the date is changed.
558+
/// - Returns: Void
559+
private func actionOnChangeDate() -> Void {
560+
self.date = DateHelper.todayShort(self.state.session.date, format: "MMMM d, yyyy")
561+
self.isToday = self.areSameDate(self.state.session.date, Date())
562+
}
563+
564+
/// Determine if two dates are the same
565+
/// - Parameters:
566+
/// - lhs: Date
567+
/// - rhs: Date
568+
/// - Returns: Void
569+
private func areSameDate(_ lhs: Date, _ rhs: Date) -> Bool {
570+
let df = DateFormatter()
571+
df.dateFormat = "MMMM d"
572+
let fmtDate = df.string(from: lhs)
573+
let fmtSessionDate = df.string(from: rhs)
574+
575+
return fmtDate == fmtSessionDate
576+
}
577+
578+
/// Decrement the current day
579+
/// - Returns: Void
580+
private func actionPreviousDay() -> Void {
581+
self.state.session.date -= 86400
582+
}
583+
584+
/// Increment the current day
585+
/// - Returns: Void
586+
private func actionNextDay() -> Void {
587+
self.state.session.date += 86400
588+
}
438589
}
439590

440591
extension WidgetLibrary.UI.Buttons.ResetUserChoices {

KlockWork/Utils/Navigation.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ extension Navigation {
557557
public let all: [HistoryPage] = [
558558
HistoryPage(page: .dashboard, view: AnyView(Dashboard()), sidebar: AnyView(DashboardSidebar()), title: "Dashboard"),
559559
HistoryPage(page: .planning, view: AnyView(Planning()), sidebar: AnyView(DefaultPlanningSidebar()), title: "Planning"),
560-
HistoryPage(page: .today, view: AnyView(Today()), sidebar: AnyView(TodaySidebar()), title: "Today", navButtons: [.CLIMode, .createRecord, .resetUserChoices]),
560+
HistoryPage(page: .today, view: AnyView(Today()), sidebar: AnyView(TodaySidebar()), title: "Today", navButtons: [.CLIFilter, .CLIMode, .resetUserChoices]),
561561
HistoryPage(page: .companies, view: AnyView(CompanyDashboard()), sidebar: AnyView(DefaultCompanySidebar()), title: "Companies & Projects", navButtons: [.createCompany, .createProject]),
562562
HistoryPage(page: .companyDetail, view: AnyView(CompanyView()), sidebar: AnyView(DefaultCompanySidebar()), title: "Company"),
563563
HistoryPage(page: .jobs, view: AnyView(JobDashboardRedux()), sidebar: AnyView(JobDashboardSidebar()), title: "Jobs", navButtons: [.resetUserChoices, .createJob]),

0 commit comments

Comments
 (0)