修复:部署目标降至 11.0,秒数/12小时制改为可配置

- 将 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 死代码现已可经设置启用
This commit is contained in:
2026-08-06 10:08:36 +08:00
parent 691ea69038
commit ddfbe8aaa2
2 changed files with 84 additions and 33 deletions
+4 -4
View File
@@ -191,7 +191,7 @@
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES; LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 27.0; MACOSX_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
@@ -247,7 +247,7 @@
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES; LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 27.0; MACOSX_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
SDKROOT = macosx; SDKROOT = macosx;
@@ -266,7 +266,7 @@
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
INFOPLIST_KEY_NSPrincipalClass = FlipClockSaverView; INFOPLIST_KEY_NSPrincipalClass = FlipClockSaverView;
INSTALL_PATH = "$(HOME)/Library/Screen Savers"; INSTALL_PATH = "$(HOME)/Library/Screen Savers";
MACOSX_DEPLOYMENT_TARGET = 15.6; MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.liucheng.FlipClockSaver; PRODUCT_BUNDLE_IDENTIFIER = com.liucheng.FlipClockSaver;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
@@ -291,7 +291,7 @@
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
INFOPLIST_KEY_NSPrincipalClass = FlipClockSaverView; INFOPLIST_KEY_NSPrincipalClass = FlipClockSaverView;
INSTALL_PATH = "$(HOME)/Library/Screen Savers"; INSTALL_PATH = "$(HOME)/Library/Screen Savers";
MACOSX_DEPLOYMENT_TARGET = 15.6; MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.liucheng.FlipClockSaver; PRODUCT_BUNDLE_IDENTIFIER = com.liucheng.FlipClockSaver;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
+80 -29
View File
@@ -146,9 +146,9 @@ final class FlipDigit {
@objc(FlipClockSaverView) @objc(FlipClockSaverView)
final class FlipClockSaverView: ScreenSaverView { final class FlipClockSaverView: ScreenSaverView {
// //
static let showSeconds = true private var showSeconds = true
static let use24Hour = true private var use24Hour = true
// / fitScale // / fitScale
private let unitW: CGFloat = 108 private let unitW: CGFloat = 108
@@ -228,11 +228,11 @@ final class FlipClockSaverView: ScreenSaverView {
addDigit(h0); addDigit(h1); addColon() addDigit(h0); addDigit(h1); addColon()
addDigit(m0); addDigit(m1) 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 digits = ds; rects = rs; colonRects = cols
if !Self.use24Hour { if !use24Hour {
ampmRect = CGRect(x: cur, y: 0, width: 120, height: unitH) ampmRect = CGRect(x: cur, y: 0, width: 120, height: unitH)
cur += 120 + spacing cur += 120 + spacing
} }
@@ -245,7 +245,7 @@ final class FlipClockSaverView: ScreenSaverView {
let now = Calendar.current.dateComponents([.hour, .minute, .second], from: Date()) let now = Calendar.current.dateComponents([.hour, .minute, .second], from: Date())
var h = now.hour ?? 0 var h = now.hour ?? 0
var ampm = "" var ampm = ""
if !Self.use24Hour { if !use24Hour {
ampm = h >= 12 ? "PM" : "AM" ampm = h >= 12 ? "PM" : "AM"
h = h % 12 h = h % 12
if h == 0 { 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(hh.prefix(1))) ?? 0, Int(String(hh.suffix(1))) ?? 0,
Int(String(mm.prefix(1))) ?? 0, Int(String(mm.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.prefix(1))) ?? 0)
vals.append(Int(String(ss.suffix(1))) ?? 0) vals.append(Int(String(ss.suffix(1))) ?? 0)
} }
@@ -292,11 +292,17 @@ final class FlipClockSaverView: ScreenSaverView {
let newScale = FlipClockSettings.fitScale let newScale = FlipClockSettings.fitScale
let newShowDate = FlipClockSettings.showDate let newShowDate = FlipClockSettings.showDate
let newShowLunar = FlipClockSettings.showLunar 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 let togglesChanged = newShowDate != showDate || newShowLunar != showLunar
|| newShowSeconds != showSeconds || newUse24Hour != use24Hour
fitScale = newScale fitScale = newScale
showDate = newShowDate showDate = newShowDate
showLunar = newShowLunar showLunar = newShowLunar
showSeconds = newShowSeconds
use24Hour = newUse24Hour
if togglesChanged { if togglesChanged {
buildLayout() buildLayout()
update(animated: false, at: frameTime) update(animated: false, at: frameTime)
@@ -321,7 +327,7 @@ final class FlipClockSaverView: ScreenSaverView {
cardBg: cardBg, textColor: textColor, now: now) cardBg: cardBg, textColor: textColor, now: now)
} }
for c in colonRects { drawColon(in: ctx, rect: c) } 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) } if showDate || showLunar { drawInfo(in: ctx, rect: infoRect) }
ctx.restoreGState() ctx.restoreGState()
} }
@@ -418,16 +424,21 @@ final class FlipClockSaverView: ScreenSaverView {
@objc private func handleSettingsChanged(_ note: Notification) { @objc private func handleSettingsChanged(_ note: Notification) {
let oldShowDate = showDate let oldShowDate = showDate
let oldShowLunar = showLunar let oldShowLunar = showLunar
let oldShowSeconds = showSeconds
let oldUse24Hour = use24Hour
if let info = note.userInfo, !info.isEmpty { if let info = note.userInfo, !info.isEmpty {
// defaults // defaults
if let v = info[FlipClockSettings.keyScale] as? Double { fitScale = CGFloat(v) } 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.keyShowDate] as? Bool { showDate = v }
if let v = info[FlipClockSettings.keyShowLunar] as? Bool { showLunar = 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 { } else {
loadSettings() loadSettings()
} }
NSLog("[FlipClock] view 收到设置通知,已应用 scale=%.2f", Double(fitScale)) NSLog("[FlipClock] view 收到设置通知,已应用 scale=%.2f", Double(fitScale))
if oldShowDate != showDate || oldShowLunar != showLunar { if oldShowDate != showDate || oldShowLunar != showLunar
|| oldShowSeconds != showSeconds || oldUse24Hour != use24Hour {
buildLayout() buildLayout()
update(animated: false, at: frameTime) update(animated: false, at: frameTime)
} }
@@ -438,6 +449,8 @@ final class FlipClockSaverView: ScreenSaverView {
fitScale = FlipClockSettings.fitScale fitScale = FlipClockSettings.fitScale
showDate = FlipClockSettings.showDate showDate = FlipClockSettings.showDate
showLunar = FlipClockSettings.showLunar showLunar = FlipClockSettings.showLunar
showSeconds = FlipClockSettings.showSeconds
use24Hour = FlipClockSettings.use24Hour
} }
} }
@@ -451,6 +464,8 @@ enum FlipClockSettings {
static let keyScale = "fitScale" static let keyScale = "fitScale"
static let keyShowDate = "showDate" static let keyShowDate = "showDate"
static let keyShowLunar = "showLunar" static let keyShowLunar = "showLunar"
static let keyShowSeconds = "showSeconds"
static let keyUse24Hour = "use24Hour"
static let defaultScale = 0.55 static let defaultScale = 0.55
static let defaults: ScreenSaverDefaults = { static let defaults: ScreenSaverDefaults = {
@@ -459,7 +474,8 @@ enum FlipClockSettings {
}() }()
static func registerDefaults() { 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 // plist cfprefsd
@@ -477,8 +493,9 @@ enum FlipClockSettings {
return dict return dict
} }
static func save(scale: Double, showDate: Bool, showLunar: Bool) { static func save(scale: Double, showDate: Bool, showLunar: Bool, showSeconds: Bool, use24Hour: Bool) {
let dict: [String: Any] = [keyScale: scale, keyShowDate: showDate, keyShowLunar: showLunar] let dict: [String: Any] = [keyScale: scale, keyShowDate: showDate, keyShowLunar: showLunar,
keyShowSeconds: showSeconds, keyUse24Hour: use24Hour]
var fileOK = false var fileOK = false
if let data = try? PropertyListSerialization.data(fromPropertyList: dict, format: .xml, options: 0) { if let data = try? PropertyListSerialization.data(fromPropertyList: dict, format: .xml, options: 0) {
try? FileManager.default.createDirectory(at: settingsURL.deletingLastPathComponent(), try? FileManager.default.createDirectory(at: settingsURL.deletingLastPathComponent(),
@@ -495,7 +512,10 @@ enum FlipClockSettings {
d.set(scale, forKey: keyScale) d.set(scale, forKey: keyScale)
d.set(showDate, forKey: keyShowDate) d.set(showDate, forKey: keyShowDate)
d.set(showLunar, forKey: keyShowLunar) 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 { static var fitScale: CGFloat {
@@ -513,6 +533,16 @@ enum FlipClockSettings {
if let v = readFile()[keyShowLunar] as? Bool { return v } if let v = readFile()[keyShowLunar] as? Bool { return v }
return defaults.object(forKey: keyShowLunar) as? Bool ?? true 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 // MARK: - xib
@@ -524,14 +554,18 @@ final class FlipClockConfigController: NSWindowController {
private let scaleLabel = NSTextField(labelWithString: "55%") private let scaleLabel = NSTextField(labelWithString: "55%")
private let showDateBox = NSButton(checkboxWithTitle: "显示公历日期", target: nil, action: nil) private let showDateBox = NSButton(checkboxWithTitle: "显示公历日期", target: nil, action: nil)
private let showLunarBox = 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 originalScale: Double = 0.55
private var originalShowDate = true private var originalShowDate = true
private var originalShowLunar = true private var originalShowLunar = true
private var originalShowSeconds = true
private var originalUse24Hour = true
init() { 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) styleMask: [.titled], backing: .buffered, defer: false)
window.title = "翻页时钟设置" window.title = "翻页时钟设置"
window.isReleasedWhenClosed = false window.isReleasedWhenClosed = false
@@ -546,9 +580,13 @@ final class FlipClockConfigController: NSWindowController {
originalScale = Double(FlipClockSettings.fitScale) originalScale = Double(FlipClockSettings.fitScale)
originalShowDate = FlipClockSettings.showDate originalShowDate = FlipClockSettings.showDate
originalShowLunar = FlipClockSettings.showLunar originalShowLunar = FlipClockSettings.showLunar
originalShowSeconds = FlipClockSettings.showSeconds
originalUse24Hour = FlipClockSettings.use24Hour
scaleSlider.doubleValue = originalScale scaleSlider.doubleValue = originalScale
showDateBox.state = originalShowDate ? .on : .off showDateBox.state = originalShowDate ? .on : .off
showLunarBox.state = originalShowLunar ? .on : .off showLunarBox.state = originalShowLunar ? .on : .off
showSecondsBox.state = originalShowSeconds ? .on : .off
use24Box.state = originalUse24Hour ? .on : .off
updateScaleLabel() updateScaleLabel()
} }
@@ -557,36 +595,43 @@ final class FlipClockConfigController: NSWindowController {
} }
private func buildUI() { 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 window?.contentView = content
let left: CGFloat = 20 let left: CGFloat = 20
let titleLabel = NSTextField(labelWithString: "整体缩放:") let titleLabel = NSTextField(labelWithString: "整体缩放:")
titleLabel.frame = CGRect(x: left, y: 152, width: 76, height: 17) titleLabel.frame = CGRect(x: left, y: 212, width: 76, height: 17)
scaleSlider.frame = CGRect(x: left + 76, y: 148, width: 170, height: 24) scaleSlider.frame = CGRect(x: left + 76, y: 208, width: 170, height: 24)
scaleSlider.target = self scaleSlider.target = self
scaleSlider.action = #selector(sliderChanged) 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 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.target = self
showDateBox.action = #selector(controlChanged) 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.target = self
showLunarBox.action = #selector(controlChanged) 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)) let okBtn = NSButton(title: "", target: self, action: #selector(okPressed))
okBtn.bezelStyle = .rounded okBtn.bezelStyle = .rounded
okBtn.keyEquivalent = "\r" 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)) let cancelBtn = NSButton(title: "取消", target: self, action: #selector(cancelPressed))
cancelBtn.bezelStyle = .rounded cancelBtn.bezelStyle = .rounded
cancelBtn.keyEquivalent = "\u{1b}" 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) } for v in views { content.addSubview(v) }
} }
@@ -600,23 +645,29 @@ final class FlipClockConfigController: NSWindowController {
private func applyCurrentValues() { private func applyCurrentValues() {
apply(scale: scaleSlider.doubleValue, apply(scale: scaleSlider.doubleValue,
showDate: showDateBox.state == .on, showDate: showDateBox.state == .on,
showLunar: showLunarBox.state == .on) showLunar: showLunarBox.state == .on,
showSeconds: showSecondsBox.state == .on,
use24Hour: use24Box.state == .on)
} }
// 广userInfo // 广userInfo
private func apply(scale: Double, showDate: Bool, showLunar: Bool) { private func apply(scale: Double, showDate: Bool, showLunar: Bool, showSeconds: Bool, use24Hour: Bool) {
FlipClockSettings.save(scale: scale, showDate: showDate, showLunar: showLunar) FlipClockSettings.save(scale: scale, showDate: showDate, showLunar: showLunar,
showSeconds: showSeconds, use24Hour: use24Hour)
NotificationCenter.default.post(name: .flipClockSettingsDidChange, object: nil, NotificationCenter.default.post(name: .flipClockSettingsDidChange, object: nil,
userInfo: [FlipClockSettings.keyScale: scale, userInfo: [FlipClockSettings.keyScale: scale,
FlipClockSettings.keyShowDate: showDate, FlipClockSettings.keyShowDate: showDate,
FlipClockSettings.keyShowLunar: showLunar]) FlipClockSettings.keyShowLunar: showLunar,
FlipClockSettings.keyShowSeconds: showSeconds,
FlipClockSettings.keyUse24Hour: use24Hour])
} }
@objc private func okPressed() { dismissSheet() } @objc private func okPressed() { dismissSheet() }
@objc private func cancelPressed() { @objc private func cancelPressed() {
// //
apply(scale: originalScale, showDate: originalShowDate, showLunar: originalShowLunar) apply(scale: originalScale, showDate: originalShowDate, showLunar: originalShowLunar,
showSeconds: originalShowSeconds, use24Hour: originalUse24Hour)
dismissSheet() dismissSheet()
} }