|
| 1 | +// |
| 2 | +// Copyright 2025 Jamf. All rights reserved. |
| 3 | +// |
| 4 | + |
| 5 | +import AppKit |
| 6 | +import Cocoa |
| 7 | +import Foundation |
| 8 | + |
| 9 | +class AboutVC: NSViewController { |
| 10 | + |
| 11 | + @IBOutlet weak var optOut_button: NSButton! |
| 12 | + |
| 13 | + @IBAction func optOut_action(_ sender: NSButton) { |
| 14 | + UserDefaults.standard.set(sender.state == .on, forKey: "optOut") |
| 15 | + TelemetryDeckConfig.OptOut = (sender.state == .on) |
| 16 | + } |
| 17 | + |
| 18 | + let supportText = """ |
| 19 | + This application helps identify how items are used/scoped. Identifies how/where items like extension attributes, scripts, packages, configuration payloads are used. |
| 20 | +
|
| 21 | + By default Object Info sends basic hardware, OS, and usage data for the app. Data is sent anonymously to https://telemetrydeck.com and used to aid in application development. To disable the sending of data click the 'Opt out of analytics' below. |
| 22 | + |
| 23 | + """ |
| 24 | + |
| 25 | + let feedback = """ |
| 26 | +
|
| 27 | + Please share feedback by filing an issue. |
| 28 | +
|
| 29 | + """ |
| 30 | + |
| 31 | + let warningText = """ |
| 32 | +
|
| 33 | + Due to occasional changes to the API and introduction of new items the results may not include some items. |
| 34 | +
|
| 35 | + """ |
| 36 | + |
| 37 | + let agreementText = """ |
| 38 | + |
| 39 | + This software is licensed under the terms of the Jamf Concepts Use Agreement |
| 40 | +
|
| 41 | + Copyright xxxx, Jamf Software, LLC. |
| 42 | + """ |
| 43 | + |
| 44 | + func formattedText() -> NSAttributedString { |
| 45 | + let basicFont = NSFont.systemFont(ofSize: 12) |
| 46 | + let basicAttributes = [NSAttributedString.Key.font: basicFont, .foregroundColor: defaultTextColor] |
| 47 | + let supportText = NSMutableAttributedString(string: supportText, attributes: basicAttributes) |
| 48 | + |
| 49 | + let tdRange = supportText.mutableString.range(of: "https://telemetrydeck.com") |
| 50 | + if tdRange.location != NSNotFound { |
| 51 | + supportText.addAttribute(NSAttributedString.Key.link, value: "https://telemetrydeck.com", range: tdRange) |
| 52 | + } |
| 53 | + |
| 54 | + let aboutString = supportText |
| 55 | + |
| 56 | + let currentYear = "\(Calendar.current.component(.year, from: Date()))" |
| 57 | + |
| 58 | + let feedbackString = NSMutableAttributedString(string: feedback, attributes: basicAttributes) |
| 59 | +// let feedbackRange = feedbackString.mutableString.range(of: "<repoPlaceHolder>/api-roles-and-clients/discussions") |
| 60 | +// if feedbackRange.location != NSNotFound { |
| 61 | +// feedbackString.addAttribute(NSAttributedString.Key.link, value: "<repoPlaceHolder>/api-roles-and-clients/discussions", range: feedbackRange) |
| 62 | +// } |
| 63 | +// aboutString.append(feedbackString) |
| 64 | + |
| 65 | + let issuesRange = feedbackString.mutableString.range(of: "filing an issue") |
| 66 | + if issuesRange.location != NSNotFound { |
| 67 | + feedbackString.addAttribute(NSAttributedString.Key.link, value: "https://github.com/Jamf-Concepts/api-roles-and-clients/issues", range: issuesRange) |
| 68 | + } |
| 69 | + aboutString.append(feedbackString) |
| 70 | + |
| 71 | + let warningFont = NSFont(name: "HelveticaNeue-Italic", size: 12) |
| 72 | + // let warningFont = NSFont.systemFont(ofSize: 12) |
| 73 | + let warningAttributes = [NSAttributedString.Key.font: warningFont, .foregroundColor: defaultTextColor] |
| 74 | + let warningString = NSMutableAttributedString(string: warningText, attributes: warningAttributes as [NSAttributedString.Key : Any]) |
| 75 | + aboutString.append(warningString) |
| 76 | + |
| 77 | + let agreementString = NSMutableAttributedString(string: agreementText.replacingOccurrences(of: "Copyright xxxx", with: "Copyright \(currentYear)"), attributes: basicAttributes) |
| 78 | + let foundRange = agreementString.mutableString.range(of: "Jamf Concepts Use Agreement") |
| 79 | + if foundRange.location != NSNotFound { |
| 80 | + agreementString.addAttribute(NSAttributedString.Key.link, value: "https://resources.jamf.com/documents/jamf-concept-projects-use-agreement.pdf", range: foundRange) |
| 81 | + } |
| 82 | + aboutString.append(agreementString) |
| 83 | + |
| 84 | + return aboutString |
| 85 | + } |
| 86 | + |
| 87 | + @IBOutlet weak var about_image: NSImageView! |
| 88 | + |
| 89 | + @IBOutlet weak var appName_textfield: NSTextField! |
| 90 | + @IBOutlet weak var version_textfield: NSTextField! |
| 91 | + @IBOutlet var license_textfield: NSTextView! |
| 92 | + |
| 93 | + |
| 94 | + @objc func interfaceModeChanged(sender: NSNotification) { |
| 95 | + setTheme(darkMode: isDarkMode) |
| 96 | + } |
| 97 | + func setTheme(darkMode: Bool) { |
| 98 | + self.view.layer?.backgroundColor = darkMode ? CGColor.init(gray: 0.2, alpha: 1.0):CGColor.init(gray: 0.2, alpha: 0.2) |
| 99 | + defaultTextColor = isDarkMode ? NSColor.white:NSColor.black |
| 100 | + license_textfield.textStorage?.setAttributedString(formattedText()) |
| 101 | + } |
| 102 | + |
| 103 | + override func viewDidLoad() { |
| 104 | + super.viewDidLoad() |
| 105 | + |
| 106 | + optOut_button.state = UserDefaults.standard.bool(forKey: "optOut") ? .on : .off |
| 107 | + |
| 108 | + DistributedNotificationCenter.default.addObserver(self, selector: #selector(interfaceModeChanged(sender:)), name: NSNotification.Name(rawValue: "AppleInterfaceThemeChangedNotification"), object: nil) |
| 109 | + |
| 110 | + // Do any additional setup after loading the view. |
| 111 | + self.view.wantsLayer = true |
| 112 | + setTheme(darkMode: isDarkMode) |
| 113 | + view.window?.titlebarAppearsTransparent = true |
| 114 | + view.window?.isOpaque = false |
| 115 | + |
| 116 | + about_image.image = NSImage(named: "AppIcon") |
| 117 | + appName_textfield.stringValue = "\(AppInfo.name)" |
| 118 | + version_textfield.stringValue = "Version \(AppInfo.version) (\(AppInfo.build))" |
| 119 | + license_textfield.textStorage?.setAttributedString(formattedText()) |
| 120 | + } |
| 121 | + |
| 122 | + override func viewWillDisappear() { |
| 123 | + super.viewWillDisappear() |
| 124 | + DistributedNotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "AppleInterfaceThemeChangedNotification"), object: nil) |
| 125 | + } |
| 126 | + |
| 127 | + func grayscale(image: CGImage, theSize: NSSize) -> NSImage? { |
| 128 | + let context = CIContext(options: nil) |
| 129 | + // CIPhotoEffectNoir |
| 130 | + // CIPhotoEffectMono |
| 131 | + // CIPhotoEffectTonal |
| 132 | + if let filter = CIFilter(name: "CIPhotoEffectTonal") { |
| 133 | + |
| 134 | + filter.setValue(CIImage(cgImage: image), forKey: kCIInputImageKey) |
| 135 | + |
| 136 | + if let output = filter.outputImage { |
| 137 | + if let cgImage = context.createCGImage(output, from: output.extent) { |
| 138 | + return NSImage(cgImage: cgImage, size: theSize) |
| 139 | + } |
| 140 | + } |
| 141 | + } |
| 142 | + return nil |
| 143 | + } |
| 144 | + |
| 145 | +} |
| 146 | + |
| 147 | +extension NSImage { |
| 148 | + func newCIImage() -> CIImage? { |
| 149 | + if let cgImage = self.newCGImage() { |
| 150 | + return CIImage(cgImage: cgImage) |
| 151 | + } |
| 152 | + return nil |
| 153 | + } |
| 154 | + |
| 155 | + func newCGImage() -> CGImage? { |
| 156 | + var imageRect = NSRect(origin: CGPoint(x: 0, y: 0), size: self.size) |
| 157 | + return self.cgImage(forProposedRect: &imageRect, context: NSGraphicsContext.current, hints: nil) |
| 158 | + } |
| 159 | +} |
0 commit comments