Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
parent
687ca8cca4
commit
3190d610f3
@ -22,104 +22,43 @@ struct ClockView: View {
|
|||||||
|
|
||||||
GeometryReader { geometry in
|
GeometryReader { geometry in
|
||||||
ZStack {
|
ZStack {
|
||||||
// Time display - fills entire available space
|
// Main clock display container
|
||||||
TimeDisplayView(
|
ClockDisplayContainer(
|
||||||
date: viewModel.currentTime,
|
currentTime: viewModel.currentTime,
|
||||||
use24Hour: viewModel.style.use24Hour,
|
style: viewModel.style,
|
||||||
showSeconds: viewModel.style.showSeconds,
|
isDisplayMode: viewModel.isDisplayMode
|
||||||
digitColor: viewModel.style.digitColor,
|
|
||||||
glowIntensity: viewModel.style.glowIntensity,
|
|
||||||
manualScale: viewModel.style.digitScale,
|
|
||||||
stretched: viewModel.style.stretched,
|
|
||||||
showAmPmBadge: viewModel.style.showAmPmBadge,
|
|
||||||
clockOpacity: viewModel.style.clockOpacity,
|
|
||||||
fontFamily: viewModel.style.fontFamily,
|
|
||||||
fontWeight: viewModel.style.fontWeight,
|
|
||||||
fontDesign: viewModel.style.fontDesign
|
|
||||||
)
|
)
|
||||||
.transition(.opacity)
|
|
||||||
|
|
||||||
// Top overlay - positioned at top with safe area consideration
|
// Top overlay container
|
||||||
VStack {
|
ClockOverlayContainer(style: viewModel.style)
|
||||||
if viewModel.style.showBattery || viewModel.style.showDate {
|
|
||||||
TopOverlayView(
|
|
||||||
showBattery: viewModel.style.showBattery,
|
|
||||||
showDate: viewModel.style.showDate,
|
|
||||||
color: viewModel.style.digitColor.opacity(UIConstants.Opacity.primary),
|
|
||||||
opacity: viewModel.style.overlayOpacity
|
|
||||||
)
|
|
||||||
.padding(.top, UIConstants.Spacing.small)
|
|
||||||
.padding(.horizontal, UIConstants.Spacing.large)
|
|
||||||
.transition(.opacity)
|
|
||||||
}
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.scaleEffect(viewModel.isDisplayMode ? 1.0 : 0.995)
|
|
||||||
.animation(UIConstants.AnimationCurves.smooth, value: viewModel.isDisplayMode)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.ignoresSafeArea(.all, edges: viewModel.isDisplayMode ? .bottom : [])
|
.ignoresSafeArea(.all, edges: viewModel.isDisplayMode ? .bottom : [])
|
||||||
.navigationTitle(viewModel.isDisplayMode ? "" : "Clock")
|
|
||||||
.toolbar {
|
|
||||||
if !viewModel.isDisplayMode {
|
|
||||||
ToolbarItem(placement: .navigationBarTrailing) {
|
|
||||||
Button {
|
|
||||||
showSettings = true
|
|
||||||
} label: {
|
|
||||||
Image(systemName: "gear")
|
|
||||||
.font(.title2)
|
|
||||||
.transition(.opacity)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.navigationBarBackButtonHidden(viewModel.isDisplayMode)
|
|
||||||
.toolbar(viewModel.isDisplayMode ? .hidden : .automatic)
|
|
||||||
.statusBarHidden(viewModel.isDisplayMode)
|
.statusBarHidden(viewModel.isDisplayMode)
|
||||||
.onAppear {
|
|
||||||
setTabBarHidden(viewModel.isDisplayMode, animated: false)
|
|
||||||
}
|
|
||||||
.onDisappear {
|
|
||||||
setTabBarHidden(false, animated: false)
|
|
||||||
}
|
|
||||||
.sheet(isPresented: $showSettings) {
|
.sheet(isPresented: $showSettings) {
|
||||||
ClockSettingsView(style: viewModel.style) { newStyle in
|
ClockSettingsView(style: viewModel.style) { newStyle in
|
||||||
viewModel.updateStyle(newStyle)
|
viewModel.updateStyle(newStyle)
|
||||||
}
|
}
|
||||||
.presentationDetents([.medium, .large])
|
.presentationDetents([.medium, .large])
|
||||||
}
|
}
|
||||||
.contentShape(Rectangle())
|
.overlay {
|
||||||
.simultaneousGesture(
|
// Toolbar overlay
|
||||||
LongPressGesture(minimumDuration: AppConstants.DisplayMode.longPressDuration)
|
ClockToolbar(
|
||||||
.onEnded { _ in
|
isDisplayMode: viewModel.isDisplayMode,
|
||||||
viewModel.toggleDisplayMode()
|
onSettingsTap: { showSettings = true }
|
||||||
setTabBarHidden(viewModel.isDisplayMode, animated: true)
|
)
|
||||||
// Status bar hiding is handled by the .statusBarHidden modifier
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Private Methods
|
|
||||||
private func setTabBarHidden(_ hidden: Bool, animated: Bool) {
|
|
||||||
// This will be handled by the View extension
|
|
||||||
// For now, we'll keep the UIKit implementation
|
|
||||||
#if canImport(UIKit)
|
|
||||||
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
|
|
||||||
let window = windowScene.windows.first,
|
|
||||||
let tabBarController = window.rootViewController?.findTabBarController() else { return }
|
|
||||||
|
|
||||||
let tabBar = tabBarController.tabBar
|
|
||||||
let changes = {
|
|
||||||
tabBar.alpha = hidden ? 0 : 1
|
|
||||||
}
|
}
|
||||||
if animated {
|
.overlay {
|
||||||
UIView.animate(withDuration: AppConstants.AnimationDurations.short, animations: changes)
|
// Tab bar management overlay
|
||||||
} else {
|
ClockTabBarManager(isDisplayMode: viewModel.isDisplayMode, animated: true)
|
||||||
changes()
|
}
|
||||||
|
.overlay {
|
||||||
|
// Gesture handling overlay
|
||||||
|
ClockGestureHandler {
|
||||||
|
viewModel.toggleDisplayMode()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tabBar.isUserInteractionEnabled = !hidden
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,52 @@
|
|||||||
|
//
|
||||||
|
// ClockDisplayContainer.swift
|
||||||
|
// TheNoiseClock
|
||||||
|
//
|
||||||
|
// Created by Matt Bruce on 9/8/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
/// Container component that handles the main clock display layout and scaling
|
||||||
|
struct ClockDisplayContainer: View {
|
||||||
|
|
||||||
|
// MARK: - Properties
|
||||||
|
let currentTime: Date
|
||||||
|
let style: ClockStyle
|
||||||
|
let isDisplayMode: Bool
|
||||||
|
|
||||||
|
// MARK: - Body
|
||||||
|
var body: some View {
|
||||||
|
GeometryReader { geometry in
|
||||||
|
ZStack {
|
||||||
|
// Time display - fills entire available space
|
||||||
|
TimeDisplayView(
|
||||||
|
date: currentTime,
|
||||||
|
use24Hour: style.use24Hour,
|
||||||
|
showSeconds: style.showSeconds,
|
||||||
|
digitColor: style.digitColor,
|
||||||
|
glowIntensity: style.glowIntensity,
|
||||||
|
manualScale: style.digitScale,
|
||||||
|
stretched: style.stretched,
|
||||||
|
showAmPmBadge: style.showAmPmBadge,
|
||||||
|
clockOpacity: style.clockOpacity,
|
||||||
|
fontFamily: style.fontFamily,
|
||||||
|
fontWeight: style.fontWeight,
|
||||||
|
fontDesign: style.fontDesign
|
||||||
|
)
|
||||||
|
.transition(.opacity)
|
||||||
|
}
|
||||||
|
.scaleEffect(isDisplayMode ? 1.0 : 0.995)
|
||||||
|
.animation(UIConstants.AnimationCurves.smooth, value: isDisplayMode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Preview
|
||||||
|
#Preview {
|
||||||
|
ClockDisplayContainer(
|
||||||
|
currentTime: Date(),
|
||||||
|
style: ClockStyle(),
|
||||||
|
isDisplayMode: false
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
//
|
||||||
|
// ClockGestureHandler.swift
|
||||||
|
// TheNoiseClock
|
||||||
|
//
|
||||||
|
// Created by Matt Bruce on 9/8/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
/// Component that handles gesture interactions for the clock view
|
||||||
|
struct ClockGestureHandler: View {
|
||||||
|
|
||||||
|
// MARK: - Properties
|
||||||
|
let onLongPress: () -> Void
|
||||||
|
|
||||||
|
// MARK: - Body
|
||||||
|
var body: some View {
|
||||||
|
EmptyView()
|
||||||
|
.contentShape(Rectangle())
|
||||||
|
.simultaneousGesture(
|
||||||
|
LongPressGesture(minimumDuration: AppConstants.DisplayMode.longPressDuration)
|
||||||
|
.onEnded { _ in
|
||||||
|
onLongPress()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Preview
|
||||||
|
#Preview {
|
||||||
|
ClockGestureHandler(onLongPress: {})
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
//
|
||||||
|
// ClockOverlayContainer.swift
|
||||||
|
// TheNoiseClock
|
||||||
|
//
|
||||||
|
// Created by Matt Bruce on 9/8/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
/// Container component that handles the positioning and display of top overlays
|
||||||
|
struct ClockOverlayContainer: View {
|
||||||
|
|
||||||
|
// MARK: - Properties
|
||||||
|
let style: ClockStyle
|
||||||
|
|
||||||
|
// MARK: - Body
|
||||||
|
var body: some View {
|
||||||
|
VStack {
|
||||||
|
if style.showBattery || style.showDate {
|
||||||
|
TopOverlayView(
|
||||||
|
showBattery: style.showBattery,
|
||||||
|
showDate: style.showDate,
|
||||||
|
color: style.digitColor.opacity(UIConstants.Opacity.primary),
|
||||||
|
opacity: style.overlayOpacity
|
||||||
|
)
|
||||||
|
.padding(.top, UIConstants.Spacing.small)
|
||||||
|
.padding(.horizontal, UIConstants.Spacing.large)
|
||||||
|
.transition(.opacity)
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Preview
|
||||||
|
#Preview {
|
||||||
|
ClockOverlayContainer(style: ClockStyle())
|
||||||
|
}
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
//
|
||||||
|
// ClockTabBarManager.swift
|
||||||
|
// TheNoiseClock
|
||||||
|
//
|
||||||
|
// Created by Matt Bruce on 9/8/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
/// Component that manages tab bar visibility for display mode
|
||||||
|
struct ClockTabBarManager: View {
|
||||||
|
|
||||||
|
// MARK: - Properties
|
||||||
|
let isDisplayMode: Bool
|
||||||
|
let animated: Bool
|
||||||
|
|
||||||
|
// MARK: - Body
|
||||||
|
var body: some View {
|
||||||
|
EmptyView()
|
||||||
|
.onAppear {
|
||||||
|
setTabBarHidden(isDisplayMode, animated: false)
|
||||||
|
}
|
||||||
|
.onDisappear {
|
||||||
|
setTabBarHidden(false, animated: false)
|
||||||
|
}
|
||||||
|
.onChange(of: isDisplayMode) { _, newValue in
|
||||||
|
setTabBarHidden(newValue, animated: animated)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Private Methods
|
||||||
|
private func setTabBarHidden(_ hidden: Bool, animated: Bool) {
|
||||||
|
#if canImport(UIKit)
|
||||||
|
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
|
||||||
|
let window = windowScene.windows.first,
|
||||||
|
let tabBarController = window.rootViewController?.findTabBarController() else { return }
|
||||||
|
|
||||||
|
let tabBar = tabBarController.tabBar
|
||||||
|
let changes = {
|
||||||
|
tabBar.alpha = hidden ? 0 : 1
|
||||||
|
}
|
||||||
|
if animated {
|
||||||
|
UIView.animate(withDuration: AppConstants.AnimationDurations.short, animations: changes)
|
||||||
|
} else {
|
||||||
|
changes()
|
||||||
|
}
|
||||||
|
tabBar.isUserInteractionEnabled = !hidden
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Preview
|
||||||
|
#Preview {
|
||||||
|
ClockTabBarManager(isDisplayMode: false, animated: false)
|
||||||
|
}
|
||||||
47
TheNoiseClock/Views/Clock/Components/ClockToolbar.swift
Normal file
47
TheNoiseClock/Views/Clock/Components/ClockToolbar.swift
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
//
|
||||||
|
// ClockToolbar.swift
|
||||||
|
// TheNoiseClock
|
||||||
|
//
|
||||||
|
// Created by Matt Bruce on 9/8/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
/// Component that handles the clock view toolbar and navigation
|
||||||
|
struct ClockToolbar: View {
|
||||||
|
|
||||||
|
// MARK: - Properties
|
||||||
|
let isDisplayMode: Bool
|
||||||
|
let onSettingsTap: () -> Void
|
||||||
|
|
||||||
|
// MARK: - Body
|
||||||
|
var body: some View {
|
||||||
|
EmptyView()
|
||||||
|
.navigationTitle(isDisplayMode ? "" : "Clock")
|
||||||
|
.toolbar {
|
||||||
|
if !isDisplayMode {
|
||||||
|
ToolbarItem(placement: .navigationBarTrailing) {
|
||||||
|
Button {
|
||||||
|
onSettingsTap()
|
||||||
|
} label: {
|
||||||
|
Image(systemName: "gear")
|
||||||
|
.font(.title2)
|
||||||
|
.transition(.opacity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.navigationBarBackButtonHidden(isDisplayMode)
|
||||||
|
.toolbar(isDisplayMode ? .hidden : .automatic)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Preview
|
||||||
|
#Preview {
|
||||||
|
NavigationStack {
|
||||||
|
ClockToolbar(
|
||||||
|
isDisplayMode: false,
|
||||||
|
onSettingsTap: {}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user