From d0b31d2c3ef4177dda7d2ad32d5ab053c2b27ebb Mon Sep 17 00:00:00 2001 From: Laurent Date: Fri, 10 Mar 2023 10:38:13 +0100 Subject: [PATCH] Visual changes --- LeCountdown.xcodeproj/project.pbxproj | 4 + LeCountdown/Intent/TimerShortcuts.swift | 7 +- LeCountdown/Views/ContentView.swift | 11 +- LeCountdown/Views/LiveTimerListView.swift | 181 ++++++++---------- LeCountdown/Views/PresetsView.swift | 13 +- .../Views/Reusable/SeparatorView.swift | 25 +++ 6 files changed, 123 insertions(+), 118 deletions(-) create mode 100644 LeCountdown/Views/Reusable/SeparatorView.swift diff --git a/LeCountdown.xcodeproj/project.pbxproj b/LeCountdown.xcodeproj/project.pbxproj index 7fb48d4..fdde7a8 100644 --- a/LeCountdown.xcodeproj/project.pbxproj +++ b/LeCountdown.xcodeproj/project.pbxproj @@ -167,6 +167,7 @@ C4E5D67C29B8D4A5008E7465 /* Low_Tom_Disto_Earth.wav in Resources */ = {isa = PBXBuildFile; fileRef = C4E5D67B29B8D4A5008E7465 /* Low_Tom_Disto_Earth.wav */; }; C4E5D68029B8FD93008E7465 /* Store.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E5D67F29B8FD93008E7465 /* Store.swift */; }; C4E5D68229B93583008E7465 /* PVP_Stab_Oneshot_Bleep_Em.wav in Resources */ = {isa = PBXBuildFile; fileRef = C4E5D68129B93583008E7465 /* PVP_Stab_Oneshot_Bleep_Em.wav */; }; + C4E5D68429BB2425008E7465 /* SeparatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E5D68329BB2425008E7465 /* SeparatorView.swift */; }; C4F8B1532987FE6F005C86A5 /* LaunchWidgetLiveActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = C438C7D72981216200BF3EF9 /* LaunchWidgetLiveActivity.swift */; }; C4F8B15729891271005C86A5 /* Conductor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F8B15629891271005C86A5 /* Conductor.swift */; }; C4F8B15929891528005C86A5 /* forest_stream.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = C4F8B15829891528005C86A5 /* forest_stream.mp3 */; }; @@ -383,6 +384,7 @@ C4E5D67B29B8D4A5008E7465 /* Low_Tom_Disto_Earth.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = Low_Tom_Disto_Earth.wav; sourceTree = ""; }; C4E5D67F29B8FD93008E7465 /* Store.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Store.swift; sourceTree = ""; }; C4E5D68129B93583008E7465 /* PVP_Stab_Oneshot_Bleep_Em.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = PVP_Stab_Oneshot_Bleep_Em.wav; sourceTree = ""; }; + C4E5D68329BB2425008E7465 /* SeparatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatorView.swift; sourceTree = ""; }; C4F8B15629891271005C86A5 /* Conductor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Conductor.swift; sourceTree = ""; }; C4F8B15829891528005C86A5 /* forest_stream.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = forest_stream.mp3; sourceTree = ""; }; C4F8B15E298961A7005C86A5 /* ReorderableForEach.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReorderableForEach.swift; sourceTree = ""; }; @@ -774,6 +776,7 @@ C4742B5A298414B000D5D950 /* ImageSelectionView.swift */, C4F8B1D1298BF646005C86A5 /* PermissionAlertView.swift */, C4F8B15E298961A7005C86A5 /* ReorderableForEach.swift */, + C4E5D68329BB2425008E7465 /* SeparatorView.swift */, C4F8B165298A9ABB005C86A5 /* SoundImageFormView.swift */, C4BA2AD52993F62700CB4FBA /* SoundSelectionView.swift */, C4BA2ADA299549BC00CB4FBA /* TimerModel.swift */, @@ -1023,6 +1026,7 @@ C4E5D67A29B8C5A1008E7465 /* VolumeView.swift in Sources */, C4BA2B04299A42EF00CB4FBA /* NewDataView.swift in Sources */, C4BA2B4C299FCE0C00CB4FBA /* Stopwatch+CoreDataProperties.swift in Sources */, + C4E5D68429BB2425008E7465 /* SeparatorView.swift in Sources */, C4E5D67429B88734008E7465 /* DelaySoundPlayer.swift in Sources */, C438C7FF2981300500BF3EF9 /* IntentDataProvider.swift in Sources */, C4E5D66629B73AED008E7465 /* StartTimerIntent.swift in Sources */, diff --git a/LeCountdown/Intent/TimerShortcuts.swift b/LeCountdown/Intent/TimerShortcuts.swift index 4ad21ca..3a7615d 100644 --- a/LeCountdown/Intent/TimerShortcuts.swift +++ b/LeCountdown/Intent/TimerShortcuts.swift @@ -11,11 +11,12 @@ struct TimerShortcuts: AppShortcutsProvider { static var appShortcuts: [AppShortcut] { AppShortcut(intent: StartTimerIntent(), phrases: [ - "Start \(.applicationName)", - "Launch \(.applicationName)", + "\(.applicationName) \(\.$timer)", "Start \(\.$timer) with \(.applicationName)", "Launch \(\.$timer) with \(.applicationName)", - "\(.applicationName) \(\.$timer)"]) + "Start \(.applicationName)", + "Launch \(.applicationName)" + ]) } } diff --git a/LeCountdown/Views/ContentView.swift b/LeCountdown/Views/ContentView.swift index 40e1495..5887135 100644 --- a/LeCountdown/Views/ContentView.swift +++ b/LeCountdown/Views/ContentView.swift @@ -119,6 +119,7 @@ struct ContentView: View { LiveTimerListView() .environment(\.managedObjectContext, viewContext) .environmentObject(conductor) + .padding(.horizontal, 12.0) .foregroundColor(.white) .background(Color(white: 0.1)) .cornerRadius(32.0, corners: [.topRight, .topLeft]) @@ -137,8 +138,6 @@ struct ContentView: View { PermissionAlertView() } .sheet(isPresented: $boringContext.isShowingNewData, content: { -// self._newView(isPresented: $boringContext.isShowingNewData) -// .environment(\.managedObjectContext, viewContext) }) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { @@ -293,14 +292,6 @@ fileprivate extension Countdown { return endDate != nil } -// var colorForStatus: Color { -// if isLive { -// return Color(red: 0.9, green: 1.0, blue: 0.95) -// } else { -// return Color(red: 0.9, green: 0.95, blue: 1.0) -// } -// } - } struct ContentView_Previews: PreviewProvider { diff --git a/LeCountdown/Views/LiveTimerListView.swift b/LeCountdown/Views/LiveTimerListView.swift index 630f308..e7799c2 100644 --- a/LeCountdown/Views/LiveTimerListView.swift +++ b/LeCountdown/Views/LiveTimerListView.swift @@ -21,19 +21,9 @@ class LiveStopwatchModel: ObservableObject { } } -struct SeparatorView: View { - - var body: some View { - Spacer() - .frame(minWidth: 0.0, maxWidth: .infinity, minHeight: 1.0, maxHeight: 1.0) - .background(Color(white: 0.85)) - .padding(.vertical, 8.0) - } - -} - fileprivate let liveViewSize: CGFloat = 70.0 fileprivate let timerFontSize: CGFloat = 32.0 +fileprivate let actionButtonFontSize: CGFloat = 36.0 struct TimeView: View { @@ -61,58 +51,51 @@ struct LiveStopwatchView: View { let running = (self.model.endDate == nil) - VStack(alignment: .trailing) { + HStack { - if running { - TimelineView(.periodic(from: self.date, by: 0.01)) { context in - - TimeView(text: self._formattedDuration(date: context.date)) + VStack(alignment: .leading) { + + if running { + TimelineView(.periodic(from: self.date, by: 0.01)) { context in + TimeView(text: self._formattedDuration(date: context.date)) + } + } else { + let duration = self.model.endDate?.timeIntervalSince(self.date) ?? 0.0 + TimeView(text: duration.hourMinuteSecondHS) } - } else { - let duration = self.model.endDate?.timeIntervalSince(self.date) ?? 0.0 - TimeView(text: duration.hourMinuteSecondHS) + Text(stopwatch.displayName.uppercased()) } + + Spacer() -// if running { -// -//// Button { -//// self.model.stop(stopwatch) -//// } label: { -//// -//// Image(systemName: "stop.circle.fill") -//// .font(.title) -//// .foregroundColor(.white) -//// .cornerRadius(8.0) -//// .frame(minWidth: 0.0, maxWidth: 60.0, minHeight: 0.0, maxHeight: .infinity) -//// }.background(.red) -// -// } else { -// GreenCheckmarkView() -// } -// SeparatorView() - HStack { + Group { if !running { GreenCheckmarkView() - } - Text(stopwatch.displayName.uppercased()) - } - - }.onTapGesture { - withAnimation { - if self.model.endDate == nil { - self.model.stop(stopwatch) } else { - self._dismiss() + Image(systemName: "stop.circle.fill") + .foregroundColor(.accentColor) } - } + }.font(.system(size: actionButtonFontSize)) + } - .frame(height: liveViewSize) -// .foregroundColor(.white) .monospaced() -// .background(Color(white: 0.2)) -// .cornerRadius(16.0) + .frame(height: liveViewSize) + .contentShape(Rectangle()) + .onTapGesture { + self._actionHandler() + } } + fileprivate func _actionHandler() { + withAnimation { + if self.model.endDate == nil { + self.model.stop(stopwatch) + } else { + self._dismiss() + } + } + } + fileprivate func _dismiss() { conductor.removeLiveTimer(id: self.stopwatch.stringId) } @@ -134,50 +117,58 @@ struct LiveCountdownView: View { var body: some View { TimelineView(.periodic(from: self.date, by: 0.01)) { context in - VStack(alignment: .trailing) { + + HStack { let running = self.date > context.date let cancelled = conductor.cancelledCountdowns.contains(where: { $0 == self.countdown.stringId }) - - if cancelled { - TimeView(text: NSLocalizedString("Cancelled", comment: "")) - } else if running { - TimeView(text: self._formattedDuration(date: context.date)) - } else { - TimeView(text: self.date.formatted(date: .omitted, time: .shortened)) + + VStack(alignment: .leading) { + + if cancelled { + TimeView(text: NSLocalizedString("Cancelled", comment: "")) + } else if running { + TimeView(text: self._formattedDuration(date: context.date)) + } else { + TimeView(text: self.date.formatted(date: .omitted, time: .shortened)) + } + + Text(self.countdown.displayName.uppercased()) + } -// SeparatorView() - HStack { + Spacer() + + Group { if cancelled { - XMarkView() + Image(systemName: "xmark.circle").foregroundColor(.accentColor) } else if !running { GreenCheckmarkView() + } else { + Image(systemName: "xmark.circle.fill").foregroundColor(.accentColor) } - Text(self.countdown.displayName.uppercased()) -// .padding(.top, 2.0) - } + }.font(.system(size: actionButtonFontSize)) } } - .contentShape(Rectangle()) // make the onTap react everywhere + .contentShape(Rectangle()) .onTapGesture { - withAnimation { - if conductor.currentCountdowns[self.countdown.stringId] != nil { - self._cancelCountdown() - } else { - self._dismiss() - } - } + self._actionHandler() } .frame(height: liveViewSize) -// .foregroundColor(.white) .monospaced() -// .background(Color(white: 0.2)) -// .cornerRadius(16.0) + } + + fileprivate func _actionHandler() { + withAnimation { + if conductor.currentCountdowns[self.countdown.stringId] != nil { + self._cancelCountdown() + } else { + self._dismiss() + } + } } fileprivate func _dismiss() { -// conductor.cancelCountdown(id: self.countdown.stringId) conductor.removeLiveTimer(id: self.countdown.stringId) } @@ -199,31 +190,27 @@ struct LiveTimerListView: View { var body: some View { -// ScrollView { + // ScrollView { + + VStack { - LazyVGrid( - columns: self._columns(), - alignment: .trailing, - spacing: 0.0 - ) { + ForEach(conductor.liveTimers) { liveTimer in - ForEach(conductor.liveTimers) { liveTimer in + if let timer: AbstractTimer = liveTimer.timer(context: self.viewContext) { - if let timer: AbstractTimer = liveTimer.timer(context: self.viewContext) { - - switch timer { - case let cd as Countdown: - LiveCountdownView(countdown: cd, date: liveTimer.date) - case let sw as Stopwatch: - LiveStopwatchView(stopwatch: sw, date: liveTimer.date) - default: - Text("unmanaged timer: \(timer)") - } - + switch timer { + case let cd as Countdown: + LiveCountdownView(countdown: cd, date: liveTimer.date) + case let sw as Stopwatch: + LiveStopwatchView(stopwatch: sw, date: liveTimer.date) + default: + Text("unmanaged timer: \(timer)") } } -// } + + } + }.padding() } @@ -231,7 +218,7 @@ struct LiveTimerListView: View { fileprivate func _columnCount() -> Int { #if os(iOS) if UIDevice.isPhoneIdiom { - return 2 + return 18 } else { return 3 } diff --git a/LeCountdown/Views/PresetsView.swift b/LeCountdown/Views/PresetsView.swift index 8791c0b..45402a4 100644 --- a/LeCountdown/Views/PresetsView.swift +++ b/LeCountdown/Views/PresetsView.swift @@ -55,19 +55,15 @@ struct PresetsView: View { Text("Create countdown".uppercased()) .frame(maxWidth: .infinity) .frame(height: 40.0) - } - + }.monospaced().buttonStyle(.bordered) + Button { self.isShowingNewStopwatch = true } label: { Text("Create stopwatch".uppercased()) .frame(maxWidth: .infinity) .frame(height: 40.0) - } - }.padding(.horizontal).monospaced().buttonStyle(.bordered) - - VStack(alignment: .leading) { - SeparatorView() + }.monospaced().buttonStyle(.bordered) Text("Presets") .font(.system(.title, weight: .heavy)) @@ -77,7 +73,8 @@ struct PresetsView: View { .font(.callout) }.padding(.horizontal) - + .padding(.bottom) + LazyVGrid( columns: self._columns(), alignment: .leading, diff --git a/LeCountdown/Views/Reusable/SeparatorView.swift b/LeCountdown/Views/Reusable/SeparatorView.swift new file mode 100644 index 0000000..62c85ed --- /dev/null +++ b/LeCountdown/Views/Reusable/SeparatorView.swift @@ -0,0 +1,25 @@ +// +// SeparatorView.swift +// LeCountdown +// +// Created by Laurent Morvillier on 10/03/2023. +// + +import SwiftUI + +struct SeparatorView: View { + + var body: some View { + Spacer() + .frame(minWidth: 0.0, maxWidth: .infinity, minHeight: 1.0, maxHeight: 1.0) + .background(Color(white: 0.85)) + .padding(.vertical, 8.0) + } + +} + +struct SeparatorView_Previews: PreviewProvider { + static var previews: some View { + SeparatorView() + } +}