From 0b7b6c58d4a21c5d26631bd8868ca47c066c2d83 Mon Sep 17 00:00:00 2001 From: bk-openai Date: Sun, 10 Aug 2025 16:12:33 -0700 Subject: [PATCH 1/2] Refactor simple mode options --- CHANGELOG.md | 5 +++ .../com.github.macadmins.Nudge.json | 4 +++ .../com.github.macadmins.Nudge.mobileconfig | 9 +++++ .../com.github.macadmins.Nudge.tester.json | 6 ++++ .../com.github.macadmins.Nudge.tester.plist | 25 +++++++++----- .../Preferences/DefaultPreferencesNudge.swift | 25 ++++++++++++++ Nudge/Preferences/PreferencesStructure.swift | 9 ++++- Nudge/UI/SimpleMode/SimpleMode.swift | 26 +++++++++++++- Nudge/Utilities/Preferences.swift | 3 +- README.md | 1 + Schema/jamf/com.github.macadmins.Nudge.json | 34 +++++++++++++++++++ 11 files changed, 135 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3f23a60..f39e4e48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Added +- `simpleModeOptions` dictionary lets you toggle `showRequiredOSVersion` and `showRequiredDate` while keeping `simpleMode` as a top-level boolean + ## [2.0.12] - 2024-09-18 Requires macOS 12.0 and higher. diff --git a/Example Assets/com.github.macadmins.Nudge.json b/Example Assets/com.github.macadmins.Nudge.json index 467b14f3..0f513e73 100644 --- a/Example Assets/com.github.macadmins.Nudge.json +++ b/Example Assets/com.github.macadmins.Nudge.json @@ -75,6 +75,10 @@ "screenShotLightPath": "/somewhere/screenShotLight.png", "showDeferralCount": true, "simpleMode": false, + "simpleModeOptions": { + "showRequiredDate": true, + "showRequiredOSVersion": true + }, "singleQuitButton": false, "updateElements": [ { diff --git a/Example Assets/com.github.macadmins.Nudge.mobileconfig b/Example Assets/com.github.macadmins.Nudge.mobileconfig index 0bf2f119..a392a34c 100644 --- a/Example Assets/com.github.macadmins.Nudge.mobileconfig +++ b/Example Assets/com.github.macadmins.Nudge.mobileconfig @@ -157,8 +157,17 @@ /somewhere/screenShotLight.png showDeferralCount + showRequiredDate + simpleMode + simpleModeOptions + + showRequiredDate + + showRequiredOSVersion + + singleQuitButton updateElements diff --git a/Example Assets/com.github.macadmins.Nudge.tester.json b/Example Assets/com.github.macadmins.Nudge.tester.json index b6fd09b5..974b47fb 100644 --- a/Example Assets/com.github.macadmins.Nudge.tester.json +++ b/Example Assets/com.github.macadmins.Nudge.tester.json @@ -22,6 +22,12 @@ "screenShotDarkPath": "https://github.com/macadmins/nudge/blob/main/assets/standard_mode/demo_dark_1_icon.png?raw=true", "screenShotLightPath": "https://github.com/macadmins/nudge/blob/main/assets/standard_mode/demo_light_1_icon.png?raw=true", "applicationTerminatedNotificationImagePath": "/Library/Application Support/Nudge/logoLight.png", + "showRequiredDate": true, + "simpleMode": false, + "simpleModeOptions": { + "showRequiredDate": true, + "showRequiredOSVersion": true + }, "updateElements": [ { "_language": "en", diff --git a/Example Assets/com.github.macadmins.Nudge.tester.plist b/Example Assets/com.github.macadmins.Nudge.tester.plist index 01368c3b..cdae0a81 100644 --- a/Example Assets/com.github.macadmins.Nudge.tester.plist +++ b/Example Assets/com.github.macadmins.Nudge.tester.plist @@ -59,14 +59,23 @@ https://github.com/macadmins/nudge/blob/main/assets/NudgeIconInverted.png?raw=true iconLightPath https://github.com/macadmins/nudge/blob/main/assets/NudgeIcon.png?raw=true - screenShotDarkPath - https://github.com/macadmins/nudge/blob/main/assets/standard_mode/demo_dark_1_icon.png?raw=true - screenShotLightPath - https://github.com/macadmins/nudge/blob/main/assets/standard_mode/demo_light_1_icon.png?raw=true - simpleMode - - updateElements - + screenShotDarkPath + https://github.com/macadmins/nudge/blob/main/assets/standard_mode/demo_dark_1_icon.png?raw=true + screenShotLightPath + https://github.com/macadmins/nudge/blob/main/assets/standard_mode/demo_light_1_icon.png?raw=true + showRequiredDate + + simpleMode + + simpleModeOptions + + showRequiredDate + + showRequiredOSVersion + + + updateElements + _language en diff --git a/Nudge/Preferences/DefaultPreferencesNudge.swift b/Nudge/Preferences/DefaultPreferencesNudge.swift index ad785943..b24e4436 100644 --- a/Nudge/Preferences/DefaultPreferencesNudge.swift +++ b/Nudge/Preferences/DefaultPreferencesNudge.swift @@ -626,6 +626,31 @@ struct UserInterfaceVariables { false } + static var simpleModeEnabled: Bool { + if let simpleMode = userInterfaceProfile?["simpleMode"] as? Bool { + return simpleMode + } + return userInterfaceJSON?.simpleMode ?? false + } + + static var simpleModeShowRequiredDate: Bool { + guard simpleModeEnabled else { return false } + if let options = userInterfaceProfile?["simpleModeOptions"] as? [String: Any], + let value = options["showRequiredDate"] as? Bool { + return value + } + return userInterfaceJSON?.simpleModeOptions?.showRequiredDate ?? false + } + + static var simpleModeShowRequiredOSVersion: Bool { + guard simpleModeEnabled else { return false } + if let options = userInterfaceProfile?["simpleModeOptions"] as? [String: Any], + let value = options["showRequiredOSVersion"] as? Bool { + return value + } + return userInterfaceJSON?.simpleModeOptions?.showRequiredOSVersion ?? false + } + static var singleQuitButton: Bool { userInterfaceProfile?["singleQuitButton"] as? Bool ?? userInterfaceJSON?.singleQuitButton ?? diff --git a/Nudge/Preferences/PreferencesStructure.swift b/Nudge/Preferences/PreferencesStructure.swift index 65572c35..60ca9911 100644 --- a/Nudge/Preferences/PreferencesStructure.swift +++ b/Nudge/Preferences/PreferencesStructure.swift @@ -458,9 +458,14 @@ struct UserInterface: Codable { var actionButtonPath, applicationTerminatedNotificationImagePath, fallbackLanguage: String? var forceFallbackLanguage, forceScreenShotIcon: Bool? var iconDarkPath, iconLightPath, requiredInstallationDisplayFormat, screenShotDarkPath, screenShotLightPath: String? - var showActivelyExploitedCVEs, showDeferralCount, showDaysRemainingToUpdate, showRequiredDate, simpleMode, singleQuitButton: Bool? + var showActivelyExploitedCVEs, showDeferralCount, showDaysRemainingToUpdate, showRequiredDate, singleQuitButton: Bool? + var simpleMode: Bool? + var simpleModeOptions: SimpleModeOptions? var updateElements: [UpdateElement]? } +struct SimpleModeOptions: Codable { + var showRequiredDate, showRequiredOSVersion: Bool? +} // MARK: UserInterface convenience initializers and mutators extension UserInterface { @@ -496,6 +501,7 @@ extension UserInterface { showDaysRemainingToUpdate: Bool? = nil, showRequiredDate: Bool? = nil, simpleMode: Bool? = nil, + simpleModeOptions: SimpleModeOptions? = nil, singleQuitButton: Bool? = nil, updateElements: [UpdateElement]? = nil ) -> UserInterface { @@ -515,6 +521,7 @@ extension UserInterface { showDaysRemainingToUpdate: showDaysRemainingToUpdate ?? self.showDaysRemainingToUpdate, showRequiredDate: showRequiredDate ?? self.showRequiredDate, simpleMode: simpleMode ?? self.simpleMode, + simpleModeOptions: simpleModeOptions ?? self.simpleModeOptions, singleQuitButton: singleQuitButton ?? self.singleQuitButton, updateElements: updateElements ?? self.updateElements ) diff --git a/Nudge/UI/SimpleMode/SimpleMode.swift b/Nudge/UI/SimpleMode/SimpleMode.swift index 26cadae0..5cb81551 100644 --- a/Nudge/UI/SimpleMode/SimpleMode.swift +++ b/Nudge/UI/SimpleMode/SimpleMode.swift @@ -32,7 +32,15 @@ struct SimpleMode: View { Text(appState.deviceSupportedByOSVersion ? getMainHeader().localized(desiredLanguage: getDesiredLanguage(locale: appState.locale)) : getMainHeaderUnsupported().localized(desiredLanguage: getDesiredLanguage(locale: appState.locale))) .font(.title) - + + if UserInterfaceVariables.simpleModeShowRequiredOSVersion { + requiredOSVersionView + } + + if UserInterfaceVariables.simpleModeShowRequiredDate { + requiredDateView + } + remainingTimeView if UserInterfaceVariables.showDeferralCount { @@ -85,6 +93,22 @@ struct SimpleMode: View { .font(.title2) } } + + private var requiredOSVersionView: some View { + HStack { + Text("Required OS Version:".localized(desiredLanguage: getDesiredLanguage(locale: appState.locale))) + Text(String(appState.requiredMinimumOSVersion)) + .foregroundColor(infoTextColor) + } + } + + private var requiredDateView: some View { + HStack { + Text("Required Date:".localized(desiredLanguage: getDesiredLanguage(locale: appState.locale))) + Text(DateManager().coerceDateToString(date: requiredInstallationDate, formatterString: UserInterfaceVariables.requiredInstallationDisplayFormat)) + .foregroundColor(infoTextColor) + } + } private var bottomButtons: some View { HStack { diff --git a/Nudge/Utilities/Preferences.swift b/Nudge/Utilities/Preferences.swift index fdbd1288..28e52aaf 100644 --- a/Nudge/Utilities/Preferences.swift +++ b/Nudge/Utilities/Preferences.swift @@ -391,6 +391,5 @@ func getMainHeaderUnsupported() -> String { func simpleMode() -> Bool { return CommandLineUtilities().simpleModeEnabled() || - UserInterfaceVariables.userInterfaceProfile?["simpleMode"] as? Bool ?? - Globals.nudgeJSONPreferences?.userInterface?.simpleMode ?? false + UserInterfaceVariables.simpleModeEnabled } diff --git a/README.md b/README.md index c81222fb..872154b8 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ For more information about installation, deployment, and the user experience, pl # Examples of the User Interface ## simpleMode +SimpleMode offers a streamlined experience and can optionally display the required OS version and due date. Enable simple mode with the top-level `simpleMode` key and configure the `simpleModeOptions` dictionary with `showRequiredOSVersion` and `showRequiredDate` keys to control this behavior. ### English #### Light diff --git a/Schema/jamf/com.github.macadmins.Nudge.json b/Schema/jamf/com.github.macadmins.Nudge.json index 5847b295..9652a17b 100644 --- a/Schema/jamf/com.github.macadmins.Nudge.json +++ b/Schema/jamf/com.github.macadmins.Nudge.json @@ -1451,6 +1451,40 @@ } ] }, + "simpleModeOptions": { + "description": "Configuration options for the simplified user experience.", + "type": "object", + "properties": { + "showRequiredDate": { + "description": "When enabled, Nudge will show the requiredInstallationDate when using simpleMode.", + "anyOf": [ + { + "title": "Not Configured", + "type": "null" + }, + { + "title": "Configured", + "default": false, + "type": "boolean" + } + ] + }, + "showRequiredOSVersion": { + "description": "When enabled, Nudge will show the requiredMinimumOSVersion when using simpleMode.", + "anyOf": [ + { + "title": "Not Configured", + "type": "null" + }, + { + "title": "Configured", + "default": false, + "type": "boolean" + } + ] + } + } + }, "singleQuitButton": { "description": "Only display one quit button regardless of proximity to the due date.", "anyOf": [ From f4622c7389b2c624d1f716f8c5819e3c2e8ec0d8 Mon Sep 17 00:00:00 2001 From: BK Date: Sun, 10 Aug 2025 16:38:48 -0700 Subject: [PATCH 2/2] fix compiler error due to trying to resolve too many variables in a single expression --- Nudge/Preferences/PreferencesStructure.swift | 56 +++++++++++++------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/Nudge/Preferences/PreferencesStructure.swift b/Nudge/Preferences/PreferencesStructure.swift index 60ca9911..559c98c0 100644 --- a/Nudge/Preferences/PreferencesStructure.swift +++ b/Nudge/Preferences/PreferencesStructure.swift @@ -505,27 +505,47 @@ extension UserInterface { singleQuitButton: Bool? = nil, updateElements: [UpdateElement]? = nil ) -> UserInterface { + let actionButtonPath = actionButtonPath ?? self.actionButtonPath + let applicationTerminatedNotificationImagePath = applicationTerminatedNotificationImagePath ?? self.applicationTerminatedNotificationImagePath + let fallbackLanguage = fallbackLanguage ?? self.fallbackLanguage + let forceFallbackLanguage = forceFallbackLanguage ?? self.forceFallbackLanguage + let forceScreenShotIcon = forceScreenShotIcon ?? self.forceScreenShotIcon + let iconDarkPath = iconDarkPath ?? self.iconDarkPath + let iconLightPath = iconLightPath ?? self.iconLightPath + let requiredInstallationDisplayFormat = requiredInstallationDisplayFormat ?? self.requiredInstallationDisplayFormat + let screenShotDarkPath = screenShotDarkPath ?? self.screenShotDarkPath + let screenShotLightPath = screenShotLightPath ?? self.screenShotLightPath + let showActivelyExploitedCVEs = showActivelyExploitedCVEs ?? self.showActivelyExploitedCVEs + let showDeferralCount = showDeferralCount ?? self.showDeferralCount + let showDaysRemainingToUpdate = showDaysRemainingToUpdate ?? self.showDaysRemainingToUpdate + let showRequiredDate = showRequiredDate ?? self.showRequiredDate + let simpleMode = simpleMode ?? self.simpleMode + let simpleModeOptions = simpleModeOptions ?? self.simpleModeOptions + let singleQuitButton = singleQuitButton ?? self.singleQuitButton + let updateElements = updateElements ?? self.updateElements + return UserInterface( - actionButtonPath: actionButtonPath ?? self.actionButtonPath, - applicationTerminatedNotificationImagePath: applicationTerminatedNotificationImagePath ?? self.applicationTerminatedNotificationImagePath, - fallbackLanguage: fallbackLanguage ?? self.fallbackLanguage, - forceFallbackLanguage: forceFallbackLanguage ?? self.forceFallbackLanguage, - forceScreenShotIcon: forceScreenShotIcon ?? self.forceScreenShotIcon, - iconDarkPath: iconDarkPath ?? self.iconDarkPath, - iconLightPath: iconLightPath ?? self.iconLightPath, - requiredInstallationDisplayFormat: requiredInstallationDisplayFormat ?? self.requiredInstallationDisplayFormat, - screenShotDarkPath: screenShotDarkPath ?? self.screenShotDarkPath, - screenShotLightPath: screenShotLightPath ?? self.screenShotLightPath, - showActivelyExploitedCVEs: showActivelyExploitedCVEs ?? self.showActivelyExploitedCVEs, - showDeferralCount: showDeferralCount ?? self.showDeferralCount, - showDaysRemainingToUpdate: showDaysRemainingToUpdate ?? self.showDaysRemainingToUpdate, - showRequiredDate: showRequiredDate ?? self.showRequiredDate, - simpleMode: simpleMode ?? self.simpleMode, - simpleModeOptions: simpleModeOptions ?? self.simpleModeOptions, - singleQuitButton: singleQuitButton ?? self.singleQuitButton, - updateElements: updateElements ?? self.updateElements + actionButtonPath: actionButtonPath, + applicationTerminatedNotificationImagePath: applicationTerminatedNotificationImagePath, + fallbackLanguage: fallbackLanguage, + forceFallbackLanguage: forceFallbackLanguage, + forceScreenShotIcon: forceScreenShotIcon, + iconDarkPath: iconDarkPath, + iconLightPath: iconLightPath, + requiredInstallationDisplayFormat: requiredInstallationDisplayFormat, + screenShotDarkPath: screenShotDarkPath, + screenShotLightPath: screenShotLightPath, + showActivelyExploitedCVEs: showActivelyExploitedCVEs, + showDeferralCount: showDeferralCount, + showDaysRemainingToUpdate: showDaysRemainingToUpdate, + showRequiredDate: showRequiredDate, + singleQuitButton: singleQuitButton, + simpleMode: simpleMode, + simpleModeOptions: simpleModeOptions, + updateElements: updateElements ) } + } // MARK: - UpdateElement