From ddfbe8aaa24ab5b58fb8d8ae28f127334138c30d Mon Sep 17 00:00:00 2001 From: cnliucheng Date: Thu, 6 Aug 2026 10:08:36 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=EF=BC=9A=E9=83=A8=E7=BD=B2?= =?UTF-8?q?=E7=9B=AE=E6=A0=87=E9=99=8D=E8=87=B3=2011.0=EF=BC=8C=E7=A7=92?= =?UTF-8?q?=E6=95=B0/12=E5=B0=8F=E6=97=B6=E5=88=B6=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E5=8F=AF=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 MACOSX_DEPLOYMENT_TARGET 由项目级 27.0 / 目标级 15.6 统一改为 11.0 (代码所用 API 的最低门槛为 11.0),使屏保可在当前及更早系统加载 - showSeconds / use24Hour 由写死的 static let 改为设置驱动的可选项: * FlipClockSettings 新增键 showSeconds / use24Hour,支持持久化与读取 * 设置面板新增「显示秒数」「24 小时制」两个勾选项,取消可回滚 * 视图的 loadSettings / 跨进程轮询 / 设置通知均同步新选项 * 原 use24Hour=false 的 AM/PM 死代码现已可经设置启用 --- FlipClockSaver.xcodeproj/project.pbxproj | 8 +- FlipClockSaver/FlipClockSaver.swift | 109 +++++++++++++++++------ 2 files changed, 84 insertions(+), 33 deletions(-) diff --git a/FlipClockSaver.xcodeproj/project.pbxproj b/FlipClockSaver.xcodeproj/project.pbxproj index 394ddaa..41a90ce 100644 --- a/FlipClockSaver.xcodeproj/project.pbxproj +++ b/FlipClockSaver.xcodeproj/project.pbxproj @@ -191,7 +191,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MACOSX_DEPLOYMENT_TARGET = 27.0; + MACOSX_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -247,7 +247,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MACOSX_DEPLOYMENT_TARGET = 27.0; + MACOSX_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = macosx; @@ -266,7 +266,7 @@ INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSPrincipalClass = FlipClockSaverView; INSTALL_PATH = "$(HOME)/Library/Screen Savers"; - MACOSX_DEPLOYMENT_TARGET = 15.6; + MACOSX_DEPLOYMENT_TARGET = 11.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.liucheng.FlipClockSaver; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -291,7 +291,7 @@ INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSPrincipalClass = FlipClockSaverView; INSTALL_PATH = "$(HOME)/Library/Screen Savers"; - MACOSX_DEPLOYMENT_TARGET = 15.6; + MACOSX_DEPLOYMENT_TARGET = 11.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.liucheng.FlipClockSaver; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/FlipClockSaver/FlipClockSaver.swift b/FlipClockSaver/FlipClockSaver.swift index a59d68b..5b3cddd 100644 --- a/FlipClockSaver/FlipClockSaver.swift +++ b/FlipClockSaver/FlipClockSaver.swift @@ -146,9 +146,9 @@ final class FlipDigit { @objc(FlipClockSaverView) final class FlipClockSaverView: ScreenSaverView { - // 顶部可配置项 - static let showSeconds = true - static let use24Hour = true + // 顶部可配置项(运行时由设置驱动,不再写死) + private var showSeconds = true + private var use24Hour = true // 尺寸 / 缩放(fitScale 可在设置面板中调整) private let unitW: CGFloat = 108 @@ -228,11 +228,11 @@ final class FlipClockSaverView: ScreenSaverView { addDigit(h0); addDigit(h1); addColon() addDigit(m0); addDigit(m1) - if Self.showSeconds { addColon(); addDigit(s0); addDigit(s1) } + if showSeconds { addColon(); addDigit(s0); addDigit(s1) } digits = ds; rects = rs; colonRects = cols - if !Self.use24Hour { + if !use24Hour { ampmRect = CGRect(x: cur, y: 0, width: 120, height: unitH) cur += 120 + spacing } @@ -245,7 +245,7 @@ final class FlipClockSaverView: ScreenSaverView { let now = Calendar.current.dateComponents([.hour, .minute, .second], from: Date()) var h = now.hour ?? 0 var ampm = "" - if !Self.use24Hour { + if !use24Hour { ampm = h >= 12 ? "PM" : "AM" h = h % 12 if h == 0 { h = 12 } @@ -257,7 +257,7 @@ final class FlipClockSaverView: ScreenSaverView { Int(String(hh.prefix(1))) ?? 0, Int(String(hh.suffix(1))) ?? 0, Int(String(mm.prefix(1))) ?? 0, Int(String(mm.suffix(1))) ?? 0 ] - if Self.showSeconds { + if showSeconds { vals.append(Int(String(ss.prefix(1))) ?? 0) vals.append(Int(String(ss.suffix(1))) ?? 0) } @@ -292,11 +292,17 @@ final class FlipClockSaverView: ScreenSaverView { let newScale = FlipClockSettings.fitScale let newShowDate = FlipClockSettings.showDate let newShowLunar = FlipClockSettings.showLunar - guard newScale != fitScale || newShowDate != showDate || newShowLunar != showLunar else { return } + let newShowSeconds = FlipClockSettings.showSeconds + let newUse24Hour = FlipClockSettings.use24Hour + guard newScale != fitScale || newShowDate != showDate || newShowLunar != showLunar + || newShowSeconds != showSeconds || newUse24Hour != use24Hour else { return } let togglesChanged = newShowDate != showDate || newShowLunar != showLunar + || newShowSeconds != showSeconds || newUse24Hour != use24Hour fitScale = newScale showDate = newShowDate showLunar = newShowLunar + showSeconds = newShowSeconds + use24Hour = newUse24Hour if togglesChanged { buildLayout() update(animated: false, at: frameTime) @@ -321,7 +327,7 @@ final class FlipClockSaverView: ScreenSaverView { cardBg: cardBg, textColor: textColor, now: now) } for c in colonRects { drawColon(in: ctx, rect: c) } - if !Self.use24Hour, let ar = ampmRect { drawAmPm(in: ctx, rect: ar) } + if !use24Hour, let ar = ampmRect { drawAmPm(in: ctx, rect: ar) } if showDate || showLunar { drawInfo(in: ctx, rect: infoRect) } ctx.restoreGState() } @@ -418,16 +424,21 @@ final class FlipClockSaverView: ScreenSaverView { @objc private func handleSettingsChanged(_ note: Notification) { let oldShowDate = showDate let oldShowLunar = showLunar + let oldShowSeconds = showSeconds + let oldUse24Hour = use24Hour if let info = note.userInfo, !info.isEmpty { // 直接从通知携带的值应用,不依赖 defaults 读回路径 if let v = info[FlipClockSettings.keyScale] as? Double { fitScale = CGFloat(v) } if let v = info[FlipClockSettings.keyShowDate] as? Bool { showDate = v } if let v = info[FlipClockSettings.keyShowLunar] as? Bool { showLunar = v } + if let v = info[FlipClockSettings.keyShowSeconds] as? Bool { showSeconds = v } + if let v = info[FlipClockSettings.keyUse24Hour] as? Bool { use24Hour = v } } else { loadSettings() } NSLog("[FlipClock] view 收到设置通知,已应用 scale=%.2f", Double(fitScale)) - if oldShowDate != showDate || oldShowLunar != showLunar { + if oldShowDate != showDate || oldShowLunar != showLunar + || oldShowSeconds != showSeconds || oldUse24Hour != use24Hour { buildLayout() update(animated: false, at: frameTime) } @@ -438,6 +449,8 @@ final class FlipClockSaverView: ScreenSaverView { fitScale = FlipClockSettings.fitScale showDate = FlipClockSettings.showDate showLunar = FlipClockSettings.showLunar + showSeconds = FlipClockSettings.showSeconds + use24Hour = FlipClockSettings.use24Hour } } @@ -451,6 +464,8 @@ enum FlipClockSettings { static let keyScale = "fitScale" static let keyShowDate = "showDate" static let keyShowLunar = "showLunar" + static let keyShowSeconds = "showSeconds" + static let keyUse24Hour = "use24Hour" static let defaultScale = 0.55 static let defaults: ScreenSaverDefaults = { @@ -459,7 +474,8 @@ enum FlipClockSettings { }() static func registerDefaults() { - defaults.register(defaults: [keyScale: defaultScale, keyShowDate: true, keyShowLunar: true]) + defaults.register(defaults: [keyScale: defaultScale, keyShowDate: true, keyShowLunar: true, + keyShowSeconds: true, keyUse24Hour: true]) } // 主存储:直接读写 plist 文件,绕开 cfprefsd 缓存。 @@ -477,8 +493,9 @@ enum FlipClockSettings { return dict } - static func save(scale: Double, showDate: Bool, showLunar: Bool) { - let dict: [String: Any] = [keyScale: scale, keyShowDate: showDate, keyShowLunar: showLunar] + static func save(scale: Double, showDate: Bool, showLunar: Bool, showSeconds: Bool, use24Hour: Bool) { + let dict: [String: Any] = [keyScale: scale, keyShowDate: showDate, keyShowLunar: showLunar, + keyShowSeconds: showSeconds, keyUse24Hour: use24Hour] var fileOK = false if let data = try? PropertyListSerialization.data(fromPropertyList: dict, format: .xml, options: 0) { try? FileManager.default.createDirectory(at: settingsURL.deletingLastPathComponent(), @@ -495,7 +512,10 @@ enum FlipClockSettings { d.set(scale, forKey: keyScale) d.set(showDate, forKey: keyShowDate) d.set(showLunar, forKey: keyShowLunar) - NSLog("[FlipClock] 设置已保存(fileOK=%d): scale=%.2f date=%d lunar=%d", fileOK, scale, showDate, showLunar) + d.set(showSeconds, forKey: keyShowSeconds) + d.set(use24Hour, forKey: keyUse24Hour) + NSLog("[FlipClock] 设置已保存(fileOK=%d): scale=%.2f date=%d lunar=%d seconds=%d hour24=%d", + fileOK, scale, showDate, showLunar, showSeconds, use24Hour) } static var fitScale: CGFloat { @@ -513,6 +533,16 @@ enum FlipClockSettings { if let v = readFile()[keyShowLunar] as? Bool { return v } return defaults.object(forKey: keyShowLunar) as? Bool ?? true } + + static var showSeconds: Bool { + if let v = readFile()[keyShowSeconds] as? Bool { return v } + return defaults.object(forKey: keyShowSeconds) as? Bool ?? true + } + + static var use24Hour: Bool { + if let v = readFile()[keyUse24Hour] as? Bool { return v } + return defaults.object(forKey: keyUse24Hour) as? Bool ?? true + } } // MARK: - 设置窗口(纯代码构建,无 xib) @@ -524,14 +554,18 @@ final class FlipClockConfigController: NSWindowController { private let scaleLabel = NSTextField(labelWithString: "55%") private let showDateBox = NSButton(checkboxWithTitle: "显示公历日期", target: nil, action: nil) private let showLunarBox = NSButton(checkboxWithTitle: "显示农历", target: nil, action: nil) + private let showSecondsBox = NSButton(checkboxWithTitle: "显示秒数", target: nil, action: nil) + private let use24Box = NSButton(checkboxWithTitle: "24 小时制", target: nil, action: nil) // 打开时的原始值,用于“取消”时回滚 private var originalScale: Double = 0.55 private var originalShowDate = true private var originalShowLunar = true + private var originalShowSeconds = true + private var originalUse24Hour = true init() { - let window = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 340, height: 196), + let window = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 340, height: 256), styleMask: [.titled], backing: .buffered, defer: false) window.title = "翻页时钟设置" window.isReleasedWhenClosed = false @@ -546,9 +580,13 @@ final class FlipClockConfigController: NSWindowController { originalScale = Double(FlipClockSettings.fitScale) originalShowDate = FlipClockSettings.showDate originalShowLunar = FlipClockSettings.showLunar + originalShowSeconds = FlipClockSettings.showSeconds + originalUse24Hour = FlipClockSettings.use24Hour scaleSlider.doubleValue = originalScale showDateBox.state = originalShowDate ? .on : .off showLunarBox.state = originalShowLunar ? .on : .off + showSecondsBox.state = originalShowSeconds ? .on : .off + use24Box.state = originalUse24Hour ? .on : .off updateScaleLabel() } @@ -557,36 +595,43 @@ final class FlipClockConfigController: NSWindowController { } private func buildUI() { - let content = NSView(frame: NSRect(x: 0, y: 0, width: 340, height: 196)) + let content = NSView(frame: NSRect(x: 0, y: 0, width: 340, height: 256)) window?.contentView = content let left: CGFloat = 20 let titleLabel = NSTextField(labelWithString: "整体缩放:") - titleLabel.frame = CGRect(x: left, y: 152, width: 76, height: 17) - scaleSlider.frame = CGRect(x: left + 76, y: 148, width: 170, height: 24) + titleLabel.frame = CGRect(x: left, y: 212, width: 76, height: 17) + scaleSlider.frame = CGRect(x: left + 76, y: 208, width: 170, height: 24) scaleSlider.target = self scaleSlider.action = #selector(sliderChanged) - scaleLabel.frame = CGRect(x: left + 254, y: 152, width: 56, height: 17) + scaleLabel.frame = CGRect(x: left + 254, y: 212, width: 56, height: 17) scaleLabel.alignment = .right - showDateBox.frame = CGRect(x: left, y: 116, width: 200, height: 20) + showDateBox.frame = CGRect(x: left, y: 176, width: 200, height: 20) showDateBox.target = self showDateBox.action = #selector(controlChanged) - showLunarBox.frame = CGRect(x: left, y: 84, width: 200, height: 20) + showLunarBox.frame = CGRect(x: left, y: 144, width: 200, height: 20) showLunarBox.target = self showLunarBox.action = #selector(controlChanged) + showSecondsBox.frame = CGRect(x: left, y: 112, width: 200, height: 20) + showSecondsBox.target = self + showSecondsBox.action = #selector(controlChanged) + use24Box.frame = CGRect(x: left, y: 80, width: 200, height: 20) + use24Box.target = self + use24Box.action = #selector(controlChanged) let okBtn = NSButton(title: "好", target: self, action: #selector(okPressed)) okBtn.bezelStyle = .rounded okBtn.keyEquivalent = "\r" - okBtn.frame = CGRect(x: 244, y: 20, width: 76, height: 32) + okBtn.frame = CGRect(x: 244, y: 24, width: 76, height: 32) let cancelBtn = NSButton(title: "取消", target: self, action: #selector(cancelPressed)) cancelBtn.bezelStyle = .rounded cancelBtn.keyEquivalent = "\u{1b}" - cancelBtn.frame = CGRect(x: 160, y: 20, width: 76, height: 32) + cancelBtn.frame = CGRect(x: 160, y: 24, width: 76, height: 32) - let views: [NSView] = [titleLabel, scaleSlider, scaleLabel, showDateBox, showLunarBox, okBtn, cancelBtn] + let views: [NSView] = [titleLabel, scaleSlider, scaleLabel, showDateBox, showLunarBox, + showSecondsBox, use24Box, okBtn, cancelBtn] for v in views { content.addSubview(v) } } @@ -600,23 +645,29 @@ final class FlipClockConfigController: NSWindowController { private func applyCurrentValues() { apply(scale: scaleSlider.doubleValue, showDate: showDateBox.state == .on, - showLunar: showLunarBox.state == .on) + showLunar: showLunarBox.state == .on, + showSeconds: showSecondsBox.state == .on, + use24Hour: use24Box.state == .on) } // 实时保存并广播(userInfo 携带最新值):同进程即时生效,跨进程靠文件轮询同步 - private func apply(scale: Double, showDate: Bool, showLunar: Bool) { - FlipClockSettings.save(scale: scale, showDate: showDate, showLunar: showLunar) + private func apply(scale: Double, showDate: Bool, showLunar: Bool, showSeconds: Bool, use24Hour: Bool) { + FlipClockSettings.save(scale: scale, showDate: showDate, showLunar: showLunar, + showSeconds: showSeconds, use24Hour: use24Hour) NotificationCenter.default.post(name: .flipClockSettingsDidChange, object: nil, userInfo: [FlipClockSettings.keyScale: scale, FlipClockSettings.keyShowDate: showDate, - FlipClockSettings.keyShowLunar: showLunar]) + FlipClockSettings.keyShowLunar: showLunar, + FlipClockSettings.keyShowSeconds: showSeconds, + FlipClockSettings.keyUse24Hour: use24Hour]) } @objc private func okPressed() { dismissSheet() } @objc private func cancelPressed() { // 恢复打开前的设置 - apply(scale: originalScale, showDate: originalShowDate, showLunar: originalShowLunar) + apply(scale: originalScale, showDate: originalShowDate, showLunar: originalShowLunar, + showSeconds: originalShowSeconds, use24Hour: originalUse24Hour) dismissSheet() }