From e3379eaf696d10b17961a1243aef1bb5ddd1a482 Mon Sep 17 00:00:00 2001 From: Federico Imberti <66013290+FI-153@users.noreply.github.com> Date: Sun, 28 Dec 2025 11:18:01 +0100 Subject: [PATCH 1/6] Removed redundant trimming --- DynamicIsland/managers/DoNotDisturbManager.swift | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/DynamicIsland/managers/DoNotDisturbManager.swift b/DynamicIsland/managers/DoNotDisturbManager.swift index 0afcc92..b77f663 100644 --- a/DynamicIsland/managers/DoNotDisturbManager.swift +++ b/DynamicIsland/managers/DoNotDisturbManager.swift @@ -434,19 +434,17 @@ extension FocusModeType { } static func resolve(identifier: String?, name: String?) -> FocusModeType { - let trimmedName = name?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "" - if !trimmedName.isEmpty { + if let name, !name.isEmpty { if let match = FocusModeType.allCases.first(where: { guard !$0.displayName.isEmpty else { return false } - return $0.displayName.compare(trimmedName, options: [.caseInsensitive, .diacriticInsensitive]) == .orderedSame + return $0.displayName.compare(name, options: [.caseInsensitive, .diacriticInsensitive]) == .orderedSame }) { return match } } - let trimmedIdentifier = identifier?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "" - if !trimmedIdentifier.isEmpty { - return FocusModeType(identifier: trimmedIdentifier) + if let identifier, !identifier.isEmpty { + return FocusModeType(identifier: identifier) } return .doNotDisturb From bb8cb12b35e9d84de600c5980af669ac8f1e1012 Mon Sep 17 00:00:00 2001 From: Federico Imberti <66013290+FI-153@users.noreply.github.com> Date: Sun, 28 Dec 2025 11:18:24 +0100 Subject: [PATCH 2/6] Fixed identification of custom focuses --- DynamicIsland/managers/DoNotDisturbManager.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DynamicIsland/managers/DoNotDisturbManager.swift b/DynamicIsland/managers/DoNotDisturbManager.swift index b77f663..7b1e017 100644 --- a/DynamicIsland/managers/DoNotDisturbManager.swift +++ b/DynamicIsland/managers/DoNotDisturbManager.swift @@ -425,7 +425,7 @@ extension FocusModeType { return } - if normalizedLowercased.hasPrefix("com.apple.focus.") { + if normalizedLowercased.hasPrefix("com.apple.focus") { self = .custom return } From 6b55e55db8117a352ebc914afe631753cb57ef29 Mon Sep 17 00:00:00 2001 From: Federico Imberti <66013290+FI-153@users.noreply.github.com> Date: Sun, 28 Dec 2025 11:34:44 +0100 Subject: [PATCH 3/6] Added "Reduce Interruptions" focus --- DynamicIsland/managers/DoNotDisturbManager.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/DynamicIsland/managers/DoNotDisturbManager.swift b/DynamicIsland/managers/DoNotDisturbManager.swift index 7b1e017..36572c5 100644 --- a/DynamicIsland/managers/DoNotDisturbManager.swift +++ b/DynamicIsland/managers/DoNotDisturbManager.swift @@ -307,6 +307,7 @@ enum FocusModeType: String, CaseIterable { case gaming = "com.apple.focus.gaming" case mindfulness = "com.apple.focus.mindfulness" case reading = "com.apple.focus.reading" + case reduceInterruptions = "com.apple.focus.reduce-interruptions" case custom = "com.apple.focus.custom" case unknown = "" @@ -321,6 +322,7 @@ enum FocusModeType: String, CaseIterable { case .gaming: return "Gaming" case .mindfulness: return "Mindfulness" case .reading: return "Reading" + case .reduceInterruptions: return "Reduce Interruptions" case .custom: return "Focus" case .unknown: return "Focus Mode" } @@ -337,6 +339,7 @@ enum FocusModeType: String, CaseIterable { case .gaming: return "gamecontroller.fill" case .mindfulness: return "circle.hexagongrid" case .reading: return "book.closed.fill" + case .reduceInterruptions: return "apple.intelligence" case .custom: return "app.badge" case .unknown: return "moon.fill" } @@ -385,6 +388,8 @@ enum FocusModeType: String, CaseIterable { return Color(red: 0.361, green: 0.898, blue: 0.883, opacity: 1.0) case .reading: return Color(red: 1.000, green: 0.622, blue: 0.044, opacity: 1.0) + case .reduceInterruptions: + return Color(red: 0.686, green: 0.322, blue: 0.871, opacity: 1.0) case .custom: return Color(red: 0.513, green: 0.478, blue: 0.965) case .unknown: From 3004d159a1353de9240293f5ca2b40f12d0aaaa5 Mon Sep 17 00:00:00 2001 From: Federico Imberti <66013290+FI-153@users.noreply.github.com> Date: Fri, 2 Jan 2026 09:42:26 +0100 Subject: [PATCH 4/6] Correct custom icons and colors instead of placeholders --- .../managers/DoNotDisturbManager.swift | 102 +++++++++++++++++- 1 file changed, 100 insertions(+), 2 deletions(-) diff --git a/DynamicIsland/managers/DoNotDisturbManager.swift b/DynamicIsland/managers/DoNotDisturbManager.swift index 36572c5..2cb9dce 100644 --- a/DynamicIsland/managers/DoNotDisturbManager.swift +++ b/DynamicIsland/managers/DoNotDisturbManager.swift @@ -365,7 +365,11 @@ enum FocusModeType: String, CaseIterable { return image } - return Image(systemName: sfSymbol) + return Image( + systemName: self == .custom + ? self.getCustomIconFromFile() + : sfSymbol + ) } var accentColor: Color { @@ -391,7 +395,7 @@ enum FocusModeType: String, CaseIterable { case .reduceInterruptions: return Color(red: 0.686, green: 0.322, blue: 0.871, opacity: 1.0) case .custom: - return Color(red: 0.513, green: 0.478, blue: 0.965) + return self.getCustomAccentColorFromFile() case .unknown: return Color(red: 0.370, green: 0.360, blue: 0.902) } @@ -454,6 +458,16 @@ extension FocusModeType { return .doNotDisturb } + + func getCustomIconFromFile() -> String { + return FocusMetadataReader.shared + .getIcon(for: DoNotDisturbManager.shared.currentFocusModeName) + } + + func getCustomAccentColorFromFile() -> Color { + return FocusMetadataReader.shared + .getColor(for: DoNotDisturbManager.shared.currentFocusModeName) + } } // MARK: - Metadata helpers @@ -946,3 +960,87 @@ private enum FocusMetadataDecoder { return nil } } + +private final class FocusMetadataReader { + private let pathToDatabase:URL = FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent("Library/DoNotDisturb/DB/ModeConfigurations.json") + + struct DNDConfigRoot: Codable { + let data: [DNDDataEntry] + } + + struct DNDDataEntry: Codable { + let modeConfigurations: [String: DNDModeWrapper] + } + + struct DNDModeWrapper: Codable { + let mode: DNDMode + } + + struct DNDMode: Codable { + let name: String + let symbolImageName: String? + let tintColorName: String? + } + + private init(){} + + static let shared = FocusMetadataReader() + + private func getModeConfig(for focusName: String) -> DNDMode? { + print(">>> Debug: Reading from \(pathToDatabase.path)") + + do { + let data = try Data(contentsOf: pathToDatabase) + let root = try JSONDecoder().decode(DNDConfigRoot.self, from: data) + + for entry in root.data { + for wrapper in entry.modeConfigurations.values { + if wrapper.mode.name + .localizedCaseInsensitiveContains(focusName){ + return wrapper.mode + } + } + } + } catch { + print(">>> JSON Error: \(error)") + } + return nil + } + + func getIcon(for focus: String) -> String { + guard let mode = getModeConfig(for: focus) else { return "app.badge" } + return mode.symbolImageName ?? "app.badge" + } + + func getColor(for focus: String) -> Color { + guard let mode = getModeConfig(for: focus), + let colorName = mode.tintColorName else { return .gray } + + return Color.stringToColor(for: colorName) + } + +} + +extension Color { + static func stringToColor(for string:String) -> Color { + let cleanName = string.lowercased() + .replacingOccurrences(of: "system", with: "") + .replacingOccurrences(of: "color", with: "") + + switch cleanName { + case "red": return .red + case "orange": return .orange + case "yellow": return .yellow + case "green": return .green + case "mint": return .mint + case "teal": return .teal + case "cyan": return .cyan + case "blue": return .blue + case "indigo": return .indigo + case "purple": return .purple + case "pink": return .pink + case "gray", "grey": return .gray + default: return .indigo + } + } +} From 2e5be4d4c649aba5af6417fb3fbb25a1b8f22345 Mon Sep 17 00:00:00 2001 From: Federico Imberti <66013290+FI-153@users.noreply.github.com> Date: Fri, 2 Jan 2026 09:49:55 +0100 Subject: [PATCH 5/6] Refactoring --- DynamicIsland/managers/DoNotDisturbManager.swift | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/DynamicIsland/managers/DoNotDisturbManager.swift b/DynamicIsland/managers/DoNotDisturbManager.swift index 2cb9dce..d724d34 100644 --- a/DynamicIsland/managers/DoNotDisturbManager.swift +++ b/DynamicIsland/managers/DoNotDisturbManager.swift @@ -466,7 +466,7 @@ extension FocusModeType { func getCustomAccentColorFromFile() -> Color { return FocusMetadataReader.shared - .getColor(for: DoNotDisturbManager.shared.currentFocusModeName) + .getAccentColor(for: DoNotDisturbManager.shared.currentFocusModeName) } } @@ -987,8 +987,6 @@ private final class FocusMetadataReader { static let shared = FocusMetadataReader() private func getModeConfig(for focusName: String) -> DNDMode? { - print(">>> Debug: Reading from \(pathToDatabase.path)") - do { let data = try Data(contentsOf: pathToDatabase) let root = try JSONDecoder().decode(DNDConfigRoot.self, from: data) @@ -996,25 +994,29 @@ private final class FocusMetadataReader { for entry in root.data { for wrapper in entry.modeConfigurations.values { if wrapper.mode.name - .localizedCaseInsensitiveContains(focusName){ + .localizedCaseInsensitiveCompare(focusName) == .orderedSame { return wrapper.mode } } } } catch { - print(">>> JSON Error: \(error)") + print("JSON Error: \(error)") } return nil } + /// Fetch the icon for the current focus from disk. If the focus is not found return the placeholder `app.badge` + /// - Returns A string representing the sfSymbol of the current focus func getIcon(for focus: String) -> String { guard let mode = getModeConfig(for: focus) else { return "app.badge" } return mode.symbolImageName ?? "app.badge" } - func getColor(for focus: String) -> Color { + /// Fetch the accent color for the current focus from disk. If the focus is not found return the placeholder `Color.indigo` + /// - Returns A Color representing the accent color for the current focus + func getAccentColor(for focus: String) -> Color { guard let mode = getModeConfig(for: focus), - let colorName = mode.tintColorName else { return .gray } + let colorName = mode.tintColorName else { return .indigo } return Color.stringToColor(for: colorName) } From f591d7da1ed09398aa3d18ad97b1b1d7016583b5 Mon Sep 17 00:00:00 2001 From: Federico Imberti <66013290+FI-153@users.noreply.github.com> Date: Fri, 2 Jan 2026 10:43:21 +0100 Subject: [PATCH 6/6] Truncated "Reduce Interruptions" to "Reduce Interr." to avoid scrolling text --- DynamicIsland/managers/DoNotDisturbManager.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/DynamicIsland/managers/DoNotDisturbManager.swift b/DynamicIsland/managers/DoNotDisturbManager.swift index d724d34..ff45acc 100644 --- a/DynamicIsland/managers/DoNotDisturbManager.swift +++ b/DynamicIsland/managers/DoNotDisturbManager.swift @@ -131,6 +131,9 @@ final class DoNotDisturbManager: ObservableObject { if nameChanged { self.currentFocusModeName = finalName + .localizedCaseInsensitiveContains( + "Reduce Interruptions" + ) ? "Reduce Interr." : finalName } if identifierChanged || nameChanged || shouldToggleActive { @@ -322,7 +325,7 @@ enum FocusModeType: String, CaseIterable { case .gaming: return "Gaming" case .mindfulness: return "Mindfulness" case .reading: return "Reading" - case .reduceInterruptions: return "Reduce Interruptions" + case .reduceInterruptions: return "Reduce Interr." case .custom: return "Focus" case .unknown: return "Focus Mode" }