mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
Working - need to fix ui issues
This commit is contained in:
parent
97566b754b
commit
fed1a43f88
12 changed files with 510 additions and 65 deletions
83
DynamicIsland/components/MinimalisticMusicView.swift
Normal file
83
DynamicIsland/components/MinimalisticMusicView.swift
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
//
|
||||
// MinimalisticMusicView.swift
|
||||
// DynamicIsland
|
||||
//
|
||||
// Created for minimalistic UI mode
|
||||
// A clean, focused music player for closed notch state
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Defaults
|
||||
|
||||
struct MinimalisticMusicView: View {
|
||||
@EnvironmentObject var vm: DynamicIslandViewModel
|
||||
@ObservedObject var musicManager = MusicManager.shared
|
||||
@State private var isHovering: Bool = false
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 0) {
|
||||
// Left: Album Art
|
||||
albumArtView
|
||||
|
||||
// Middle: Song Title (scrolling if needed)
|
||||
Rectangle()
|
||||
.fill(.black)
|
||||
.overlay(
|
||||
HStack(alignment: .center) {
|
||||
if !musicManager.songTitle.isEmpty {
|
||||
MarqueeText(
|
||||
.constant(musicManager.songTitle),
|
||||
textColor: Defaults[.coloredSpectrogram] ? Color(nsColor: musicManager.avgColor) : Color.gray,
|
||||
minDuration: 0.4,
|
||||
frameWidth: 100
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
.frame(width: vm.closedNotchSize.width)
|
||||
|
||||
// Right: Music Visualizer
|
||||
visualizerView
|
||||
}
|
||||
.frame(height: vm.effectiveClosedNotchHeight + (isHovering ? 8 : 0), alignment: .center)
|
||||
.onHover { hovering in
|
||||
isHovering = hovering
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Album Art
|
||||
|
||||
private var albumArtView: some View {
|
||||
HStack {
|
||||
Color.clear
|
||||
.aspectRatio(1, contentMode: .fit)
|
||||
.background(
|
||||
Image(nsImage: musicManager.albumArt)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
)
|
||||
.clipped()
|
||||
.clipShape(RoundedRectangle(cornerRadius: 18)) // Dramatically increased corner radius for minimalistic mode
|
||||
.frame(width: max(0, vm.effectiveClosedNotchHeight - 12), height: max(0, vm.effectiveClosedNotchHeight - 12))
|
||||
}
|
||||
.frame(width: max(0, vm.effectiveClosedNotchHeight - (isHovering ? 0 : 12)), height: max(0, vm.effectiveClosedNotchHeight - (isHovering ? 0 : 12)))
|
||||
}
|
||||
|
||||
// MARK: - Visualizer
|
||||
|
||||
private var visualizerView: some View {
|
||||
HStack {
|
||||
Rectangle()
|
||||
.fill(Defaults[.coloredSpectrogram] ? Color(nsColor: musicManager.avgColor).gradient : Color.gray.gradient)
|
||||
.frame(width: 50, alignment: .center)
|
||||
.mask {
|
||||
AudioSpectrumView(isPlaying: $musicManager.isPlaying)
|
||||
.frame(width: 16, height: 12)
|
||||
}
|
||||
.frame(width: max(0, vm.effectiveClosedNotchHeight - (isHovering ? 0 : 12)),
|
||||
height: max(0, vm.effectiveClosedNotchHeight - (isHovering ? 0 : 12)), alignment: .center)
|
||||
}
|
||||
.frame(width: max(0, vm.effectiveClosedNotchHeight - (isHovering ? 0 : 12)),
|
||||
height: max(0, vm.effectiveClosedNotchHeight - (isHovering ? 0 : 12)), alignment: .center)
|
||||
}
|
||||
}
|
||||
|
|
@ -20,20 +20,22 @@ struct DynamicIslandHeader: View {
|
|||
|
||||
var body: some View {
|
||||
HStack(spacing: 0) {
|
||||
HStack {
|
||||
if (!tvm.isEmpty || coordinator.alwaysShowTabs) && Defaults[.dynamicShelf] {
|
||||
TabSelectionView()
|
||||
} else if vm.notchState == .open {
|
||||
EmptyView()
|
||||
if !Defaults[.enableMinimalisticUI] {
|
||||
HStack {
|
||||
if (!tvm.isEmpty || coordinator.alwaysShowTabs) && Defaults[.dynamicShelf] {
|
||||
TabSelectionView()
|
||||
} else if vm.notchState == .open {
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.opacity(vm.notchState == .closed ? 0 : 1)
|
||||
.blur(radius: vm.notchState == .closed ? 20 : 0)
|
||||
.animation(.smooth.delay(0.1), value: vm.notchState)
|
||||
.zIndex(2)
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.opacity(vm.notchState == .closed ? 0 : 1)
|
||||
.blur(radius: vm.notchState == .closed ? 20 : 0)
|
||||
.animation(.smooth.delay(0.1), value: vm.notchState)
|
||||
.zIndex(2)
|
||||
|
||||
if vm.notchState == .open {
|
||||
if vm.notchState == .open && !Defaults[.enableMinimalisticUI] {
|
||||
Rectangle()
|
||||
.fill(NSScreen.screens
|
||||
.first(where: { $0.localizedName == coordinator.selectedScreen })?.safeAreaInsets.top ?? 0 > 0 ? .black : .clear)
|
||||
|
|
@ -44,7 +46,7 @@ struct DynamicIslandHeader: View {
|
|||
}
|
||||
|
||||
HStack(spacing: 4) {
|
||||
if vm.notchState == .open {
|
||||
if vm.notchState == .open && !Defaults[.enableMinimalisticUI] {
|
||||
if Defaults[.showMirror] {
|
||||
Button(action: {
|
||||
vm.toggleCameraPreview()
|
||||
|
|
|
|||
254
DynamicIsland/components/Notch/MinimalisticMusicPlayerView.swift
Normal file
254
DynamicIsland/components/Notch/MinimalisticMusicPlayerView.swift
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
//
|
||||
// MinimalisticMusicPlayerView.swift
|
||||
// DynamicIsland
|
||||
//
|
||||
// Created for minimalistic UI mode - Open state music player
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Defaults
|
||||
|
||||
struct MinimalisticMusicPlayerView: View {
|
||||
@EnvironmentObject var vm: DynamicIslandViewModel
|
||||
let albumArtNamespace: Namespace.ID
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 6) {
|
||||
// Music banner: Album art + Song info + Visualizer
|
||||
musicBanner
|
||||
|
||||
// Full-width progress bar with time labels
|
||||
progressBar
|
||||
|
||||
// Larger playback controls
|
||||
playbackControls
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.top, 4)
|
||||
.padding(.bottom, 4)
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
|
||||
// MARK: - Music Banner (Compact)
|
||||
|
||||
@Default(.useMusicVisualizer) var useMusicVisualizer
|
||||
|
||||
private var musicBanner: some View {
|
||||
HStack(spacing: 10) {
|
||||
// Album Art - Smaller
|
||||
MinimalisticAlbumArtView(vm: vm, albumArtNamespace: albumArtNamespace)
|
||||
.frame(width: 50, height: 50)
|
||||
|
||||
// Song Title and Artist
|
||||
songInfo
|
||||
|
||||
Spacer()
|
||||
|
||||
// Visualizer from live activity (only if enabled)
|
||||
if useMusicVisualizer {
|
||||
visualizer
|
||||
}
|
||||
}
|
||||
.frame(height: 50)
|
||||
}
|
||||
|
||||
private var songInfo: some View {
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text(MusicManager.shared.songTitle)
|
||||
.font(.system(size: 14, weight: .semibold))
|
||||
.foregroundColor(.white)
|
||||
.lineLimit(1)
|
||||
|
||||
Text(MusicManager.shared.artistName)
|
||||
.font(.system(size: 12, weight: .regular))
|
||||
.foregroundColor(Defaults[.playerColorTinting] ? Color(nsColor: MusicManager.shared.avgColor).ensureMinimumBrightness(factor: 0.6) : .gray)
|
||||
.lineLimit(1)
|
||||
}
|
||||
}
|
||||
|
||||
private var visualizer: some View {
|
||||
Rectangle()
|
||||
.fill(Defaults[.coloredSpectrogram] ? Color(nsColor: MusicManager.shared.avgColor).gradient : Color.gray.gradient)
|
||||
.mask {
|
||||
AudioSpectrumView(isPlaying: .constant(MusicManager.shared.isPlaying))
|
||||
.frame(width: 20, height: 16)
|
||||
}
|
||||
.frame(width: 20, height: 16)
|
||||
.matchedGeometryEffect(id: "spectrum", in: albumArtNamespace)
|
||||
}
|
||||
|
||||
// MARK: - Progress Bar (Full Width)
|
||||
|
||||
@ObservedObject var musicManager = MusicManager.shared
|
||||
@State private var sliderValue: Double = 0
|
||||
@State private var dragging: Bool = false
|
||||
@State private var lastDragged: Date = .distantPast
|
||||
|
||||
private var progressBar: some View {
|
||||
HStack(spacing: 8) {
|
||||
// Elapsed time - left
|
||||
Text(formatTime(dragging ? sliderValue : musicManager.elapsedTime))
|
||||
.font(.system(size: 11, weight: .medium, design: .monospaced))
|
||||
.foregroundColor(.white.opacity(0.7))
|
||||
.frame(width: 42, alignment: .leading)
|
||||
|
||||
// Progress bar
|
||||
TimelineView(.animation(minimumInterval: 0.05)) { timeline in
|
||||
GeometryReader { geometry in
|
||||
ZStack(alignment: .leading) {
|
||||
// Background track
|
||||
RoundedRectangle(cornerRadius: 3)
|
||||
.fill(Color.white.opacity(0.2))
|
||||
.frame(height: 6)
|
||||
|
||||
// Filled portion
|
||||
RoundedRectangle(cornerRadius: 3)
|
||||
.fill(sliderColor)
|
||||
.frame(width: max(0, geometry.size.width * (currentSliderValue(timeline.date) / max(musicManager.songDuration, 1))), height: 6)
|
||||
}
|
||||
.gesture(
|
||||
DragGesture(minimumDistance: 0)
|
||||
.onChanged { value in
|
||||
dragging = true
|
||||
let newValue = min(max(0, Double(value.location.x / geometry.size.width) * musicManager.songDuration), musicManager.songDuration)
|
||||
sliderValue = newValue
|
||||
lastDragged = Date()
|
||||
}
|
||||
.onEnded { _ in
|
||||
musicManager.seek(to: sliderValue)
|
||||
dragging = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
.frame(height: 6)
|
||||
|
||||
// Time remaining - right
|
||||
Text("-\(formatTime(musicManager.songDuration - (dragging ? sliderValue : musicManager.elapsedTime)))")
|
||||
.font(.system(size: 11, weight: .medium, design: .monospaced))
|
||||
.foregroundColor(.white.opacity(0.7))
|
||||
.frame(width: 48, alignment: .trailing)
|
||||
}
|
||||
.onAppear {
|
||||
sliderValue = musicManager.elapsedTime
|
||||
}
|
||||
}
|
||||
|
||||
private func currentSliderValue(_ date: Date) -> Double {
|
||||
if dragging {
|
||||
return sliderValue
|
||||
}
|
||||
|
||||
// Update slider value based on playback
|
||||
if musicManager.isPlaying {
|
||||
let timeSinceLastUpdate = date.timeIntervalSince(musicManager.lastUpdated)
|
||||
let estimatedElapsed = musicManager.elapsedTime + (timeSinceLastUpdate * musicManager.playbackRate)
|
||||
return min(estimatedElapsed, musicManager.songDuration)
|
||||
}
|
||||
|
||||
return musicManager.elapsedTime
|
||||
}
|
||||
|
||||
private var sliderColor: Color {
|
||||
switch Defaults[.sliderColor] {
|
||||
case .white:
|
||||
return .white
|
||||
case .albumArt:
|
||||
return Color(nsColor: musicManager.avgColor)
|
||||
case .accent:
|
||||
return .accentColor
|
||||
}
|
||||
}
|
||||
|
||||
private func formatTime(_ time: TimeInterval) -> String {
|
||||
let minutes = Int(time) / 60
|
||||
let seconds = Int(time) % 60
|
||||
return String(format: "%d:%02d", minutes, seconds)
|
||||
}
|
||||
|
||||
// MARK: - Playback Controls (Larger)
|
||||
|
||||
private var playbackControls: some View {
|
||||
HStack(spacing: 20) {
|
||||
if Defaults[.showShuffleAndRepeat] {
|
||||
controlButton(icon: "shuffle", isActive: musicManager.isShuffled) {
|
||||
Task { await musicManager.toggleShuffle() }
|
||||
}
|
||||
}
|
||||
|
||||
controlButton(icon: "backward.fill", size: 18) {
|
||||
Task { await musicManager.previousTrack() }
|
||||
}
|
||||
|
||||
playPauseButton
|
||||
|
||||
controlButton(icon: "forward.fill", size: 18) {
|
||||
Task { await musicManager.nextTrack() }
|
||||
}
|
||||
|
||||
if Defaults[.showShuffleAndRepeat] {
|
||||
controlButton(icon: repeatIcon, isActive: musicManager.repeatMode != .off) {
|
||||
Task { await musicManager.toggleRepeat() }
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.padding(.top, 2)
|
||||
}
|
||||
|
||||
private var playPauseButton: some View {
|
||||
Button(action: {
|
||||
Task { await musicManager.togglePlay() }
|
||||
}) {
|
||||
Image(systemName: musicManager.isPlaying ? "pause.fill" : "play.fill")
|
||||
.font(.system(size: 24, weight: .semibold))
|
||||
.foregroundColor(.white)
|
||||
.frame(width: 50, height: 50)
|
||||
}
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
}
|
||||
|
||||
private func controlButton(icon: String, size: CGFloat = 18, isActive: Bool = false, action: @escaping () -> Void) -> some View {
|
||||
Button(action: action) {
|
||||
Image(systemName: icon)
|
||||
.font(.system(size: size, weight: .medium))
|
||||
.foregroundColor(isActive ? .red : .white.opacity(0.8))
|
||||
}
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
}
|
||||
|
||||
private var repeatIcon: String {
|
||||
switch musicManager.repeatMode {
|
||||
case .off: return "repeat"
|
||||
case .all: return "repeat"
|
||||
case .one: return "repeat.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Minimalistic Album Art
|
||||
|
||||
struct MinimalisticAlbumArtView: View {
|
||||
@ObservedObject var musicManager = MusicManager.shared
|
||||
@ObservedObject var vm: DynamicIslandViewModel
|
||||
let albumArtNamespace: Namespace.ID
|
||||
|
||||
var body: some View {
|
||||
Button {
|
||||
musicManager.openMusicApp()
|
||||
} label: {
|
||||
Color.clear
|
||||
.aspectRatio(1, contentMode: .fit)
|
||||
.background(
|
||||
Image(nsImage: musicManager.albumArt)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
)
|
||||
.clipped()
|
||||
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||
.matchedGeometryEffect(id: "albumArt", in: albumArtNamespace)
|
||||
}
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
.opacity(musicManager.isPlaying ? 1 : 0.4)
|
||||
}
|
||||
}
|
||||
|
|
@ -246,23 +246,29 @@ struct NotchHomeView: View {
|
|||
|
||||
private var mainContent: some View {
|
||||
HStack(alignment: .top, spacing: 20) {
|
||||
MusicPlayerView(albumArtNamespace: albumArtNamespace)
|
||||
|
||||
if Defaults[.showCalendar] {
|
||||
CalendarView()
|
||||
.onHover { isHovering in
|
||||
vm.isHoveringCalendar = isHovering
|
||||
}
|
||||
.environmentObject(vm)
|
||||
}
|
||||
|
||||
if Defaults[.showMirror],
|
||||
webcamManager.cameraAvailable,
|
||||
vm.notchState == .open {
|
||||
CameraPreviewView(webcamManager: webcamManager)
|
||||
.scaledToFit()
|
||||
.opacity(vm.notchState == .closed ? 0 : 1)
|
||||
.blur(radius: vm.notchState == .closed ? 20 : 0)
|
||||
if Defaults[.enableMinimalisticUI] {
|
||||
// Minimalistic mode: Only show compact music player
|
||||
MinimalisticMusicPlayerView(albumArtNamespace: albumArtNamespace)
|
||||
} else {
|
||||
// Normal mode: Show full music player with optional calendar and webcam
|
||||
MusicPlayerView(albumArtNamespace: albumArtNamespace)
|
||||
|
||||
if Defaults[.showCalendar] {
|
||||
CalendarView()
|
||||
.onHover { isHovering in
|
||||
vm.isHoveringCalendar = isHovering
|
||||
}
|
||||
.environmentObject(vm)
|
||||
}
|
||||
|
||||
if Defaults[.showMirror],
|
||||
webcamManager.cameraAvailable,
|
||||
vm.notchState == .open {
|
||||
CameraPreviewView(webcamManager: webcamManager)
|
||||
.scaledToFit()
|
||||
.opacity(vm.notchState == .closed ? 0 : 1)
|
||||
.blur(radius: vm.notchState == .closed ? 20 : 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
.transition(.opacity.animation(.smooth.speed(0.9))
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import UniformTypeIdentifiers
|
|||
struct SettingsView: View {
|
||||
@StateObject var extensionManager = DynamicIslandExtensionManager()
|
||||
@State private var selectedTab = "General"
|
||||
@Default(.enableMinimalisticUI) var enableMinimalisticUI
|
||||
|
||||
let updaterController: SPUStandardUpdaterController?
|
||||
|
||||
|
|
@ -38,8 +39,10 @@ struct SettingsView: View {
|
|||
NavigationLink(value: "Media") {
|
||||
Label("Media", systemImage: "play.laptopcomputer")
|
||||
}
|
||||
NavigationLink(value: "Calendar") {
|
||||
Label("Calendar", systemImage: "calendar")
|
||||
if !enableMinimalisticUI {
|
||||
NavigationLink(value: "Calendar") {
|
||||
Label("Calendar", systemImage: "calendar")
|
||||
}
|
||||
}
|
||||
NavigationLink(value: "HUD") {
|
||||
Label("HUDs", systemImage: "dial.medium.fill")
|
||||
|
|
@ -47,20 +50,22 @@ struct SettingsView: View {
|
|||
NavigationLink(value: "Battery") {
|
||||
Label("Battery", systemImage: "battery.100.bolt")
|
||||
}
|
||||
NavigationLink(value: "Timer") {
|
||||
Label("Timer", systemImage: "timer")
|
||||
}
|
||||
NavigationLink(value: "Stats") {
|
||||
Label("Stats", systemImage: "chart.xyaxis.line")
|
||||
}
|
||||
NavigationLink(value: "Clipboard") {
|
||||
Label("Clipboard", systemImage: "clipboard")
|
||||
}
|
||||
NavigationLink(value: "ScreenAssistant") {
|
||||
Label("Screen Assistant", systemImage: "brain.head.profile")
|
||||
}
|
||||
NavigationLink(value: "ColorPicker") {
|
||||
Label("Color Picker", systemImage: "eyedropper")
|
||||
if !enableMinimalisticUI {
|
||||
NavigationLink(value: "Timer") {
|
||||
Label("Timer", systemImage: "timer")
|
||||
}
|
||||
NavigationLink(value: "Stats") {
|
||||
Label("Stats", systemImage: "chart.xyaxis.line")
|
||||
}
|
||||
NavigationLink(value: "Clipboard") {
|
||||
Label("Clipboard", systemImage: "clipboard")
|
||||
}
|
||||
NavigationLink(value: "ScreenAssistant") {
|
||||
Label("Screen Assistant", systemImage: "brain.head.profile")
|
||||
}
|
||||
NavigationLink(value: "ColorPicker") {
|
||||
Label("Color Picker", systemImage: "eyedropper")
|
||||
}
|
||||
}
|
||||
if extensionManager.installedExtensions
|
||||
.contains(where: { $0.bundleIdentifier == downloadManagerExtension }) {
|
||||
|
|
@ -68,8 +73,10 @@ struct SettingsView: View {
|
|||
Label("Downloads", systemImage: "square.and.arrow.down")
|
||||
}
|
||||
}
|
||||
NavigationLink(value: "Shelf") {
|
||||
Label("Shelf", systemImage: "books.vertical")
|
||||
if !enableMinimalisticUI {
|
||||
NavigationLink(value: "Shelf") {
|
||||
Label("Shelf", systemImage: "books.vertical")
|
||||
}
|
||||
}
|
||||
NavigationLink(value: "Shortcuts") {
|
||||
Label("Shortcuts", systemImage: "keyboard")
|
||||
|
|
@ -165,9 +172,24 @@ struct GeneralSettings: View {
|
|||
@Default(.openNotchOnHover) var openNotchOnHover
|
||||
@Default(.enableScreenRecordingDetection) var enableScreenRecordingDetection
|
||||
@Default(.showRecordingIndicator) var showRecordingIndicator
|
||||
@Default(.enableMinimalisticUI) var enableMinimalisticUI
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section {
|
||||
Defaults.Toggle("Enable Minimalistic UI", key: .enableMinimalisticUI)
|
||||
.onChange(of: enableMinimalisticUI) { _, newValue in
|
||||
if newValue {
|
||||
// Auto-enable simpler animation mode
|
||||
Defaults[.useModernCloseAnimation] = true
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("UI Mode")
|
||||
} footer: {
|
||||
Text("Minimalistic mode focuses on media controls and system HUDs, hiding all extra features for a clean, focused experience. Automatically enables simpler animations.")
|
||||
}
|
||||
|
||||
Section {
|
||||
Defaults.Toggle("Menubar icon", key: .menubarIcon)
|
||||
LaunchAtLogin.Toggle("Launch at login")
|
||||
|
|
@ -563,6 +585,7 @@ struct Media: View {
|
|||
@Default(.hideNotchOption) var hideNotchOption
|
||||
@Default(.enableSneakPeek) private var enableSneakPeek
|
||||
@Default(.sneakPeekStyles) var sneakPeekStyles
|
||||
@Default(.enableMinimalisticUI) var enableMinimalisticUI
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
|
|
@ -616,7 +639,21 @@ struct Media: View {
|
|||
ForEach(SneakPeekStyle.allCases) { style in
|
||||
Text(style.rawValue).tag(style)
|
||||
}
|
||||
}.disabled(!enableSneakPeek)
|
||||
}
|
||||
.disabled(!enableSneakPeek || enableMinimalisticUI)
|
||||
.onChange(of: enableMinimalisticUI) { _, isMinimalistic in
|
||||
// Force standard sneak peek style when minimalistic UI is enabled
|
||||
if isMinimalistic {
|
||||
sneakPeekStyles = .standard
|
||||
}
|
||||
}
|
||||
|
||||
if enableMinimalisticUI {
|
||||
Text("Sneak peek style is locked to Standard in minimalistic mode")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
HStack {
|
||||
Stepper(value: $waitInterval, in: 0...10, step: 1) {
|
||||
HStack {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue