diff --git a/.gitignore b/.gitignore index b79764f..73bb1be 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,3 @@ -# Created by https://www.gitignore.io/api/swift,xcode - -### Swift ### # Xcode # # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore @@ -50,9 +47,6 @@ playground.xcworkspace # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control # # Pods/ -# -# Add this line if you want to avoid checking in source code from the Xcode workspace -# *.xcworkspace # Carthage # @@ -72,32 +66,5 @@ fastlane/report.xml fastlane/Preview.html fastlane/screenshots/**/*.png fastlane/test_output - -# Code Injection -# -# After new code Injection tools there's a generated folder /iOSInjectionProject -# https://github.com/johnno1962/injectionforxcode - -iOSInjectionProject/ - -### Xcode ### -# Xcode -# -# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore - -## User settings - -## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) - -## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) - -### Xcode Patch ### -*.xcodeproj/* -!*.xcodeproj/project.pbxproj -!*.xcodeproj/xcshareddata/ -!*.xcworkspace/contents.xcworkspacedata -/*.gcno -**/xcshareddata/WorkspaceSettings.xcsettings - - -# End of https://www.gitignore.io/api/swift,xcode +.DS_Store +*.xcuserstate diff --git a/enrollment/.swiftlint.yml b/enrollment/.swiftlint.yml new file mode 100644 index 0000000..07403b9 --- /dev/null +++ b/enrollment/.swiftlint.yml @@ -0,0 +1,9 @@ +disabled_rules: # rule identifiers to exclude from running + - trailing_whitespace + - line_length + - nesting + - type_body_length + - cyclomatic_complexity +excluded: # paths to ignore during linting. Takes precedence over `included`. + - Carthage + - Pods diff --git a/enrollment/EnrollmentLoginHelper/Info.plist b/enrollment/EnrollmentLoginHelper/Info.plist index 8646bb1..886bd88 100644 --- a/enrollment/EnrollmentLoginHelper/Info.plist +++ b/enrollment/EnrollmentLoginHelper/Info.plist @@ -2,8 +2,6 @@ - LSBackgroundOnly - CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable @@ -21,7 +19,11 @@ CFBundleShortVersionString 1.0 CFBundleVersion - 1 + 76 + LSApplicationCategoryType + public.app-category.utilities + LSBackgroundOnly + LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright diff --git a/enrollment/EnrollmentLoginHelper/LoginHelperAppDelegate.swift b/enrollment/EnrollmentLoginHelper/LoginHelperAppDelegate.swift index f2cca9a..eeceb27 100644 --- a/enrollment/EnrollmentLoginHelper/LoginHelperAppDelegate.swift +++ b/enrollment/EnrollmentLoginHelper/LoginHelperAppDelegate.swift @@ -29,4 +29,3 @@ class LoginHelperAppDelegate: NSObject, NSApplicationDelegate { } } } - diff --git a/enrollment/EnrollmentLoginHelper/de.lproj/MainMenu.strings b/enrollment/EnrollmentLoginHelper/de.lproj/MainMenu.strings new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/enrollment/EnrollmentLoginHelper/de.lproj/MainMenu.strings @@ -0,0 +1 @@ + diff --git a/enrollment/JAMFIntegrationHelper/main.swift b/enrollment/JAMFIntegrationHelper/main.swift deleted file mode 100644 index d3703a4..0000000 --- a/enrollment/JAMFIntegrationHelper/main.swift +++ /dev/null @@ -1,12 +0,0 @@ -// -// main.swift -// JAMFIntegrationHelper -// -// Created by Jay on 10/11/18. -// Copyright © 2018 IBM. All rights reserved. -// - -import Foundation - -print("Hello, World!") - diff --git a/enrollment/Mac@IBM EnrollmentTests/BundleInstallationPageTests.swift b/enrollment/Mac@IBM EnrollmentTests/BundleInstallationPageTests.swift new file mode 100644 index 0000000..7bc5d35 --- /dev/null +++ b/enrollment/Mac@IBM EnrollmentTests/BundleInstallationPageTests.swift @@ -0,0 +1,60 @@ +// +// BundleInstalationPageTests.swift +// Mac@IBM EnrollmentTests +// +// Created by Jan Valentik on 04/05/2020. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import XCTest +@testable import Mac_IBM_Enrollment + +class BundleInstallationPageTests: XCTestCase { + let bundleInstallationPageJsonStub = """ + { + "title": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + }, + "subtitle": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + }, + "bundleInstallationStatus": true, + "bundleInstallationWarning": true + } + """ + + func testBundleInstallationPageInitializedCorrectly() throws { + // Given + let decoder = JSONDecoder() + var sut: BundleInstallationPage + + // When + sut = try decoder.decode(BundleInstallationPage.self, from: bundleInstallationPageJsonStub.data(using: .utf8)!) + + // Then + XCTAssert((sut as Any) is BundleInstallationPage) + XCTAssert((sut.title as Any) is InfoLabel) + XCTAssert((sut.subtitle as Any) is InfoLabel) + } +} diff --git a/enrollment/Mac@IBM EnrollmentTests/BundleSelectionPageTests.swift b/enrollment/Mac@IBM EnrollmentTests/BundleSelectionPageTests.swift new file mode 100644 index 0000000..4f1f743 --- /dev/null +++ b/enrollment/Mac@IBM EnrollmentTests/BundleSelectionPageTests.swift @@ -0,0 +1,82 @@ +// +// BundleSelectionPageTests.swift +// Mac@IBM EnrollmentTests +// +// Created by Jan Valentik on 04/05/2020. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import XCTest +@testable import Mac_IBM_Enrollment + +class BundleSelectionPageTests: XCTestCase { + let bundleSelectionPageJsonStub = """ + { + "title": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + }, + "subtitle": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + }, + "bundles": [ + { + "title": "testTitle", + "extendedTitle": "testExtendedTitle", + "description": "testDescription", + "key": "testKey", + "icon": "testIcon", + "status": -1, + "warningMessage": "testWarningMessage", + "time": "testTime", + "size": "testSize", + "recommended": true, + "apps": [ + { + "title": "appTitle", + "description": "appDescription", + "key": "appKey", + "status": -1, + "icon": "appIcon" + } + ] + } + ] + } + """ + + func testBundleSelectionPageInitializedCorrectly() throws { + // Given + let decoder = JSONDecoder() + var sut: BundleSelectionPage + + // When + sut = try decoder.decode(BundleSelectionPage.self, from: bundleSelectionPageJsonStub.data(using: .utf8)!) + + // Then + XCTAssert((sut as Any) is BundleSelectionPage) + XCTAssert((sut.title as Any) is InfoLabel) + XCTAssert((sut.subtitle as Any) is InfoLabel) + XCTAssert((sut.bundles as Any) is [EnrollmentBundle]) + } +} diff --git a/enrollment/Mac@IBM EnrollmentTests/EnrollmentBundleTests.swift b/enrollment/Mac@IBM EnrollmentTests/EnrollmentBundleTests.swift new file mode 100644 index 0000000..269aec4 --- /dev/null +++ b/enrollment/Mac@IBM EnrollmentTests/EnrollmentBundleTests.swift @@ -0,0 +1,50 @@ +// +// EnrollmentBundleTests.swift +// Mac@IBM EnrollmentTests +// +// Created by Jan Valentik on 04/05/2020. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import XCTest +@testable import Mac_IBM_Enrollment + +class EnrollmentBundleTests: XCTestCase { + let enrollmentBundleJsonStub = """ + { + "title": "testTitle", + "extendedTitle": "testExtendedTitle", + "description": "testDescription", + "key": "testKey", + "icon": "testIcon", + "status": -1, + "warningMessage": "testWarningMessage", + "time": "testTime", + "size": "testSize", + "recommended": true, + "apps": [ + { + "title": "appTitle", + "description": "appDescription", + "key": "appKey", + "status": -1, + "icon": "appIcon" + } + ] + } + """ + + func testEnrollmentBundleInitializedCorrectly() throws { + // Given + let decoder = JSONDecoder() + var sut: EnrollmentBundle + + // When + sut = try decoder.decode(EnrollmentBundle.self, from: enrollmentBundleJsonStub.data(using: .utf8)!) + + // Then + XCTAssert((sut as Any) is EnrollmentBundle) + XCTAssert((sut.apps as Any) is [EnrollmentBundle.App]) + } +} diff --git a/enrollment/Mac@IBM EnrollmentTests/EnrollmentDataSetTests.swift b/enrollment/Mac@IBM EnrollmentTests/EnrollmentDataSetTests.swift new file mode 100644 index 0000000..ca6ff73 --- /dev/null +++ b/enrollment/Mac@IBM EnrollmentTests/EnrollmentDataSetTests.swift @@ -0,0 +1,260 @@ +// +// EnrollmentDataSetTests.swift +// Mac@IBM EnrollmentTests +// +// Created by Jan Valentik on 04/05/2020. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import XCTest +@testable import Mac_IBM_Enrollment + +class EnrollmentDataSetTests: XCTestCase { + let enrollmentDatatSetJsonStub = """ + { + "userInfo": { + "hrFirstName": "johny" + }, + "networkInfo": { + "speedTestResult": "speed", + "jpsCommSeconds": "jps" + }, + "phase": "phase", + "selectedBundles": [ + "selectedBundles" + ], + "policies": { + "registrationPolicy": "testPolicy", + "bundleInstallationPolicy": "test", + "removeFramework": "test" + }, + "registration": { + "pages": [ + { + "title": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + }, + "subtitle": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + }, + "fields": [ + { + "title": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + }, + "key": "fakeKey", + "multipleChoiseAllowed": true, + "showTitle": true, + "options": [ + { + "key": "optionKey", + "label": "optionLabel", + "isExclusive": true + } + ] + } + ], + "footer": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + } + } + ], + "registrationStatus": true + }, + "bundleSelectionPage": { + "title": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + }, + "subtitle": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + }, + "bundles": [ + { + "title": "testTitle", + "extendedTitle": "testExtendedTitle", + "description": "testDescription", + "key": "testKey", + "icon": "testIcon", + "status": -1, + "warningMessage": "testWarningMessage", + "time": "testTime", + "size": "testSize", + "recommended": true, + "apps": [ + { + "title": "appTitle", + "description": "appDescription", + "key": "appKey", + "status": -1, + "icon": "appIcon" + } + ] + } + ] + }, + "bundleInstallationPage": { + "title": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + }, + "subtitle": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + }, + "bundleInstallationStatus": true, + "bundleInstallationWarning": true + }, + "summaryScreen": { + "title": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + }, + "subtitle": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + }, + "items": [ + { + "title": "fakeTitle", + "description": "fakeDescription", + "alternateDescription": "fakeAlternateDescription", + "policyOrUrl": "fakePolicy", + "iconName": "testIconName", + "ctaType": "testType" + } + + ] + }, + "selectedRegistrationInfo": [ + { + "fieldKey": "fieldKey", + "fieldTitle": "fieldTitle", + "selectedOptionKeys": [ + "keys" + ], + "selectedOptionTitles": [ + "titles" + ], + "isMultipleChoiseAllowed": true + } + ] + } + """ + + func testEnrollmentDataSetInitializedCorrectly() throws { + // Given + let decoder = JSONDecoder() + var sut: EnrollmentDataSet + + // When + sut = try decoder.decode(EnrollmentDataSet.self, from: enrollmentDatatSetJsonStub.data(using: .utf8)!) + + // Then + XCTAssert((sut as Any) is EnrollmentDataSet) + XCTAssert((sut.userInfo as Any) is EnrollmentDataSet.UserInfo) + XCTAssert((sut.networkInfo as Any) is EnrollmentDataSet.NetworkInfo) + XCTAssert((sut.selectedBundles as Any) is [String]) + XCTAssert((sut.bundleInstallationPage as Any) is BundleInstallationPage) + XCTAssert((sut.bundleSelectionPage as Any) is BundleSelectionPage) + XCTAssert((sut.summaryScreen as Any) is SummaryPage) + + } + +} diff --git a/enrollment/Mac@IBM EnrollmentTests/Info.plist b/enrollment/Mac@IBM EnrollmentTests/Info.plist new file mode 100644 index 0000000..12a10ed --- /dev/null +++ b/enrollment/Mac@IBM EnrollmentTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 76 + + diff --git a/enrollment/Mac@IBM EnrollmentTests/InfoLabelTests.swift b/enrollment/Mac@IBM EnrollmentTests/InfoLabelTests.swift new file mode 100644 index 0000000..56b0542 --- /dev/null +++ b/enrollment/Mac@IBM EnrollmentTests/InfoLabelTests.swift @@ -0,0 +1,59 @@ +// +// InfoLabelTests.swift +// Mac@IBM EnrollmentTests +// +// Created by Jan Valentik on 03/05/2020. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import XCTest +@testable import Mac_IBM_Enrollment + +class InfoLabelTests: XCTestCase { + let infoLabelJsonStub = """ + { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + } + """ + + func testInfoLabelDeserializedCorrectly() throws { + + // Given + let decoder = JSONDecoder() + var sut: InfoLabel + + // When + sut = try decoder.decode(InfoLabel.self, from: infoLabelJsonStub.data(using: .utf8)!) + + // Then + XCTAssert((sut as Any) is InfoLabel) + XCTAssert((sut.infoSection as Any) is InfoSection) + } + + func disabledTestInfoLabelSerializedCorrectly() throws { + + // Given + let encoder = JSONEncoder() + let decoder = JSONDecoder() + var sut: InfoLabel + + // When + sut = try decoder.decode(InfoLabel.self, from: infoLabelJsonStub.data(using: .utf8)!) + let data = try encoder.encode(sut) + let jsonString = String(data: data, encoding: .utf8) + + // Then + XCTAssertTrue(jsonString!.contains(infoLabelJsonStub)) + } +} diff --git a/enrollment/Mac@IBM EnrollmentTests/PoliciesTests.swift b/enrollment/Mac@IBM EnrollmentTests/PoliciesTests.swift new file mode 100644 index 0000000..a1a2274 --- /dev/null +++ b/enrollment/Mac@IBM EnrollmentTests/PoliciesTests.swift @@ -0,0 +1,45 @@ +// +// PoliciesTests.swift +// Mac@IBM EnrollmentTests +// +// Created by Jan Valentik on 04/05/2020. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import XCTest +@testable import Mac_IBM_Enrollment + +class PoliciesTests: XCTestCase { + let policiesJsonStub = """ + { + "registrationPolicy": "testPolicy", + "bundleInstallationPolicy": "test", + "removeFramework": "test" + } + """ + + func testPoliciesInitializedCorrectly() { + // Given + + // When + let policies = JamfPoliciesStore("fakePolicy", bundleInstallationPolicy: "fakeBundlePolicy", removeFramework: "remove") + + // Then + XCTAssertNotNil(policies) + } + + func testPoliciesDeserializedCorrectly() throws { + // Given + let decoder = JSONDecoder() + var sut: JamfPoliciesStore + + // When + sut = try decoder.decode(JamfPoliciesStore.self, from: policiesJsonStub.data(using: .utf8)!) + + // Then + XCTAssert((sut as Any) is JamfPoliciesStore) + + } + +} diff --git a/enrollment/Mac@IBM EnrollmentTests/RegistrationChoiceTests.swift b/enrollment/Mac@IBM EnrollmentTests/RegistrationChoiceTests.swift new file mode 100644 index 0000000..a053cdc --- /dev/null +++ b/enrollment/Mac@IBM EnrollmentTests/RegistrationChoiceTests.swift @@ -0,0 +1,27 @@ +// +// RegistrationChoiceTests.swift +// Mac@IBM EnrollmentTests +// +// Created by Jan Valentik on 04/05/2020. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import XCTest +@testable import Mac_IBM_Enrollment + +class RegistrationChoiceTests: XCTestCase { + + func testRegistrationChoiceInitializedCorrectly() { + // Given + + // When + let registrationPage = RegistrationChoice("fieldKey", fieldTitle: "fieldTitle", + selectedOptionKeys: ["filedKey"], + selectedOptionTitles: ["fieldTitle"]) + + // Then + XCTAssertNotNil(registrationPage) + } + +} diff --git a/enrollment/Mac@IBM EnrollmentTests/RegistrationDataTests.swift b/enrollment/Mac@IBM EnrollmentTests/RegistrationDataTests.swift new file mode 100644 index 0000000..c23c788 --- /dev/null +++ b/enrollment/Mac@IBM EnrollmentTests/RegistrationDataTests.swift @@ -0,0 +1,103 @@ +// +// RegistrationDataTests.swift +// Mac@IBM EnrollmentTests +// +// Created by Jan Valentik on 04/05/2020. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import XCTest +@testable import Mac_IBM_Enrollment + +class RegistrationDataTests: XCTestCase { + let registrationDataJsonStub = """ + { + "pages": [ + { + "title": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + }, + "subtitle": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + }, + "fields": [ + { + "title": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + }, + "key": "fakeKey", + "multipleChoiseAllowed": true, + "showTitle": true, + "options": [ + { + "key": "optionKey", + "label": "optionLabel", + "isExclusive": true + } + ] + } + ], + "footer": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + } + } + ], + "registrationStatus": true + } + """ + + func testRegistrationDataInitializedCorrectly() throws { + // Given + let decoder = JSONDecoder() + var sut: RegistrationData + + // When + sut = try decoder.decode(RegistrationData.self, from: registrationDataJsonStub.data(using: .utf8)!) + + // Then + XCTAssert((sut as Any) is RegistrationData) + XCTAssert((sut.pages as Any) is [RegistrationPage]) + XCTAssertNotNil(sut.registrationStatus) + } +} diff --git a/enrollment/Mac@IBM EnrollmentTests/RegistrationFieldTests.swift b/enrollment/Mac@IBM EnrollmentTests/RegistrationFieldTests.swift new file mode 100644 index 0000000..e476ab9 --- /dev/null +++ b/enrollment/Mac@IBM EnrollmentTests/RegistrationFieldTests.swift @@ -0,0 +1,55 @@ +// +// RegistrationFieldTests.swift +// Mac@IBM EnrollmentTests +// +// Created by Jan Valentik on 04/05/2020. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import XCTest +@testable import Mac_IBM_Enrollment + +class RegistrationFieldTests: XCTestCase { + let registrationFieldJsonStub = """ + { + "title": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + }, + "key": "fakeKey", + "multipleChoiseAllowed": true, + "showTitle": true, + "options": [ + { + "key": "optionKey", + "label": "optionLabel", + "isExclusive": true + } + ] + } + """ + + func testRegistrationFieldInitializedCorrectly() throws { + // Given + let decoder = JSONDecoder() + var sut: RegistrationField + + // When + sut = try decoder.decode(RegistrationField.self, from: registrationFieldJsonStub.data(using: .utf8)!) + + // Then + XCTAssert((sut as Any) is RegistrationField) + XCTAssert((sut.options as Any) is [RegistrationField.Option]) + } + +} diff --git a/enrollment/Mac@IBM EnrollmentTests/RegistrationPageTests.swift b/enrollment/Mac@IBM EnrollmentTests/RegistrationPageTests.swift new file mode 100644 index 0000000..1d981d0 --- /dev/null +++ b/enrollment/Mac@IBM EnrollmentTests/RegistrationPageTests.swift @@ -0,0 +1,101 @@ +// +// RegistrationPageTests.swift +// Mac@IBM EnrollmentTests +// +// Created by Jan Valentik on 04/05/2020. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import XCTest +@testable import Mac_IBM_Enrollment + +class RegistrationPageTests: XCTestCase { + + let registrationPageJsonStub = """ + { + "title": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + }, + "subtitle": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + }, + "fields": [ + { + "title": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + }, + "key": "fakeKey", + "multipleChoiseAllowed": true, + "showTitle": true, + "options": [ + { + "key": "optionKey", + "label": "optionLabel", + "isExclusive": true + } + ] + } + ], + "footer": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + } + } + """ + + func testRegistrationPageInitializedCorrectly() throws { + // Given + let decoder = JSONDecoder() + var sut: RegistrationPage + + // When + sut = try decoder.decode(RegistrationPage.self, from: registrationPageJsonStub.data(using: .utf8)!) + + // Then + XCTAssert((sut as Any) is RegistrationPage) + XCTAssert((sut.title as Any) is InfoLabel) + XCTAssert((sut.subtitle as Any) is InfoLabel) + XCTAssert((sut.fields as Any) is [RegistrationField]) + XCTAssert((sut.footer as Any) is InfoLabel) + } +} diff --git a/enrollment/Mac@IBM EnrollmentTests/SummaryPageTests.swift b/enrollment/Mac@IBM EnrollmentTests/SummaryPageTests.swift new file mode 100644 index 0000000..dbe70f1 --- /dev/null +++ b/enrollment/Mac@IBM EnrollmentTests/SummaryPageTests.swift @@ -0,0 +1,71 @@ +// +// SummaryPageTests.swift +// Mac@IBM EnrollmentTests +// +// Created by Jan Valentik on 04/05/2020. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import XCTest +@testable import Mac_IBM_Enrollment + +class SummaryPageTests: XCTestCase { + + let summaryPageJsonStub = """ + { + "title": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + }, + "subtitle": { + "label": "testLabel", + "alternateLabel": "testAlternateLabel", + "infoSection": { + "fields": [ + { + "label": "testLabel", + "description": "testDescription", + "iconName": "testIconName" + } + ] + } + }, + "items": [ + { + "title": "fakeTitle", + "description": "fakeDescription", + "alternateDescription": "fakeAlternateDescription", + "policyOrUrl": "fakePolicy", + "iconName": "testIconName", + "ctaType": "testType" + } + + ] + } + """ + + func testSummaryPageInitializedCorrectly() throws { + // Given + let decoder = JSONDecoder() + var sut: SummaryPage + + // When + sut = try decoder.decode(SummaryPage.self, from: summaryPageJsonStub.data(using: .utf8)!) + + // Then + XCTAssert((sut as Any) is SummaryPage) + XCTAssert((sut.subtitle as Any) is InfoLabel) + XCTAssert((sut.title as Any) is InfoLabel) + XCTAssert((sut.items as Any) is [SummaryPage.Item]) + } +} diff --git a/enrollment/JAMFIntegrationHelper/JAMFIntegrationHelper-Info.plist b/enrollment/PrivilegedCommandsHelper/PrivilegedCommandsHelper-Info.plist similarity index 69% rename from enrollment/JAMFIntegrationHelper/JAMFIntegrationHelper-Info.plist rename to enrollment/PrivilegedCommandsHelper/PrivilegedCommandsHelper-Info.plist index a902866..11c4b72 100644 --- a/enrollment/JAMFIntegrationHelper/JAMFIntegrationHelper-Info.plist +++ b/enrollment/PrivilegedCommandsHelper/PrivilegedCommandsHelper-Info.plist @@ -3,14 +3,14 @@ CFBundleIdentifier - com.ibm.jamf.IntegrationHelper + com.ibm.cio.be.PrivilegedCommandsHelper CFBundleInfoDictionaryVersion 6.0 CFBundleName - com.ibm.jamf.IntegrationHelper + com.ibm.cio.be.privileged-commands-helper CFBundleShortVersionString - 1.3 + 1.1 CFBundleVersion - 1.3 + 1.1 diff --git a/enrollment/JAMFIntegrationHelper/JAMFIntegrationHelper-Launchd.plist b/enrollment/PrivilegedCommandsHelper/PrivilegedCommandsHelper-Launchd.plist similarity index 53% rename from enrollment/JAMFIntegrationHelper/JAMFIntegrationHelper-Launchd.plist rename to enrollment/PrivilegedCommandsHelper/PrivilegedCommandsHelper-Launchd.plist index 857c0c5..48337af 100644 --- a/enrollment/JAMFIntegrationHelper/JAMFIntegrationHelper-Launchd.plist +++ b/enrollment/PrivilegedCommandsHelper/PrivilegedCommandsHelper-Launchd.plist @@ -3,14 +3,10 @@ Label - com.ibm.jamf.IntegrationHelper - ProgramArguments - - /Library/PrivilegedHelperTools/com.ibm.jamf.IntegrationHelper - + com.ibm.cio.be.PrivilegedCommandsHelper MachServices - com.ibm.jamf.IntegrationHelper + com.ibm.cio.be.PrivilegedCommandsHelper diff --git a/enrollment/PrivilegedCommandsHelper/PrivilegedCommandsHelper.swift b/enrollment/PrivilegedCommandsHelper/PrivilegedCommandsHelper.swift new file mode 100644 index 0000000..47359f2 --- /dev/null +++ b/enrollment/PrivilegedCommandsHelper/PrivilegedCommandsHelper.swift @@ -0,0 +1,61 @@ +// +// PrivilegedCommandsHelper.swift +// PrivilegedCommandsHelper +// +// Created by Simone Martorelli on 8/24/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Foundation +import AppKit +import os.log + +class PrivilegedCommandsHelper: NSObject, NSXPCListenerDelegate { + + var listener: NSXPCListener + + override init() { + self.listener = NSXPCListener(machServiceName: "com.ibm.cio.be.PrivilegedCommandsHelper") + super.init() + self.listener.delegate = self + } + + func run() { + self.listener.resume() + RunLoop.current.run() + os_log("PrivilegedCommandsHelper running") + } + + func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool { + newConnection.exportedInterface = NSXPCInterface(with: RemoteProcessProtocol.self) + newConnection.exportedObject = self + newConnection.resume() + return true + } +} + +extension PrivilegedCommandsHelper: RemoteProcessProtocol { + func getVersion(reply: @escaping (String?) -> Void) { + os_log("PrivilegedCommandsHelper received \"getVersion\" request") + reply(Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String) + } + + private func runCommand(path: String?, arguments: [String], reply: @escaping (String?) -> Void) { + os_log("PrivilegedCommandsHelper received \"runCommand\" request with path: %@ and argments: %@", path ?? "No path", arguments.description) + let process = Process() + process.launchPath = path + process.arguments = arguments + let pipe = Pipe() + process.standardOutput = pipe + process.launch() + process.waitUntilExit() + reply(String(data: pipe.fileHandleForReading.readDataToEndOfFile(), encoding: String.Encoding.utf8)) + } + + func runPolicy(event: String, reply: @escaping (String?) -> Void) { + let jamfLaunchPath = "/usr/local/jamf/bin/jamf" + let jamfArguments = ["policy", "-event", event] + runCommand(path: jamfLaunchPath, arguments: jamfArguments, reply: reply) + } +} diff --git a/enrollment/PrivilegedCommandsHelper/main.swift b/enrollment/PrivilegedCommandsHelper/main.swift new file mode 100644 index 0000000..5199e4f --- /dev/null +++ b/enrollment/PrivilegedCommandsHelper/main.swift @@ -0,0 +1,13 @@ +// +// main.swift +// PrivilegedCommandsHelper +// +// Created by Simone Martorelli on 8/24/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Foundation + +let helper = PrivilegedCommandsHelper() +helper.run() diff --git a/enrollment/enrollment.xcodeproj/project.pbxproj b/enrollment/enrollment.xcodeproj/project.pbxproj index 56f5ab4..bf03724 100644 --- a/enrollment/enrollment.xcodeproj/project.pbxproj +++ b/enrollment/enrollment.xcodeproj/project.pbxproj @@ -3,99 +3,131 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 52; objects = { /* Begin PBXBuildFile section */ - 6901E575210A52F300EACAF1 /* TermDefinition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6901E574210A52F300EACAF1 /* TermDefinition.swift */; }; - 6901E579210A54BD00EACAF1 /* SecurityDescriptionPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6901E578210A54BD00EACAF1 /* SecurityDescriptionPopover.swift */; }; - 6901E57B210A5CFC00EACAF1 /* InfoPopOverConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6901E57A210A5CFC00EACAF1 /* InfoPopOverConstants.swift */; }; - 690ACB33213884DF00F8B1F0 /* DefineBundleInfoPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 690ACB32213884DF00F8B1F0 /* DefineBundleInfoPopover.swift */; }; - 690ACB37213C5F1900F8B1F0 /* NSView+Rotation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 690ACB36213C5F1900F8B1F0 /* NSView+Rotation.swift */; }; + 6904AB7021B6E2C600AE31BB /* bee-lowlight.gif in Resources */ = {isa = PBXBuildFile; fileRef = 6904AB6F21B6E2C600AE31BB /* bee-lowlight.gif */; }; + 6904AB7221B81FAC00AE31BB /* AppleInterfaceStyleMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6904AB7121B81FAC00AE31BB /* AppleInterfaceStyleMonitor.swift */; }; + 690ACB37213C5F1900F8B1F0 /* RotableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 690ACB36213C5F1900F8B1F0 /* RotableView.swift */; }; 690ACB39213C6BF900F8B1F0 /* Indicators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 690ACB38213C6BF900F8B1F0 /* Indicators.swift */; }; - 690ACB3B213C8F2E00F8B1F0 /* BundleInstallationChildViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 690ACB3A213C8F2E00F8B1F0 /* BundleInstallationChildViewController.swift */; }; - 691F680821C4323600700C78 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 691F680721C4323600700C78 /* MainView.swift */; }; 6922610A21415DE9007419A6 /* EnrollmentLoginHelper.app in Copy LoginItem Helper */ = {isa = PBXBuildFile; fileRef = 69A1F5D221022FC2004F461A /* EnrollmentLoginHelper.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 6922F6AC21273FDD00EB8003 /* BundleItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6922F6AB21273FDD00EB8003 /* BundleItemCell.swift */; }; - 6922F6AF212DB17D00EB8003 /* StackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6922F6AE212DB17D00EB8003 /* StackView.swift */; }; - 6922F6B1212DD0A900EB8003 /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6922F6B0212DD0A900EB8003 /* BaseViewController.swift */; }; - 6922F6B3212DD39700EB8003 /* HeaderViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6922F6B2212DD39700EB8003 /* HeaderViewController.swift */; }; - 6933FF82216FA34200417BD3 /* com.ibm.jamf.IntegrationHelper in Copy Helper */ = {isa = PBXBuildFile; fileRef = 69B411E9216FA214005B6332 /* com.ibm.jamf.IntegrationHelper */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; - 6950CD58210B67EF007C97DF /* Info4Popover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6950CD57210B67EF007C97DF /* Info4Popover.swift */; }; - 6950CD5A210B6F8A007C97DF /* Info2Popover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6950CD59210B6F8A007C97DF /* Info2Popover.swift */; }; 6950CD5D210B9BBE007C97DF /* RemoteProcessProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6950CD5C210B9BBE007C97DF /* RemoteProcessProtocol.swift */; }; 6950CD65210F67FE007C97DF /* AlertConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6950CD64210F67FE007C97DF /* AlertConstants.swift */; }; - 6950CD6B2110D583007C97DF /* OptionPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6950CD6A2110D583007C97DF /* OptionPopover.swift */; }; 6950CD6F211228F1007C97DF /* AnimatedGIFImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6950CD6E211228F1007C97DF /* AnimatedGIFImageView.swift */; }; 6950CD7121123283007C97DF /* AnimatedGIFProgressViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6950CD7021123283007C97DF /* AnimatedGIFProgressViewController.swift */; }; - 6950CD7321133ED5007C97DF /* RegistrationCompleteChildViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6950CD7221133ED5007C97DF /* RegistrationCompleteChildViewController.swift */; }; - 6950CD76211375A0007C97DF /* BundleSelectionChildViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6950CD75211375A0007C97DF /* BundleSelectionChildViewController.swift */; }; - 6950CD7C2114F385007C97DF /* StackItems.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6950CD792114F385007C97DF /* StackItems.storyboard */; }; + 6950CD7321133ED5007C97DF /* PostRegistrationPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6950CD7221133ED5007C97DF /* PostRegistrationPageViewController.swift */; }; 6950CD7D2114F385007C97DF /* BundleItemCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6950CD7A2114F385007C97DF /* BundleItemCell.xib */; }; - 6950CD7E2114F385007C97DF /* HeaderViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6950CD7B2114F385007C97DF /* HeaderViewController.storyboard */; }; - 6950CD812118C865007C97DF /* SetupCompleteChildViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6950CD802118C865007C97DF /* SetupCompleteChildViewController.swift */; }; - 6950CD85211A2D89007C97DF /* ProgressStates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6950CD84211A2D89007C97DF /* ProgressStates.swift */; }; - 6950CD87211B83CF007C97DF /* BundleInstallButtonVisibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6950CD86211B83CF007C97DF /* BundleInstallButtonVisibility.swift */; }; 6950CD8B211C8B64007C97DF /* NSTextField+Attributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6950CD8A211C8B64007C97DF /* NSTextField+Attributes.swift */; }; - 6950CD902121E03B007C97DF /* SetupCompleteButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6950CD8F2121E03B007C97DF /* SetupCompleteButtons.swift */; }; - 6958337A2135D29C00D6B606 /* BundleCProgressStackItemViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 695833792135D29C00D6B606 /* BundleCProgressStackItemViewController.swift */; }; - 6958337C2135D2C900D6B606 /* BundleBProgressStackItemViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6958337B2135D2C800D6B606 /* BundleBProgressStackItemViewController.swift */; }; - 6958337E2135D2F200D6B606 /* BundleAProgressStackItemViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6958337D2135D2F200D6B606 /* BundleAProgressStackItemViewController.swift */; }; 69583381213729D700D6B606 /* BundlePopOverViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6958337F213729D700D6B606 /* BundlePopOverViewController.swift */; }; - 696BBB0D217664A10094BE76 /* JAMFIntegrationHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69EEA009216F8CAF0032C2E1 /* JAMFIntegrationHelper.swift */; }; - 696BBB76217BAE7B0094BE76 /* PrimaryRegistrationChildVCConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 696BBB75217BAE7B0094BE76 /* PrimaryRegistrationChildVCConstants.swift */; }; - 696BBB78217BB6540094BE76 /* SecondaryRegistrationChildVCConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 696BBB77217BB6540094BE76 /* SecondaryRegistrationChildVCConstants.swift */; }; - 696BBB7A217BBC190094BE76 /* AnimatedGIFProgressChildVCConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 696BBB79217BBC190094BE76 /* AnimatedGIFProgressChildVCConstants.swift */; }; - 696BBB7C217BBDEB0094BE76 /* RegistrationCompleteChildVCConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 696BBB7B217BBDEB0094BE76 /* RegistrationCompleteChildVCConstants.swift */; }; - 696BBB84217BC8D40094BE76 /* CircularStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 696BBB83217BC8D40094BE76 /* CircularStatus.swift */; }; - 696BBB87217BCA3D0094BE76 /* SetupCompleteChildVCConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 696BBB86217BCA3D0094BE76 /* SetupCompleteChildVCConstants.swift */; }; - 696BBB89217BCC4B0094BE76 /* BundleSelectionChildVCConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 696BBB88217BCC4B0094BE76 /* BundleSelectionChildVCConstants.swift */; }; - 696BBB8B217BCE090094BE76 /* BundleInstallationChildVCConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 696BBB8A217BCE090094BE76 /* BundleInstallationChildVCConstants.swift */; }; + 69671B41219B7B100014E3D5 /* bee-blue.gif in Resources */ = {isa = PBXBuildFile; fileRef = 69671B40219B7B100014E3D5 /* bee-blue.gif */; }; 696BBB8D217CBA9E0094BE76 /* NetworkValidationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 696BBB8C217CBA9E0094BE76 /* NetworkValidationService.swift */; }; 696BBB8F217CD57F0094BE76 /* IssueAlertService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 696BBB8E217CD57F0094BE76 /* IssueAlertService.swift */; }; - 698263402124B9940085647A /* WebLinkButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6982633F2124B9940085647A /* WebLinkButtons.swift */; }; - 698263612125C46E0085647A /* Hyperlink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 698263602125C46E0085647A /* Hyperlink.swift */; }; - 6991C19D2171064700BA7C56 /* XPCService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6991C19C2171064700BA7C56 /* XPCService.swift */; }; 69A1F5B42102269B004F461A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69A1F5B32102269B004F461A /* AppDelegate.swift */; }; 69A1F5B82102269C004F461A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 69A1F5B72102269C004F461A /* Assets.xcassets */; }; 69A1F5D521022FC2004F461A /* LoginHelperAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69A1F5D421022FC2004F461A /* LoginHelperAppDelegate.swift */; }; 69A1F5D721022FC2004F461A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 69A1F5D621022FC2004F461A /* Assets.xcassets */; }; 69A1F5DA21022FC2004F461A /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 69A1F5D821022FC2004F461A /* MainMenu.xib */; }; 69A1F5E121023006004F461A /* EnrollmentLoginHelper.app in Resources */ = {isa = PBXBuildFile; fileRef = 69A1F5D221022FC2004F461A /* EnrollmentLoginHelper.app */; }; - 69B411F0216FA22D005B6332 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69EEA004216F8C050032C2E1 /* main.swift */; }; - 69B411F2216FA22D005B6332 /* JAMFIntegrationHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69EEA009216F8CAF0032C2E1 /* JAMFIntegrationHelper.swift */; }; - 69B411F3216FA293005B6332 /* RemoteProcessProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6950CD5C210B9BBE007C97DF /* RemoteProcessProtocol.swift */; }; - 69B411F5216FA29A005B6332 /* JAMFHelperConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69EE9FF3216D0E780032C2E1 /* JAMFHelperConstants.swift */; }; - 69C292D7213E163B00639383 /* AppBundleConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69C292D6213E163B00639383 /* AppBundleConstants.swift */; }; - 69C292D9213EB6C600639383 /* UpdateAppBundleInstallationUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69C292D8213EB6C600639383 /* UpdateAppBundleInstallationUI.swift */; }; 69C56FDB21023BF300766B15 /* ColorConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69C56FDA21023BF300766B15 /* ColorConstants.swift */; }; 69C56FDD210260C700766B15 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69C56FDC210260C700766B15 /* MainViewController.swift */; }; - 69C56FDF2102628E00766B15 /* MainStoryboardConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69C56FDE2102628E00766B15 /* MainStoryboardConstants.swift */; }; 69C56FE121063DBD00766B15 /* EnrollmentWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69C56FE021063DBD00766B15 /* EnrollmentWindowController.swift */; }; 69C56FE32106598700766B15 /* SubViewControllerManagerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69C56FE22106598700766B15 /* SubViewControllerManagerViewController.swift */; }; - 69C56FE82106635B00766B15 /* PrimaryRegistrationChildViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69C56FE72106635B00766B15 /* PrimaryRegistrationChildViewController.swift */; }; - 69C56FEC2107B03500766B15 /* InfoBubble.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69C56FEB2107B03500766B15 /* InfoBubble.swift */; }; 69C56FF12108DEE000766B15 /* JAMFConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69C56FF02108DEE000766B15 /* JAMFConstants.swift */; }; 69C56FF32108F17B00766B15 /* NSButton+TextColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69C56FF22108F17B00766B15 /* NSButton+TextColor.swift */; }; 69C56FF52108F1CE00766B15 /* NSView+FadeTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69C56FF42108F1CE00766B15 /* NSView+FadeTransition.swift */; }; - 69C56FF82108F48100766B15 /* SecondaryRegistrationChildViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69C56FF72108F48100766B15 /* SecondaryRegistrationChildViewController.swift */; }; 69C56FFA2108F5D400766B15 /* CrossfadeStoryBoardSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69C56FF92108F5D400766B15 /* CrossfadeStoryBoardSegue.swift */; }; - 69C56FFC2108FA9300766B15 /* DestinationIDConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69C56FFB2108FA9300766B15 /* DestinationIDConstants.swift */; }; - 69D0DFEC215C1D3A00D0E5B7 /* IncorrectUserPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69D0DFEB215C1D3A00D0E5B7 /* IncorrectUserPopover.swift */; }; 69D0DFF0215D605800D0E5B7 /* BundlePopOverViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 69D0DFEF215D605800D0E5B7 /* BundlePopOverViewController.xib */; }; 69D0DFF2215D607500D0E5B7 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 69D0DFF1215D607500D0E5B7 /* Main.storyboard */; }; - 69D0DFFF2162A31500D0E5B7 /* LinkOutItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69D0DFFD2162A31500D0E5B7 /* LinkOutItemCell.swift */; }; 69D0E0002162A31500D0E5B7 /* LinkOutItemCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 69D0DFFE2162A31500D0E5B7 /* LinkOutItemCell.xib */; }; - 69EE9FF4216D0E780032C2E1 /* JAMFHelperConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69EE9FF3216D0E780032C2E1 /* JAMFHelperConstants.swift */; }; + 69F1F23421BFFAA100F2270F /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69F1F23321BFFAA100F2270F /* MainView.swift */; }; + B9128E4E258A2F0500E2FDAA /* PostRegistrationPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9128E4D258A2F0500E2FDAA /* PostRegistrationPage.swift */; }; + B916473D243F51D000A836C9 /* BundleInstallationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B916473C243F51D000A836C9 /* BundleInstallationViewController.swift */; }; + B916473F243F51E500A836C9 /* PostInstallationPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B916473E243F51E500A836C9 /* PostInstallationPageViewController.swift */; }; + B929F78B240E492F0037DFE1 /* MultipleRegistrationFieldsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B929F789240E492F0037DFE1 /* MultipleRegistrationFieldsViewController.swift */; }; + B929F78F240E4AB20037DFE1 /* CompactRegistrationField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B929F78D240E4AB20037DFE1 /* CompactRegistrationField.swift */; }; + B929F790240E4AB20037DFE1 /* CompactRegistrationField.xib in Resources */ = {isa = PBXBuildFile; fileRef = B929F78E240E4AB20037DFE1 /* CompactRegistrationField.xib */; }; + B929F792240E4C700037DFE1 /* InfoLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B929F791240E4C700037DFE1 /* InfoLabelView.swift */; }; + B929F794240E4C980037DFE1 /* InfoLabelView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B929F793240E4C980037DFE1 /* InfoLabelView.xib */; }; + B949BABD245033C20030D077 /* RotableImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B949BABC245033C20030D077 /* RotableImageView.swift */; }; + B949BAC12451A9300030D077 /* SummaryItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B949BABF2451A9300030D077 /* SummaryItemCell.swift */; }; + B949BAC22451A9300030D077 /* SummaryItemCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B949BAC02451A9300030D077 /* SummaryItemCell.xib */; }; + B949BAC42451C9EE0030D077 /* LabelButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B949BAC32451C9EE0030D077 /* LabelButton.swift */; }; + B9537F512411347600C1D137 /* LoadableNib.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9537F502411347600C1D137 /* LoadableNib.swift */; }; + B96C630B2445C2E800BE8ACF /* BundleInstallationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B96C630A2445C2E800BE8ACF /* BundleInstallationViewModel.swift */; }; + B96C630E2445CF7500BE8ACF /* BundleInstallationStackViewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B96C630C2445CF7500BE8ACF /* BundleInstallationStackViewItem.swift */; }; + B96C630F2445CF7500BE8ACF /* BundleInstallationStackViewItem.xib in Resources */ = {isa = PBXBuildFile; fileRef = B96C630D2445CF7500BE8ACF /* BundleInstallationStackViewItem.xib */; }; + B96C63122448531A00BE8ACF /* AppInstallationStackViewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B96C63112448531A00BE8ACF /* AppInstallationStackViewItem.swift */; }; + B96C63142448535A00BE8ACF /* AppInstallationStackViewItem.xib in Resources */ = {isa = PBXBuildFile; fileRef = B96C63132448535A00BE8ACF /* AppInstallationStackViewItem.xib */; }; + B97598A0241B8D7500956D4B /* Registration.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B975989F241B8D7500956D4B /* Registration.storyboard */; }; + B97DB78025A70C8700378A3E /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = B97DB77F25A70C8700378A3E /* Constants.swift */; }; + B98AEF9D23EAF87E00A34462 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B98AEF9F23EAF87E00A34462 /* Localizable.strings */; }; + B98AEFA223EAFA6900A34462 /* String-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B98AEFA123EAFA6900A34462 /* String-Extensions.swift */; }; + B99A09DA24489E6E00014BC0 /* LoaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99A09D924489E6E00014BC0 /* LoaderView.swift */; }; + B99D1E362534639600661954 /* PrivilegedCommandsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99D1E342534639600661954 /* PrivilegedCommandsHelper.swift */; }; + B99D1E552534652A00661954 /* PrivilegedHelperController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99D1E472534645B00661954 /* PrivilegedHelperController.swift */; }; + B99D1E5E2534670D00661954 /* RemoteProcessProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6950CD5C210B9BBE007C97DF /* RemoteProcessProtocol.swift */; }; + B99D1E792534678000661954 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99D1E312534639600661954 /* main.swift */; }; + B99D1E882534745D00661954 /* com.ibm.cio.be.PrivilegedCommandsHelper in Copy Helper */ = {isa = PBXBuildFile; fileRef = B99D1E262534637700661954 /* com.ibm.cio.be.PrivilegedCommandsHelper */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + B99F78562476CA7600893906 /* ConfigurationErrorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99F78552476CA7600893906 /* ConfigurationErrorViewController.swift */; }; + B99F785A2476CEB700893906 /* ConfigurationErrorViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = B99F78582476CEB700893906 /* ConfigurationErrorViewController.xib */; }; + B9B2990B23FE8F0500C13F3E /* MoreCodable in Frameworks */ = {isa = PBXBuildFile; productRef = B9B2990A23FE8F0500C13F3E /* MoreCodable */; }; + B9B2991123FEBF5000C13F3E /* UserDefaultHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9B2991023FEBF5000C13F3E /* UserDefaultHelper.swift */; }; + B9B57492243E10F100114D54 /* RegistrationChoice.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9B57491243E10F100114D54 /* RegistrationChoice.swift */; }; + B9BCE50F23FBD80E00CD0B16 /* RegistrationData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9BCE50523FBD80E00CD0B16 /* RegistrationData.swift */; }; + B9BCE51023FBD80E00CD0B16 /* RegistrationField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9BCE50623FBD80E00CD0B16 /* RegistrationField.swift */; }; + B9BCE51123FBD80E00CD0B16 /* JamfPoliciesStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9BCE50723FBD80E00CD0B16 /* JamfPoliciesStore.swift */; }; + B9BCE51223FBD80E00CD0B16 /* EnrollmentDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9BCE50823FBD80E00CD0B16 /* EnrollmentDataSet.swift */; }; + B9BCE51323FBD80E00CD0B16 /* InfoLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9BCE50923FBD80E00CD0B16 /* InfoLabel.swift */; }; + B9BCE51423FBD80E00CD0B16 /* BundleInstallationPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9BCE50A23FBD80E00CD0B16 /* BundleInstallationPage.swift */; }; + B9BCE51523FBD80E00CD0B16 /* BundleSelectionPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9BCE50B23FBD80E00CD0B16 /* BundleSelectionPage.swift */; }; + B9BCE51623FBD80E00CD0B16 /* RegistrationPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9BCE50C23FBD80E00CD0B16 /* RegistrationPage.swift */; }; + B9BCE51723FBD80E00CD0B16 /* EnrollmentBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9BCE50D23FBD80E00CD0B16 /* EnrollmentBundle.swift */; }; + B9BCE51823FBD80E00CD0B16 /* PostInstallationPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9BCE50E23FBD80E00CD0B16 /* PostInstallationPage.swift */; }; + B9BCE51A23FBED6600CD0B16 /* Context.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9BCE51923FBED6600CD0B16 /* Context.swift */; }; + B9C684BB241FC8A400F4A7C5 /* InfoPopOverViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9C684B9241FC8A400F4A7C5 /* InfoPopOverViewController.swift */; }; + B9C684BC241FC8A400F4A7C5 /* InfoPopOverViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = B9C684BA241FC8A400F4A7C5 /* InfoPopOverViewController.xib */; }; + B9C684BF241FCBC400F4A7C5 /* InfoPopOverStackItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9C684BE241FCBC400F4A7C5 /* InfoPopOverStackItem.swift */; }; + B9C684C1241FCBD300F4A7C5 /* InfoPopOverStackItem.xib in Resources */ = {isa = PBXBuildFile; fileRef = B9C684C0241FCBD300F4A7C5 /* InfoPopOverStackItem.xib */; }; + B9C684C32421548200F4A7C5 /* HorizontalLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9C684C22421548200F4A7C5 /* HorizontalLine.swift */; }; + B9CEEF5D244DAAEB00C81293 /* InstallationProcessController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9CEEF5C244DAAEB00C81293 /* InstallationProcessController.swift */; }; + B9D0EA24242B5B8800A78DC3 /* ExtendedRegistrationField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D0EA23242B5B8800A78DC3 /* ExtendedRegistrationField.swift */; }; + B9D0EA26242B5FD500A78DC3 /* ExtendedRegistrationField.xib in Resources */ = {isa = PBXBuildFile; fileRef = B9D0EA25242B5B9600A78DC3 /* ExtendedRegistrationField.xib */; }; + B9D0EA28242B611800A78DC3 /* ExtendedRegistrationFieldItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D0EA27242B611800A78DC3 /* ExtendedRegistrationFieldItem.swift */; }; + B9D0EA2A242B614500A78DC3 /* ExtendedRegistrationFieldItem.xib in Resources */ = {isa = PBXBuildFile; fileRef = B9D0EA29242B614500A78DC3 /* ExtendedRegistrationFieldItem.xib */; }; + B9D7E231246997DF0083AB50 /* CustomStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D7E230246997DF0083AB50 /* CustomStackView.swift */; }; + B9E3D2AD243343CD0084BF46 /* BundleSelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9E3D2AB243343CD0084BF46 /* BundleSelectionViewController.swift */; }; + B9E3D2B02433442E0084BF46 /* Installation.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B9E3D2AF2433442E0084BF46 /* Installation.storyboard */; }; + B9E3D2B4243344B20084BF46 /* SelectableBundleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9E3D2B2243344B20084BF46 /* SelectableBundleCell.swift */; }; + B9E3D2B5243344B20084BF46 /* SelectableBundleCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B9E3D2B3243344B20084BF46 /* SelectableBundleCell.xib */; }; + F433F10A245F251800D61A57 /* InfoLabelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F433F109245F251800D61A57 /* InfoLabelTests.swift */; }; + F4F1A81C246018AA0043EDCF /* SummaryPageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4F1A81B246018AA0043EDCF /* SummaryPageTests.swift */; }; + F4F1A81E246020B70043EDCF /* RegistrationDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4F1A81D246020B70043EDCF /* RegistrationDataTests.swift */; }; + F4F1A82024602E620043EDCF /* RegistrationFieldTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4F1A81F24602E620043EDCF /* RegistrationFieldTests.swift */; }; + F4F1A822246039600043EDCF /* RegistrationPageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4F1A821246039600043EDCF /* RegistrationPageTests.swift */; }; + F4F1A82424603D4A0043EDCF /* RegistrationChoiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4F1A82324603D4A0043EDCF /* RegistrationChoiceTests.swift */; }; + F4F1A826246041320043EDCF /* PoliciesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4F1A825246041320043EDCF /* PoliciesTests.swift */; }; + F4F1A8282460422D0043EDCF /* EnrollmentBundleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4F1A8272460422D0043EDCF /* EnrollmentBundleTests.swift */; }; + F4F1A82A246045800043EDCF /* BundleInstallationPageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4F1A829246045800043EDCF /* BundleInstallationPageTests.swift */; }; + F4F1A82C246047EA0043EDCF /* BundleSelectionPageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4F1A82B246047EA0043EDCF /* BundleSelectionPageTests.swift */; }; + F4F1A82E24604CA50043EDCF /* EnrollmentDataSetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4F1A82D24604CA50043EDCF /* EnrollmentDataSetTests.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 69CC617A2170F9F400DC4BA1 /* PBXContainerItemProxy */ = { + B99D1E82253467D400661954 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 69A1F5A82102269B004F461A /* Project object */; proxyType = 1; - remoteGlobalIDString = 69B411E8216FA214005B6332; - remoteInfo = com.ibm.JAMFIntegrationHelper; + remoteGlobalIDString = B99D1E252534637700661954; + remoteInfo = PrivilegedCommandsHelper; + }; + F46A1B652448339F009F2738 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 69A1F5A82102269B004F461A /* Project object */; + proxyType = 1; + remoteGlobalIDString = 69A1F5AF2102269B004F461A; + remoteInfo = "Mac@IBM Enrollment"; }; /* End PBXContainerItemProxy section */ @@ -117,12 +149,21 @@ dstPath = Contents/Library/LaunchServices; dstSubfolderSpec = 1; files = ( - 6933FF82216FA34200417BD3 /* com.ibm.jamf.IntegrationHelper in Copy Helper */, + B99D1E882534745D00661954 /* com.ibm.cio.be.PrivilegedCommandsHelper in Copy Helper */, ); name = "Copy Helper"; runOnlyForDeploymentPostprocessing = 0; }; - 69B411E7216FA214005B6332 /* CopyFiles */ = { + 69671B5421A35CB70014E3D5 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = Fonts; + dstSubfolderSpec = 7; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B99D1E242534637700661954 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = /usr/share/man/man1/; @@ -134,53 +175,23 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 6901E574210A52F300EACAF1 /* TermDefinition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TermDefinition.swift; sourceTree = ""; }; - 6901E578210A54BD00EACAF1 /* SecurityDescriptionPopover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecurityDescriptionPopover.swift; sourceTree = ""; }; - 6901E57A210A5CFC00EACAF1 /* InfoPopOverConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoPopOverConstants.swift; sourceTree = ""; }; - 690ACB32213884DF00F8B1F0 /* DefineBundleInfoPopover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefineBundleInfoPopover.swift; sourceTree = ""; }; - 690ACB36213C5F1900F8B1F0 /* NSView+Rotation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSView+Rotation.swift"; sourceTree = ""; }; + 6904AB6F21B6E2C600AE31BB /* bee-lowlight.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = "bee-lowlight.gif"; sourceTree = ""; }; + 6904AB7121B81FAC00AE31BB /* AppleInterfaceStyleMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleInterfaceStyleMonitor.swift; sourceTree = ""; }; + 690ACB36213C5F1900F8B1F0 /* RotableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RotableView.swift; sourceTree = ""; }; 690ACB38213C6BF900F8B1F0 /* Indicators.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Indicators.swift; sourceTree = ""; }; - 690ACB3A213C8F2E00F8B1F0 /* BundleInstallationChildViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleInstallationChildViewController.swift; sourceTree = ""; }; - 691F680721C4323600700C78 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; 6922F6AB21273FDD00EB8003 /* BundleItemCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleItemCell.swift; sourceTree = ""; }; - 6922F6AE212DB17D00EB8003 /* StackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackView.swift; sourceTree = ""; }; - 6922F6B0212DD0A900EB8003 /* BaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = ""; }; - 6922F6B2212DD39700EB8003 /* HeaderViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderViewController.swift; sourceTree = ""; }; - 6950CD57210B67EF007C97DF /* Info4Popover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Info4Popover.swift; sourceTree = ""; }; - 6950CD59210B6F8A007C97DF /* Info2Popover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Info2Popover.swift; sourceTree = ""; }; 6950CD5C210B9BBE007C97DF /* RemoteProcessProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteProcessProtocol.swift; sourceTree = ""; }; 6950CD64210F67FE007C97DF /* AlertConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertConstants.swift; sourceTree = ""; }; - 6950CD6A2110D583007C97DF /* OptionPopover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OptionPopover.swift; sourceTree = ""; }; 6950CD6E211228F1007C97DF /* AnimatedGIFImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimatedGIFImageView.swift; sourceTree = ""; }; 6950CD7021123283007C97DF /* AnimatedGIFProgressViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimatedGIFProgressViewController.swift; sourceTree = ""; }; - 6950CD7221133ED5007C97DF /* RegistrationCompleteChildViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegistrationCompleteChildViewController.swift; sourceTree = ""; }; - 6950CD75211375A0007C97DF /* BundleSelectionChildViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleSelectionChildViewController.swift; sourceTree = ""; }; - 6950CD792114F385007C97DF /* StackItems.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = StackItems.storyboard; sourceTree = ""; }; + 6950CD7221133ED5007C97DF /* PostRegistrationPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostRegistrationPageViewController.swift; sourceTree = ""; }; 6950CD7A2114F385007C97DF /* BundleItemCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BundleItemCell.xib; sourceTree = ""; }; - 6950CD7B2114F385007C97DF /* HeaderViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = HeaderViewController.storyboard; sourceTree = ""; }; - 6950CD802118C865007C97DF /* SetupCompleteChildViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupCompleteChildViewController.swift; sourceTree = ""; }; - 6950CD84211A2D89007C97DF /* ProgressStates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressStates.swift; sourceTree = ""; }; - 6950CD86211B83CF007C97DF /* BundleInstallButtonVisibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleInstallButtonVisibility.swift; sourceTree = ""; }; 6950CD8A211C8B64007C97DF /* NSTextField+Attributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSTextField+Attributes.swift"; sourceTree = ""; }; - 6950CD8F2121E03B007C97DF /* SetupCompleteButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupCompleteButtons.swift; sourceTree = ""; }; - 695833792135D29C00D6B606 /* BundleCProgressStackItemViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleCProgressStackItemViewController.swift; sourceTree = ""; }; - 6958337B2135D2C800D6B606 /* BundleBProgressStackItemViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleBProgressStackItemViewController.swift; sourceTree = ""; }; - 6958337D2135D2F200D6B606 /* BundleAProgressStackItemViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleAProgressStackItemViewController.swift; sourceTree = ""; }; 6958337F213729D700D6B606 /* BundlePopOverViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundlePopOverViewController.swift; sourceTree = ""; }; - 696BBB75217BAE7B0094BE76 /* PrimaryRegistrationChildVCConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrimaryRegistrationChildVCConstants.swift; sourceTree = ""; }; - 696BBB77217BB6540094BE76 /* SecondaryRegistrationChildVCConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondaryRegistrationChildVCConstants.swift; sourceTree = ""; }; - 696BBB79217BBC190094BE76 /* AnimatedGIFProgressChildVCConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimatedGIFProgressChildVCConstants.swift; sourceTree = ""; }; - 696BBB7B217BBDEB0094BE76 /* RegistrationCompleteChildVCConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegistrationCompleteChildVCConstants.swift; sourceTree = ""; }; - 696BBB83217BC8D40094BE76 /* CircularStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CircularStatus.swift; path = enrollment/Controllers/AppBundles/CircularStatus.swift; sourceTree = SOURCE_ROOT; }; - 696BBB86217BCA3D0094BE76 /* SetupCompleteChildVCConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupCompleteChildVCConstants.swift; sourceTree = ""; }; - 696BBB88217BCC4B0094BE76 /* BundleSelectionChildVCConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleSelectionChildVCConstants.swift; sourceTree = ""; }; - 696BBB8A217BCE090094BE76 /* BundleInstallationChildVCConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleInstallationChildVCConstants.swift; sourceTree = ""; }; + 69671B40219B7B100014E3D5 /* bee-blue.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = "bee-blue.gif"; sourceTree = ""; }; 696BBB8C217CBA9E0094BE76 /* NetworkValidationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkValidationService.swift; sourceTree = ""; }; 696BBB8E217CD57F0094BE76 /* IssueAlertService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IssueAlertService.swift; sourceTree = ""; }; - 6982633F2124B9940085647A /* WebLinkButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebLinkButtons.swift; sourceTree = ""; }; - 698263602125C46E0085647A /* Hyperlink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Hyperlink.swift; sourceTree = ""; }; - 6991C19C2171064700BA7C56 /* XPCService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XPCService.swift; sourceTree = ""; }; - 69A1F5B02102269B004F461A /* enrollment.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = enrollment.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 69A1F5B02102269B004F461A /* Mac@IBM Enrollment.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Mac@IBM Enrollment.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 69A1F5B32102269B004F461A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 69A1F5B72102269C004F461A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 69A1F5BC2102269C004F461A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -191,32 +202,90 @@ 69A1F5D921022FC2004F461A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 69A1F5DB21022FC2004F461A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 69A1F5DC21022FC2004F461A /* EnrollmentLoginHelper.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = EnrollmentLoginHelper.entitlements; sourceTree = ""; }; - 69B411E9216FA214005B6332 /* com.ibm.jamf.IntegrationHelper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = com.ibm.jamf.IntegrationHelper; sourceTree = BUILT_PRODUCTS_DIR; }; - 69C292D6213E163B00639383 /* AppBundleConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppBundleConstants.swift; sourceTree = ""; }; - 69C292D8213EB6C600639383 /* UpdateAppBundleInstallationUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateAppBundleInstallationUI.swift; sourceTree = ""; }; 69C56FDA21023BF300766B15 /* ColorConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorConstants.swift; sourceTree = ""; }; 69C56FDC210260C700766B15 /* MainViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; - 69C56FDE2102628E00766B15 /* MainStoryboardConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainStoryboardConstants.swift; sourceTree = ""; }; 69C56FE021063DBD00766B15 /* EnrollmentWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnrollmentWindowController.swift; sourceTree = ""; }; 69C56FE22106598700766B15 /* SubViewControllerManagerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubViewControllerManagerViewController.swift; sourceTree = ""; }; - 69C56FE72106635B00766B15 /* PrimaryRegistrationChildViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrimaryRegistrationChildViewController.swift; sourceTree = ""; }; - 69C56FEB2107B03500766B15 /* InfoBubble.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InfoBubble.swift; sourceTree = ""; }; 69C56FF02108DEE000766B15 /* JAMFConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JAMFConstants.swift; sourceTree = ""; }; 69C56FF22108F17B00766B15 /* NSButton+TextColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSButton+TextColor.swift"; sourceTree = ""; }; 69C56FF42108F1CE00766B15 /* NSView+FadeTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSView+FadeTransition.swift"; sourceTree = ""; }; - 69C56FF72108F48100766B15 /* SecondaryRegistrationChildViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondaryRegistrationChildViewController.swift; sourceTree = ""; }; 69C56FF92108F5D400766B15 /* CrossfadeStoryBoardSegue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrossfadeStoryBoardSegue.swift; sourceTree = ""; }; - 69C56FFB2108FA9300766B15 /* DestinationIDConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DestinationIDConstants.swift; sourceTree = ""; }; - 69D0DFEB215C1D3A00D0E5B7 /* IncorrectUserPopover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncorrectUserPopover.swift; sourceTree = ""; }; 69D0DFEF215D605800D0E5B7 /* BundlePopOverViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BundlePopOverViewController.xib; sourceTree = ""; }; 69D0DFF1215D607500D0E5B7 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; - 69D0DFFD2162A31500D0E5B7 /* LinkOutItemCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkOutItemCell.swift; sourceTree = ""; }; 69D0DFFE2162A31500D0E5B7 /* LinkOutItemCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LinkOutItemCell.xib; sourceTree = ""; }; - 69EE9FF3216D0E780032C2E1 /* JAMFHelperConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JAMFHelperConstants.swift; sourceTree = ""; }; - 69EEA004216F8C050032C2E1 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = main.swift; path = ../enrollmentJAMFIntegrationHelper/main.swift; sourceTree = ""; }; - 69EEA009216F8CAF0032C2E1 /* JAMFIntegrationHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JAMFIntegrationHelper.swift; sourceTree = ""; }; - 69EEA011216F95FD0032C2E1 /* JAMFIntegrationHelper-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "JAMFIntegrationHelper-Info.plist"; sourceTree = ""; }; - 69EEA012216F969A0032C2E1 /* JAMFIntegrationHelper-Launchd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "JAMFIntegrationHelper-Launchd.plist"; sourceTree = ""; }; + 69F1F23321BFFAA100F2270F /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; + B9128E4D258A2F0500E2FDAA /* PostRegistrationPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostRegistrationPage.swift; sourceTree = ""; }; + B916473C243F51D000A836C9 /* BundleInstallationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleInstallationViewController.swift; sourceTree = ""; }; + B916473E243F51E500A836C9 /* PostInstallationPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostInstallationPageViewController.swift; sourceTree = ""; }; + B929F789240E492F0037DFE1 /* MultipleRegistrationFieldsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultipleRegistrationFieldsViewController.swift; sourceTree = ""; }; + B929F78D240E4AB20037DFE1 /* CompactRegistrationField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompactRegistrationField.swift; sourceTree = ""; }; + B929F78E240E4AB20037DFE1 /* CompactRegistrationField.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CompactRegistrationField.xib; sourceTree = ""; }; + B929F791240E4C700037DFE1 /* InfoLabelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoLabelView.swift; sourceTree = ""; }; + B929F793240E4C980037DFE1 /* InfoLabelView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = InfoLabelView.xib; sourceTree = ""; }; + B949BABC245033C20030D077 /* RotableImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RotableImageView.swift; sourceTree = ""; }; + B949BABF2451A9300030D077 /* SummaryItemCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SummaryItemCell.swift; sourceTree = ""; }; + B949BAC02451A9300030D077 /* SummaryItemCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SummaryItemCell.xib; sourceTree = ""; }; + B949BAC32451C9EE0030D077 /* LabelButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelButton.swift; sourceTree = ""; }; + B9537F502411347600C1D137 /* LoadableNib.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadableNib.swift; sourceTree = ""; }; + B96C630A2445C2E800BE8ACF /* BundleInstallationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleInstallationViewModel.swift; sourceTree = ""; }; + B96C630C2445CF7500BE8ACF /* BundleInstallationStackViewItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleInstallationStackViewItem.swift; sourceTree = ""; }; + B96C630D2445CF7500BE8ACF /* BundleInstallationStackViewItem.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = BundleInstallationStackViewItem.xib; sourceTree = ""; }; + B96C63112448531A00BE8ACF /* AppInstallationStackViewItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppInstallationStackViewItem.swift; sourceTree = ""; }; + B96C63132448535A00BE8ACF /* AppInstallationStackViewItem.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AppInstallationStackViewItem.xib; sourceTree = ""; }; + B975989F241B8D7500956D4B /* Registration.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Registration.storyboard; sourceTree = ""; }; + B97DB77F25A70C8700378A3E /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; + B98AEF9E23EAF87E00A34462 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; + B98AEFA123EAFA6900A34462 /* String-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String-Extensions.swift"; sourceTree = ""; }; + B99A09D924489E6E00014BC0 /* LoaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoaderView.swift; sourceTree = ""; }; + B99D1E262534637700661954 /* com.ibm.cio.be.PrivilegedCommandsHelper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = com.ibm.cio.be.PrivilegedCommandsHelper; sourceTree = BUILT_PRODUCTS_DIR; }; + B99D1E312534639600661954 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; + B99D1E322534639600661954 /* PrivilegedCommandsHelper-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "PrivilegedCommandsHelper-Info.plist"; sourceTree = ""; }; + B99D1E332534639600661954 /* PrivilegedCommandsHelper-Launchd.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "PrivilegedCommandsHelper-Launchd.plist"; sourceTree = ""; }; + B99D1E342534639600661954 /* PrivilegedCommandsHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrivilegedCommandsHelper.swift; sourceTree = ""; }; + B99D1E472534645B00661954 /* PrivilegedHelperController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrivilegedHelperController.swift; sourceTree = ""; }; + B99F78552476CA7600893906 /* ConfigurationErrorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationErrorViewController.swift; sourceTree = ""; }; + B99F78582476CEB700893906 /* ConfigurationErrorViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ConfigurationErrorViewController.xib; sourceTree = ""; }; + B9B2991023FEBF5000C13F3E /* UserDefaultHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultHelper.swift; sourceTree = ""; }; + B9B57491243E10F100114D54 /* RegistrationChoice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegistrationChoice.swift; sourceTree = ""; }; + B9BCE50523FBD80E00CD0B16 /* RegistrationData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RegistrationData.swift; sourceTree = ""; }; + B9BCE50623FBD80E00CD0B16 /* RegistrationField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RegistrationField.swift; sourceTree = ""; }; + B9BCE50723FBD80E00CD0B16 /* JamfPoliciesStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JamfPoliciesStore.swift; sourceTree = ""; }; + B9BCE50823FBD80E00CD0B16 /* EnrollmentDataSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnrollmentDataSet.swift; sourceTree = ""; }; + B9BCE50923FBD80E00CD0B16 /* InfoLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InfoLabel.swift; sourceTree = ""; }; + B9BCE50A23FBD80E00CD0B16 /* BundleInstallationPage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BundleInstallationPage.swift; sourceTree = ""; }; + B9BCE50B23FBD80E00CD0B16 /* BundleSelectionPage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BundleSelectionPage.swift; sourceTree = ""; }; + B9BCE50C23FBD80E00CD0B16 /* RegistrationPage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RegistrationPage.swift; sourceTree = ""; }; + B9BCE50D23FBD80E00CD0B16 /* EnrollmentBundle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnrollmentBundle.swift; sourceTree = ""; }; + B9BCE50E23FBD80E00CD0B16 /* PostInstallationPage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PostInstallationPage.swift; sourceTree = ""; }; + B9BCE51923FBED6600CD0B16 /* Context.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Context.swift; sourceTree = ""; }; + B9C684B9241FC8A400F4A7C5 /* InfoPopOverViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoPopOverViewController.swift; sourceTree = ""; }; + B9C684BA241FC8A400F4A7C5 /* InfoPopOverViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = InfoPopOverViewController.xib; sourceTree = ""; }; + B9C684BE241FCBC400F4A7C5 /* InfoPopOverStackItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoPopOverStackItem.swift; sourceTree = ""; }; + B9C684C0241FCBD300F4A7C5 /* InfoPopOverStackItem.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = InfoPopOverStackItem.xib; sourceTree = ""; }; + B9C684C22421548200F4A7C5 /* HorizontalLine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HorizontalLine.swift; sourceTree = ""; }; + B9CEEF5C244DAAEB00C81293 /* InstallationProcessController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallationProcessController.swift; sourceTree = ""; }; + B9D0EA23242B5B8800A78DC3 /* ExtendedRegistrationField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtendedRegistrationField.swift; sourceTree = ""; }; + B9D0EA25242B5B9600A78DC3 /* ExtendedRegistrationField.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ExtendedRegistrationField.xib; sourceTree = ""; }; + B9D0EA27242B611800A78DC3 /* ExtendedRegistrationFieldItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtendedRegistrationFieldItem.swift; sourceTree = ""; }; + B9D0EA29242B614500A78DC3 /* ExtendedRegistrationFieldItem.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ExtendedRegistrationFieldItem.xib; sourceTree = ""; }; + B9D7E230246997DF0083AB50 /* CustomStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomStackView.swift; sourceTree = ""; }; + B9E3D2AB243343CD0084BF46 /* BundleSelectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleSelectionViewController.swift; sourceTree = ""; }; + B9E3D2AF2433442E0084BF46 /* Installation.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Installation.storyboard; sourceTree = ""; }; + B9E3D2B2243344B20084BF46 /* SelectableBundleCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectableBundleCell.swift; sourceTree = ""; }; + B9E3D2B3243344B20084BF46 /* SelectableBundleCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SelectableBundleCell.xib; sourceTree = ""; }; + F433F109245F251800D61A57 /* InfoLabelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoLabelTests.swift; sourceTree = ""; }; + F46A1B602448339F009F2738 /* Mac@IBM EnrollmentTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Mac@IBM EnrollmentTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + F46A1B642448339F009F2738 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + F4F1A81B246018AA0043EDCF /* SummaryPageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SummaryPageTests.swift; sourceTree = ""; }; + F4F1A81D246020B70043EDCF /* RegistrationDataTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegistrationDataTests.swift; sourceTree = ""; }; + F4F1A81F24602E620043EDCF /* RegistrationFieldTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegistrationFieldTests.swift; sourceTree = ""; }; + F4F1A821246039600043EDCF /* RegistrationPageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegistrationPageTests.swift; sourceTree = ""; }; + F4F1A82324603D4A0043EDCF /* RegistrationChoiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegistrationChoiceTests.swift; sourceTree = ""; }; + F4F1A825246041320043EDCF /* PoliciesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PoliciesTests.swift; sourceTree = ""; }; + F4F1A8272460422D0043EDCF /* EnrollmentBundleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnrollmentBundleTests.swift; sourceTree = ""; }; + F4F1A829246045800043EDCF /* BundleInstallationPageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleInstallationPageTests.swift; sourceTree = ""; }; + F4F1A82B246047EA0043EDCF /* BundleSelectionPageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleSelectionPageTests.swift; sourceTree = ""; }; + F4F1A82D24604CA50043EDCF /* EnrollmentDataSetTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnrollmentDataSetTests.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -224,6 +293,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + B9B2990B23FE8F0500C13F3E /* MoreCodable in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -234,7 +304,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 69B411E6216FA214005B6332 /* Frameworks */ = { + B99D1E232534637700661954 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F46A1B5D2448339F009F2738 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( @@ -244,292 +321,389 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 6901E57C210A61BE00EACAF1 /* PopOvers */ = { + 6950CD5B210B9B2D007C97DF /* Shared */ = { isa = PBXGroup; children = ( - 69D0DFEB215C1D3A00D0E5B7 /* IncorrectUserPopover.swift */, - 6950CD59210B6F8A007C97DF /* Info2Popover.swift */, - 6950CD57210B67EF007C97DF /* Info4Popover.swift */, - 6901E578210A54BD00EACAF1 /* SecurityDescriptionPopover.swift */, - 6950CD6A2110D583007C97DF /* OptionPopover.swift */, - 6922F6AD21273FED00EB8003 /* Bundles */, - ); - path = PopOvers; + 6950CD5C210B9BBE007C97DF /* RemoteProcessProtocol.swift */, + ); + path = Shared; sourceTree = ""; }; - 6922F6AD21273FED00EB8003 /* Bundles */ = { + 6950CD8C211CBA50007C97DF /* Images */ = { isa = PBXGroup; children = ( - 6958337F213729D700D6B606 /* BundlePopOverViewController.swift */, - 6922F6AB21273FDD00EB8003 /* BundleItemCell.swift */, + 6950CD6E211228F1007C97DF /* AnimatedGIFImageView.swift */, + 690ACB38213C6BF900F8B1F0 /* Indicators.swift */, ); - path = Bundles; + path = Images; sourceTree = ""; }; - 6950CD5B210B9B2D007C97DF /* Shared */ = { + 69671B4B21A35C540014E3D5 /* Resources */ = { isa = PBXGroup; children = ( - 69EE9FF3216D0E780032C2E1 /* JAMFHelperConstants.swift */, - 6950CD5C210B9BBE007C97DF /* RemoteProcessProtocol.swift */, - 69EEA009216F8CAF0032C2E1 /* JAMFIntegrationHelper.swift */, + 6950CD8C211CBA50007C97DF /* Images */, + 69671B40219B7B100014E3D5 /* bee-blue.gif */, + 6904AB6F21B6E2C600AE31BB /* bee-lowlight.gif */, ); - path = Shared; + path = Resources; sourceTree = ""; }; - 6950CD8C211CBA50007C97DF /* Images */ = { + 6991C19B2171061600BA7C56 /* Services */ = { isa = PBXGroup; children = ( - 6950CD6E211228F1007C97DF /* AnimatedGIFImageView.swift */, - 69C56FEB2107B03500766B15 /* InfoBubble.swift */, - 6950CD8F2121E03B007C97DF /* SetupCompleteButtons.swift */, - 690ACB38213C6BF900F8B1F0 /* Indicators.swift */, + B99D1E472534645B00661954 /* PrivilegedHelperController.swift */, + 696BBB8C217CBA9E0094BE76 /* NetworkValidationService.swift */, + 696BBB8E217CD57F0094BE76 /* IssueAlertService.swift */, + 6904AB7121B81FAC00AE31BB /* AppleInterfaceStyleMonitor.swift */, ); - path = Images; + path = Services; sourceTree = ""; }; - 696BBB72217BADFA0094BE76 /* VC Constants */ = { + 69A1F5A72102269B004F461A = { isa = PBXGroup; children = ( - 696BBB7D217BC6FF0094BE76 /* Phase 0 Regisistration */, - 696BBB7F217BC7490094BE76 /* Phase 1 Bundle Installation */, - 696BBB80217BC76B0094BE76 /* Phase 2 Education */, + 69A1F5B22102269B004F461A /* enrollment */, + 69A1F5D321022FC2004F461A /* EnrollmentLoginHelper */, + F46A1B612448339F009F2738 /* Mac@IBM EnrollmentTests */, + B99D1E272534637700661954 /* PrivilegedCommandsHelper */, + 69A1F5B12102269B004F461A /* Products */, ); - path = "VC Constants"; sourceTree = ""; }; - 696BBB7D217BC6FF0094BE76 /* Phase 0 Regisistration */ = { + 69A1F5B12102269B004F461A /* Products */ = { isa = PBXGroup; children = ( - 696BBB75217BAE7B0094BE76 /* PrimaryRegistrationChildVCConstants.swift */, - 696BBB77217BB6540094BE76 /* SecondaryRegistrationChildVCConstants.swift */, - 6901E57A210A5CFC00EACAF1 /* InfoPopOverConstants.swift */, - 696BBB79217BBC190094BE76 /* AnimatedGIFProgressChildVCConstants.swift */, - 696BBB7B217BBDEB0094BE76 /* RegistrationCompleteChildVCConstants.swift */, + 69A1F5B02102269B004F461A /* Mac@IBM Enrollment.app */, + 69A1F5D221022FC2004F461A /* EnrollmentLoginHelper.app */, + F46A1B602448339F009F2738 /* Mac@IBM EnrollmentTests.xctest */, + B99D1E262534637700661954 /* com.ibm.cio.be.PrivilegedCommandsHelper */, ); - path = "Phase 0 Regisistration"; + name = Products; sourceTree = ""; }; - 696BBB7F217BC7490094BE76 /* Phase 1 Bundle Installation */ = { + 69A1F5B22102269B004F461A /* enrollment */ = { isa = PBXGroup; children = ( - 696BBB88217BCC4B0094BE76 /* BundleSelectionChildVCConstants.swift */, - 696BBB8A217BCE090094BE76 /* BundleInstallationChildVCConstants.swift */, - 69C292D6213E163B00639383 /* AppBundleConstants.swift */, + 69A1F5B32102269B004F461A /* AppDelegate.swift */, + B9537F4F2411346600C1D137 /* Protocols */, + B98AEFA023EAFA5700A34462 /* Extensions */, + 6991C19B2171061600BA7C56 /* Services */, + B9B5748F243E101F00114D54 /* Model */, + B9CEEF5A244DAAC000C81293 /* Controllers */, + B9B57490243E102B00114D54 /* ViewControllers */, + B9537F552417A6A000C1D137 /* Views */, + 6950CD5B210B9B2D007C97DF /* Shared */, + 69671B4B21A35C540014E3D5 /* Resources */, + 69A1F5B72102269C004F461A /* Assets.xcassets */, + B98AEF9F23EAF87E00A34462 /* Localizable.strings */, + 69A1F5BC2102269C004F461A /* Info.plist */, + 69A1F5BD2102269C004F461A /* enrollment.entitlements */, ); - path = "Phase 1 Bundle Installation"; + path = enrollment; sourceTree = ""; }; - 696BBB80217BC76B0094BE76 /* Phase 2 Education */ = { + 69A1F5D321022FC2004F461A /* EnrollmentLoginHelper */ = { isa = PBXGroup; children = ( - 696BBB86217BCA3D0094BE76 /* SetupCompleteChildVCConstants.swift */, - 6982633F2124B9940085647A /* WebLinkButtons.swift */, + 69A1F5D421022FC2004F461A /* LoginHelperAppDelegate.swift */, + 69A1F5D621022FC2004F461A /* Assets.xcassets */, + 69A1F5D821022FC2004F461A /* MainMenu.xib */, + 69A1F5DB21022FC2004F461A /* Info.plist */, + 69A1F5DC21022FC2004F461A /* EnrollmentLoginHelper.entitlements */, ); - path = "Phase 2 Education"; + path = EnrollmentLoginHelper; sourceTree = ""; }; - 696BBB81217BC8800094BE76 /* Phase 0 Registration */ = { + 69C56FED2108DE1D00766B15 /* Constants */ = { isa = PBXGroup; children = ( - 69C56FE72106635B00766B15 /* PrimaryRegistrationChildViewController.swift */, - 69C56FF72108F48100766B15 /* SecondaryRegistrationChildViewController.swift */, - 6950CD7021123283007C97DF /* AnimatedGIFProgressViewController.swift */, - 6950CD7221133ED5007C97DF /* RegistrationCompleteChildViewController.swift */, + 69C56FDA21023BF300766B15 /* ColorConstants.swift */, + 6950CD64210F67FE007C97DF /* AlertConstants.swift */, + B9B2991023FEBF5000C13F3E /* UserDefaultHelper.swift */, + 69C56FF02108DEE000766B15 /* JAMFConstants.swift */, ); - path = "Phase 0 Registration"; + path = Constants; sourceTree = ""; }; - 696BBB82217BC8B50094BE76 /* Phase 1 Bundle Installation */ = { + B949BABE2451A9010030D077 /* SummaryItemCell */ = { isa = PBXGroup; children = ( - 696BBB83217BC8D40094BE76 /* CircularStatus.swift */, - 6950CD75211375A0007C97DF /* BundleSelectionChildViewController.swift */, - 690ACB3A213C8F2E00F8B1F0 /* BundleInstallationChildViewController.swift */, - 6958337D2135D2F200D6B606 /* BundleAProgressStackItemViewController.swift */, - 6958337B2135D2C800D6B606 /* BundleBProgressStackItemViewController.swift */, - 695833792135D29C00D6B606 /* BundleCProgressStackItemViewController.swift */, - 6922F6AE212DB17D00EB8003 /* StackView.swift */, - 6922F6B0212DD0A900EB8003 /* BaseViewController.swift */, - 6922F6B2212DD39700EB8003 /* HeaderViewController.swift */, - ); - path = "Phase 1 Bundle Installation"; + B949BABF2451A9300030D077 /* SummaryItemCell.swift */, + B949BAC02451A9300030D077 /* SummaryItemCell.xib */, + ); + path = SummaryItemCell; sourceTree = ""; }; - 696BBB85217BC9090094BE76 /* Phase 2 Education */ = { + B9537F4F2411346600C1D137 /* Protocols */ = { isa = PBXGroup; children = ( - 6950CD802118C865007C97DF /* SetupCompleteChildViewController.swift */, - 69D0DFFD2162A31500D0E5B7 /* LinkOutItemCell.swift */, + B9537F502411347600C1D137 /* LoadableNib.swift */, ); - path = "Phase 2 Education"; + path = Protocols; sourceTree = ""; }; - 6991C19B2171061600BA7C56 /* Services */ = { + B9537F522417A66700C1D137 /* Cells */ = { isa = PBXGroup; children = ( - 6991C19C2171064700BA7C56 /* XPCService.swift */, - 696BBB8C217CBA9E0094BE76 /* NetworkValidationService.swift */, - 696BBB8E217CD57F0094BE76 /* IssueAlertService.swift */, + B9D0EA22242B5B0F00A78DC3 /* ExtendedRegistrationField */, + B9537F532417A67600C1D137 /* CompactRegistrationField */, ); - path = Services; + path = Cells; sourceTree = ""; }; - 69A1F5A72102269B004F461A = { + B9537F532417A67600C1D137 /* CompactRegistrationField */ = { isa = PBXGroup; children = ( - 69A1F5B22102269B004F461A /* enrollment */, - 69A1F5D321022FC2004F461A /* EnrollmentLoginHelper */, - 69B411EA216FA214005B6332 /* JAMFIntegrationHelper */, - 69A1F5B12102269B004F461A /* Products */, + B929F78D240E4AB20037DFE1 /* CompactRegistrationField.swift */, + B929F78E240E4AB20037DFE1 /* CompactRegistrationField.xib */, ); + path = CompactRegistrationField; sourceTree = ""; }; - 69A1F5B12102269B004F461A /* Products */ = { + B9537F542417A68E00C1D137 /* Registration */ = { isa = PBXGroup; children = ( - 69A1F5B02102269B004F461A /* enrollment.app */, - 69A1F5D221022FC2004F461A /* EnrollmentLoginHelper.app */, - 69B411E9216FA214005B6332 /* com.ibm.jamf.IntegrationHelper */, + B9537F522417A66700C1D137 /* Cells */, + B9C684BD241FC8E800F4A7C5 /* InfoPopOver */, + B975989F241B8D7500956D4B /* Registration.storyboard */, + B929F789240E492F0037DFE1 /* MultipleRegistrationFieldsViewController.swift */, + 6950CD7021123283007C97DF /* AnimatedGIFProgressViewController.swift */, + 6950CD7221133ED5007C97DF /* PostRegistrationPageViewController.swift */, ); - name = Products; + path = Registration; sourceTree = ""; }; - 69A1F5B22102269B004F461A /* enrollment */ = { + B9537F552417A6A000C1D137 /* Views */ = { isa = PBXGroup; children = ( - 6991C19B2171061600BA7C56 /* Services */, + B9D7E230246997DF0083AB50 /* CustomStackView.swift */, 69C56FED2108DE1D00766B15 /* Constants */, - 69C56FEA2107661D00766B15 /* Models */, - 69C56FE9210765B200766B15 /* Views */, - 69C56FE4210662D500766B15 /* Controllers */, - 6950CD5B210B9B2D007C97DF /* Shared */, - 69A1F5B72102269C004F461A /* Assets.xcassets */, - 69A1F5BC2102269C004F461A /* Info.plist */, - 69A1F5BD2102269C004F461A /* enrollment.entitlements */, + 69D0DFFE2162A31500D0E5B7 /* LinkOutItemCell.xib */, + 69F1F23321BFFAA100F2270F /* MainView.swift */, + 690ACB36213C5F1900F8B1F0 /* RotableView.swift */, + B949BAC32451C9EE0030D077 /* LabelButton.swift */, + B949BABC245033C20030D077 /* RotableImageView.swift */, + B929F793240E4C980037DFE1 /* InfoLabelView.xib */, + B9C684C22421548200F4A7C5 /* HorizontalLine.swift */, + B929F791240E4C700037DFE1 /* InfoLabelView.swift */, + B99A09D924489E6E00014BC0 /* LoaderView.swift */, ); - path = enrollment; + path = Views; sourceTree = ""; }; - 69A1F5D321022FC2004F461A /* EnrollmentLoginHelper */ = { + B96C63092445BBE000BE8ACF /* BundleInstallationCell */ = { isa = PBXGroup; children = ( - 69A1F5D421022FC2004F461A /* LoginHelperAppDelegate.swift */, - 69A1F5D621022FC2004F461A /* Assets.xcassets */, - 69A1F5D821022FC2004F461A /* MainMenu.xib */, - 69A1F5DB21022FC2004F461A /* Info.plist */, - 69A1F5DC21022FC2004F461A /* EnrollmentLoginHelper.entitlements */, + B96C630C2445CF7500BE8ACF /* BundleInstallationStackViewItem.swift */, + B96C630D2445CF7500BE8ACF /* BundleInstallationStackViewItem.xib */, + B96C63112448531A00BE8ACF /* AppInstallationStackViewItem.swift */, + B96C63132448535A00BE8ACF /* AppInstallationStackViewItem.xib */, ); - path = EnrollmentLoginHelper; + path = BundleInstallationCell; sourceTree = ""; }; - 69B411EA216FA214005B6332 /* JAMFIntegrationHelper */ = { + B98AEFA023EAFA5700A34462 /* Extensions */ = { isa = PBXGroup; children = ( - 69EEA004216F8C050032C2E1 /* main.swift */, - 69EEA011216F95FD0032C2E1 /* JAMFIntegrationHelper-Info.plist */, - 69EEA012216F969A0032C2E1 /* JAMFIntegrationHelper-Launchd.plist */, + 69C56FF22108F17B00766B15 /* NSButton+TextColor.swift */, + 69C56FF42108F1CE00766B15 /* NSView+FadeTransition.swift */, + 6950CD8A211C8B64007C97DF /* NSTextField+Attributes.swift */, + B98AEFA123EAFA6900A34462 /* String-Extensions.swift */, ); - path = JAMFIntegrationHelper; + path = Extensions; sourceTree = ""; }; - 69C56FE4210662D500766B15 /* Controllers */ = { + B99D1E272534637700661954 /* PrivilegedCommandsHelper */ = { + isa = PBXGroup; + children = ( + B99D1E312534639600661954 /* main.swift */, + B99D1E322534639600661954 /* PrivilegedCommandsHelper-Info.plist */, + B99D1E332534639600661954 /* PrivilegedCommandsHelper-Launchd.plist */, + B99D1E342534639600661954 /* PrivilegedCommandsHelper.swift */, + ); + path = PrivilegedCommandsHelper; + sourceTree = ""; + }; + B99F785B2476D00C00893906 /* Configuration */ = { + isa = PBXGroup; + children = ( + B99F78552476CA7600893906 /* ConfigurationErrorViewController.swift */, + B99F78582476CEB700893906 /* ConfigurationErrorViewController.xib */, + ); + path = Configuration; + sourceTree = ""; + }; + B9B5748E243E0F3100114D54 /* Cells */ = { + isa = PBXGroup; + children = ( + B949BABE2451A9010030D077 /* SummaryItemCell */, + B96C63092445BBE000BE8ACF /* BundleInstallationCell */, + B9E3D2B1243344870084BF46 /* SelectableBundleCell */, + ); + path = Cells; + sourceTree = ""; + }; + B9B5748F243E101F00114D54 /* Model */ = { isa = PBXGroup; children = ( - 69A1F5B32102269B004F461A /* AppDelegate.swift */, 69C56FF92108F5D400766B15 /* CrossfadeStoryBoardSegue.swift */, - 69C56FE52106631100766B15 /* MainWindow */, - 696BBB81217BC8800094BE76 /* Phase 0 Registration */, - 696BBB82217BC8B50094BE76 /* Phase 1 Bundle Installation */, - 696BBB85217BC9090094BE76 /* Phase 2 Education */, - 6901E57C210A61BE00EACAF1 /* PopOvers */, + B97DB77F25A70C8700378A3E /* Constants.swift */, + B9BCE51923FBED6600CD0B16 /* Context.swift */, + B9BCE50423FBD80E00CD0B16 /* ContextModel */, ); - path = Controllers; + path = Model; sourceTree = ""; }; - 69C56FE52106631100766B15 /* MainWindow */ = { + B9B57490243E102B00114D54 /* ViewControllers */ = { isa = PBXGroup; children = ( + 69D0DFF1215D607500D0E5B7 /* Main.storyboard */, 69C56FDC210260C700766B15 /* MainViewController.swift */, - 691F680721C4323600700C78 /* MainView.swift */, - 69C56FE22106598700766B15 /* SubViewControllerManagerViewController.swift */, 69C56FE021063DBD00766B15 /* EnrollmentWindowController.swift */, + 69C56FE22106598700766B15 /* SubViewControllerManagerViewController.swift */, + B99F785B2476D00C00893906 /* Configuration */, + B9537F542417A68E00C1D137 /* Registration */, + B9E3D2AA2433428C0084BF46 /* Installation */, ); - path = MainWindow; + path = ViewControllers; sourceTree = ""; }; - 69C56FE9210765B200766B15 /* Views */ = { + B9BCE50423FBD80E00CD0B16 /* ContextModel */ = { isa = PBXGroup; children = ( - 6950CD7A2114F385007C97DF /* BundleItemCell.xib */, - 69D0DFFE2162A31500D0E5B7 /* LinkOutItemCell.xib */, - 6950CD7B2114F385007C97DF /* HeaderViewController.storyboard */, - 69D0DFEF215D605800D0E5B7 /* BundlePopOverViewController.xib */, - 69D0DFF1215D607500D0E5B7 /* Main.storyboard */, - 6950CD792114F385007C97DF /* StackItems.storyboard */, + B9BCE50523FBD80E00CD0B16 /* RegistrationData.swift */, + B9B57491243E10F100114D54 /* RegistrationChoice.swift */, + B9BCE50623FBD80E00CD0B16 /* RegistrationField.swift */, + B9BCE50723FBD80E00CD0B16 /* JamfPoliciesStore.swift */, + B9BCE50823FBD80E00CD0B16 /* EnrollmentDataSet.swift */, + B9128E4D258A2F0500E2FDAA /* PostRegistrationPage.swift */, + B9BCE50923FBD80E00CD0B16 /* InfoLabel.swift */, + B9BCE50A23FBD80E00CD0B16 /* BundleInstallationPage.swift */, + B9BCE50B23FBD80E00CD0B16 /* BundleSelectionPage.swift */, + B9BCE50C23FBD80E00CD0B16 /* RegistrationPage.swift */, + B9BCE50D23FBD80E00CD0B16 /* EnrollmentBundle.swift */, + B9BCE50E23FBD80E00CD0B16 /* PostInstallationPage.swift */, ); - path = Views; + path = ContextModel; sourceTree = ""; }; - 69C56FEA2107661D00766B15 /* Models */ = { + B9C684BD241FC8E800F4A7C5 /* InfoPopOver */ = { isa = PBXGroup; children = ( - 69C56FDE2102628E00766B15 /* MainStoryboardConstants.swift */, - 6901E574210A52F300EACAF1 /* TermDefinition.swift */, - 698263602125C46E0085647A /* Hyperlink.swift */, - 6950CD84211A2D89007C97DF /* ProgressStates.swift */, - 6950CD86211B83CF007C97DF /* BundleInstallButtonVisibility.swift */, - 690ACB32213884DF00F8B1F0 /* DefineBundleInfoPopover.swift */, - 69C292D8213EB6C600639383 /* UpdateAppBundleInstallationUI.swift */, - 6950CD8C211CBA50007C97DF /* Images */, - 69C56FF62108F26C00766B15 /* Extensions */, + B9C684B9241FC8A400F4A7C5 /* InfoPopOverViewController.swift */, + B9C684BA241FC8A400F4A7C5 /* InfoPopOverViewController.xib */, + B9C684BE241FCBC400F4A7C5 /* InfoPopOverStackItem.swift */, + B9C684C0241FCBD300F4A7C5 /* InfoPopOverStackItem.xib */, ); - path = Models; + path = InfoPopOver; sourceTree = ""; }; - 69C56FED2108DE1D00766B15 /* Constants */ = { + B9CEEF5A244DAAC000C81293 /* Controllers */ = { isa = PBXGroup; children = ( - 696BBB72217BADFA0094BE76 /* VC Constants */, - 69C56FDA21023BF300766B15 /* ColorConstants.swift */, - 6950CD64210F67FE007C97DF /* AlertConstants.swift */, - 69C56FFB2108FA9300766B15 /* DestinationIDConstants.swift */, - 69C56FF02108DEE000766B15 /* JAMFConstants.swift */, + B9CEEF5B244DAAD100C81293 /* Installation */, ); - path = Constants; + path = Controllers; sourceTree = ""; }; - 69C56FF62108F26C00766B15 /* Extensions */ = { + B9CEEF5B244DAAD100C81293 /* Installation */ = { isa = PBXGroup; children = ( - 69C56FF22108F17B00766B15 /* NSButton+TextColor.swift */, - 69C56FF42108F1CE00766B15 /* NSView+FadeTransition.swift */, - 6950CD8A211C8B64007C97DF /* NSTextField+Attributes.swift */, - 690ACB36213C5F1900F8B1F0 /* NSView+Rotation.swift */, + B9CEEF5C244DAAEB00C81293 /* InstallationProcessController.swift */, ); - path = Extensions; + path = Installation; + sourceTree = ""; + }; + B9D0EA22242B5B0F00A78DC3 /* ExtendedRegistrationField */ = { + isa = PBXGroup; + children = ( + B9D0EA23242B5B8800A78DC3 /* ExtendedRegistrationField.swift */, + B9D0EA25242B5B9600A78DC3 /* ExtendedRegistrationField.xib */, + B9D0EA27242B611800A78DC3 /* ExtendedRegistrationFieldItem.swift */, + B9D0EA29242B614500A78DC3 /* ExtendedRegistrationFieldItem.xib */, + ); + path = ExtendedRegistrationField; + sourceTree = ""; + }; + B9E3D2AA2433428C0084BF46 /* Installation */ = { + isa = PBXGroup; + children = ( + B9B5748E243E0F3100114D54 /* Cells */, + B9E3D2B6243E02270084BF46 /* BundlePopOver */, + B9E3D2AB243343CD0084BF46 /* BundleSelectionViewController.swift */, + B916473C243F51D000A836C9 /* BundleInstallationViewController.swift */, + B96C630A2445C2E800BE8ACF /* BundleInstallationViewModel.swift */, + B916473E243F51E500A836C9 /* PostInstallationPageViewController.swift */, + B9E3D2AF2433442E0084BF46 /* Installation.storyboard */, + ); + path = Installation; + sourceTree = ""; + }; + B9E3D2B1243344870084BF46 /* SelectableBundleCell */ = { + isa = PBXGroup; + children = ( + B9E3D2B2243344B20084BF46 /* SelectableBundleCell.swift */, + B9E3D2B3243344B20084BF46 /* SelectableBundleCell.xib */, + ); + path = SelectableBundleCell; + sourceTree = ""; + }; + B9E3D2B6243E02270084BF46 /* BundlePopOver */ = { + isa = PBXGroup; + children = ( + 69D0DFEF215D605800D0E5B7 /* BundlePopOverViewController.xib */, + 6958337F213729D700D6B606 /* BundlePopOverViewController.swift */, + 6950CD7A2114F385007C97DF /* BundleItemCell.xib */, + 6922F6AB21273FDD00EB8003 /* BundleItemCell.swift */, + ); + path = BundlePopOver; + sourceTree = ""; + }; + F46A1B612448339F009F2738 /* Mac@IBM EnrollmentTests */ = { + isa = PBXGroup; + children = ( + F46A1B642448339F009F2738 /* Info.plist */, + F433F109245F251800D61A57 /* InfoLabelTests.swift */, + F4F1A81B246018AA0043EDCF /* SummaryPageTests.swift */, + F4F1A81D246020B70043EDCF /* RegistrationDataTests.swift */, + F4F1A81F24602E620043EDCF /* RegistrationFieldTests.swift */, + F4F1A821246039600043EDCF /* RegistrationPageTests.swift */, + F4F1A82324603D4A0043EDCF /* RegistrationChoiceTests.swift */, + F4F1A825246041320043EDCF /* PoliciesTests.swift */, + F4F1A8272460422D0043EDCF /* EnrollmentBundleTests.swift */, + F4F1A829246045800043EDCF /* BundleInstallationPageTests.swift */, + F4F1A82B246047EA0043EDCF /* BundleSelectionPageTests.swift */, + F4F1A82D24604CA50043EDCF /* EnrollmentDataSetTests.swift */, + ); + path = "Mac@IBM EnrollmentTests"; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 69A1F5AF2102269B004F461A /* enrollment */ = { + 69A1F5AF2102269B004F461A /* Mac@IBM Enrollment */ = { isa = PBXNativeTarget; - buildConfigurationList = 69A1F5C02102269C004F461A /* Build configuration list for PBXNativeTarget "enrollment" */; + buildConfigurationList = 69A1F5C02102269C004F461A /* Build configuration list for PBXNativeTarget "Mac@IBM Enrollment" */; buildPhases = ( 69A1F5AC2102269B004F461A /* Sources */, 69A1F5AD2102269B004F461A /* Frameworks */, 69A1F5AE2102269B004F461A /* Resources */, 6922610B21415DFF007419A6 /* Copy Helper */, 6922610921415DC6007419A6 /* Copy LoginItem Helper */, + 69671B5421A35CB70014E3D5 /* CopyFiles */, + B9F02566246D783800FB02FD /* ShellScript */, ); buildRules = ( ); dependencies = ( - 69CC617B2170F9F400DC4BA1 /* PBXTargetDependency */, + B99D1E83253467D400661954 /* PBXTargetDependency */, + ); + name = "Mac@IBM Enrollment"; + packageProductDependencies = ( + B9B2990A23FE8F0500C13F3E /* MoreCodable */, ); - name = enrollment; productName = enrollment; - productReference = 69A1F5B02102269B004F461A /* enrollment.app */; + productReference = 69A1F5B02102269B004F461A /* Mac@IBM Enrollment.app */; productType = "com.apple.product-type.application"; }; 69A1F5D121022FC2004F461A /* EnrollmentLoginHelper */ = { @@ -549,36 +723,54 @@ productReference = 69A1F5D221022FC2004F461A /* EnrollmentLoginHelper.app */; productType = "com.apple.product-type.application"; }; - 69B411E8216FA214005B6332 /* com.ibm.jamf.IntegrationHelper */ = { + B99D1E252534637700661954 /* PrivilegedCommandsHelper */ = { isa = PBXNativeTarget; - buildConfigurationList = 69B411ED216FA214005B6332 /* Build configuration list for PBXNativeTarget "com.ibm.jamf.IntegrationHelper" */; + buildConfigurationList = B99D1E2A2534637700661954 /* Build configuration list for PBXNativeTarget "PrivilegedCommandsHelper" */; buildPhases = ( - 69B411E5216FA214005B6332 /* Sources */, - 69B411E6216FA214005B6332 /* Frameworks */, - 69B411E7216FA214005B6332 /* CopyFiles */, + B99D1E222534637700661954 /* Sources */, + B99D1E232534637700661954 /* Frameworks */, + B99D1E242534637700661954 /* CopyFiles */, ); buildRules = ( ); dependencies = ( ); - name = com.ibm.jamf.IntegrationHelper; - productName = JAMFIntegrationHelper; - productReference = 69B411E9216FA214005B6332 /* com.ibm.jamf.IntegrationHelper */; + name = PrivilegedCommandsHelper; + productName = PrivilegedCommandsHelper; + productReference = B99D1E262534637700661954 /* com.ibm.cio.be.PrivilegedCommandsHelper */; productType = "com.apple.product-type.tool"; }; + F46A1B5F2448339F009F2738 /* Mac@IBM EnrollmentTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = F46A1B692448339F009F2738 /* Build configuration list for PBXNativeTarget "Mac@IBM EnrollmentTests" */; + buildPhases = ( + F46A1B5C2448339F009F2738 /* Sources */, + F46A1B5D2448339F009F2738 /* Frameworks */, + F46A1B5E2448339F009F2738 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + F46A1B662448339F009F2738 /* PBXTargetDependency */, + ); + name = "Mac@IBM EnrollmentTests"; + productName = "Mac@IBM EnrollmentTests"; + productReference = F46A1B602448339F009F2738 /* Mac@IBM EnrollmentTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 69A1F5A82102269B004F461A /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 1000; - LastUpgradeCheck = 0940; + LastSwiftUpdateCheck = 1200; + LastUpgradeCheck = 1200; ORGANIZATIONNAME = IBM; TargetAttributes = { 69A1F5AF2102269B004F461A = { CreatedOnToolsVersion = 9.4.1; - LastSwiftMigration = 1000; + LastSwiftMigration = 1020; SystemCapabilities = { com.apple.ApplicationGroups.Mac = { enabled = 0; @@ -596,15 +788,19 @@ }; 69A1F5D121022FC2004F461A = { CreatedOnToolsVersion = 9.4.1; - LastSwiftMigration = 1000; + LastSwiftMigration = 1020; }; - 69B411E8216FA214005B6332 = { - CreatedOnToolsVersion = 10.0; + B99D1E252534637700661954 = { + CreatedOnToolsVersion = 12.0.1; + }; + F46A1B5F2448339F009F2738 = { + CreatedOnToolsVersion = 11.4.1; + TestTargetID = 69A1F5AF2102269B004F461A; }; }; }; buildConfigurationList = 69A1F5AB2102269B004F461A /* Build configuration list for PBXProject "enrollment" */; - compatibilityVersion = "Xcode 9.3"; + compatibilityVersion = "Xcode 10.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -612,13 +808,17 @@ Base, ); mainGroup = 69A1F5A72102269B004F461A; + packageReferences = ( + B9B2990923FE8F0500C13F3E /* XCRemoteSwiftPackageReference "MoreCodable" */, + ); productRefGroup = 69A1F5B12102269B004F461A /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( - 69A1F5AF2102269B004F461A /* enrollment */, + 69A1F5AF2102269B004F461A /* Mac@IBM Enrollment */, 69A1F5D121022FC2004F461A /* EnrollmentLoginHelper */, - 69B411E8216FA214005B6332 /* com.ibm.jamf.IntegrationHelper */, + F46A1B5F2448339F009F2738 /* Mac@IBM EnrollmentTests */, + B99D1E252534637700661954 /* PrivilegedCommandsHelper */, ); }; /* End PBXProject section */ @@ -628,13 +828,27 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + B9E3D2B02433442E0084BF46 /* Installation.storyboard in Resources */, + B9D0EA26242B5FD500A78DC3 /* ExtendedRegistrationField.xib in Resources */, + B929F794240E4C980037DFE1 /* InfoLabelView.xib in Resources */, + B96C630F2445CF7500BE8ACF /* BundleInstallationStackViewItem.xib in Resources */, + B99F785A2476CEB700893906 /* ConfigurationErrorViewController.xib in Resources */, + 6904AB7021B6E2C600AE31BB /* bee-lowlight.gif in Resources */, + B96C63142448535A00BE8ACF /* AppInstallationStackViewItem.xib in Resources */, + B9D0EA2A242B614500A78DC3 /* ExtendedRegistrationFieldItem.xib in Resources */, + B97598A0241B8D7500956D4B /* Registration.storyboard in Resources */, + B9E3D2B5243344B20084BF46 /* SelectableBundleCell.xib in Resources */, + B949BAC22451A9300030D077 /* SummaryItemCell.xib in Resources */, + B9C684C1241FCBD300F4A7C5 /* InfoPopOverStackItem.xib in Resources */, 69A1F5E121023006004F461A /* EnrollmentLoginHelper.app in Resources */, + B929F790240E4AB20037DFE1 /* CompactRegistrationField.xib in Resources */, 69D0E0002162A31500D0E5B7 /* LinkOutItemCell.xib in Resources */, - 6950CD7E2114F385007C97DF /* HeaderViewController.storyboard in Resources */, 69D0DFF0215D605800D0E5B7 /* BundlePopOverViewController.xib in Resources */, 6950CD7D2114F385007C97DF /* BundleItemCell.xib in Resources */, + 69671B41219B7B100014E3D5 /* bee-blue.gif in Resources */, + B98AEF9D23EAF87E00A34462 /* Localizable.strings in Resources */, + B9C684BC241FC8A400F4A7C5 /* InfoPopOverViewController.xib in Resources */, 69D0DFF2215D607500D0E5B7 /* Main.storyboard in Resources */, - 6950CD7C2114F385007C97DF /* StackItems.storyboard in Resources */, 69A1F5B82102269C004F461A /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -648,76 +862,103 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + F46A1B5E2448339F009F2738 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + B9F02566246D783800FB02FD /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 69A1F5AC2102269B004F461A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 6950CD902121E03B007C97DF /* SetupCompleteButtons.swift in Sources */, - 691F680821C4323600700C78 /* MainView.swift in Sources */, - 690ACB33213884DF00F8B1F0 /* DefineBundleInfoPopover.swift in Sources */, - 696BBB89217BCC4B0094BE76 /* BundleSelectionChildVCConstants.swift in Sources */, - 698263612125C46E0085647A /* Hyperlink.swift in Sources */, - 6901E575210A52F300EACAF1 /* TermDefinition.swift in Sources */, - 6922F6B1212DD0A900EB8003 /* BaseViewController.swift in Sources */, - 6950CD87211B83CF007C97DF /* BundleInstallButtonVisibility.swift in Sources */, - 6991C19D2171064700BA7C56 /* XPCService.swift in Sources */, - 6922F6B3212DD39700EB8003 /* HeaderViewController.swift in Sources */, - 69D0DFEC215C1D3A00D0E5B7 /* IncorrectUserPopover.swift in Sources */, + B9BCE51723FBD80E00CD0B16 /* EnrollmentBundle.swift in Sources */, + B96C630B2445C2E800BE8ACF /* BundleInstallationViewModel.swift in Sources */, 6922F6AC21273FDD00EB8003 /* BundleItemCell.swift in Sources */, + B9BCE51A23FBED6600CD0B16 /* Context.swift in Sources */, 69583381213729D700D6B606 /* BundlePopOverViewController.swift in Sources */, - 690ACB37213C5F1900F8B1F0 /* NSView+Rotation.swift in Sources */, - 69C292D9213EB6C600639383 /* UpdateAppBundleInstallationUI.swift in Sources */, - 69C56FE82106635B00766B15 /* PrimaryRegistrationChildViewController.swift in Sources */, - 696BBB7C217BBDEB0094BE76 /* RegistrationCompleteChildVCConstants.swift in Sources */, - 69C56FDF2102628E00766B15 /* MainStoryboardConstants.swift in Sources */, - 69C56FFC2108FA9300766B15 /* DestinationIDConstants.swift in Sources */, + B9BCE51223FBD80E00CD0B16 /* EnrollmentDataSet.swift in Sources */, + B949BAC42451C9EE0030D077 /* LabelButton.swift in Sources */, + B9BCE51823FBD80E00CD0B16 /* PostInstallationPage.swift in Sources */, + 690ACB37213C5F1900F8B1F0 /* RotableView.swift in Sources */, + B9BCE51323FBD80E00CD0B16 /* InfoLabel.swift in Sources */, + B916473D243F51D000A836C9 /* BundleInstallationViewController.swift in Sources */, 6950CD5D210B9BBE007C97DF /* RemoteProcessProtocol.swift in Sources */, 69A1F5B42102269B004F461A /* AppDelegate.swift in Sources */, + 6904AB7221B81FAC00AE31BB /* AppleInterfaceStyleMonitor.swift in Sources */, + B9BCE51423FBD80E00CD0B16 /* BundleInstallationPage.swift in Sources */, + B99A09DA24489E6E00014BC0 /* LoaderView.swift in Sources */, + B9B2991123FEBF5000C13F3E /* UserDefaultHelper.swift in Sources */, + B9BCE51023FBD80E00CD0B16 /* RegistrationField.swift in Sources */, 6950CD65210F67FE007C97DF /* AlertConstants.swift in Sources */, + B9D0EA28242B611800A78DC3 /* ExtendedRegistrationFieldItem.swift in Sources */, + B929F78F240E4AB20037DFE1 /* CompactRegistrationField.swift in Sources */, + B9C684BB241FC8A400F4A7C5 /* InfoPopOverViewController.swift in Sources */, 69C56FF52108F1CE00766B15 /* NSView+FadeTransition.swift in Sources */, - 6950CD76211375A0007C97DF /* BundleSelectionChildViewController.swift in Sources */, - 6958337C2135D2C900D6B606 /* BundleBProgressStackItemViewController.swift in Sources */, 6950CD6F211228F1007C97DF /* AnimatedGIFImageView.swift in Sources */, - 69C56FEC2107B03500766B15 /* InfoBubble.swift in Sources */, + B9BCE50F23FBD80E00CD0B16 /* RegistrationData.swift in Sources */, 69C56FF32108F17B00766B15 /* NSButton+TextColor.swift in Sources */, 690ACB39213C6BF900F8B1F0 /* Indicators.swift in Sources */, - 6958337E2135D2F200D6B606 /* BundleAProgressStackItemViewController.swift in Sources */, 69C56FE121063DBD00766B15 /* EnrollmentWindowController.swift in Sources */, - 690ACB3B213C8F2E00F8B1F0 /* BundleInstallationChildViewController.swift in Sources */, + B9E3D2AD243343CD0084BF46 /* BundleSelectionViewController.swift in Sources */, 69C56FDB21023BF300766B15 /* ColorConstants.swift in Sources */, - 696BBB87217BCA3D0094BE76 /* SetupCompleteChildVCConstants.swift in Sources */, - 6922F6AF212DB17D00EB8003 /* StackView.swift in Sources */, - 696BBB78217BB6540094BE76 /* SecondaryRegistrationChildVCConstants.swift in Sources */, - 6950CD58210B67EF007C97DF /* Info4Popover.swift in Sources */, - 696BBB84217BC8D40094BE76 /* CircularStatus.swift in Sources */, - 6950CD6B2110D583007C97DF /* OptionPopover.swift in Sources */, - 6901E57B210A5CFC00EACAF1 /* InfoPopOverConstants.swift in Sources */, + B949BAC12451A9300030D077 /* SummaryItemCell.swift in Sources */, + B9BCE51623FBD80E00CD0B16 /* RegistrationPage.swift in Sources */, 696BBB8F217CD57F0094BE76 /* IssueAlertService.swift in Sources */, + B99D1E552534652A00661954 /* PrivilegedHelperController.swift in Sources */, 69C56FFA2108F5D400766B15 /* CrossfadeStoryBoardSegue.swift in Sources */, - 69EE9FF4216D0E780032C2E1 /* JAMFHelperConstants.swift in Sources */, + B9BCE51123FBD80E00CD0B16 /* JamfPoliciesStore.swift in Sources */, + 69F1F23421BFFAA100F2270F /* MainView.swift in Sources */, 69C56FF12108DEE000766B15 /* JAMFConstants.swift in Sources */, - 698263402124B9940085647A /* WebLinkButtons.swift in Sources */, - 6950CD85211A2D89007C97DF /* ProgressStates.swift in Sources */, - 69C292D7213E163B00639383 /* AppBundleConstants.swift in Sources */, - 69D0DFFF2162A31500D0E5B7 /* LinkOutItemCell.swift in Sources */, - 69C56FF82108F48100766B15 /* SecondaryRegistrationChildViewController.swift in Sources */, + B9C684BF241FCBC400F4A7C5 /* InfoPopOverStackItem.swift in Sources */, + B9B57492243E10F100114D54 /* RegistrationChoice.swift in Sources */, + B9D7E231246997DF0083AB50 /* CustomStackView.swift in Sources */, + B9CEEF5D244DAAEB00C81293 /* InstallationProcessController.swift in Sources */, + B9C684C32421548200F4A7C5 /* HorizontalLine.swift in Sources */, + B929F78B240E492F0037DFE1 /* MultipleRegistrationFieldsViewController.swift in Sources */, + B929F792240E4C700037DFE1 /* InfoLabelView.swift in Sources */, 69C56FE32106598700766B15 /* SubViewControllerManagerViewController.swift in Sources */, 6950CD8B211C8B64007C97DF /* NSTextField+Attributes.swift in Sources */, - 696BBB8B217BCE090094BE76 /* BundleInstallationChildVCConstants.swift in Sources */, - 6950CD812118C865007C97DF /* SetupCompleteChildViewController.swift in Sources */, - 696BBB7A217BBC190094BE76 /* AnimatedGIFProgressChildVCConstants.swift in Sources */, - 696BBB76217BAE7B0094BE76 /* PrimaryRegistrationChildVCConstants.swift in Sources */, - 6950CD7321133ED5007C97DF /* RegistrationCompleteChildViewController.swift in Sources */, - 6901E579210A54BD00EACAF1 /* SecurityDescriptionPopover.swift in Sources */, - 6950CD5A210B6F8A007C97DF /* Info2Popover.swift in Sources */, - 6958337A2135D29C00D6B606 /* BundleCProgressStackItemViewController.swift in Sources */, + B916473F243F51E500A836C9 /* PostInstallationPageViewController.swift in Sources */, + B96C63122448531A00BE8ACF /* AppInstallationStackViewItem.swift in Sources */, + B9BCE51523FBD80E00CD0B16 /* BundleSelectionPage.swift in Sources */, + 6950CD7321133ED5007C97DF /* PostRegistrationPageViewController.swift in Sources */, + B949BABD245033C20030D077 /* RotableImageView.swift in Sources */, + B9E3D2B4243344B20084BF46 /* SelectableBundleCell.swift in Sources */, + B97DB78025A70C8700378A3E /* Constants.swift in Sources */, + B9128E4E258A2F0500E2FDAA /* PostRegistrationPage.swift in Sources */, + B98AEFA223EAFA6900A34462 /* String-Extensions.swift in Sources */, + B9537F512411347600C1D137 /* LoadableNib.swift in Sources */, 696BBB8D217CBA9E0094BE76 /* NetworkValidationService.swift in Sources */, - 696BBB0D217664A10094BE76 /* JAMFIntegrationHelper.swift in Sources */, + B9D0EA24242B5B8800A78DC3 /* ExtendedRegistrationField.swift in Sources */, 6950CD7121123283007C97DF /* AnimatedGIFProgressViewController.swift in Sources */, 69C56FDD210260C700766B15 /* MainViewController.swift in Sources */, + B96C630E2445CF7500BE8ACF /* BundleInstallationStackViewItem.swift in Sources */, + B99F78562476CA7600893906 /* ConfigurationErrorViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -729,24 +970,46 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 69B411E5216FA214005B6332 /* Sources */ = { + B99D1E222534637700661954 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B99D1E792534678000661954 /* main.swift in Sources */, + B99D1E362534639600661954 /* PrivilegedCommandsHelper.swift in Sources */, + B99D1E5E2534670D00661954 /* RemoteProcessProtocol.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F46A1B5C2448339F009F2738 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 69B411F2216FA22D005B6332 /* JAMFIntegrationHelper.swift in Sources */, - 69B411F3216FA293005B6332 /* RemoteProcessProtocol.swift in Sources */, - 69B411F0216FA22D005B6332 /* main.swift in Sources */, - 69B411F5216FA29A005B6332 /* JAMFHelperConstants.swift in Sources */, + F4F1A82E24604CA50043EDCF /* EnrollmentDataSetTests.swift in Sources */, + F4F1A82A246045800043EDCF /* BundleInstallationPageTests.swift in Sources */, + F4F1A82C246047EA0043EDCF /* BundleSelectionPageTests.swift in Sources */, + F4F1A822246039600043EDCF /* RegistrationPageTests.swift in Sources */, + F433F10A245F251800D61A57 /* InfoLabelTests.swift in Sources */, + F4F1A82024602E620043EDCF /* RegistrationFieldTests.swift in Sources */, + F4F1A8282460422D0043EDCF /* EnrollmentBundleTests.swift in Sources */, + F4F1A826246041320043EDCF /* PoliciesTests.swift in Sources */, + F4F1A82424603D4A0043EDCF /* RegistrationChoiceTests.swift in Sources */, + F4F1A81C246018AA0043EDCF /* SummaryPageTests.swift in Sources */, + F4F1A81E246020B70043EDCF /* RegistrationDataTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 69CC617B2170F9F400DC4BA1 /* PBXTargetDependency */ = { + B99D1E83253467D400661954 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B99D1E252534637700661954 /* PrivilegedCommandsHelper */; + targetProxy = B99D1E82253467D400661954 /* PBXContainerItemProxy */; + }; + F46A1B662448339F009F2738 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 69B411E8216FA214005B6332 /* com.ibm.jamf.IntegrationHelper */; - targetProxy = 69CC617A2170F9F400DC4BA1 /* PBXContainerItemProxy */; + target = 69A1F5AF2102269B004F461A /* Mac@IBM Enrollment */; + targetProxy = F46A1B652448339F009F2738 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ @@ -759,6 +1022,14 @@ name = MainMenu.xib; sourceTree = ""; }; + B98AEF9F23EAF87E00A34462 /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + B98AEF9E23EAF87E00A34462 /* en */, + ); + name = Localizable.strings; + sourceTree = ""; + }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ @@ -766,6 +1037,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -788,6 +1060,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -813,7 +1086,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -827,6 +1100,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -849,6 +1123,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -868,7 +1143,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SKIP_INSTALL = NO; @@ -882,19 +1157,23 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = enrollment/enrollment.entitlements; - CODE_SIGN_IDENTITY = "Mac Developer"; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; - DEVELOPMENT_TEAM = ""; + CURRENT_PROJECT_VERSION = 76; + DEVELOPMENT_TEAM = Q7W47GFKL3; + ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = enrollment/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 10.14; + MARKETING_VERSION = 2.0.0; PRODUCT_BUNDLE_IDENTIFIER = com.ibm.enrollment; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -903,19 +1182,23 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = enrollment/enrollment.entitlements; - CODE_SIGN_IDENTITY = "Mac Developer"; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; - DEVELOPMENT_TEAM = ""; + CURRENT_PROJECT_VERSION = 76; + DEVELOPMENT_TEAM = Q7W47GFKL3; + ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = enrollment/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 10.14; + MARKETING_VERSION = 2.0.0; PRODUCT_BUNDLE_IDENTIFIER = com.ibm.enrollment; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; }; name = Release; }; @@ -924,20 +1207,22 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = EnrollmentLoginHelper/EnrollmentLoginHelper.entitlements; - CODE_SIGN_IDENTITY = "Mac Developer"; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = Q7W47GFKL3; + ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = EnrollmentLoginHelper/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 10.14; PRODUCT_BUNDLE_IDENTIFIER = com.ibm.EnrollmentLoginHelper; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SKIP_INSTALL = YES; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -946,73 +1231,126 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = EnrollmentLoginHelper/EnrollmentLoginHelper.entitlements; - CODE_SIGN_IDENTITY = "Mac Developer"; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = Q7W47GFKL3; + ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = EnrollmentLoginHelper/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 10.14; PRODUCT_BUNDLE_IDENTIFIER = com.ibm.EnrollmentLoginHelper; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SKIP_INSTALL = YES; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; }; name = Release; }; - 69B411EE216FA214005B6332 /* Debug */ = { + B99D1E2B2534637700661954 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = "Mac Developer"; CODE_SIGN_STYLE = Manual; - DEVELOPMENT_TEAM = ""; - INFOPLIST_FILE = "$(SRCROOT)/JAMFIntegrationHelper/JAMFIntegrationHelper-Info.plist"; - MACOSX_DEPLOYMENT_TARGET = 10.13; + DEVELOPMENT_TEAM = Q7W47GFKL3; + ENABLE_HARDENED_RUNTIME = YES; + INFOPLIST_FILE = "$(SRCROOT)/PrivilegedCommandsHelper/PrivilegedCommandsHelper-Info.plist"; + MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; OTHER_LDFLAGS = ( "-sectcreate", __TEXT, __info_plist, - "\"$(SRCROOT)/JAMFIntegrationHelper/JAMFIntegrationHelper-Info.plist\"", + "\"$(SRCROOT)/PrivilegedCommandsHelper/PrivilegedCommandsHelper-Info.plist\"", "-sectcreate", __TEXT, __launchd_plist, - "\"$(SRCROOT)/JAMFIntegrationHelper/JAMFIntegrationHelper-Launchd.plist\"", + "\"$(SRCROOT)/PrivilegedCommandsHelper/PrivilegedCommandsHelper-Launchd.plist\"", ); - PRODUCT_BUNDLE_IDENTIFIER = com.ibm.jamf.IntegrationHelper; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 4.2; + PRODUCT_BUNDLE_IDENTIFIER = com.ibm.cio.be.PrivilegedCommandsHelper; + PRODUCT_MODULE_NAME = PrivilegedCommandsHelper; + PRODUCT_NAME = com.ibm.cio.be.PrivilegedCommandsHelper; + SWIFT_VERSION = 5.0; }; name = Debug; }; - 69B411EF216FA214005B6332 /* Release */ = { + B99D1E2C2534637700661954 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = "Mac Developer"; CODE_SIGN_STYLE = Manual; - DEVELOPMENT_TEAM = ""; - INFOPLIST_FILE = "$(SRCROOT)/JAMFIntegrationHelper/JAMFIntegrationHelper-Info.plist"; - MACOSX_DEPLOYMENT_TARGET = 10.13; + DEVELOPMENT_TEAM = Q7W47GFKL3; + ENABLE_HARDENED_RUNTIME = YES; + INFOPLIST_FILE = "$(SRCROOT)/PrivilegedCommandsHelper/PrivilegedCommandsHelper-Info.plist"; + MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_FAST_MATH = YES; OTHER_LDFLAGS = ( "-sectcreate", __TEXT, __info_plist, - "\"$(SRCROOT)/JAMFIntegrationHelper/JAMFIntegrationHelper-Info.plist\"", + "\"$(SRCROOT)/PrivilegedCommandsHelper/PrivilegedCommandsHelper-Info.plist\"", "-sectcreate", __TEXT, __launchd_plist, - "\"$(SRCROOT)/JAMFIntegrationHelper/JAMFIntegrationHelper-Launchd.plist\"", + "\"$(SRCROOT)/PrivilegedCommandsHelper/PrivilegedCommandsHelper-Launchd.plist\"", ); - PRODUCT_BUNDLE_IDENTIFIER = com.ibm.jamf.IntegrationHelper; + PRODUCT_BUNDLE_IDENTIFIER = com.ibm.cio.be.PrivilegedCommandsHelper; + PRODUCT_MODULE_NAME = PrivilegedCommandsHelper; + PRODUCT_NAME = com.ibm.cio.be.PrivilegedCommandsHelper; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + F46A1B672448339F009F2738 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_IDENTITY = "Mac Developer"; + CODE_SIGN_STYLE = Manual; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = Q7W47GFKL3; + INFOPLIST_FILE = "Mac@IBM EnrollmentTests/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = "com.ibm.enrollment.Mac-IBM-EnrollmentTests"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Mac@IBM Enrollment.app/Contents/MacOS/Mac@IBM Enrollment"; + }; + name = Debug; + }; + F46A1B682448339F009F2738 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_IDENTITY = "Mac Developer"; + CODE_SIGN_STYLE = Manual; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = Q7W47GFKL3; + INFOPLIST_FILE = "Mac@IBM EnrollmentTests/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = "com.ibm.enrollment.Mac-IBM-EnrollmentTests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Mac@IBM Enrollment.app/Contents/MacOS/Mac@IBM Enrollment"; }; name = Release; }; @@ -1028,7 +1366,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 69A1F5C02102269C004F461A /* Build configuration list for PBXNativeTarget "enrollment" */ = { + 69A1F5C02102269C004F461A /* Build configuration list for PBXNativeTarget "Mac@IBM Enrollment" */ = { isa = XCConfigurationList; buildConfigurations = ( 69A1F5C12102269C004F461A /* Debug */, @@ -1046,16 +1384,44 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 69B411ED216FA214005B6332 /* Build configuration list for PBXNativeTarget "com.ibm.jamf.IntegrationHelper" */ = { + B99D1E2A2534637700661954 /* Build configuration list for PBXNativeTarget "PrivilegedCommandsHelper" */ = { isa = XCConfigurationList; buildConfigurations = ( - 69B411EE216FA214005B6332 /* Debug */, - 69B411EF216FA214005B6332 /* Release */, + B99D1E2B2534637700661954 /* Debug */, + B99D1E2C2534637700661954 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F46A1B692448339F009F2738 /* Build configuration list for PBXNativeTarget "Mac@IBM EnrollmentTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F46A1B672448339F009F2738 /* Debug */, + F46A1B682448339F009F2738 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + B9B2990923FE8F0500C13F3E /* XCRemoteSwiftPackageReference "MoreCodable" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/tattn/MoreCodable.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.2.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + B9B2990A23FE8F0500C13F3E /* MoreCodable */ = { + isa = XCSwiftPackageProductDependency; + package = B9B2990923FE8F0500C13F3E /* XCRemoteSwiftPackageReference "MoreCodable" */; + productName = MoreCodable; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 69A1F5A82102269B004F461A /* Project object */; } diff --git a/enrollment/enrollment.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/enrollment/enrollment.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 75bea4f..919434a 100644 --- a/enrollment/enrollment.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/enrollment/enrollment.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/enrollment/enrollment.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/enrollment/enrollment.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..b537cff --- /dev/null +++ b/enrollment/enrollment.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,16 @@ +{ + "object": { + "pins": [ + { + "package": "MoreCodable", + "repositoryURL": "https://github.com/tattn/MoreCodable.git", + "state": { + "branch": null, + "revision": "360a8fccc5047e6045d24be5069218187a3c6e3a", + "version": "1.2.0" + } + } + ] + }, + "version": 1 +} diff --git a/enrollment/enrollment.xcodeproj/xcshareddata/xcschemes/Mac@IBM Enrollment.xcscheme b/enrollment/enrollment.xcodeproj/xcshareddata/xcschemes/Mac@IBM Enrollment.xcscheme new file mode 100644 index 0000000..ceecfce --- /dev/null +++ b/enrollment/enrollment.xcodeproj/xcshareddata/xcschemes/Mac@IBM Enrollment.xcscheme @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/enrollment/enrollment/AppDelegate.swift b/enrollment/enrollment/AppDelegate.swift new file mode 100644 index 0000000..6c6fc33 --- /dev/null +++ b/enrollment/enrollment/AppDelegate.swift @@ -0,0 +1,48 @@ +// +// AppDelegate.swift +// enrollment +// +// Created by Jay Latman on 7/20/18. +// Copyright © 2018 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Cocoa + +@NSApplicationMain +class AppDelegate: NSObject, NSApplicationDelegate { + let context = Context.main + + func applicationDidFinishLaunching(_ aNotification: Notification) { + // Validate if the jamf binary is present, if so initate an authorization reference + if FileManager.default.fileExists(atPath: JPSPaths.binaryPath) == true { + PrivilegedHelperController.shared.setupHelperController() + } + } + + func applicationWillTerminate(_ aNotification: Notification) { + // Validate if the jamf binary is present, if so release the authorization reference + if FileManager.default.fileExists(atPath: JPSPaths.binaryPath) == true { + PrivilegedHelperController.shared.releaseAuthorizationRef() + } + } + + func application(_ application: NSApplication, open urls: [URL]) { + for url in urls { + guard let components = NSURLComponents(url: url, resolvingAgainstBaseURL: true), + let path = components.path, path == "updateuistatus", + let params = components.queryItems else { + return + } + for param in params { + guard let value = param.value else { continue } + guard let statusRawValue = Int(value), + let newStatus = EnrollmentBundle.InstallationStatus.init(rawValue: statusRawValue) else { + Context.main?.receivedNewMessage(for: param.name, newMessage: value.replacingOccurrences(of: "_", with: " ")) + return + } + Context.main?.receivedNewStatus(for: param.name, newStatus: newStatus) + } + } + } +} diff --git a/enrollment/enrollment/Assets.xcassets/App Icons/Contents.json b/enrollment/enrollment/Assets.xcassets/App Icons/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/enrollment/enrollment/Assets.xcassets/App Icons/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/128x128.png b/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/128x128.png new file mode 100644 index 0000000..342101d Binary files /dev/null and b/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/128x128.png differ diff --git a/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/128x128@2x.png b/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/128x128@2x.png new file mode 100644 index 0000000..8a148ac Binary files /dev/null and b/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/128x128@2x.png differ diff --git a/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/16x16.png b/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/16x16.png new file mode 100644 index 0000000..d13320f Binary files /dev/null and b/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/16x16.png differ diff --git a/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/16x16@2x.png b/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/16x16@2x.png new file mode 100644 index 0000000..10d3a6e Binary files /dev/null and b/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/16x16@2x.png differ diff --git a/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/256x256.png b/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/256x256.png new file mode 100644 index 0000000..6f0f2bd Binary files /dev/null and b/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/256x256.png differ diff --git a/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/256x256@2x.png b/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/256x256@2x.png new file mode 100644 index 0000000..17d246e Binary files /dev/null and b/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/256x256@2x.png differ diff --git a/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/32x32.png b/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/32x32.png new file mode 100644 index 0000000..10d3a6e Binary files /dev/null and b/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/32x32.png differ diff --git a/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/32x32@2x.png b/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/32x32@2x.png new file mode 100644 index 0000000..3dc5646 Binary files /dev/null and b/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/32x32@2x.png differ diff --git a/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/512x512.png b/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/512x512.png new file mode 100644 index 0000000..17d246e Binary files /dev/null and b/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/512x512.png differ diff --git a/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/512x512@2x.png b/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/512x512@2x.png new file mode 100644 index 0000000..5a3e8a3 Binary files /dev/null and b/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/512x512@2x.png differ diff --git a/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/Contents.json b/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/Contents.json index 2db2b1c..2c5bee3 100644 --- a/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/enrollment/enrollment/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,58 +1,68 @@ { "images" : [ { + "filename" : "16x16.png", "idiom" : "mac", - "size" : "16x16", - "scale" : "1x" + "scale" : "1x", + "size" : "16x16" }, { + "filename" : "16x16@2x.png", "idiom" : "mac", - "size" : "16x16", - "scale" : "2x" + "scale" : "2x", + "size" : "16x16" }, { + "filename" : "32x32.png", "idiom" : "mac", - "size" : "32x32", - "scale" : "1x" + "scale" : "1x", + "size" : "32x32" }, { + "filename" : "32x32@2x.png", "idiom" : "mac", - "size" : "32x32", - "scale" : "2x" + "scale" : "2x", + "size" : "32x32" }, { + "filename" : "128x128.png", "idiom" : "mac", - "size" : "128x128", - "scale" : "1x" + "scale" : "1x", + "size" : "128x128" }, { + "filename" : "128x128@2x.png", "idiom" : "mac", - "size" : "128x128", - "scale" : "2x" + "scale" : "2x", + "size" : "128x128" }, { + "filename" : "256x256.png", "idiom" : "mac", - "size" : "256x256", - "scale" : "1x" + "scale" : "1x", + "size" : "256x256" }, { + "filename" : "256x256@2x.png", "idiom" : "mac", - "size" : "256x256", - "scale" : "2x" + "scale" : "2x", + "size" : "256x256" }, { + "filename" : "512x512.png", "idiom" : "mac", - "size" : "512x512", - "scale" : "1x" + "scale" : "1x", + "size" : "512x512" }, { + "filename" : "512x512@2x.png", "idiom" : "mac", - "size" : "512x512", - "scale" : "2x" + "scale" : "2x", + "size" : "512x512" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/enrollment/enrollment/Assets.xcassets/Contents.json b/enrollment/enrollment/Assets.xcassets/Contents.json index da4a164..73c0059 100644 --- a/enrollment/enrollment/Assets.xcassets/Contents.json +++ b/enrollment/enrollment/Assets.xcassets/Contents.json @@ -1,6 +1,6 @@ { "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/enrollment/enrollment/Assets.xcassets/Generic Assets/Contents.json b/enrollment/enrollment/Assets.xcassets/Generic Assets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/enrollment/enrollment/Assets.xcassets/Generic Assets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/enrollment/enrollment/Assets.xcassets/Generic Assets/left-panel.imageset/Contents.json b/enrollment/enrollment/Assets.xcassets/Generic Assets/left-panel.imageset/Contents.json new file mode 100644 index 0000000..d81bfae --- /dev/null +++ b/enrollment/enrollment/Assets.xcassets/Generic Assets/left-panel.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "filename" : "Light - 2.pdf", + "idiom" : "mac" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "Dark - 2.pdf", + "idiom" : "mac" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/enrollment/enrollment/Assets.xcassets/Generic Assets/left-panel.imageset/Dark - 2.pdf b/enrollment/enrollment/Assets.xcassets/Generic Assets/left-panel.imageset/Dark - 2.pdf new file mode 100644 index 0000000..787dcd6 Binary files /dev/null and b/enrollment/enrollment/Assets.xcassets/Generic Assets/left-panel.imageset/Dark - 2.pdf differ diff --git a/enrollment/enrollment/Assets.xcassets/Generic Assets/left-panel.imageset/Light - 2.pdf b/enrollment/enrollment/Assets.xcassets/Generic Assets/left-panel.imageset/Light - 2.pdf new file mode 100644 index 0000000..b094bb2 Binary files /dev/null and b/enrollment/enrollment/Assets.xcassets/Generic Assets/left-panel.imageset/Light - 2.pdf differ diff --git a/enrollment/enrollment/Assets.xcassets/Generic Icons/Contents.json b/enrollment/enrollment/Assets.xcassets/Generic Icons/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/enrollment/enrollment/Assets.xcassets/Generic Icons/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/enrollment/enrollment/Assets.xcassets/Generic Icons/IBMLogo.imageset/Contents.json b/enrollment/enrollment/Assets.xcassets/Generic Icons/IBMLogo.imageset/Contents.json new file mode 100644 index 0000000..dc2dc9f --- /dev/null +++ b/enrollment/enrollment/Assets.xcassets/Generic Icons/IBMLogo.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "filename" : "IBMblue.pdf", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "IBMwhite.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/enrollment/enrollment/Assets.xcassets/Generic Icons/IBMLogo.imageset/IBMblue.pdf b/enrollment/enrollment/Assets.xcassets/Generic Icons/IBMLogo.imageset/IBMblue.pdf new file mode 100644 index 0000000..b6b924c Binary files /dev/null and b/enrollment/enrollment/Assets.xcassets/Generic Icons/IBMLogo.imageset/IBMblue.pdf differ diff --git a/enrollment/enrollment/Assets.xcassets/Generic Icons/IBMLogo.imageset/IBMwhite.pdf b/enrollment/enrollment/Assets.xcassets/Generic Icons/IBMLogo.imageset/IBMwhite.pdf new file mode 100644 index 0000000..a4bc2ee Binary files /dev/null and b/enrollment/enrollment/Assets.xcassets/Generic Icons/IBMLogo.imageset/IBMwhite.pdf differ diff --git a/enrollment/enrollment/Assets.xcassets/generic-app-icon.imageset/Contents.json b/enrollment/enrollment/Assets.xcassets/Generic Icons/generic-app-icon.imageset/Contents.json similarity index 88% rename from enrollment/enrollment/Assets.xcassets/generic-app-icon.imageset/Contents.json rename to enrollment/enrollment/Assets.xcassets/Generic Icons/generic-app-icon.imageset/Contents.json index 3d11d39..8f58f27 100644 --- a/enrollment/enrollment/Assets.xcassets/generic-app-icon.imageset/Contents.json +++ b/enrollment/enrollment/Assets.xcassets/Generic Icons/generic-app-icon.imageset/Contents.json @@ -1,23 +1,23 @@ { "images" : [ { - "idiom" : "universal", "filename" : "generic.png", + "idiom" : "universal", "scale" : "1x" }, { - "idiom" : "universal", "filename" : "generic@2x.png", + "idiom" : "universal", "scale" : "2x" }, { - "idiom" : "universal", "filename" : "generic@3x.png", + "idiom" : "universal", "scale" : "3x" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/enrollment/enrollment/Assets.xcassets/Generic Icons/generic-app-icon.imageset/generic.png b/enrollment/enrollment/Assets.xcassets/Generic Icons/generic-app-icon.imageset/generic.png new file mode 100644 index 0000000..1cbe630 Binary files /dev/null and b/enrollment/enrollment/Assets.xcassets/Generic Icons/generic-app-icon.imageset/generic.png differ diff --git a/enrollment/enrollment/Assets.xcassets/Generic Icons/generic-app-icon.imageset/generic@2x.png b/enrollment/enrollment/Assets.xcassets/Generic Icons/generic-app-icon.imageset/generic@2x.png new file mode 100644 index 0000000..1cbe630 Binary files /dev/null and b/enrollment/enrollment/Assets.xcassets/Generic Icons/generic-app-icon.imageset/generic@2x.png differ diff --git a/enrollment/enrollment/Assets.xcassets/Generic Icons/generic-app-icon.imageset/generic@3x.png b/enrollment/enrollment/Assets.xcassets/Generic Icons/generic-app-icon.imageset/generic@3x.png new file mode 100644 index 0000000..1cbe630 Binary files /dev/null and b/enrollment/enrollment/Assets.xcassets/Generic Icons/generic-app-icon.imageset/generic@3x.png differ diff --git a/enrollment/enrollment/Assets.xcassets/Generic Icons/infoBubble.imageset/Contents.json b/enrollment/enrollment/Assets.xcassets/Generic Icons/infoBubble.imageset/Contents.json new file mode 100644 index 0000000..5140449 --- /dev/null +++ b/enrollment/enrollment/Assets.xcassets/Generic Icons/infoBubble.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "infoBubble 2.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/enrollment/enrollment/Assets.xcassets/Generic Icons/infoBubble.imageset/infoBubble 2.pdf b/enrollment/enrollment/Assets.xcassets/Generic Icons/infoBubble.imageset/infoBubble 2.pdf new file mode 100644 index 0000000..f545fa5 Binary files /dev/null and b/enrollment/enrollment/Assets.xcassets/Generic Icons/infoBubble.imageset/infoBubble 2.pdf differ diff --git a/enrollment/enrollment/Assets.xcassets/Installation Status Icons/Contents.json b/enrollment/enrollment/Assets.xcassets/Installation Status Icons/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/enrollment/enrollment/Assets.xcassets/Installation Status Icons/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/enrollment/enrollment/Assets.xcassets/Installation Status Icons/failure.imageset/Contents.json b/enrollment/enrollment/Assets.xcassets/Installation Status Icons/failure.imageset/Contents.json new file mode 100644 index 0000000..49ca4fb --- /dev/null +++ b/enrollment/enrollment/Assets.xcassets/Installation Status Icons/failure.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "failure.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/enrollment/enrollment/Assets.xcassets/Installation Status Icons/failure.imageset/failure.pdf b/enrollment/enrollment/Assets.xcassets/Installation Status Icons/failure.imageset/failure.pdf new file mode 100644 index 0000000..5ed738b Binary files /dev/null and b/enrollment/enrollment/Assets.xcassets/Installation Status Icons/failure.imageset/failure.pdf differ diff --git a/enrollment/enrollment/Assets.xcassets/Installation Status Icons/inProgress.imageset/Contents.json b/enrollment/enrollment/Assets.xcassets/Installation Status Icons/inProgress.imageset/Contents.json new file mode 100644 index 0000000..8283cfe --- /dev/null +++ b/enrollment/enrollment/Assets.xcassets/Installation Status Icons/inProgress.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "inProgress.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/enrollment/enrollment/Assets.xcassets/Installation Status Icons/inProgress.imageset/inProgress.pdf b/enrollment/enrollment/Assets.xcassets/Installation Status Icons/inProgress.imageset/inProgress.pdf new file mode 100644 index 0000000..5bffca9 Binary files /dev/null and b/enrollment/enrollment/Assets.xcassets/Installation Status Icons/inProgress.imageset/inProgress.pdf differ diff --git a/enrollment/enrollment/Assets.xcassets/Installation Status Icons/inQueue.imageset/Contents.json b/enrollment/enrollment/Assets.xcassets/Installation Status Icons/inQueue.imageset/Contents.json new file mode 100644 index 0000000..342055b --- /dev/null +++ b/enrollment/enrollment/Assets.xcassets/Installation Status Icons/inQueue.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "inQueue.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/enrollment/enrollment/Assets.xcassets/Installation Status Icons/inQueue.imageset/inQueue.pdf b/enrollment/enrollment/Assets.xcassets/Installation Status Icons/inQueue.imageset/inQueue.pdf new file mode 100644 index 0000000..5a5ec77 Binary files /dev/null and b/enrollment/enrollment/Assets.xcassets/Installation Status Icons/inQueue.imageset/inQueue.pdf differ diff --git a/enrollment/enrollment/Assets.xcassets/Installation Status Icons/partial.imageset/Contents.json b/enrollment/enrollment/Assets.xcassets/Installation Status Icons/partial.imageset/Contents.json new file mode 100644 index 0000000..04eb76b --- /dev/null +++ b/enrollment/enrollment/Assets.xcassets/Installation Status Icons/partial.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "partial.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/enrollment/enrollment/Assets.xcassets/Installation Status Icons/partial.imageset/partial.pdf b/enrollment/enrollment/Assets.xcassets/Installation Status Icons/partial.imageset/partial.pdf new file mode 100644 index 0000000..9e99766 Binary files /dev/null and b/enrollment/enrollment/Assets.xcassets/Installation Status Icons/partial.imageset/partial.pdf differ diff --git a/enrollment/enrollment/Assets.xcassets/Installation Status Icons/success.imageset/Contents.json b/enrollment/enrollment/Assets.xcassets/Installation Status Icons/success.imageset/Contents.json new file mode 100644 index 0000000..4288168 --- /dev/null +++ b/enrollment/enrollment/Assets.xcassets/Installation Status Icons/success.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "success.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/enrollment/enrollment/Assets.xcassets/Installation Status Icons/success.imageset/success.pdf b/enrollment/enrollment/Assets.xcassets/Installation Status Icons/success.imageset/success.pdf new file mode 100644 index 0000000..37ca7e8 Binary files /dev/null and b/enrollment/enrollment/Assets.xcassets/Installation Status Icons/success.imageset/success.pdf differ diff --git a/enrollment/enrollment/Assets.xcassets/colors/view_colors/popover_bg_color.colorset/Contents.json b/enrollment/enrollment/Assets.xcassets/colors/view_colors/popover_bg_color.colorset/Contents.json index 89dd968..e7c3f27 100644 --- a/enrollment/enrollment/Assets.xcassets/colors/view_colors/popover_bg_color.colorset/Contents.json +++ b/enrollment/enrollment/Assets.xcassets/colors/view_colors/popover_bg_color.colorset/Contents.json @@ -11,7 +11,7 @@ "components" : { "red" : "0.965", "alpha" : "0.000", - "blue" : "0.961", + "blue" : "0.965", "green" : "0.965" } } diff --git a/enrollment/enrollment/Assets.xcassets/generic-app-icon.imageset/generic.png b/enrollment/enrollment/Assets.xcassets/generic-app-icon.imageset/generic.png deleted file mode 100644 index 289ff9f..0000000 Binary files a/enrollment/enrollment/Assets.xcassets/generic-app-icon.imageset/generic.png and /dev/null differ diff --git a/enrollment/enrollment/Assets.xcassets/generic-app-icon.imageset/generic@2x.png b/enrollment/enrollment/Assets.xcassets/generic-app-icon.imageset/generic@2x.png deleted file mode 100644 index 289ff9f..0000000 Binary files a/enrollment/enrollment/Assets.xcassets/generic-app-icon.imageset/generic@2x.png and /dev/null differ diff --git a/enrollment/enrollment/Assets.xcassets/generic-app-icon.imageset/generic@3x.png b/enrollment/enrollment/Assets.xcassets/generic-app-icon.imageset/generic@3x.png deleted file mode 100644 index 289ff9f..0000000 Binary files a/enrollment/enrollment/Assets.xcassets/generic-app-icon.imageset/generic@3x.png and /dev/null differ diff --git a/enrollment/enrollment/Assets.xcassets/left-panel.imageset/Contents.json b/enrollment/enrollment/Assets.xcassets/left-panel.imageset/Contents.json deleted file mode 100644 index 129709e..0000000 --- a/enrollment/enrollment/Assets.xcassets/left-panel.imageset/Contents.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "images" : [ - { - "idiom" : "mac", - "filename" : "left-panel-1x.png", - "scale" : "1x" - }, - { - "idiom" : "mac", - "filename" : "left-panel-2x.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/enrollment/enrollment/Assets.xcassets/left-panel.imageset/left-panel-1x.png b/enrollment/enrollment/Assets.xcassets/left-panel.imageset/left-panel-1x.png deleted file mode 100644 index 695dd60..0000000 Binary files a/enrollment/enrollment/Assets.xcassets/left-panel.imageset/left-panel-1x.png and /dev/null differ diff --git a/enrollment/enrollment/Assets.xcassets/left-panel.imageset/left-panel-2x.png b/enrollment/enrollment/Assets.xcassets/left-panel.imageset/left-panel-2x.png deleted file mode 100644 index 04e713a..0000000 Binary files a/enrollment/enrollment/Assets.xcassets/left-panel.imageset/left-panel-2x.png and /dev/null differ diff --git a/enrollment/enrollment/Constants/AlertConstants.swift b/enrollment/enrollment/Constants/AlertConstants.swift deleted file mode 100644 index 8309e4e..0000000 --- a/enrollment/enrollment/Constants/AlertConstants.swift +++ /dev/null @@ -1,152 +0,0 @@ -// -// AlertConstants.swift -// enrollment -// -// Created by Jay Latman on 7/30/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -/** - Structure definition containing reference assignments of stored values for alert messaging. - - child structs: - - RegistrationCancelAlert, BundleSelectionWarning, BundleInstallationWarning, FailureToLaunch, NetworkWarnings, RegistrationComplete - */ -struct AlertText { - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - String values used for displaying alert sheet to user upon cancelling / opting out of enrollment. - - • header : header message string - - • message : body message string - */ - struct RegistrationCancelAlert{ - static let header: String = "Are you sure you want to quit the enrollment process?" - static let message: String = "Cancelling now will undo all security settings and remove this computer from the management." - } - - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - String values used for displaying alert sheet to user when attempting to install bundles where the estimated download time exceeds the `estimatedDownloadTimeInSecondsThreshold`. - - • header : header message string - - • message : body message string - */ - struct BundleSelectionWarning { - static let header: String = "Are you sure you want to proceed?" - static let message: String = "It looks like your network speeds are slow at this time. We recommend installing fewer bundles." - } - - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - String value used for displaying alert string to user if any bundle app installations experienced failures. - - • message : string value to be displayed below the header string of the bundle installation view - */ - struct BundleInstallationWarning { - static let message: String = "We had trouble installing some applications - use Self Service to install them later." - } - - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - String values used for displaying alert window to user in the event that the application is launched and can not locate the jamf binary. - - • header : header message string - - • message : body message string - */ - struct FailureToLaunch { - static let header: String = "This application requires device management." - static let message: String = "Please enroll this device." - } - - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - String values used for displaying alert sheet to user if the internal or external network is not available. - - child structs: - - External, Internal - */ - struct NetworkValidationMessaging { - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - String values used for displaying alert sheet to user should the public network not be reachable or the JPS is not available. - • `network`: network alert string - - • `jps`: jps unreachable alert string - */ - struct External { - static let network: String = "You are not connected to the Internet. Please make sure that your Mac is connected to a network with Internet access before continuing." - static let jps: String = "Self Service is not available at this time. Please try again later." - } - - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - String values used for displaying alert sheet to user should the intranet not be reachable. - - • url : string value of an internal URL for validation - - • warning : message displayed to the user - */ - struct Internal { - static let url = "" - static let warning = """ - - You must connect to the intranet to proceed. - """ - } - } -} - -/** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - Time in seconds limit for retaining `BundleInstallationWarning`. - - • estimatedDownloadTimeInSecondsThreshold : Double - */ -struct CalculationThresholds { - static let estimatedDownloadTimeInSecondsThreshold = 3000.0 -} - - -/** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - String values used for user interaction button labels. - - • yes - - • no - - • quit - - Child structs: - InteractionLogText - */ -struct UserInteractionButtons { - static let yes = "Yes" - static let no = "No" - static let quit = "Quit" - - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - */ - struct InteractionLogText { - static let removeFrameworkCancelledLog = "Remove Framework action cancelled" - } -} diff --git a/enrollment/enrollment/Constants/DestinationIDConstants.swift b/enrollment/enrollment/Constants/DestinationIDConstants.swift deleted file mode 100644 index 78b3dab..0000000 --- a/enrollment/enrollment/Constants/DestinationIDConstants.swift +++ /dev/null @@ -1,80 +0,0 @@ -// -// DestinationIDConstants.swift -// enrollment -// -// Created by Jay Latman on 7/25/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Foundation - -/** - Structure definition containing reference to Storyboard Segue Identifiers found in interface builder and used throughout the navigation. - - child structs: - - ReturnTo, ForwardTo, SkipTo, Popover - */ -struct SegueDestinationID { - struct ReturnTo { - static let primaryRegistrationChildViewController = "ReturnToPrimaryRegistrationChildViewControllerSegue" - static let setupCompleteChildViewControllerSegue = "ReturnToSetupCompleteChildViewControllerSegue" - } - - struct ForwardTo { - static let secondaryRegistrationChildViewController = "ForwardToSecondaryRegistrationChildViewControllerSegue" - static let progressRegistrationChildViewController = "ForwardToProgressChildViewControllerSegue" - static let registrationCompleteChildViewControllter = "ForwardToRegistrationCompleteChildViewControllerSegue" - static let bundleInstallationChildViewController = "ForwardToBundleInstallationChildViewControllerSegue" - static let setupCompleteChildViewController = "ForwardToSetupCompleteChildViewControllerSegue" - } - - struct SkipTo { - static let setupCompleteChildViewConroller = "SkipToSetupCompleteChildViewControllerSegue" - } - - struct Popover { - struct PrimaryRegisrationChildViewController { - static let securityDescription = "PopoverSegueSecurityDescription" - static let info4 = "PopoverSegueInfo4" - static let info2 = "PopoverSegueInfo2" - } - struct SecondaryRegistrationChildViewController { - static let optionDescriptions = "PopoverSegueOptionDescription" - } - struct BundleSelectionChildViewController { - static let essentials = "PopoverSegueEssentialsBundle" - static let productivity = "PopoverSegueProductivityBundle" - } - } -} - -/** - Structure definition containing reference to Storyboard Identifiers used for key phases referenced in `SubViewControllerManagerViewController` . - - • primaryRegistrationChildViewController : First registration view displayed on first launch - - • bundleSelectionChildViewController : View displayed after restart allowing users to select and install software - - • setupCompleteChildViewController : Final view that the user can choose to return to well after the first run - - child structs: - - Keys - */ -struct StartingPointID { - static let setupCompleteChildViewController = "SetupCompleteChildViewController" - static let bundleSelectionChildViewController = "BundleSelectionChildViewController" - static let primaryRegistrationChildViewController = "PrimaryRegistrationChildViewController" - - /** - • `phase` : [Key] String interpreted integer corresponding to phase of enrollment - # 0 = Registration - # 1 = Bundle Installation - # 2 = Setup Complete - */ - struct Keys { - static let phase = "phase" - } -} diff --git a/enrollment/enrollment/Constants/JAMFConstants.swift b/enrollment/enrollment/Constants/JAMFConstants.swift deleted file mode 100644 index 9dbe8ae..0000000 --- a/enrollment/enrollment/Constants/JAMFConstants.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// JAMFConstants.swift -// enrollment -// -// Created by Jay Latman on 7/25/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Foundation - -/** - Structure containing stored property strings pertaining to paths used by the jamf binary process - - • binaryPath : path location for the jamf binary - - child structs: - - HealthCheckURLs - */ -struct JPSPaths { - static let binaryPath = "/usr/local/jamf/bin/jamf" - - /** - Structure containing the stored property strings for the health check URL's used for testing network reachability to the Jamf infrastructure. Setting the environment in the application's user level property list allows you to override the healthCheck URL for testing. If your organization only has one environment, fill in the healthCheckURL for the Prod struct. - */ - struct HealthCheckURLs { - struct Eng { - static let healthCheckURL = "" - } - struct QA { - static let healthCheckURL = "" - } - struct Prod { - static let healthCheckURL = "" - } - } -} - -/** - Structure containing the Jamf event policy trigger strings for execution. - - The enrollment app uses Jamf policy events issued through the XPC communication to the Jamf Integration Helper to perform actions against the jamf binary. - - - softwareInstall : policy event trigger string that is used on load of the `BundleInstallationChildViewController` to start the process of bundle installation. The script attributed to this policy would analyze the selections made by the customer and stored in the application's user level property list, running the policy chain to install software and update the progress using the same user level property list. - - - removeFramework : to comply with GDPR, we offer the option for customers to opt out of the service. This policy event trigger string is used at the `PrimaryRegistrationChildViewController` to execute a policy which would remove the framework and any other components we have installed. - */ -struct JAMFPolicyEventID { - static let softwareInstall = "" - static let removeFramework = "" -} diff --git a/enrollment/enrollment/Constants/VC Constants/Phase 0 Regisistration/AnimatedGIFProgressChildVCConstants.swift b/enrollment/enrollment/Constants/VC Constants/Phase 0 Regisistration/AnimatedGIFProgressChildVCConstants.swift deleted file mode 100644 index b526391..0000000 --- a/enrollment/enrollment/Constants/VC Constants/Phase 0 Regisistration/AnimatedGIFProgressChildVCConstants.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// AnimatedGIFProgressChildVCConstants.swift -// enrollment -// -// Created by Jay Latman on 10/20/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Foundation - -struct AnimatedGIFProgressChildVC_Constants { - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - Note: these are text string values to be displayed while the AnimatedGIFProgressView is active. - - • `stateOne`: first text string to be displayed in timed sequence - - • `stateTwo`: second text string to be displayed in timed sequence - */ - struct RegistrationProgress { - static let stateOne = "Testing network speed" - static let stateTwo = "Completing enrollment" - } - - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - Note: GIF file to be displayed in the center of of the AnimatedGIFProgressView. - - • `fileName`: reference for gif file living in the asset catalog - */ - struct AnimatedProgressGIF { - static let fileName = "" - } -} diff --git a/enrollment/enrollment/Constants/VC Constants/Phase 0 Regisistration/InfoPopOverConstants.swift b/enrollment/enrollment/Constants/VC Constants/Phase 0 Regisistration/InfoPopOverConstants.swift deleted file mode 100644 index 0d70e02..0000000 --- a/enrollment/enrollment/Constants/VC Constants/Phase 0 Regisistration/InfoPopOverConstants.swift +++ /dev/null @@ -1,86 +0,0 @@ -// -// InfoPopOverConstants.swift -// enrollment -// -// Created by Jay Latman on 7/26/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -struct InfoPopoverConstants { - struct PrimaryRegistrationVC { - - /** - String value attributed to the info popover on the `PrimaryRegistrationChildViewController` detailing what to do if the username is incorrect - */ - static let incorrectUserMessage = "" - - - /** - Term / Definition combinations to be displayed in the Security Descriptions Popover - - Notes: - - `SegueID : PopoverSegueSecurityDescription` - */ - struct SecuritySettings { - static let object1 = TermDefinition(term: "Firewall", definition: State.init().enabled) - static let object2 = TermDefinition(term: "Stealth Mode", definition: State.init().enabled) - static let object3 = TermDefinition(term: "Guest User Account", definition: State.init().disabled) - static let object4 = TermDefinition(term: "FileVault Disk Encryption", definition: State.init().enabled) - static let object5 = TermDefinition(term: "Initial macOS Password Change", definition: State.init().required) - static let object6 = TermDefinition(term: "ScreenSaver Password", definition: State.init().required) - static let object7 = TermDefinition(term: "ScreenSaver Start Time", definition: "30 minutes of inactivity") - } - - /** - Term / Definition combinations to be displayed for PopupButton 2 Info - - Notes: - - `SegueID : PopoverSegueInfo2` - */ - struct Info2 { - static let object1 = TermDefinition(term: "Type 1", definition: "") - static let object2 = TermDefinition(term: "Type 2", definition: "") - static let object3 = TermDefinition(term: "Type 3", definition: "") - static let object4 = TermDefinition(term: "Type 4", definition: "") - static let object5 = TermDefinition(term: "Type 5", definition: "") - static let object6 = TermDefinition(term: "Type 6", definition: "") - } - - /** - Term / Definition combinations to be displayed for PopupButton 4 Info - - Notes: - - `SegueID : PopoverSegueInfo4` - */ - struct Info4 { - static let object1 = TermDefinition(term: "Type A", definition: "") - static let object2 = TermDefinition(term: "Type B", definition: "") - static let object3 = TermDefinition(term: "Type C", definition: "") - } - } - - struct SecondaryRegistrationVC { - /** - Term / Definition combinations to be displayed for Option checkbox buttons - - Notes: - - `SegueID : PopoverSegueOptionDescription` - */ - struct Option { - static let object1 = TermDefinition(term: "Option 1", definition: "") - static let object2 = TermDefinition(term: "Option 2", definition: "") - static let object3 = TermDefinition(term: "Option 3", definition: "") - static let object4 = TermDefinition(term: "Option 4", definition: "") - static let object5 = TermDefinition(term: "Option 5", definition: "") - static let object6 = TermDefinition(term: "Option 6", definition: "") - static let none = TermDefinition(term: "None of the above", definition: "") - } - } -} diff --git a/enrollment/enrollment/Constants/VC Constants/Phase 0 Regisistration/PrimaryRegistrationChildVCConstants.swift b/enrollment/enrollment/Constants/VC Constants/Phase 0 Regisistration/PrimaryRegistrationChildVCConstants.swift deleted file mode 100644 index 7dfac3e..0000000 --- a/enrollment/enrollment/Constants/VC Constants/Phase 0 Regisistration/PrimaryRegistrationChildVCConstants.swift +++ /dev/null @@ -1,153 +0,0 @@ -// -// PrimaryRegistrationChildVCConstants.swift -// enrollment -// -// Created by Jay Latman on 10/20/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Foundation - - -struct PrimaryRegistrationChildVC_Constants { - - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - Note: - • [Keys] `hrFirstName` : property list key reference for retrieving the first name of the user to be displayed on the - primary registration view. This value is recorded based on API request during enrollment action and stored to be available on launch. - */ - struct Keys { - static let hrFirstName = "hrFirstName" - } - - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - Note: Child structs: - - Headers, PopupBoxes - */ - struct PopupButtons { - struct Headers { - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - Note: string values associated with header labels for popup buttons - - • `popup1Header` - - • `popup2Header` - - • `popup3Header` - - • `popup4Header` - */ - struct LabelText { - static let popup1Header = "Region" - static let popup2Header = "popup2" - static let popup3Header = "popup3" - static let popup4Header = "popup4" - } - } - - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - Note: Child structs: - - Info1, Info2, Info3, Info4 - */ - struct PopupBoxes { - - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - Note: Popup button contents to be both displayed to the user as well as recorded for business purposes - - • `list` : Array of values to be displayed as items in the popup button - - • `codes` : Corresponding coded values to `list` items - - • `selectedType` : value used for calculating whether all popbutton's have had an item selected - - • [Keys] `key` : property list key for storing the associated `codes` value from selection - */ - struct Info1 { - static let list = ["","USA","Canada","EMEA (Europe, Middle East, Africa)","LA (Latin America)","AP (Asia Pacific)"] - static let codes = ["","US","Canada","EMEA","LA","AP"] - static let selectedType = "info1" - static let key = "infoChoice1" - } - - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - Note: Popup button contents to be both displayed to the user as well as recorded for business purposes - - • `list` : Array of values to be displayed as items in the popup button - - • `codes` : Corresponding coded values to `list` items - - • `selectedType` : value used for calculating whether all popbutton's have had an item selected - - • [Keys] `key` : property list key for storing the associated `codes` value from selection - */ - struct Info2 { - static let list = ["","1","2","3","4","5","6"] - static let codes = ["","1","2","3","4","5","6"] - static let selectedType = "info2" - static let key = "infoChoice2" - } - - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - Note: Popup button contents to be both displayed to the user as well as recorded for business purposes - - • `list` : Array of values to be displayed as items in the popup button - - • `codes` : Corresponding coded values to `list` items - - • `selectedType` : value used for calculating whether all popbutton's have had an item selected - - • [Keys] `key` : property list key for storing the associated `codes` value from selection - */ - struct Info3 { - static let list = ["","1","2","3","4","5"] - static let codes = ["","1","2","3","4","5"] - static let selectedType = "info3" - static let key = "infoChoice3" - } - - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - Note: Popup button contents to be both displayed to the user as well as recorded for business purposes - - • `list` : Array of values to be displayed as items in the popup button - - • `codes` : Corresponding coded values to `list` items - - • `selectedType` : value used for calculating whether all popbutton's have had an item selected - - • [Keys] `key` : property list key for storing the associated `codes` value from selection - */ - struct Info4 { - static let list = ["","A","B","C"] - static let codes = ["","A","B","C"] - static let selectedType = "info4" - static let key = "infoChoice4" - } - } - } - - /** - Text to be displayed at the bottom portion of the screen. - - _example_: A security compliance message - */ - static let additionalPolicyMessage = "Organization security policies will automatically be applied." -} - - - - - - - - diff --git a/enrollment/enrollment/Constants/VC Constants/Phase 0 Regisistration/RegistrationCompleteChildVCConstants.swift b/enrollment/enrollment/Constants/VC Constants/Phase 0 Regisistration/RegistrationCompleteChildVCConstants.swift deleted file mode 100644 index a8a66f8..0000000 --- a/enrollment/enrollment/Constants/VC Constants/Phase 0 Regisistration/RegistrationCompleteChildVCConstants.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// RegistrationCompleteChildVCConstants.swift -// enrollment -// -// Created by Jay Latman on 10/20/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Foundation - -struct RegistrationCompleteChildVC_Constants { - static let header = "Registration complete" - static let subheader = "Let's get your Mac set up!" - static let initialCountdownValue = 5 - static let countdownMessage = "Your Mac will be restarted automatically in \(RegistrationCompleteChildVC_Constants.initialCountdownValue) minutes to continue the setup process." - static let instructionalMessage = "After your next log in, you'll be prompted for a new macOS login password and to enable FileVault disk encryption." - - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - Note: these are text string values to be displayed in the event of restart command failure. - - • `message`: string value to be displayed to the user - - • `comment`: string value to be potentially recorded by the app - */ - struct FailureToRestart { - static let message = "Your computer could not be restarted" - static let comment = "Restart failure alert" - } -} diff --git a/enrollment/enrollment/Constants/VC Constants/Phase 0 Regisistration/SecondaryRegistrationChildVCConstants.swift b/enrollment/enrollment/Constants/VC Constants/Phase 0 Regisistration/SecondaryRegistrationChildVCConstants.swift deleted file mode 100644 index a1a9657..0000000 --- a/enrollment/enrollment/Constants/VC Constants/Phase 0 Regisistration/SecondaryRegistrationChildVCConstants.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// SecondaryRegistrationChildVCConstants.swift -// enrollment -// -// Created by Jay Latman on 10/20/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Foundation - -struct SecondaryRegistrationChildVC_Constants { - static let header = "Lorem Ipsum" - static let subheader = "Lorem ipsum dolor sit amet, consectetur adipiscing elit." - - /** - Structure definition containing the key name assignments for storing the Option checkbox values - - • [Keys] `optionArray` : key name for the array to store the options - - • `PersistenceStoredSelectedOption` : array values corresponding to the option choices that a user has selected - */ - struct Keys { - static let optionArray = "Options" - struct Options { - struct PersistenceStoredSelectedOption { - static let one = "1" - static let two = "2" - static let three = "3" - static let four = "4" - static let five = "5" - static let six = "6" - static let none = "none" - } - } - } -} diff --git a/enrollment/enrollment/Constants/VC Constants/Phase 1 Bundle Installation/AppBundleConstants.swift b/enrollment/enrollment/Constants/VC Constants/Phase 1 Bundle Installation/AppBundleConstants.swift deleted file mode 100644 index 31538f5..0000000 --- a/enrollment/enrollment/Constants/VC Constants/Phase 1 Bundle Installation/AppBundleConstants.swift +++ /dev/null @@ -1,308 +0,0 @@ -// -// AppBundleConstants.swift -// enrollment -// -// Created by Jay Latman on 9/3/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -/** - Structure definition containing the reference assignments of stored values or property list key names for storing and retrieving values. - - Child structs : - - • Keys - Key names used for storing and retrieving values in processing and displaying app bundles - - • PersistanceArrayMember - Bundle array names to be anayalzed by the jamf install event to determine customer choices - - • Bundle - Keys and values used for display and updating of UI - */ -struct AppBundlesConstants { - /** - - `bundleArrayKey` - key name used for the array of bundle selections made by the customer - - - `speedRate` - key name used for the stored value of the download rate in MB / second - - - `jamfBufferTime` - key name used for the stored value of the estimated communication buffer time with the jps - - - `installClockTotal` - key name used for the stored total download time to be referenced between selection and install views - - child struct : AppInstallScreen - */ - struct Keys { - static let bundleArrayKey = "SelectedBundles" - static let speedRate = "speedTestResult" - static let jamfBufferTime = "jpsCommSeconds" - static let installClockTotal = "installClockTotal" - - /** - - `status` - key name used for storing the boolean value to set the state of the total install process indicator - - - `warning` - key name used for the storing of the boolean value to set the state of visibility for the warning string if the install process encountered a failure - */ - struct AppInstallScreen { - static let status = "appScreenStatus" - static let warning = "appScreenWarning" - } - } - - /** - Bundle choice names stored by selection and anaylzed by the jamf policy for installation process - */ - struct PersistanceArrayMember { - static let a = "connectivity" - static let b = "essentials" - static let c = "productivity" - } - - struct Bundle { - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values relating to the first bundle choice displayed on the selection view - - child structs : - - • Keys - key names used for storing and retrieving values in processing and displaying the bundle - - • Infopopover - strings and NSImages to be displayed for the corresponding info popover - - • DownloadTime - key anmes used for storing and retrieving values to display and calculate estimated download times - */ - struct A { - struct Keys { - /** - Key names for storing and retrieving bundle status - - `messaging` - key name used for storing and referencing the messaging string for bundle progress - - `status` - key name used for storing and referencing the integer value determining bundle install status - - child struct : AppStatus - */ - struct Bundle { - - static let messaging = "connectivityMessaging" - static let status = "connectivityBundleStatus" - - /** - Struct containing the key names for storing and referencing the integer value for each app in the bundle to determine install status - */ - struct AppStatus { - static let app1 = "connectivityApp1Status" - } - } - } - - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values relating to the first bundle choice info popover. - - • header - string value attributed to the first line of text on the popover - - • mainDescription - string value attributed to the description / second line of text on the popover - - • titles - [Array] of string values attributed to the individual app titles within the bundle - - • icons - [Array] of NSImages provided from the asset catalog for each app title - - • descriptions - [Array] of string values attributed to each app title - */ - struct Infopopover { - static let header = "Connectivity bundle" - static let mainDescription = "Get connected to our network with certificates and software" - static let titles: [String] = [ - "app1" - ] - static let icons : [NSImage] = [ - #imageLiteral(resourceName: "generic-app-icon") - ] - static let descriptions: [String] = [ - "Ipsum lorem 1" - ] - } - - /** - Structure definition containing the key names used for storing and retrieving values realted to the first bundle's install duration - - `size` - key name used for the bundle size in megabytes - - `time` - key name used for the bundle install time in seconds - */ - struct DownloadTime { - static let size = "connectivityBundleSize" - static let time = "connectivityBundleInstallSeconds" - } - } - - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values relating to the second bundle choice displayed on the selection view - - child structs : - - • Keys - key names used for storing and retrieving values in processing and displaying the bundle - - • Infopopover - strings and NSImages to be displayed for the corresponding info popover - - • DownloadTime - key anmes used for storing and retrieving values to display and calculate estimated download times - */ - struct B { - struct Keys { - /** - Key names for storing and retrieving bundle status - - `messaging` - key name used for storing and referencing the messaging string for bundle progress - - `status` - key name used for storing and referencing the integer value determining bundle install status - - child struct : AppStatus - */ - struct Bundle { - static let messaging = "essentialsMessaging" - static let status = "essentialsBundleStatus" - - /** - Struct containing the key names for storing and referencing the integer value for each app in the bundle to determine install status - */ - struct AppStatus { - static let app1 = "essentialsApp1Status" - static let app2 = "essentialsApp2Status" - static let app3 = "essentialsApp3Status" - static let app4 = "essentialsApp4Status" - } - } - } - - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values relating to the second bundle choice info popover. - - • header - string value attributed to the first line of text on the popover - - • mainDescription - string value attributed to the description / second line of text on the popover - - • titles - [Array] of string values attributed to the individual app titles within the bundle - - • icons - [Array] of NSImages provided from the asset catalog for each app title - - • descriptions - [Array] of string values attributed to each app title - */ - struct InfoPopover { - static let header = "Essentials bundle" - static let mainDescription = "The apps used by most employees" - static let titles: [String] = [ - "app1", - "app2", - "app3", - "app4" - ] - static let icons: [NSImage] = [ - #imageLiteral(resourceName: "generic-app-icon"), - #imageLiteral(resourceName: "generic-app-icon"), - #imageLiteral(resourceName: "generic-app-icon"), - #imageLiteral(resourceName: "generic-app-icon") - ] - static let descriptions: [String] = [ - "Ipsum lorem 1", - "Ipsum lorem 2", - "Ipsum lorem 3", - "Ipsum lorem 4" - ] - } - - /** - Structure definition containing the key names used for storing and retrieving values realted to the second bundle's install duration - - `size` - key name used for the bundle size in megabytes - - `time` - key name used for the bundle install time in seconds - */ - struct DownloadTime { - static let size = "essentialsBundleSize" - static let time = "essentialsBundleInstallSeconds" - } - } - - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values relating to the third bundle choice displayed on the selection view - - child structs : - - • Keys - key names used for storing and retrieving values in processing and displaying the bundle - - • Infopopover - strings and NSImages to be displayed for the corresponding info popover - - • DownloadTime - key anmes used for storing and retrieving values to display and calculate estimated download times - */ - struct C { - struct Keys { - /** - Key names for storing and retrieving bundle status - - `messaging` - key name used for storing and referencing the messaging string for bundle progress - - `status` - key name used for storing and referencing the integer value determining bundle install status - - child struct : AppStatus - */ - struct Bundle { - static let messaging = "productivityMessaging" - static let status = "productivityBundleStatus" - - /** - Struct containing the key names for storing and referencing the integer value for each app in the bundle to determine install status - */ - struct AppStatus { - static let app1 = "productivityApp1Status" - static let app2 = "productivityApp2Status" - static let app3 = "productivityApp3Status" - } - } - } - - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values relating to the third bundle choice info popover. - - • header - string value attributed to the first line of text on the popover - - • mainDescription - string value attributed to the description / second line of text on the popover - - • titles - [Array] of string values attributed to the individual app titles within the bundle - - • icons - [Array] of NSImages provided from the asset catalog for each app title - - • descriptions - [Array] of string values attributed to each app title - */ - struct InfoPopover { - static let header = "Productivity bundle" - static let mainDescription = "Tools to help you create and collaborate." - static let titles: [String] = [ - "app1", - "app2", - "app3" - ] - static let icons: [NSImage] = [ - #imageLiteral(resourceName: "generic-app-icon"), - #imageLiteral(resourceName: "generic-app-icon"), - #imageLiteral(resourceName: "generic-app-icon") - ] - static let descriptions: [String] = [ - "Ipsum lorem 1", - "Ipsum lorem 2", - "Ipsum lorem 3" - ] - } - - /** - Structure definition containing the key names used for storing and retrieving values realted to the third bundle's install duration - - `size` - key name used for the bundle size in megabytes - - `time` - key name used for the bundle install time in seconds - */ - struct DownloadTime { - static let size = "productivityBundleSize" - static let time = "productivityBundleInstallSeconds" - } - } - } -} diff --git a/enrollment/enrollment/Constants/VC Constants/Phase 1 Bundle Installation/BundleInstallationChildVCConstants.swift b/enrollment/enrollment/Constants/VC Constants/Phase 1 Bundle Installation/BundleInstallationChildVCConstants.swift deleted file mode 100644 index eaa70d4..0000000 --- a/enrollment/enrollment/Constants/VC Constants/Phase 1 Bundle Installation/BundleInstallationChildVCConstants.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// BundleInstallationChildVCConstants.swift -// enrollment -// -// Created by Jay Latman on 10/20/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Foundation - -struct BundleInstallationChildVC_Constants { - static let header = "Installing selected app bundles…" - static let estimatedTimeRemainingMessageTextLabel = "Estimated time remaining :" - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - The following references map to string values to be applied to buttons per bundle header instance displayed on the bundle installation view. - - • open : string value for when a button is on - - • closed : string value for when a button is off - */ - struct DisclosureButtonLabelText { - static let open = "Hide Apps" - static let closed = "Show Apps" - } -} diff --git a/enrollment/enrollment/Constants/VC Constants/Phase 1 Bundle Installation/BundleSelectionChildVCConstants.swift b/enrollment/enrollment/Constants/VC Constants/Phase 1 Bundle Installation/BundleSelectionChildVCConstants.swift deleted file mode 100644 index 0c4eb5d..0000000 --- a/enrollment/enrollment/Constants/VC Constants/Phase 1 Bundle Installation/BundleSelectionChildVCConstants.swift +++ /dev/null @@ -1,72 +0,0 @@ -// -// BundleSelectionChildVCConstants.swift -// enrollment -// -// Created by Jay Latman on 10/20/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Foundation - -/** - Structure definition for the bundle selection view. - - • header : string value for the first line of text from the top of the view - - • subheader : string value for the second line of text from the top of the view - - • recommended_label : string value use for ib label objects - - • `environment` : [Keys] key name referenced for determining the environment being used to test for network reachability - - child structs : Toggle - */ -struct BundleSelectionChildVC_Constants { - static let header = "App bundles to get you started" - static let subheader = "Additional apps can be installed from Self Service at any time." - static let recommend_label = "(recommended)" - - struct Keys { - static let environment = "environment" - } - - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - Note: Child structs: - - Title, Description - */ - struct Toggle { - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - Note: The following references map to string values to be applied to each checkbox toggle button title - - • a : first checkbox button title - - • b : second checkbox button title - - • c : third checkbox button title - */ - struct Title { - static let a = "Connectivity" - static let b = "Essentials" - static let c = "Productivity" - } - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - Note: The following references map to string values to be applied below each checkbox toggle button title - - • a : first checkbox description - - • b : second checkbox description - - • c : third checkbox description - */ - struct Description { - static let a = "Lorem ipsum dolor sit amet, consectetur adipiscing elit." - static let b = "" - static let c = "" - } - } -} diff --git a/enrollment/enrollment/Constants/VC Constants/Phase 2 Education/SetupCompleteChildVCConstants.swift b/enrollment/enrollment/Constants/VC Constants/Phase 2 Education/SetupCompleteChildVCConstants.swift deleted file mode 100644 index 522cf01..0000000 --- a/enrollment/enrollment/Constants/VC Constants/Phase 2 Education/SetupCompleteChildVCConstants.swift +++ /dev/null @@ -1,71 +0,0 @@ -// -// SetupCompleteChildVCConstants.swift -// enrollment -// -// Created by Jay Latman on 10/20/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -/** - Structure definition for the setup complete / education view - - • header : string value for the text label at the top of the view - - • showOnRestartToggleLabel : string value for the text applied adjacent to the check box toggle used for adding or removing the login helper - - • helperBundleIdentifier : string value for the bundle id associated with the login helper - - child structs : LinkOuts - */ -struct SetupCompleteChildVC_Constants { - static let header = "Get started with your Mac" - static let showOnRestartToggleLabel = " Remind me the next time I restart my Mac." - static let helperBundleIdentifier = "com.ibm.EnrollmentLoginHelper" - - /** - Structure definition containing reference assignments of stored values or property list key names for retrieving values. - - LinkOuts are of the URL tied connection entries to be displayed in the scroll view. Each entry is paired based on index value per array. - - • icons : Array of images. These could be code driven or referenced from the asset catalog - - • headerLabels : Array of header strings used in conjuction with a url to create a link - - • urls : Array of URLs - - • descriptionLabels : Array of strings providing descriptions for each linkout - */ - struct LinkOuts { - static let icons: [NSImage] = [ - SetupCompleteButtons.imageOfSelfServiceButton, - SetupCompleteButtons.imageOfMigrationButton, - SetupCompleteButtons.imageOfBackupButton, - SetupCompleteButtons.imageOfQnAButton - ] - - static let headerLabels: [String] = [ - WebLinkButtons.SelfService.header, - WebLinkButtons.Migration.header, - WebLinkButtons.Backup.header, - WebLinkButtons.Help.header - ] - - static let urls: [String] = [ - WebLinkButtons.SelfService.url, - WebLinkButtons.Migration.url, - WebLinkButtons.Backup.url, - WebLinkButtons.Help.url - ] - - static let descriptionLabels: [String] = [ - WebLinkButtons.SelfService.description, - WebLinkButtons.Migration.description, - WebLinkButtons.Backup.description, - WebLinkButtons.Help.description - ] - } -} - diff --git a/enrollment/enrollment/Constants/VC Constants/Phase 2 Education/WebLinkButtons.swift b/enrollment/enrollment/Constants/VC Constants/Phase 2 Education/WebLinkButtons.swift deleted file mode 100644 index 0209641..0000000 --- a/enrollment/enrollment/Constants/VC Constants/Phase 2 Education/WebLinkButtons.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// WebLinkButtons.swift -// enrollment -// -// Created by Jay Latman on 8/15/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Foundation - -/** - Structure definition containing the stored properties for constructing the LinkOuts and directly referenced in SetupCompleteChildVCConstants.swift - */ -struct WebLinkButtons { - struct SelfService { - static let header = "Install apps with Self Service" - static let description = "Great software for productivity, collaboration, creativity, and more." - static let url = "selfservice://" - } - - struct Migration { - static let header = "Migrate your data from another computer" - static let description = "Transfer important information to your new Mac." - static let url = "https://support.apple.com/en-us/HT204087" - } - - struct Backup { - static let header = "" - static let description = "" - static let url = "" - } - - struct Help { - static let header = "" - static let description = "" - static let url = "" - } -} diff --git a/enrollment/enrollment/Controllers/AppBundles/CircularStatus.swift b/enrollment/enrollment/Controllers/AppBundles/CircularStatus.swift deleted file mode 100644 index 5b1f8bb..0000000 --- a/enrollment/enrollment/Controllers/AppBundles/CircularStatus.swift +++ /dev/null @@ -1,121 +0,0 @@ -// -// CircularStatus.swift -// enrollment -// -// Created by Jay Latman on 9/2/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -class CircularStatus: NSView, CAAnimationDelegate { - - private static let rotationAnimatonKey = "rotation" - - private let imageLayer = CAShapeLayer() - private let progressLayer = CAShapeLayer() - - var state = StatusState.inQueue { - didSet { - guard oldValue != state else { - return - } - - let borderWidthAnimation = CABasicAnimation(keyPath: #keyPath(CAShapeLayer.lineWidth)) - borderWidthAnimation.fromValue = self.imageLayer.lineWidth - borderWidthAnimation.toValue = self.state.borderWidth - - self.imageLayer.add(borderWidthAnimation, forKey: nil) - - let contentAnimation = CABasicAnimation(keyPath: #keyPath(CAShapeLayer.contents)) - contentAnimation.fromValue = self.imageLayer.contents - contentAnimation.toValue = self.state.image - - self.imageLayer.add(contentAnimation, forKey: nil) - - self.imageLayer.lineWidth = self.state.borderWidth - - self.imageLayer.contents = state.image - } - } - - - override var intrinsicContentSize: NSSize { - get { - guard let imageSize = StatusState.success.image else { - return NSSize.zero - } - return NSSize(width: imageSize.size.width + 4, height: imageSize.size.height + 4) - } - } - - convenience init() { - self.init(frame: NSRect.zero) - } - - override init(frame: NSRect) { - super.init(frame: frame) - self.configure() - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - self.configure() - } - - private func configure() { - self.layer = CALayer() - self.layer?.contentsGravity = CALayerContentsGravity.resizeAspectFill - imageLayer.contents = self.state.image - imageLayer.strokeColor = ColorConstants.Indicators.Active.ovalStroke?.cgColor - imageLayer.fillColor = NSColor.clear.cgColor - imageLayer.lineWidth = self.state.borderWidth - - layer?.addSublayer(imageLayer) - } - - override func layout() { - super.layout() - - let imageSize = StatusState.success.image?.size ?? NSSize.zero - var imageLayerFrame = CGRect(origin: CGPoint.zero, size: imageSize) - - imageLayerFrame.origin.x = self.bounds.midX - imageLayerFrame.midX - imageLayerFrame.origin.y = self.bounds.midY - imageLayerFrame.midY - - self.imageLayer.frame = imageLayerFrame - self.imageLayer.path = CGPath(ellipseIn: self.imageLayer.bounds, transform: nil) - - self.progressLayer.frame = imageLayerFrame - self.progressLayer.path = CGPath(ellipseIn: self.imageLayer.bounds, transform: nil) - } -} - -private extension StatusState { - var image: NSImage? { - get { - switch self { - case .appInQueue: return Indicators.imageQueued(imageSize: IndicatorSize.appInstall) - case .appInProgress: return Indicators.imageActive(imageSize: IndicatorSize.appInstall) - case .appSuccess: return Indicators.imageSuccess(imageSize: IndicatorSize.appInstall) - case .appFailure: return Indicators.imageFailure(imageSize: IndicatorSize.appInstall) - case .appInProgressAnimated: return Indicators.imageActiveOpen(imageSize: IndicatorSize.appInstall) - case .inProgress: return Indicators.imageActive(imageSize: IndicatorSize.bundleInstall) - case .success: return Indicators.imageSuccess(imageSize: IndicatorSize.bundleInstall) - case .failure: return Indicators.imageFailure(imageSize: IndicatorSize.bundleInstall) - case .partial: return Indicators.imagePartial(imageSize: IndicatorSize.bundleInstall) - case .inQueue: return Indicators.imageQueued(imageSize: IndicatorSize.bundleInstall) - case .inProgressAnimated: return Indicators.imageActiveOpen(imageSize: IndicatorSize.bundleInstall) - } - } - } - - var borderWidth: CGFloat { - get { - switch self { - case .inProgress, .success, .failure, .partial, .inQueue, .inProgressAnimated, .appInProgress, .appInQueue, .appSuccess, .appFailure, .appInProgressAnimated: return 0.0 - } - } - } -} diff --git a/enrollment/enrollment/Controllers/AppDelegate.swift b/enrollment/enrollment/Controllers/AppDelegate.swift deleted file mode 100644 index a3494de..0000000 --- a/enrollment/enrollment/Controllers/AppDelegate.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// AppDelegate.swift -// enrollment -// -// Created by Jay Latman on 7/20/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - - - -@NSApplicationMain -class AppDelegate: NSObject, NSApplicationDelegate { - - func applicationDidFinishLaunching(_ aNotification: Notification) { - - /// Validate if the jamf binary is present, if so initiate an authorization reference - if FileManager.default.fileExists(atPath: JPSPaths.binaryPath) == true { - XPCService.sharedInstance.initAuthorizationRef() - - /// If the helper is not found, prompt the customer to install the helper from the app bundle else validate the version and update the helper if needed - if (!XPCService.sharedInstance.checkIfHelperDaemonExists()) { - XPCService.sharedInstance.installHelperDaemon() - } else { - XPCService.sharedInstance.checkHelperVersionAndUpdateIfNecessary() - } - } - } - - func applicationWillTerminate(_ aNotification: Notification) { - - /// Validate if the jamf binary is present, if so release the authorization reference - if FileManager.default.fileExists(atPath: JPSPaths.binaryPath) == true { - XPCService.sharedInstance.releaseAuthorizationRef() - } - } -} - diff --git a/enrollment/enrollment/Controllers/Installation/InstallationProcessController.swift b/enrollment/enrollment/Controllers/Installation/InstallationProcessController.swift new file mode 100644 index 0000000..0b520bb --- /dev/null +++ b/enrollment/enrollment/Controllers/Installation/InstallationProcessController.swift @@ -0,0 +1,80 @@ +// +// InstallationProcessController.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 4/20/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Foundation + +/// This protocol provide an interface between the installation process controller and the installation view controller +protocol InstallationProcessControllerDelegate: class { + func bundleStatusUpdated(_ bundleKey: String, newStatus: EnrollmentBundle.InstallationStatus) + func bundleMessageUpdated(_ bundleKey: String, newMessage: String) + func appStatusUpdated(_ appKey: String, newStatus: EnrollmentBundle.InstallationStatus) +} + +/// This class provide a controller that handle the update of the installation status for the bundles. +public final class InstallationProcessController { + + // MARK: - Variables + + private var selectedBundles: [EnrollmentBundle] + weak var delegate: InstallationProcessControllerDelegate? + private var uiUpdateQueue: DispatchQueue + + // MARK: - Initializers + + init(with enrollmentBundles: [EnrollmentBundle]) { + self.selectedBundles = enrollmentBundles + self.uiUpdateQueue = DispatchQueue(label: "com.ibm.enrollment.installationProcessUpdate", qos: .userInteractive) + } + + // MARK: - Private methods + + /// This method handle the old way to update the UI. This will be deprecated as soon as the new plist format and the deep link engine will go in production + @objc + private func updateStatus(_ notification: Notification) { + guard let key = notification.userInfo?["key"] as? String, + let newStatus = notification.userInfo?["newStatus"] as? EnrollmentBundle.InstallationStatus else { + return + } + if selectedBundles.contains(where: { $0.key == key }) { + uiUpdateQueue.async { + self.delegate?.bundleStatusUpdated(key, newStatus: newStatus) + } + } else { + for bundle in selectedBundles where bundle.apps.contains(where: { $0.key == key }) { + uiUpdateQueue.async { + self.delegate?.appStatusUpdated(key, newStatus: newStatus) + } + } + } + } + + @objc + private func updateBundleMessaging(_ notification: Notification) { + guard let key = notification.userInfo?["key"] as? String, + let newMessage = notification.userInfo?["newMessage"] as? String else { + return + } + if selectedBundles.contains(where: { $0.key == key }) { + uiUpdateQueue.async { + self.delegate?.bundleMessageUpdated(key, newMessage: newMessage) + } + } + } + + // MARK: - Public methods + + public func startListeningForUpdate() { + NotificationCenter.default.addObserver(self, selector: #selector(updateBundleMessaging), name: Constants.NewMessageReceivedNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(updateStatus), name: Constants.NewStatusReceivedNotification, object: nil) + } + + public func stopListeningForUpdate() { + NotificationCenter.default.removeObserver(self) + } +} diff --git a/enrollment/enrollment/Controllers/MainWindow/SubViewControllerManagerViewController.swift b/enrollment/enrollment/Controllers/MainWindow/SubViewControllerManagerViewController.swift deleted file mode 100644 index 883657f..0000000 --- a/enrollment/enrollment/Controllers/MainWindow/SubViewControllerManagerViewController.swift +++ /dev/null @@ -1,57 +0,0 @@ -// -// SubViewControllerManagerViewController.swift -// enrollment -// -// Created by Jay Latman on 7/23/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -/** - NSViewController class for managing the start points of the application. - - Enrollment has three primary phases: - - - Registration - - App Bundle Selection and Installation - - Helpful links for information - */ -class SubViewControllerManagerViewController: NSViewController { - - var storyboardID : String? = nil - override func viewDidLoad() { - super.viewDidLoad() - - layoutSetup() - } - - override func viewWillAppear() { - super.viewWillAppear() - } - - func layoutSetup() { - if let startPoint = (UserDefaults.standard.string(forKey: StartingPointID.Keys.phase)) { - switch String(describing: startPoint) { - case "0" : - storyboardID = StartingPointID.primaryRegistrationChildViewController - case "1" : - storyboardID = StartingPointID.bundleSelectionChildViewController - case "2" : - storyboardID = StartingPointID.setupCompleteChildViewController - default: - storyboardID = StartingPointID.primaryRegistrationChildViewController - } - } - else { - storyboardID = StartingPointID.primaryRegistrationChildViewController - } - - let mainStoryboard: NSStoryboard = NSStoryboard(name: "Main", bundle: nil) - let sourceViewController = mainStoryboard.instantiateController(withIdentifier: storyboardID!) as! NSViewController - self.insertChild(sourceViewController, at: 0) - self.view.addSubview(sourceViewController.view) - self.view.frame = sourceViewController.view.frame - } -} diff --git a/enrollment/enrollment/Controllers/Phase 0 Registration/AnimatedGIFProgressViewController.swift b/enrollment/enrollment/Controllers/Phase 0 Registration/AnimatedGIFProgressViewController.swift deleted file mode 100644 index c2a696a..0000000 --- a/enrollment/enrollment/Controllers/Phase 0 Registration/AnimatedGIFProgressViewController.swift +++ /dev/null @@ -1,62 +0,0 @@ -// -// AnimatedGIFProgressViewController.swift -// enrollment -// -// Created by Jay Latman on 8/1/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -class AnimatedGIFProgressViewController: NSViewController { - - @IBOutlet weak var animatedGIFView: NSImageView! - @IBOutlet weak var progressAlertTextLabel: NSTextField! - - var progressCounter = 20 - - override func viewDidLoad() { - super.viewDidLoad() - progressAlertTextLabel.stringValue = AnimatedGIFProgressChildVC_Constants.RegistrationProgress.stateOne - loadAnimatedGIF() - setTextFields() - var _ = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { (Timer) in - self.updateProgressCounter() - } - } - - private func setTextFields() { - progressAlertTextLabel.textColor = .headerTextColor - } - - private func loadAnimatedGIF() { - let animatedGIF = animatedGIFView - animatedGIF?.canDrawSubviewsIntoLayer = true - animatedGIF?.imageScaling = .scaleProportionallyUpOrDown - animatedGIF?.animates = true - animatedGIF?.image = NSImage(named: AnimatedGIFProgressChildVC_Constants.AnimatedProgressGIF.fileName) - self.view.addSubview(animatedGIF!) - } - - private func updateProgressCounter() { - if (progressCounter >= 0) { - progressCounter = progressCounter - 1 - } - switch progressCounter { - case 2...10 : - progressAlertTextLabel.fadeTransition(0.10) - progressAlertTextLabel.stringValue = AnimatedGIFProgressChildVC_Constants.RegistrationProgress.stateTwo - case 11...20 : - progressAlertTextLabel.fadeTransition(0.10) - progressAlertTextLabel.stringValue = AnimatedGIFProgressChildVC_Constants.RegistrationProgress.stateOne - case 1 : - progressAlertTextLabel.fadeTransition(0.10) - progressAlertTextLabel.isHidden = true - case 0 : - self.performSegue(withIdentifier: SegueDestinationID.ForwardTo.registrationCompleteChildViewControllter, sender: self) - default: - break - } - } -} diff --git a/enrollment/enrollment/Controllers/Phase 0 Registration/PrimaryRegistrationChildViewController.swift b/enrollment/enrollment/Controllers/Phase 0 Registration/PrimaryRegistrationChildViewController.swift deleted file mode 100644 index 7f125f7..0000000 --- a/enrollment/enrollment/Controllers/Phase 0 Registration/PrimaryRegistrationChildViewController.swift +++ /dev/null @@ -1,237 +0,0 @@ -// -// PrimaryRegistrationChildViewController.swift -// enrollment -// -// Created by Jay Latman on 7/23/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -/** - NSViewController class for the first Registration View. - - example: This view contains popup buttons for choices to be selected by the user to be used for external registration requirements. - */ -class PrimaryRegistrationChildViewController: NSViewController { - - @IBOutlet var primaryRegistrationView: NSView! - - // Transition button outlets - @IBOutlet weak var continueToNextStepButton: NSButton! - @IBOutlet weak var cancelButton: NSButton! - - // Text outlets - @IBOutlet weak var welcomeMessage: NSTextField! - @IBOutlet weak var nameErrorMessage: NSTextField! - @IBOutlet weak var additionalPolicyMessage: NSTextField! - - // Info bubble outlets - @IBOutlet weak var nameErrorInfoBubble: NSButton! - @IBOutlet weak var popupBox2InfoBubble: NSButton! - @IBOutlet weak var popupBox4InfoBubble: NSButton! - @IBOutlet weak var additionalPolicyMessageInfoBubble: NSButton! - - // Popup button outlets : Header labels - @IBOutlet weak var popupButton1Header: NSTextField! - @IBOutlet weak var popupButton2Header: NSTextField! - @IBOutlet weak var popupButton3Header: NSTextField! - @IBOutlet weak var popupButton4Header: NSTextField! - - // Popup button outlets : contents - @IBOutlet weak var popupButton1: NSPopUpButton! - @IBOutlet weak var popupButton2: NSPopUpButton! - @IBOutlet weak var popupButton3: NSPopUpButton! - @IBOutlet weak var popupButton4: NSPopUpButton! - - - - /* - We store the return values of each pull down selection to be sure all for values have been selected and corresponding coded values have been written to disc before enabling the 'continueToNextStepButton'. We can validate if the array contains a 0 to disable the button - */ - var percentageOfCompletion: Array = [Int](repeating: 0, count: 4) - - var returnCODE = String() - - override func viewDidLoad() { - super.viewDidLoad() - layoutSetup() - setTextFields() - } - - override func viewWillAppear() { - super.viewWillAppear() - loadConfigurationStateFromPlist() - } - - private func layoutSetup() { - continueToNextStepButton.isEnabled = false - popupButton1Header.stringValue = PrimaryRegistrationChildVC_Constants.PopupButtons.Headers.LabelText.popup1Header - popupButton2Header.stringValue = PrimaryRegistrationChildVC_Constants.PopupButtons.Headers.LabelText.popup2Header - popupButton3Header.stringValue = PrimaryRegistrationChildVC_Constants.PopupButtons.Headers.LabelText.popup3Header - popupButton4Header.stringValue = PrimaryRegistrationChildVC_Constants.PopupButtons.Headers.LabelText.popup4Header - popupButton1.addItems(withTitles: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info1.list) - popupButton2.addItems(withTitles: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info2.list) - popupButton3.addItems(withTitles: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info3.list) - popupButton4.addItems(withTitles: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info4.list) - nameErrorInfoBubble.image = InfoBubble.imageOfInfo_bubble - popupBox2InfoBubble.image = InfoBubble.imageOfInfo_bubble - popupBox4InfoBubble.image = InfoBubble.imageOfInfo_bubble - additionalPolicyMessageInfoBubble.image = InfoBubble.imageOfInfo_bubble - } - - private func setTextFields() { - welcomeMessage.textColor = .headerTextColor - additionalPolicyMessage.set(label: PrimaryRegistrationChildVC_Constants.additionalPolicyMessage, color: .controlTextColor) - let controlTextFields = [nameErrorMessage, popupButton1Header, popupButton2Header, popupButton3Header, popupButton4Header] - for i in controlTextFields { - i?.textColor = .controlTextColor - } - } - - - /** - Function for configuring the primary welcome message and popup button state - - Note: the `hrFirstName` is stored on enrollment trigger with an API request to the JPS prior to app launch - */ - private func loadConfigurationStateFromPlist() { - if let hrFirstName = UserDefaults.standard.string(forKey: PrimaryRegistrationChildVC_Constants.Keys.hrFirstName) { - welcomeMessage.stringValue = "Welcome, \(hrFirstName.capitalized)" - nameErrorMessage.stringValue = "Not \(hrFirstName.capitalized)?" - } - validatePercentageCompletion() - } - - /** - Function for validating the percentage of completion for selecting options for every popup button based on stored values. - - Parameter aPopupChoice: Popup button choice made by user - - Parameter key: Propertylist key for reading / storing the choice made by the user - - Parameter popup: Popup button for displaying and allowing for choices - - Parameter returnCodes: Return codes associated with user facing choices - - Parameter percentageCompleteIndex: Index value is either on or off (1 or 0) - */ - private func validatePopUpBoxChoice(aPopupChoice: String, key: String, popup: NSPopUpButton!, returnCodes: [String], percentageCompleteIndex: Int) { - if let aPopupChoice = UserDefaults.standard.string(forKey: key) { - popup.selectItem(at: (returnCodes.index(of: aPopupChoice))!) - if UserDefaults.standard.string(forKey: key) != nil && UserDefaults.standard.string(forKey: key) != "" { self.percentageOfCompletion[percentageCompleteIndex] = 1} - } - } - - /** - Function for updating the UI based on the choices selected. - - Parameter aPopupChoice: Popup button choice made by user - - Parameter key: Propertylist key for reading / storing the choice made by the user - - Parameter popup: Popup button for displaying and allowing for choices - - Parameter returnCodes: Return codes associated with user facing choices - - Parameter percentageCompleteIndex: Index value is either on or off (1 or 0) - */ - private func updateUIFromSelection(aPopupChoice: String, key: String, popup: NSPopUpButton!, returnCodes: [String], perentageCompleteIndex: Int) { - let aPopupChoice = popup.indexOfSelectedItem - if aPopupChoice > 0 { - percentageOfCompletion[perentageCompleteIndex] = 1 - } else { - percentageOfCompletion[perentageCompleteIndex] = 0 - } - UserDefaults.standard.set(returnCodes[aPopupChoice], forKey: key) - UserDefaults.standard.synchronize() - setStateForContinueToNextStepButton() - } - - private func validatePercentageCompletion() { - validatePopUpBoxChoice(aPopupChoice: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info1.selectedType, - key: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info1.key, - popup: popupButton1, - returnCodes: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info1.codes, - percentageCompleteIndex: 0) - validatePopUpBoxChoice(aPopupChoice: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info2.selectedType, - key: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info2.key, - popup: popupButton2, - returnCodes: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info2.codes, - percentageCompleteIndex: 1) - validatePopUpBoxChoice(aPopupChoice: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info3.selectedType, - key: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info3.key, - popup: popupButton3, - returnCodes: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info3.codes, - percentageCompleteIndex: 2) - validatePopUpBoxChoice(aPopupChoice: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info4.selectedType, - key: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info4.key, - popup: popupButton4, - returnCodes: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info4.codes, - percentageCompleteIndex: 3) - - setStateForContinueToNextStepButton() - } - - private func setStateForContinueToNextStepButton() { - continueToNextStepButton.fadeTransition(0.25) - if percentageOfCompletion.contains(0) { - continueToNextStepButton.isEnabled = false - } else { - continueToNextStepButton.isEnabled = true - } - } - - // Popup Boxes - @IBAction func popupButton1Clicked(_ sender: NSPopUpButton) { - updateUIFromSelection(aPopupChoice: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info1.selectedType, - key: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info1.key, - popup: popupButton1, - returnCodes: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info1.codes, - perentageCompleteIndex: 0) - } - - @IBAction func popupButton2Clicked(_ sender: NSPopUpButton) { - updateUIFromSelection(aPopupChoice: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info2.selectedType, - key: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info2.key, - popup: popupButton2, - returnCodes: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info2.codes, - perentageCompleteIndex: 1) - } - - @IBAction func popupButton3Clicked(_ sender: NSPopUpButton) { - updateUIFromSelection(aPopupChoice: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info3.selectedType, - key: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info3.key, - popup: popupButton3, - returnCodes: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info3.codes, - perentageCompleteIndex: 2) - } - - @IBAction func popupButton4Clicked(_ sender: NSPopUpButton) { - updateUIFromSelection(aPopupChoice: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info4.selectedType, - key: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info4.key, - popup: popupButton4, - returnCodes: PrimaryRegistrationChildVC_Constants.PopupButtons.PopupBoxes.Info4.codes, - perentageCompleteIndex: 3) - } - - - // Info Bubble Popovers - @IBAction func info2PopoverButtonClicked(_ sender: NSButton) { - self.performSegue(withIdentifier: SegueDestinationID.Popover.PrimaryRegisrationChildViewController.info2, sender: self) - } - - @IBAction func info4PopoverButtonClicked(_ sender: NSButton) { - self.performSegue(withIdentifier: SegueDestinationID.Popover.PrimaryRegisrationChildViewController.info4, sender: self) - } - - @IBAction func infoSecurityDescriptionsPopoverButtonClicked(_ sender: NSButton) { - self.performSegue(withIdentifier: SegueDestinationID.Popover.PrimaryRegisrationChildViewController.securityDescription, sender: self) - } - - // Transition Buttons - @IBAction func cancelButtonClicked(_ sender: NSButton) { - IssueAlertService.sharedInstance.displaySheetWithJAMFAction(header: AlertText.RegistrationCancelAlert.header, - message: AlertText.RegistrationCancelAlert.message, - style: .critical, - cancelButtonLabel: UserInteractionButtons.no, - actionButtonLabel: UserInteractionButtons.yes, - jamfPolicyEvent: JAMFPolicyEventID.removeFramework, - button1LogText: UserInteractionButtons.InteractionLogText.removeFrameworkCancelledLog) - } - - @IBAction func continueToSecondaryRegistration(_ sender: NSButton) { - self.performSegue(withIdentifier: SegueDestinationID.ForwardTo.secondaryRegistrationChildViewController, sender: self) - } -} diff --git a/enrollment/enrollment/Controllers/Phase 0 Registration/RegistrationCompleteChildViewController.swift b/enrollment/enrollment/Controllers/Phase 0 Registration/RegistrationCompleteChildViewController.swift deleted file mode 100644 index 95f90a2..0000000 --- a/enrollment/enrollment/Controllers/Phase 0 Registration/RegistrationCompleteChildViewController.swift +++ /dev/null @@ -1,79 +0,0 @@ -// -// RegistrationCompleteChildViewController.swift -// enrollment -// -// Created by Jay Latman on 8/2/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -protocol RegistrationCompleteChildViewControllerDelegate: class { - func registrationCompleteChildViewControllerWillRestart(_ viewController: RegistrationCompleteChildViewController) -} - -class RegistrationCompleteChildViewController: NSViewController { - - @IBOutlet weak var headerTextLabel: NSTextField! - @IBOutlet weak var subheaderTextLabel: NSTextField! - @IBOutlet weak var countdownMessageLabel: NSTextField! - @IBOutlet weak var instructionalMessageLabel: NSTextField! - - weak var delegate: RegistrationCompleteChildViewController? - var count = RegistrationCompleteChildVC_Constants.initialCountdownValue - - override func viewDidLoad() { - super.viewDidLoad() - layoutSetup() - setTextFields() - } - - private func layoutSetup() { - var _ = Timer.scheduledTimer(withTimeInterval: 60.0, repeats: true) { (Timer) in - self.updateCounter() - } - } - - private func setTextFields() { - headerTextLabel.set(label: RegistrationCompleteChildVC_Constants.header, color: .headerTextColor) - subheaderTextLabel.set(label: RegistrationCompleteChildVC_Constants.subheader, color: .controlTextColor) - countdownMessageLabel.set(label: RegistrationCompleteChildVC_Constants.countdownMessage, color: .controlTextColor) - instructionalMessageLabel.set(label: RegistrationCompleteChildVC_Constants.instructionalMessage, color: .controlTextColor) - } - - private func restartComputer() { - var systemProcessPSN = ProcessSerialNumber(highLongOfPSN: 0, lowLongOfPSN: UInt32(kSystemProcess)) - let systemProcessDescriptor = NSAppleEventDescriptor(descriptorType: DescType(typeProcessSerialNumber), - bytes: &systemProcessPSN, - length: MemoryLayout.size(ofValue: systemProcessPSN)) - let rebootEvent = NSAppleEventDescriptor(eventClass: AEEventClass(kCoreEventClass), - eventID: AEEventID(kAERestart), - targetDescriptor: systemProcessDescriptor, - returnID: AEReturnID(kAutoGenerateReturnID), - transactionID: AETransactionID(kAnyTransactionID)) - let err = AESendMessage(rebootEvent.aeDesc, nil, AESendMode(kAENoReply), kAEDefaultTimeout) - if (err != noErr) { - let failureAlert = NSAlert() - failureAlert.messageText = NSLocalizedString(RegistrationCompleteChildVC_Constants.FailureToRestart.message, comment: RegistrationCompleteChildVC_Constants.FailureToRestart.comment) - failureAlert.runModal() - } - } - - private func updateCounter() { - if (count >= 1) { - countdownMessageLabel.stringValue = "Your Mac will be restarted automatically in \(count) minutes to continue the setup process." - count -= 1 - } else { - UserDefaults.standard.set("1", forKey: StartingPointID.Keys.phase) - self.restartComputer() - } - } - - - @IBAction func restartButtonClicked(_ sender: NSButton) { - UserDefaults.standard.set("1", forKey: StartingPointID.Keys.phase) - UserDefaults.standard.synchronize() - self.restartComputer() - } -} diff --git a/enrollment/enrollment/Controllers/Phase 0 Registration/SecondaryRegistrationChildViewController.swift b/enrollment/enrollment/Controllers/Phase 0 Registration/SecondaryRegistrationChildViewController.swift deleted file mode 100644 index 4c6bd86..0000000 --- a/enrollment/enrollment/Controllers/Phase 0 Registration/SecondaryRegistrationChildViewController.swift +++ /dev/null @@ -1,132 +0,0 @@ -// -// SecondaryRegistrationChildViewController.swift -// enrollment -// -// Created by Jay Latman on 7/25/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -class SecondaryRegistrationChildViewController: NSViewController { - - // Transition button outlets - @IBOutlet weak var continueToNextStepButton: NSButton! - - // Text outlets - @IBOutlet weak var headerTextLabel: NSTextField! - @IBOutlet weak var subheaderTextLabel: NSTextField! - - // Info bubble outlets - @IBOutlet weak var infoBubbleButton: NSButton! - - // Checkbox button outlets - @IBOutlet weak var optionCheckbox1: NSButton! - @IBOutlet weak var optionCheckbox2: NSButton! - @IBOutlet weak var optionCheckbox3: NSButton! - @IBOutlet weak var optionCheckbox4: NSButton! - @IBOutlet weak var optionCheckbox5: NSButton! - @IBOutlet weak var optionCheckbox6: NSButton! - @IBOutlet weak var noneOfTheAboveCheckbox: NSButton! - - var optionCheckboxButtons: [NSButton]! - var optionCheckboxSelected: Set = [] - - override func viewDidLoad() { - super.viewDidLoad() - layoutSetup() - setTextFields() - if (UserDefaults.standard.array(forKey: SecondaryRegistrationChildVC_Constants.Keys.optionArray)) != nil { - loadOnOffStateFromPlist() - } else { return } - setStateForContinueToNextStepButton() - } - - - private func layoutSetup() { - infoBubbleButton.image = InfoBubble.imageOfInfo_bubble - optionCheckbox1.set(toggleLabel: " " + InfoPopoverConstants.SecondaryRegistrationVC.Option.object1.term, underline: 0) - optionCheckbox2.set(toggleLabel: " " + InfoPopoverConstants.SecondaryRegistrationVC.Option.object2.term, underline: 0) - optionCheckbox3.set(toggleLabel: " " + InfoPopoverConstants.SecondaryRegistrationVC.Option.object3.term, underline: 0) - optionCheckbox4.set(toggleLabel: " " + InfoPopoverConstants.SecondaryRegistrationVC.Option.object4.term, underline: 0) - optionCheckbox5.set(toggleLabel: " " + InfoPopoverConstants.SecondaryRegistrationVC.Option.object5.term, underline: 0) - optionCheckbox6.set(toggleLabel: " " + InfoPopoverConstants.SecondaryRegistrationVC.Option.object6.term, underline: 0) - noneOfTheAboveCheckbox.set(toggleLabel: " " + InfoPopoverConstants.SecondaryRegistrationVC.Option.none.term, underline: 0) - optionCheckboxButtons = [optionCheckbox1, optionCheckbox2, optionCheckbox3, optionCheckbox4, optionCheckbox5, optionCheckbox6] - } - - private func setTextFields() { - headerTextLabel.set(label: SecondaryRegistrationChildVC_Constants.header, color: .headerTextColor) - subheaderTextLabel.set(label: SecondaryRegistrationChildVC_Constants.subheader, color: .controlTextColor ) - } - - private func loadOnOffStateFromPlist() { - var optionCheckboxToggleArray: [String] = [] - - if let optionCheckboxSelection = (UserDefaults.standard.array(forKey: SecondaryRegistrationChildVC_Constants.Keys.optionArray)) as? [String] { - for optionCheckboxToggles in optionCheckboxSelection { - optionCheckboxToggleArray.append(optionCheckboxToggles) - - if optionCheckboxToggleArray.contains(SecondaryRegistrationChildVC_Constants.Keys.Options.PersistenceStoredSelectedOption.one) { optionCheckbox1.state = .on } - if optionCheckboxToggleArray.contains(SecondaryRegistrationChildVC_Constants.Keys.Options.PersistenceStoredSelectedOption.two) { optionCheckbox2.state = .on } - if optionCheckboxToggleArray.contains(SecondaryRegistrationChildVC_Constants.Keys.Options.PersistenceStoredSelectedOption.three) { optionCheckbox3.state = .on } - if optionCheckboxToggleArray.contains(SecondaryRegistrationChildVC_Constants.Keys.Options.PersistenceStoredSelectedOption.four) { optionCheckbox4.state = .on } - if optionCheckboxToggleArray.contains(SecondaryRegistrationChildVC_Constants.Keys.Options.PersistenceStoredSelectedOption.five) { optionCheckbox5.state = .on } - if optionCheckboxToggleArray.contains(SecondaryRegistrationChildVC_Constants.Keys.Options.PersistenceStoredSelectedOption.six) { optionCheckbox6.state = .on } - if optionCheckboxToggleArray.contains(SecondaryRegistrationChildVC_Constants.Keys.Options.PersistenceStoredSelectedOption.none) { noneOfTheAboveCheckbox.state = .on } - } - } - } - - private func setStateForContinueToNextStepButton() { - let anyOptionSelected = optionCheckboxButtons.reduce(false) { $1.state == NSButton.StateValue.on ? true : $0 } - - if anyOptionSelected { - self.noneOfTheAboveCheckbox.state = .off - } - self.continueToNextStepButton.fadeTransition(0.25) - self.continueToNextStepButton.isEnabled = anyOptionSelected || self.noneOfTheAboveCheckbox.state == .on - } - - @IBAction func optionToggled(_ sender: NSButton) { - if (sender.identifier!.rawValue as String?) != SecondaryRegistrationChildVC_Constants.Keys.Options.PersistenceStoredSelectedOption.none { - optionCheckboxSelected.remove(SecondaryRegistrationChildVC_Constants.Keys.Options.PersistenceStoredSelectedOption.none) - if sender.state == .on { - optionCheckboxSelected.insert(sender.identifier!.rawValue as String) - UserDefaults.standard.set(Array(optionCheckboxSelected), forKey: SecondaryRegistrationChildVC_Constants.Keys.optionArray) - } else { - optionCheckboxSelected.remove(sender.identifier!.rawValue as String) - } - setStateForContinueToNextStepButton() - } - UserDefaults.standard.set(Array(optionCheckboxSelected), forKey: SecondaryRegistrationChildVC_Constants.Keys.optionArray) - UserDefaults.standard.synchronize() - } - - @IBAction func noneOptionToggled(_ sender: NSButton) { - if noneOfTheAboveCheckbox.state == .on { - optionCheckboxButtons.forEach { $0.state = .off} - self.setStateForContinueToNextStepButton() - optionCheckboxSelected.removeAll() - optionCheckboxSelected.insert(SecondaryRegistrationChildVC_Constants.Keys.Options.PersistenceStoredSelectedOption.none) - } else { - self.setStateForContinueToNextStepButton() - optionCheckboxSelected.remove(SecondaryRegistrationChildVC_Constants.Keys.Options.PersistenceStoredSelectedOption.none) - } - UserDefaults.standard.set(Array(optionCheckboxSelected), forKey: SecondaryRegistrationChildVC_Constants.Keys.optionArray) - UserDefaults.standard.synchronize() - } - - @IBAction func infoBubbleButtonClicked(_ sender: NSButton) { - self.performSegue(withIdentifier: SegueDestinationID.Popover.SecondaryRegistrationChildViewController.optionDescriptions, sender: self) - } - - @IBAction func backButtonClicked(_ sender: NSButton) { - self.performSegue(withIdentifier: SegueDestinationID.ReturnTo.primaryRegistrationChildViewController, sender: self) - } - - @IBAction func continueToNextStepButtonClicked(_ sender: NSButton) { - self.performSegue(withIdentifier: SegueDestinationID.ForwardTo.progressRegistrationChildViewController, sender: self) - } -} diff --git a/enrollment/enrollment/Controllers/Phase 1 Bundle Installation/BaseViewController.swift b/enrollment/enrollment/Controllers/Phase 1 Bundle Installation/BaseViewController.swift deleted file mode 100644 index f64b0fb..0000000 --- a/enrollment/enrollment/Controllers/Phase 1 Bundle Installation/BaseViewController.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// BaseViewController.swift -// enrollment -// -// Created by Jay Latman on 8/22/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -class BaseViewController: NSViewController, StackItemBody { - - @IBOutlet var bundleProgressStackHeightConstraint: NSLayoutConstraint! - - var savedDefaultHeight: CGFloat = 0 - var discloseState: StackItemContainer.DiscloseState = .closed - - func headerTitle() -> String { return "" } - - override func viewDidLoad() { - super.viewDidLoad() - savedDefaultHeight = view.bounds.height - } - - lazy var stackItemContainer: StackItemContainer? = { - var storyboardIdentifier: String - storyboardIdentifier = "HeaderViewController" - let storyboard = NSStoryboard(name: "HeaderViewController", bundle: nil) - guard let header = storyboard.instantiateController(withIdentifier: storyboardIdentifier) as? HeaderViewController else { - return .none - } - header.title = self.headerTitle() - - return StackItemContainer(header: header, body: self, state: self.discloseState) - }() - -} diff --git a/enrollment/enrollment/Controllers/Phase 1 Bundle Installation/BundleAProgressStackItemViewController.swift b/enrollment/enrollment/Controllers/Phase 1 Bundle Installation/BundleAProgressStackItemViewController.swift deleted file mode 100644 index 74c2cbf..0000000 --- a/enrollment/enrollment/Controllers/Phase 1 Bundle Installation/BundleAProgressStackItemViewController.swift +++ /dev/null @@ -1,93 +0,0 @@ -// -// BundleAProgressStackItemViewController.swift -// enrollment -// -// Created by Jay Latman on 8/28/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -class BundleAProgressStackItemViewController: BaseViewController { - - @IBOutlet weak var progressIndicatorApp1: CircularStatus! - - @IBOutlet weak var app1NameTextLabel: NSTextField! - - private var anchorStopApp1 = 0 - private var anchorStopHeader = 0 - - private var totalBundleResult: Array = [Double](repeating: 0.0, count: AppBundlesConstants.Bundle.A.Infopopover.titles.count) - - override func headerTitle() -> String { - return NSLocalizedString(AppBundlesConstants.Bundle.A.Infopopover.header.capitalized, comment: "") - } - - override func viewDidLoad() { - super.viewDidLoad() - progressIndicatorApp1.state = .appInQueue - var _ = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: true) { (Timer) in - self.updateUI() - } - } - - override func viewWillLayout() { - layoutSetup() - setTextFields() - } - - private func layoutSetup() { - progressIndicatorApp1.fadeTransition(2.0) - } - - private func setTextFields() { - app1NameTextLabel.set(label: AppBundlesConstants.Bundle.A.Infopopover.titles[0], color: .controlTextColor) - } - - private func updateUI() { - _ = UpdateUIForAppStatus(appStatusKey: AppBundlesConstants.Bundle.A.Keys.Bundle.AppStatus.app1, - appIndicator: progressIndicatorApp1, - anchorStop: &anchorStopApp1, - totalBundleResult: &totalBundleResult, - index: 0) - - if let valueConnectivityBundleMessaging = UserDefaults.standard.value(forKey: AppBundlesConstants.Bundle.A.Keys.Bundle.messaging) { - let headerVC = self.stackItemContainer?.header as! HeaderViewController - headerVC.updateWithProgressMessage(statusText: valueConnectivityBundleMessaging as! String) - } - - if let valueConnectivityBundleIndicator = UserDefaults.standard.value(forKey: AppBundlesConstants.Bundle.A.Keys.Bundle.status) { - let headerVC = self.stackItemContainer?.header as! HeaderViewController - switch String(describing: valueConnectivityBundleIndicator) { - case "0" : - headerVC.updateWithProgressIndicator(progressIndicator: .inQueue) - case "1" : - headerVC.updateWithProgressIndicator(progressIndicator: .inProgressAnimated) - if anchorStopHeader == 0 { - headerVC.bundleProgressIndicator.determineAnchorPoint(indicator: headerVC.bundleProgressIndicator) - } - anchorStopHeader = 1 - headerVC.bundleProgressIndicator.rotate() - case "2" : - headerVC.bundleProgressIndicator.stopRotation() - let sumArray = totalBundleResult.reduce(0, +) - let avgArrayValue = sumArray / Double(totalBundleResult.count) - if avgArrayValue == 1.0 { - headerVC.updateWithProgressIndicator(progressIndicator: .success) - } - else if avgArrayValue == 0.0 { - headerVC.updateWithProgressIndicator(progressIndicator: .failure) - UserDefaults.standard.set(1, forKey: AppBundlesConstants.Keys.AppInstallScreen.warning) - } - else { - headerVC.updateWithProgressIndicator(progressIndicator: .partial) - UserDefaults.standard.set(1, forKey: AppBundlesConstants.Keys.AppInstallScreen.warning) - } - default: - return - } - UserDefaults.standard.synchronize() - } - } -} diff --git a/enrollment/enrollment/Controllers/Phase 1 Bundle Installation/BundleBProgressStackItemViewController.swift b/enrollment/enrollment/Controllers/Phase 1 Bundle Installation/BundleBProgressStackItemViewController.swift deleted file mode 100644 index d47c5d1..0000000 --- a/enrollment/enrollment/Controllers/Phase 1 Bundle Installation/BundleBProgressStackItemViewController.swift +++ /dev/null @@ -1,127 +0,0 @@ -// -// BundleBProgressStackItemViewController.swift -// enrollment -// -// Created by Jay Latman on 8/28/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -class BundleBProgressStackItemViewController: BaseViewController { - - @IBOutlet weak var progressIndicatorApp1: CircularStatus! - @IBOutlet weak var progressIndicatorApp2: CircularStatus! - @IBOutlet weak var progressIndicatorApp3: CircularStatus! - @IBOutlet weak var progressIndicatorApp4: CircularStatus! - - @IBOutlet weak var app1NameTextLabel: NSTextField! - @IBOutlet weak var app2NameTextLabel: NSTextField! - @IBOutlet weak var app3NameTextLabel: NSTextField! - @IBOutlet weak var app4NameTextLabel: NSTextField! - - private var anchorStopApp1 = 0 - private var anchorStopApp2 = 0 - private var anchorStopApp3 = 0 - private var anchorStopApp4 = 0 - private var anchorStopHeader = 0 - - private var totalBundleResult: Array = [Double](repeating: 0.0, count: AppBundlesConstants.Bundle.B.InfoPopover.titles.count) - - override func headerTitle() -> String { - return NSLocalizedString(AppBundlesConstants.Bundle.B.InfoPopover.header.capitalized, comment: "") - } - - override func viewDidLoad() { - super.viewDidLoad() - progressIndicatorApp1.state = .appInQueue - progressIndicatorApp2.state = .appInQueue - progressIndicatorApp3.state = .appInQueue - progressIndicatorApp4.state = .appInQueue - var _ = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: true) { (Timer) in - self.updateUI() - } - } - - override func viewWillLayout() { - layoutSetup() - setTextFields() - } - - private func layoutSetup() { - progressIndicatorApp1.fadeTransition(2.0) - progressIndicatorApp2.fadeTransition(2.0) - progressIndicatorApp3.fadeTransition(2.0) - progressIndicatorApp4.fadeTransition(2.0) - } - - private func setTextFields() { - app1NameTextLabel.set(label: AppBundlesConstants.Bundle.B.InfoPopover.titles[0], color: .controlTextColor) - app2NameTextLabel.set(label: AppBundlesConstants.Bundle.B.InfoPopover.titles[1], color: .controlTextColor) - app3NameTextLabel.set(label: AppBundlesConstants.Bundle.B.InfoPopover.titles[2], color: .controlTextColor) - app4NameTextLabel.set(label: AppBundlesConstants.Bundle.B.InfoPopover.titles[3], color: .controlTextColor) - } - - - private func updateUI() { - _ = UpdateUIForAppStatus(appStatusKey: AppBundlesConstants.Bundle.B.Keys.Bundle.AppStatus.app1, - appIndicator: progressIndicatorApp1, - anchorStop: &anchorStopApp1, - totalBundleResult: &totalBundleResult, - index: 0) - _ = UpdateUIForAppStatus(appStatusKey: AppBundlesConstants.Bundle.B.Keys.Bundle.AppStatus.app2, - appIndicator: progressIndicatorApp2, - anchorStop: &anchorStopApp2, - totalBundleResult: &totalBundleResult, - index: 1) - _ = UpdateUIForAppStatus(appStatusKey: AppBundlesConstants.Bundle.B.Keys.Bundle.AppStatus.app3, - appIndicator: progressIndicatorApp3, - anchorStop: &anchorStopApp3, - totalBundleResult: &totalBundleResult, - index: 2) - _ = UpdateUIForAppStatus(appStatusKey: AppBundlesConstants.Bundle.B.Keys.Bundle.AppStatus.app4, - appIndicator: progressIndicatorApp4, - anchorStop: &anchorStopApp4, - totalBundleResult: &totalBundleResult, - index: 3) - - if let valueEssentialsBundleMessaging = UserDefaults.standard.value(forKey: AppBundlesConstants.Bundle.B.Keys.Bundle.messaging) { - let headerVC = self.stackItemContainer?.header as! HeaderViewController - headerVC.updateWithProgressMessage(statusText: valueEssentialsBundleMessaging as! String) - } - - if let valueEssentialsBundleIndicator = UserDefaults.standard.value(forKey: AppBundlesConstants.Bundle.B.Keys.Bundle.status) { - let headerVC = self.stackItemContainer?.header as! HeaderViewController - switch String(describing: valueEssentialsBundleIndicator) { - case "0" : - headerVC.updateWithProgressIndicator(progressIndicator: .inQueue) - case "1" : - headerVC.updateWithProgressIndicator(progressIndicator: .inProgressAnimated) - if anchorStopHeader == 0 { - headerVC.bundleProgressIndicator.determineAnchorPoint(indicator: headerVC.bundleProgressIndicator) - } - anchorStopHeader = 1 - headerVC.bundleProgressIndicator.rotate() - case "2" : - headerVC.bundleProgressIndicator.stopRotation() - let sumArray = totalBundleResult.reduce(0, +) - let avgArrayValue = sumArray / Double(totalBundleResult.count) - if avgArrayValue == 1.0 { - headerVC.updateWithProgressIndicator(progressIndicator: .success) - } - else if avgArrayValue == 0.0 { - headerVC.updateWithProgressIndicator(progressIndicator: .failure) - UserDefaults.standard.set(1, forKey: AppBundlesConstants.Keys.AppInstallScreen.warning) - } - else { - headerVC.updateWithProgressIndicator(progressIndicator: .partial) - UserDefaults.standard.set(1, forKey: AppBundlesConstants.Keys.AppInstallScreen.warning) - } - default: - return - } - UserDefaults.standard.synchronize() - } - } -} diff --git a/enrollment/enrollment/Controllers/Phase 1 Bundle Installation/BundleCProgressStackItemViewController.swift b/enrollment/enrollment/Controllers/Phase 1 Bundle Installation/BundleCProgressStackItemViewController.swift deleted file mode 100644 index 926a53b..0000000 --- a/enrollment/enrollment/Controllers/Phase 1 Bundle Installation/BundleCProgressStackItemViewController.swift +++ /dev/null @@ -1,115 +0,0 @@ -// -// BundleCProgressStackItemViewController.swift -// enrollment -// -// Created by Jay Latman on 8/28/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -class BundleCProgressStackItemViewController: BaseViewController { - - @IBOutlet weak var progressIndicatorApp1: CircularStatus! - @IBOutlet weak var progressIndicatorApp2: CircularStatus! - @IBOutlet weak var progressIndicatorApp3: CircularStatus! - - @IBOutlet weak var app1NameTextLabel: NSTextField! - @IBOutlet weak var app2NameTextLabel: NSTextField! - @IBOutlet weak var app3NameTextLabel: NSTextField! - - private var anchorStopApp1 = 0 - private var anchorStopApp2 = 0 - private var anchorStopApp3 = 0 - private var anchorStopHeader = 0 - - private var totalBundleResult: Array = [Double](repeating: 0.0, count: AppBundlesConstants.Bundle.C.InfoPopover.titles.count) - - override func headerTitle() -> String { - return NSLocalizedString(AppBundlesConstants.Bundle.C.InfoPopover.header.capitalized, comment: "") - } - - override func viewDidLoad() { - super.viewDidLoad() - progressIndicatorApp1.state = .appInQueue - progressIndicatorApp2.state = .appInQueue - progressIndicatorApp3.state = .appInQueue - var _ = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: true) { (Timer) in - self.updateUI() - } - } - - override func viewWillLayout() { - layoutSetup() - setTextFields() - } - - private func layoutSetup() { - progressIndicatorApp1.fadeTransition(2.0) - progressIndicatorApp2.fadeTransition(2.0) - progressIndicatorApp3.fadeTransition(2.0) - } - - private func setTextFields() { - app1NameTextLabel.set(label: AppBundlesConstants.Bundle.C.InfoPopover.titles[0], color: .controlTextColor) - app2NameTextLabel.set(label: AppBundlesConstants.Bundle.C.InfoPopover.titles[1], color: .controlTextColor) - app3NameTextLabel.set(label: AppBundlesConstants.Bundle.C.InfoPopover.titles[2], color: .controlTextColor) - } - - private func updateUI() { - _ = UpdateUIForAppStatus(appStatusKey: AppBundlesConstants.Bundle.C.Keys.Bundle.AppStatus.app1, - appIndicator: progressIndicatorApp1, - anchorStop: &anchorStopApp1, - totalBundleResult: &totalBundleResult, - index: 0) - _ = UpdateUIForAppStatus(appStatusKey: AppBundlesConstants.Bundle.C.Keys.Bundle.AppStatus.app2, - appIndicator: progressIndicatorApp2, - anchorStop: &anchorStopApp2, - totalBundleResult: &totalBundleResult, - index: 1) - _ = UpdateUIForAppStatus(appStatusKey: AppBundlesConstants.Bundle.C.Keys.Bundle.AppStatus.app3, - appIndicator: progressIndicatorApp3, - anchorStop: &anchorStopApp3, - totalBundleResult: &totalBundleResult, - index: 2) - - if let valueProductivityBundleMessaging = UserDefaults.standard.value(forKey: AppBundlesConstants.Bundle.C.Keys.Bundle.messaging) { - let headerVC = self.stackItemContainer?.header as! HeaderViewController - headerVC.updateWithProgressMessage(statusText: valueProductivityBundleMessaging as! String) - } - - if let valueProductivityBundleIndicator = UserDefaults.standard.value(forKey: AppBundlesConstants.Bundle.C.Keys.Bundle.status) { - let headerVC = self.stackItemContainer?.header as! HeaderViewController - switch String(describing: valueProductivityBundleIndicator) { - case "0" : - headerVC.updateWithProgressIndicator(progressIndicator: .inQueue) - case "1" : - headerVC.updateWithProgressIndicator(progressIndicator: .inProgressAnimated) - if anchorStopHeader == 0 { - headerVC.bundleProgressIndicator.determineAnchorPoint(indicator: headerVC.bundleProgressIndicator) - } - anchorStopHeader = 1 - headerVC.bundleProgressIndicator.rotate() - case "2" : - headerVC.bundleProgressIndicator.stopRotation() - let sumArray = totalBundleResult.reduce(0, +) - let avgArrayValue = sumArray / Double(totalBundleResult.count) - if avgArrayValue == 1.0 { - headerVC.updateWithProgressIndicator(progressIndicator: .success) - } - else if avgArrayValue == 0.0 { - headerVC.updateWithProgressIndicator(progressIndicator: .failure) - UserDefaults.standard.set(1, forKey: AppBundlesConstants.Keys.AppInstallScreen.warning) - } - else { - headerVC.updateWithProgressIndicator(progressIndicator: .partial) - UserDefaults.standard.set(1, forKey: AppBundlesConstants.Keys.AppInstallScreen.warning) - } - default: - return - } - UserDefaults.standard.synchronize() - } - } -} diff --git a/enrollment/enrollment/Controllers/Phase 1 Bundle Installation/BundleInstallationChildViewController.swift b/enrollment/enrollment/Controllers/Phase 1 Bundle Installation/BundleInstallationChildViewController.swift deleted file mode 100644 index 73c8a92..0000000 --- a/enrollment/enrollment/Controllers/Phase 1 Bundle Installation/BundleInstallationChildViewController.swift +++ /dev/null @@ -1,174 +0,0 @@ -// -// BundleInstallationChildViewController.swift -// enrollment -// -// Created by Jay Latman on 9/2/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -class BundleInstallationChildViewController: NSViewController, StackItemHost { - - @IBOutlet weak var headerMessageTextLabel: NSTextField! - @IBOutlet weak var errorMessageTextLabel: NSTextField! - @IBOutlet weak var estimatedTimeRemainingMessageTextLabel: NSTextField! - @IBOutlet weak var estimatedTimeRemainingLabel: NSTextField! - @IBOutlet weak var bundleStack: CustomStackView! - - @IBOutlet weak var nextButton: NSButton! - - var installClock = Double() - var myContext = 0 - - var installProgress: Progress? { - willSet { - guard let oldProgress = installProgress else { return } - oldProgress.removeObserver(self, - forKeyPath: AppBundlesConstants.Keys.AppInstallScreen.status, - context: &myContext) - } - didSet { - guard let newProgress = installProgress else { return } - newProgress.addObserver(self, - forKeyPath: AppBundlesConstants.Keys.AppInstallScreen.status, - options: .new, - context: &myContext) - } - } - - deinit { - installProgress?.removeObserver(self, - forKeyPath: AppBundlesConstants.Keys.AppInstallScreen.status, - context: &myContext) - } - - override func viewDidLoad() { - super.viewDidLoad() - createInstallTimeClockFromBundleSelectionController() - addObservers() - layoutSetup() - setTextFields() - XPCService.sharedInstance.processJAMFAction(event: JAMFPolicyEventID.softwareInstall) - var _ = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { (Timer) in - self.updateCounter() - } - } - - private func setTextFields() { - headerMessageTextLabel.set(label: BundleInstallationChildVC_Constants.header, color: .headerTextColor) - errorMessageTextLabel.set(label: AlertText.BundleInstallationWarning.message, color: .controlTextColor) - estimatedTimeRemainingLabel.stringValue = BundleInstallationChildVC_Constants.estimatedTimeRemainingMessageTextLabel - estimatedTimeRemainingMessageTextLabel.textColor = .headerTextColor - estimatedTimeRemainingLabel.textColor = .headerTextColor - } - - override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { - if keyPath == AppBundlesConstants.Keys.AppInstallScreen.status { - if context == &myContext { - if UserDefaults.standard.integer(forKey: AppBundlesConstants.Keys.AppInstallScreen.warning) == 1 { - errorMessageTextLabel.fadeTransition(0.25) - errorMessageTextLabel.isHidden = false - } - enableUIForAdvancementToNextScreen() - } - DispatchQueue.main.async { - self.view.needsDisplay = true - } - } - } - - private func createInstallTimeClockFromBundleSelectionController() { - if UserDefaults.standard.string(forKey: AppBundlesConstants.Keys.installClockTotal) != nil { - let clockStartTimeInSeconds = Double(UserDefaults.standard.string(forKey: AppBundlesConstants.Keys.installClockTotal)!) - estimatedTimeRemainingLabel.stringValue = clockFormatter(totalTimeInSeconds: clockStartTimeInSeconds!) - installClock = clockStartTimeInSeconds! - } - } - - private func layoutSetup() { - bundleStack.setHuggingPriority(NSLayoutConstraint.Priority.defaultHigh, for: .horizontal) - var bundleChoiceArray = [String]() - - if let bundleChoiceSelection = (UserDefaults.standard.array(forKey: AppBundlesConstants.Keys.bundleArrayKey)!) as? [String] { - for bundleChoice in bundleChoiceSelection { - bundleChoiceArray.append(bundleChoice) - } - } - - if bundleChoiceArray.contains(AppBundlesConstants.PersistanceArrayMember.a) { - addViewController(withIdentifier: "BundleAProgressStackItemViewController") - } - if bundleChoiceArray.contains(AppBundlesConstants.PersistanceArrayMember.b) { - addViewController(withIdentifier: "BundleBProgressStackItemViewController") - } - if bundleChoiceArray.contains(AppBundlesConstants.PersistanceArrayMember.c) { - addViewController(withIdentifier: "BundleCProgressStackItemViewController") - } - } - - private func addViewController(withIdentifier identifier: String) { - let storyboard = NSStoryboard(name: "StackItems", bundle: nil) - let viewController = storyboard.instantiateController(withIdentifier: identifier) as! BaseViewController - - let stackItem = viewController.stackItemContainer! - stackItem.header.disclose = { - self.disclose(viewController.stackItemContainer!) - } - - bundleStack.addArrangedSubview(stackItem.header.viewController.view) - bundleStack.addArrangedSubview(stackItem.body.viewController.view) - - addChild(stackItem.body.viewController) - addChild(stackItem.header.viewController) - - switch stackItem.state { - case .open: show(stackItem, animated: false) - case .closed: hide(stackItem, animated: false) - } - } - - private func enableUIForAdvancementToNextScreen() { - estimatedTimeRemainingMessageTextLabel.fadeTransition(0.25) - estimatedTimeRemainingLabel.fadeTransition(0.25) - nextButton.fadeTransition(0.25) - nextButton.isEnabled = true - estimatedTimeRemainingMessageTextLabel.isHidden = true - estimatedTimeRemainingLabel.isHidden = true - } - - private func addObservers() { - UserDefaults.standard.addObserver(self, forKeyPath: AppBundlesConstants.Keys.AppInstallScreen.status, options: .new, context: &myContext) - } - - private func updateCounter() { - if (installClock > 0) { - estimatedTimeRemainingLabel.stringValue = clockFormatter(totalTimeInSeconds: installClock) - installClock -= 1 - self.view.needsDisplay = true - } - } - - private func clockFormatter(totalTimeInSeconds: Double) -> String { - - let duration: TimeInterval = Double(totalTimeInSeconds) - - let formatter = DateComponentsFormatter() - formatter.unitsStyle = .full - formatter.allowedUnits = [ .day, .hour, .minute] - formatter.zeroFormattingBehavior = [.dropAll] - - let formattedDuration = formatter.string(from: duration) - return formattedDuration! - } - - @IBAction func nextButtonClicked(_ sender: NSButton) { - UserDefaults.standard.set("2", forKey: StartingPointID.Keys.phase) - performSegue(withIdentifier: SegueDestinationID.ForwardTo.setupCompleteChildViewController, sender: self) - } -} - -class CustomStackView: NSStackView { - override var isFlipped: Bool { return true } -} diff --git a/enrollment/enrollment/Controllers/Phase 1 Bundle Installation/BundleSelectionChildViewController.swift b/enrollment/enrollment/Controllers/Phase 1 Bundle Installation/BundleSelectionChildViewController.swift deleted file mode 100644 index ba96cff..0000000 --- a/enrollment/enrollment/Controllers/Phase 1 Bundle Installation/BundleSelectionChildViewController.swift +++ /dev/null @@ -1,392 +0,0 @@ -// -// BundleSelectionChildViewController.swift -// enrollment -// -// Created by Jay Latman on 8/2/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -class BundleSelectionChildViewController: NSViewController { - - @IBOutlet weak var headerMessageTextLabel: NSTextField! - @IBOutlet weak var subheaderMessageTextLabel: NSTextField! - @IBOutlet weak var recommendedLabel: NSTextField! - - @IBOutlet weak var aToggle: NSButton! - @IBOutlet weak var bToggle: NSButton! - @IBOutlet weak var cToggle: NSButton! - - @IBOutlet weak var aToggleDescription: NSTextField! - @IBOutlet weak var bToggleDescription: NSTextField! - @IBOutlet weak var cToggleDescription: NSTextField! - - @IBOutlet weak var aDownloadTimeLabel: NSTextField! - @IBOutlet weak var bDownloadTimeLabel: NSTextField! - @IBOutlet weak var cDownloadTimeLabel: NSTextField! - @IBOutlet weak var totalDownloadTimeLabel: NSTextField! - - - @IBOutlet weak var essentialsInfoButton: NSButton! - @IBOutlet weak var productivityInfoButton: NSButton! - @IBOutlet weak var installSelectedBundlesButton: NSButton! - @IBOutlet weak var skipButton: NSButton! - - var returnCode = String() - var jpsCheckResult = Int() - var jpsHealthCheckServiceURL: String = JPSPaths.HealthCheckURLs.Prod.healthCheckURL - - var totalInstallTime = [Double](repeating: 0.0, count: 3) - var totalBundleSize = [Double](repeating: 0.0, count: 3) - - let cancelHeader: String = AlertText.BundleSelectionWarning.header - let cancelMessage: String = AlertText.BundleSelectionWarning.message - - private var bundleToggleButtons: [NSButton]! - - var bundleChoiceSelected: Set = [] - - override func viewDidLoad() { - super.viewDidLoad() - layoutSetup() - setTextFields() - } - - override func viewWillAppear() { - super.viewWillAppear() - bundleToggleButtons = [aToggle, bToggle, cToggle] - } - - private func layoutSetup() { - aToggle.set(toggleLabel: " " + BundleSelectionChildVC_Constants.Toggle.Title.a, underline: 0) - bToggle.set(toggleLabel: " " + BundleSelectionChildVC_Constants.Toggle.Title.b, underline: 0) - cToggle.set(toggleLabel: " " + BundleSelectionChildVC_Constants.Toggle.Title.c, underline: 0) - essentialsInfoButton.image = InfoBubble.imageOfInfo_bubble - productivityInfoButton.image = InfoBubble.imageOfInfo_bubble - setKeysToFactoryDefaults() - checkForEmptyChoiceArrayAndSetButtonDisplay() - displayIndividualDownloadTimes() - - if let speedTestResult = UserDefaults.standard.string(forKey: AppBundlesConstants.Keys.speedRate) { - let totalDownloadTime = displayTotalDownloadtime(speedTestRate: Double(speedTestResult)!) - totalDownloadTimeLabel.stringValue = "+ \(totalDownloadTime)" - } - } - - private func setTextFields() { - headerMessageTextLabel.set(label: BundleSelectionChildVC_Constants.header, color: .headerTextColor) - subheaderMessageTextLabel.set(label: BundleSelectionChildVC_Constants.subheader, color: .controlTextColor) - recommendedLabel.set(label: BundleSelectionChildVC_Constants.recommend_label, color: .systemRed) - aToggleDescription.set(label: BundleSelectionChildVC_Constants.Toggle.Description.a, color: .controlTextColor) - bToggleDescription.set(label: BundleSelectionChildVC_Constants.Toggle.Description.b, color: .controlTextColor) - cToggleDescription.set(label: BundleSelectionChildVC_Constants.Toggle.Description.c, color: .controlTextColor) - totalDownloadTimeLabel.textColor = .headerTextColor - let controlTextFields = [aDownloadTimeLabel, bDownloadTimeLabel, cDownloadTimeLabel] - for i in controlTextFields { - i?.textColor = .controlTextColor - } - } - - private func setKeysToFactoryDefaults() { - UserDefaults.standard.set(false, forKey: AppBundlesConstants.Keys.AppInstallScreen.status) - UserDefaults.standard.set(false, forKey: AppBundlesConstants.Keys.AppInstallScreen.warning) - UserDefaults.standard.set(0, forKey: AppBundlesConstants.Bundle.A.Keys.Bundle.status) - UserDefaults.standard.set(0, forKey: AppBundlesConstants.Bundle.B.Keys.Bundle.status) - UserDefaults.standard.set(0, forKey: AppBundlesConstants.Bundle.C.Keys.Bundle.status) - UserDefaults.standard.set("", forKey: AppBundlesConstants.Bundle.A.Keys.Bundle.messaging) - UserDefaults.standard.set("", forKey: AppBundlesConstants.Bundle.B.Keys.Bundle.messaging) - UserDefaults.standard.set("", forKey: AppBundlesConstants.Bundle.C.Keys.Bundle.messaging) - UserDefaults.standard.set(0, forKey: AppBundlesConstants.Bundle.A.Keys.Bundle.AppStatus.app1) - UserDefaults.standard.set(0, forKey: AppBundlesConstants.Bundle.B.Keys.Bundle.AppStatus.app1) - UserDefaults.standard.set(0, forKey: AppBundlesConstants.Bundle.B.Keys.Bundle.AppStatus.app2) - UserDefaults.standard.set(0, forKey: AppBundlesConstants.Bundle.B.Keys.Bundle.AppStatus.app3) - UserDefaults.standard.set(0, forKey: AppBundlesConstants.Bundle.B.Keys.Bundle.AppStatus.app4) - UserDefaults.standard.set(0, forKey: AppBundlesConstants.Bundle.C.Keys.Bundle.AppStatus.app1) - UserDefaults.standard.set(0, forKey: AppBundlesConstants.Bundle.C.Keys.Bundle.AppStatus.app2) - UserDefaults.standard.set(0, forKey: AppBundlesConstants.Bundle.C.Keys.Bundle.AppStatus.app3) - UserDefaults.standard.set(Array(bundleChoiceSelected), forKey: AppBundlesConstants.Keys.bundleArrayKey) - UserDefaults.standard.synchronize() - } - - private func checkForEmptyChoiceArrayAndSetButtonDisplay() { - if let bundleArray = UserDefaults.standard.array(forKey: AppBundlesConstants.Keys.bundleArrayKey) { - skipButton.fadeTransition(0.25) - installSelectedBundlesButton.fadeTransition(0.25) - if (bundleArray.count ) > 0 { - BundleInstallButtonVisibility.displayButtons(label: totalDownloadTimeLabel, - labelState: false, - installButton: installSelectedBundlesButton, - installButtonState: false, - skipButton: skipButton, - skipButtonState: true) - } else { - BundleInstallButtonVisibility.displayButtons(label: totalDownloadTimeLabel, - labelState: true, - installButton: installSelectedBundlesButton, - installButtonState: true, - skipButton: skipButton, skipButtonState: false) - } - } - } - - private func timeForDownload(speedTestRate: Double, bundleSize: Double, bundleInstallTimeInSeconds: Double, jamfComBufferTimeInSeconds: Double) -> String { - - let duration: TimeInterval = ((bundleSize / speedTestRate) + bundleInstallTimeInSeconds + jamfComBufferTimeInSeconds) - - let formatter = DateComponentsFormatter() - formatter.unitsStyle = .full - formatter.allowedUnits = [ .day, .hour, .minute] - formatter.zeroFormattingBehavior = [.dropAll] - - let formattedDuration = formatter.string(from: duration) - return formattedDuration! - } - - private func returnTotalDownloadTimeInSeconds(speedTestRate: Double) -> Double{ - let bundleSizes = totalBundleSize - let bundleInstallTimeTotal = totalInstallTime - - guard let jamfBufferTime = UserDefaults.standard.string(forKey: AppBundlesConstants.Keys.jamfBufferTime) else { - return 1 - } - - let totalJAMFBufferTime = Double(jamfBufferTime)! * Double(bundleChoiceSelected.count) - - let sum = bundleSizes.reduce(0, +) - let installTimeSum = bundleInstallTimeTotal.reduce(0, +) - - let duration: TimeInterval = ((sum / speedTestRate) + installTimeSum + totalJAMFBufferTime) - - return duration - } - - private func displayTotalDownloadtime(speedTestRate: Double) -> String{ - let bundleSizes = totalBundleSize - let bundleInstallTimeTotal = totalInstallTime - - guard let jamfBuffer = UserDefaults.standard.string(forKey: AppBundlesConstants.Keys.jamfBufferTime) else { - return String(60) - } - let jamfBufferTimeTotal = Double(bundleChoiceSelected.count) * Double(jamfBuffer)! - - let sum = bundleSizes.reduce(0, +) - let installTimeSum = bundleInstallTimeTotal.reduce(0, +) - - - let duration: TimeInterval = ((sum / speedTestRate) + installTimeSum + jamfBufferTimeTotal) - - let formatter = DateComponentsFormatter() - formatter.unitsStyle = .full - formatter.allowedUnits = [ .day, .hour, .minute] - formatter.zeroFormattingBehavior = [.dropAll] - - let formattedDurationForSum = formatter.string(from: duration) - return formattedDurationForSum! - } - - private func syncToggleStateWithSelectionArray(bundleToggle: NSButton, bundleArrayMemberName: String, bundleSize: String, bundleInstallTimeInSeconds: String, index: Int) { - if bundleToggle.state == .on { - bundleChoiceSelected.insert(bundleArrayMemberName) - if let bundleSize = UserDefaults.standard.string(forKey: bundleSize) { - if let bundleInstallTimeInSeconds = UserDefaults.standard.string(forKey: bundleInstallTimeInSeconds) { - totalBundleSize[index] = Double(bundleSize)! - totalInstallTime[index] = Double(bundleInstallTimeInSeconds)! - } - } else { - totalBundleSize[index] = 0.0 - totalInstallTime[index] = 0.0 - } - } else { - bundleChoiceSelected.remove(bundleArrayMemberName) - totalBundleSize[index] = 0.0 - totalInstallTime[index] = 0.0 - } - UserDefaults.standard.set(Array(bundleChoiceSelected), forKey: AppBundlesConstants.Keys.bundleArrayKey) - UserDefaults.standard.synchronize() - if let speedTestResult = UserDefaults.standard.string(forKey: AppBundlesConstants.Keys.speedRate) { - - let totalDownloadTime = displayTotalDownloadtime(speedTestRate: Double(speedTestResult)!) - totalDownloadTimeLabel.fadeTransition(0.25) - totalDownloadTimeLabel.stringValue = "+ \(totalDownloadTime)" - } - checkForEmptyChoiceArrayAndSetButtonDisplay() - } - - private func factorIndvidualBundleDownloadTime(bundleDownloadTimeLabel: NSTextField, - speedTestResult: String, - jamfBufferTime: String, - bundleSize: String, - bundleInstallTimeInSeconds: String, - bundleArrayIndex: Int) { - if let bundleSize = UserDefaults.standard.string(forKey: bundleSize) { - if let bundleInstallTimeInSeconds = UserDefaults.standard.string(forKey: bundleInstallTimeInSeconds) { - bundleDownloadTimeLabel.stringValue = "+ \(timeForDownload(speedTestRate: Double(speedTestResult)!, bundleSize: Double(bundleSize)!, bundleInstallTimeInSeconds: Double(bundleInstallTimeInSeconds)!, jamfComBufferTimeInSeconds: Double(jamfBufferTime)!))" - } - } - } - - private func displayIndividualDownloadTimes() { - if let speedTestResult = UserDefaults.standard.string(forKey: AppBundlesConstants.Keys.speedRate) { - if let jamfBufferTime = UserDefaults.standard.string(forKey: AppBundlesConstants.Keys.jamfBufferTime) { - factorIndvidualBundleDownloadTime(bundleDownloadTimeLabel: aDownloadTimeLabel, - speedTestResult: speedTestResult, - jamfBufferTime: jamfBufferTime, - bundleSize: AppBundlesConstants.Bundle.A.DownloadTime.size, - bundleInstallTimeInSeconds: AppBundlesConstants.Bundle.A.DownloadTime.time, - bundleArrayIndex: 0) - factorIndvidualBundleDownloadTime(bundleDownloadTimeLabel: bDownloadTimeLabel, - speedTestResult: speedTestResult, - jamfBufferTime: jamfBufferTime, - bundleSize: AppBundlesConstants.Bundle.B.DownloadTime.size, - bundleInstallTimeInSeconds: AppBundlesConstants.Bundle.B.DownloadTime.time, - bundleArrayIndex: 1) - factorIndvidualBundleDownloadTime(bundleDownloadTimeLabel: cDownloadTimeLabel, - speedTestResult: speedTestResult, - jamfBufferTime: jamfBufferTime, - bundleSize: AppBundlesConstants.Bundle.C.DownloadTime.size, - bundleInstallTimeInSeconds: AppBundlesConstants.Bundle.C.DownloadTime.time, - bundleArrayIndex: 2) - } - } - } - - private func dialogOKCancel(question: String, text: String) -> Bool { - let alert = NSAlert() - alert.messageText = cancelHeader - alert.informativeText = cancelMessage - alert.alertStyle = .critical - if let speedTestResult = UserDefaults.standard.string(forKey: AppBundlesConstants.Keys.speedRate) { - let totalDownloadTime = displayTotalDownloadtime(speedTestRate: Double(speedTestResult)!) - alert.informativeText = "\(cancelMessage) \n \n Estimated install time : \(totalDownloadTime)" - } - alert.addButton(withTitle: "No") - alert.addButton(withTitle: "Yes") - alert.beginSheetModal(for: NSApp.keyWindow!, completionHandler: { [unowned self] (returnCode) -> Void in - if returnCode == NSApplication.ModalResponse.alertSecondButtonReturn { - self.returnCode = "Yes" - if let speedTestResult = UserDefaults.standard.string(forKey: AppBundlesConstants.Keys.speedRate) { - let totalDownloadTimeInSeconds = self.returnTotalDownloadTimeInSeconds(speedTestRate: Double(speedTestResult)!) - UserDefaults.standard.set(String(totalDownloadTimeInSeconds), forKey: AppBundlesConstants.Keys.installClockTotal) - } - self.performSegue(withIdentifier: SegueDestinationID.ForwardTo.bundleInstallationChildViewController, sender: self) - } else { - self.returnCode = "No" - } - }) - return true - } - - override func prepare(for segue: NSStoryboardSegue, sender: Any?) { - if segue.identifier! == SegueDestinationID.Popover.BundleSelectionChildViewController.essentials { - let popoverVC: BundlePopOverViewController = segue.destinationController as! BundlePopOverViewController - let bundleInfo = DefineBundleInfoPopover.init( - bundleTitle: AppBundlesConstants.Bundle.B.InfoPopover.header, - bundleDescription: AppBundlesConstants.Bundle.B.InfoPopover.mainDescription, - appTitles: AppBundlesConstants.Bundle.B.InfoPopover.titles, - appDescriptions: AppBundlesConstants.Bundle.B.InfoPopover.descriptions, - appIcons: AppBundlesConstants.Bundle.B.InfoPopover.icons) - - popoverVC.recievedBundleTitleString = bundleInfo.bundleTitle - popoverVC.recievedBundleDescriptionString = bundleInfo.descriptionText - popoverVC.recievedListOfTitles = bundleInfo.appTitles - popoverVC.recievedListOfDescriptions = bundleInfo.appDescriptions - popoverVC.recievedListOfIcons = bundleInfo.appIcons - } - - if segue.identifier! == SegueDestinationID.Popover.BundleSelectionChildViewController.productivity { - let popoverVC: BundlePopOverViewController = segue.destinationController as! BundlePopOverViewController - let bundleInfo = DefineBundleInfoPopover.init( - bundleTitle: AppBundlesConstants.Bundle.C.InfoPopover.header, - bundleDescription: AppBundlesConstants.Bundle.C.InfoPopover.mainDescription, - appTitles: AppBundlesConstants.Bundle.C.InfoPopover.titles, - appDescriptions: AppBundlesConstants.Bundle.C.InfoPopover.descriptions, - appIcons: AppBundlesConstants.Bundle.C.InfoPopover.icons) - - popoverVC.recievedBundleTitleString = bundleInfo.bundleTitle - popoverVC.recievedBundleDescriptionString = bundleInfo.descriptionText - popoverVC.recievedListOfTitles = bundleInfo.appTitles - popoverVC.recievedListOfDescriptions = bundleInfo.appDescriptions - popoverVC.recievedListOfIcons = bundleInfo.appIcons - } - } - - @IBAction func aToggleClicked(_ sender: NSButton) { - syncToggleStateWithSelectionArray(bundleToggle: aToggle, - bundleArrayMemberName: AppBundlesConstants.PersistanceArrayMember.a, - bundleSize: AppBundlesConstants.Bundle.A.DownloadTime.size, - bundleInstallTimeInSeconds: AppBundlesConstants.Bundle.A.DownloadTime.time, - index: 0) - } - - @IBAction func bToggleClicked(_ sender: NSButton) { - syncToggleStateWithSelectionArray(bundleToggle: bToggle, - bundleArrayMemberName: AppBundlesConstants.PersistanceArrayMember.b, - bundleSize: AppBundlesConstants.Bundle.B.DownloadTime.size, - bundleInstallTimeInSeconds: AppBundlesConstants.Bundle.B.DownloadTime.time, - index: 1) - } - - @IBAction func cToggleClicked(_ sender: NSButton) { - syncToggleStateWithSelectionArray(bundleToggle: cToggle, - bundleArrayMemberName: AppBundlesConstants.PersistanceArrayMember.c, - bundleSize: AppBundlesConstants.Bundle.C.DownloadTime.size, - bundleInstallTimeInSeconds: AppBundlesConstants.Bundle.C.DownloadTime.time, - index: 2) - } - - @IBAction func essentialsInfoButtonClicked(_ sender: NSButton) { - self.performSegue(withIdentifier: SegueDestinationID.Popover.BundleSelectionChildViewController.essentials, sender: self) - } - - @IBAction func productivityInfoButtonClicked(_ sender: NSButton) { - self.performSegue(withIdentifier: SegueDestinationID.Popover.BundleSelectionChildViewController.productivity, sender: self) - } - - @IBAction func skipButtonClicked(_ sender: NSButton) { - self.performSegue(withIdentifier: SegueDestinationID.SkipTo.setupCompleteChildViewConroller, sender: self) - } - - @IBAction func installSelectedBundlesButtonClicked(_ sender: NSButton) { - let dispatchGroup = DispatchGroup() - if NetworkValidationService.sharedInstance.isConnectedToNetwork() == true { - if let env = UserDefaults.standard.string(forKey: BundleSelectionChildVC_Constants.Keys.environment) { - if env == "eng" { - jpsHealthCheckServiceURL = JPSPaths.HealthCheckURLs.Eng.healthCheckURL - } - if env == "qa" { - jpsHealthCheckServiceURL = JPSPaths.HealthCheckURLs.QA.healthCheckURL - } - if env == "prod" { - jpsHealthCheckServiceURL = JPSPaths.HealthCheckURLs.Prod.healthCheckURL - } - } - dispatchGroup.enter() - NetworkValidationService.sharedInstance.checkForJPSAvailability(jpsURL: jpsHealthCheckServiceURL) { (result) -> () in - self.jpsCheckResult = result - dispatchGroup.leave() - } - - dispatchGroup.notify(queue: .main) { - if self.jpsCheckResult != 200 { - IssueAlertService.sharedInstance.displaySheetNetworkUnreachable(message: AlertText.NetworkValidationMessaging.External.jps) - } else { - if self.bundleChoiceSelected.count >= 1 { - if let speedTestResult = UserDefaults.standard.string(forKey: AppBundlesConstants.Keys.speedRate) { - let totalDownloadTimeInSeconds = self.returnTotalDownloadTimeInSeconds(speedTestRate: Double(speedTestResult)!) - UserDefaults.standard.set(String(totalDownloadTimeInSeconds), forKey: AppBundlesConstants.Keys.installClockTotal) - if self.returnTotalDownloadTimeInSeconds(speedTestRate: Double(speedTestResult)!) > CalculationThresholds.estimatedDownloadTimeInSecondsThreshold { - _ = self.dialogOKCancel(question: "Ok?", text: "Choose your answer.") - } else { - self.performSegue(withIdentifier: SegueDestinationID.ForwardTo.bundleInstallationChildViewController, sender: self) - } - } - } - } - } - } else { - IssueAlertService.sharedInstance.displaySheetNetworkUnreachable(message: AlertText.NetworkValidationMessaging.External.network) - } - } -} diff --git a/enrollment/enrollment/Controllers/Phase 1 Bundle Installation/HeaderViewController.swift b/enrollment/enrollment/Controllers/Phase 1 Bundle Installation/HeaderViewController.swift deleted file mode 100644 index d0ea491..0000000 --- a/enrollment/enrollment/Controllers/Phase 1 Bundle Installation/HeaderViewController.swift +++ /dev/null @@ -1,62 +0,0 @@ -// -// HeaderViewController.swift -// enrollment -// -// Created by Jay Latman on 8/22/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -class HeaderViewController: NSViewController, StackItemHeader { - - @IBOutlet weak var bundleProgressIndicator: CircularStatus! - @IBOutlet weak var headerTextLabel: NSTextField! - @IBOutlet weak var statusTextLabel: NSTextField! - @IBOutlet weak var discloseButton: NSButton! - - var disclose: (() -> ())? - - override func viewDidLoad() { - super.viewDidLoad() - setTextFields() - } - - internal func setTextFields() { - headerTextLabel.set(label: title!, color: .headerTextColor) - statusTextLabel.textColor = .controlTextColor - } - - internal func update(toDiscloseState: StackItemContainer.DiscloseState) { - switch toDiscloseState { - case .open: - discloseButton.title = BundleInstallationChildVC_Constants.DisclosureButtonLabelText.open - case .closed: - discloseButton.title = BundleInstallationChildVC_Constants.DisclosureButtonLabelText.closed - } - discloseButton.set(textColor: .linkColor, underline: NSUnderlineStyle.init(rawValue: 0).rawValue) - } - - internal func updateWithProgressIndicatorAndMessage(progressIndicator: StatusState, statusText: String) { - statusTextLabel.fadeTransition(0.20) - bundleProgressIndicator.fadeTransition(0.20) - statusTextLabel.stringValue = statusText - bundleProgressIndicator.state = progressIndicator - } - - internal func updateWithProgressMessage(statusText: String) { - statusTextLabel.fadeTransition(0.20) - statusTextLabel.stringValue = statusText - } - - internal func updateWithProgressIndicator(progressIndicator: StatusState) { - bundleProgressIndicator.fadeTransition(0.20) - bundleProgressIndicator.state = progressIndicator - } - - @IBAction func discloseButtonClicked(_ sender: NSButton) { - disclose?() - } - -} diff --git a/enrollment/enrollment/Controllers/Phase 1 Bundle Installation/StackView.swift b/enrollment/enrollment/Controllers/Phase 1 Bundle Installation/StackView.swift deleted file mode 100644 index c09b493..0000000 --- a/enrollment/enrollment/Controllers/Phase 1 Bundle Installation/StackView.swift +++ /dev/null @@ -1,101 +0,0 @@ -// -// StackView.swift -// enrollment -// -// Created by Jay on 8/22/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -protocol StackItemHost: class { - func disclose(_ stackItem: StackItemContainer) -} - -protocol StackItemHeader: class { - var viewController: NSViewController { get } - var disclose: (() -> ())? { get set } - func update(toDiscloseState: StackItemContainer.DiscloseState) -} - -protocol StackItemBody: class { - var viewController: NSViewController { get } - func show(animated: Bool) - func hide(animated: Bool) -} - -extension StackItemHost { - func disclose(_ stackItem: StackItemContainer) { - switch stackItem.state { - case .open: - hide(stackItem, animated: true) - stackItem.state = .closed - case .closed: - show(stackItem, animated: true) - stackItem.state = .open - } - stackItem.header.update(toDiscloseState: stackItem.state) - } - - func show(_ stackItem: StackItemContainer, animated: Bool) { - stackItem.body.show(animated: animated) - stackItem.header.update(toDiscloseState: .open) - } - - func hide(_ stackItem: StackItemContainer, animated: Bool) { - stackItem.body.hide(animated: animated) - stackItem.header.update(toDiscloseState: .closed) - } -} - -extension StackItemHeader where Self: NSViewController { - var viewController: NSViewController { return self } -} - -extension StackItemBody where Self: NSViewController { - var viewController: NSViewController { return self } - func animateDisclosure(disclose: Bool, animated: Bool) { - let viewController = self as! BaseViewController - if let constraint = viewController.bundleProgressStackHeightConstraint { - let heightValue = disclose ? viewController.savedDefaultHeight : 0 - - if animated { - NSAnimationContext.runAnimationGroup({ (context) -> Void in - context.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut) - constraint.animator().constant = heightValue - }, completionHandler: { - () -> Void in - }) - } else { - constraint.constant = heightValue - } - } - } - - func show(animated: Bool) { - animateDisclosure(disclose: true, animated: animated) - } - - func hide(animated: Bool) { - animateDisclosure(disclose: false, animated: animated) - } -} - - - class StackItemContainer { - enum DiscloseState: Int { - case open = 0 - case closed = 1 - } - - let header: StackItemHeader - var state: DiscloseState - let body: StackItemBody - - init(header: StackItemHeader, body: StackItemBody, state: DiscloseState) { - self.header = header - self.body = body - self.state = state - } -} diff --git a/enrollment/enrollment/Controllers/Phase 2 Education/LinkOutItemCell.swift b/enrollment/enrollment/Controllers/Phase 2 Education/LinkOutItemCell.swift deleted file mode 100644 index cdb5d28..0000000 --- a/enrollment/enrollment/Controllers/Phase 2 Education/LinkOutItemCell.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// LinkOutItemCell.swift -// enrollment -// -// Created by Jay Latman on 10/1/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -class LinkOutItemCell: NSCollectionViewItem { - - @IBOutlet var linkoutItemImage: NSImageView! - @IBOutlet var linkoutItemHeaderLabel: Hyperlink! - @IBOutlet var linkoutItemDescriptionLabel: NSTextField! - - - override func viewDidLoad() { - super.viewDidLoad() - layoutSetup() - setTextFields() - } - - private func layoutSetup() { - self.view.wantsLayer = true - } - - private func setTextFields() { - linkoutItemHeaderLabel.textColor = .linkColor - linkoutItemDescriptionLabel.textColor = .controlTextColor - } -} diff --git a/enrollment/enrollment/Controllers/Phase 2 Education/SetupCompleteChildViewController.swift b/enrollment/enrollment/Controllers/Phase 2 Education/SetupCompleteChildViewController.swift deleted file mode 100644 index d0fc5ca..0000000 --- a/enrollment/enrollment/Controllers/Phase 2 Education/SetupCompleteChildViewController.swift +++ /dev/null @@ -1,104 +0,0 @@ -// -// SetupCompleteChildViewController.swift -// enrollment -// -// Created by Jay Latman on 8/6/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa -import ServiceManagement - -class SetupCompleteChildViewController: NSViewController { - - @IBOutlet weak var headerMessageTextLabel: NSTextField! - - @IBOutlet weak var linkoutCollectionView: NSCollectionView! - - @IBOutlet weak var showOnRebootToggle: NSButton! - - @IBOutlet weak var borderedScrollView: NSScrollView! - - - let urlPath = Bundle.main - let helperBundleIdentifier = SetupCompleteChildVC_Constants.helperBundleIdentifier - - var listOfIcons = [NSImage]() - var listOfLinkOutHeaders = [String]() - var listOfURLs = [String]() - var listOfLinkDescriptions = [String]() - - override func viewDidLoad() { - super.viewDidLoad() - layoutSetup() - setTextFields() - } - - private func layoutSetup() { - let foundHelper = NSWorkspace.shared.runningApplications.contains { - $0.bundleIdentifier == helperBundleIdentifier - } - showOnRebootToggle.state = foundHelper ? .on : .off - - borderedScrollView.contentView.scroll(to: .zero) - listOfIcons = SetupCompleteChildVC_Constants.LinkOuts.icons - listOfLinkOutHeaders = SetupCompleteChildVC_Constants.LinkOuts.headerLabels - listOfLinkDescriptions = SetupCompleteChildVC_Constants.LinkOuts.descriptionLabels - listOfURLs = SetupCompleteChildVC_Constants.LinkOuts.urls - linkoutCollectionView.dataSource = self - linkoutCollectionView.delegate = self - } - - private func setTextFields() { - headerMessageTextLabel.set(label: SetupCompleteChildVC_Constants.header, color: .headerTextColor) - showOnRebootToggle.set(toggleLabel: SetupCompleteChildVC_Constants.showOnRestartToggleLabel, underline: 0) - } - - - @IBAction func showOnRebootToggleClicked(_ sender: NSButton) { - let autoLaunch = showOnRebootToggle.state == .on - if SMLoginItemSetEnabled(helperBundleIdentifier as CFString, autoLaunch) { - if autoLaunch { - NSLog("Login item added") - } else { - NSLog("Login item removed") - } - } - } - - @IBAction func closeButtonClicked(_ sender: NSButton) { - exit(0) - } -} - -extension SetupCompleteChildViewController: NSCollectionViewDelegate, NSCollectionViewDataSource, NSCollectionViewDelegateFlowLayout { - - func numberOfSections(in collectionView: NSCollectionView) -> Int { - return 1 - } - - func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int { - return listOfLinkOutHeaders.count - } - - func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem { - - let linkOutItem = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "LinkOutItemCell"), for: indexPath as IndexPath) as? LinkOutItemCell - linkOutItem?.linkoutItemImage.image = self.listOfIcons[indexPath.item] - linkOutItem?.linkoutItemHeaderLabel.stringValue = self.listOfLinkOutHeaders[indexPath.item] - linkOutItem?.linkoutItemHeaderLabel.href = self.listOfURLs[indexPath.item] - linkOutItem?.linkoutItemDescriptionLabel.stringValue = self.listOfLinkDescriptions[indexPath.item] - - return linkOutItem! - } - - - func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, insetForSectionAt section: Int) -> NSEdgeInsets { - return NSEdgeInsets(top: 0.1, left: 0, bottom: 0.1, right: 0) - } - - func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> NSSize { - return NSSize(width: 460, height: 60) - } -} diff --git a/enrollment/enrollment/Controllers/PopOvers/IncorrectUserPopover.swift b/enrollment/enrollment/Controllers/PopOvers/IncorrectUserPopover.swift deleted file mode 100644 index 7a33fe5..0000000 --- a/enrollment/enrollment/Controllers/PopOvers/IncorrectUserPopover.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// IncorrectUserPopover.swift -// enrollment -// -// Created by Jay Latman on 9/26/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -class IncorrectUserPopover: NSViewController { - - @IBOutlet weak var textField: NSTextField! - - override func viewDidLoad() { - super.viewDidLoad() - textField.textColor = .headerTextColor - textField.stringValue = InfoPopoverConstants.PrimaryRegistrationVC.incorrectUserMessage - } -} diff --git a/enrollment/enrollment/Controllers/PopOvers/Info2Popover.swift b/enrollment/enrollment/Controllers/PopOvers/Info2Popover.swift deleted file mode 100644 index 7f95078..0000000 --- a/enrollment/enrollment/Controllers/PopOvers/Info2Popover.swift +++ /dev/null @@ -1,54 +0,0 @@ -// -// Info2Popover.swift -// enrollment -// -// Created by Jay Latman on 7/27/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -class Info2Popover: NSViewController { - - // Left Column - @IBOutlet weak var obj1Left: NSTextField! - @IBOutlet weak var obj2Left: NSTextField! - @IBOutlet weak var obj3Left: NSTextField! - @IBOutlet weak var obj4Left: NSTextField! - @IBOutlet weak var obj5Left: NSTextField! - @IBOutlet weak var obj6Left: NSTextField! - - // Right Column - @IBOutlet weak var obj1Right: NSTextField! - @IBOutlet weak var obj2Right: NSTextField! - @IBOutlet weak var obj3Right: NSTextField! - @IBOutlet weak var obj4Right: NSTextField! - @IBOutlet weak var obj5Right: NSTextField! - @IBOutlet weak var obj6Right: NSTextField! - - override func viewDidLoad() { - super.viewDidLoad() - defineObjects() - } - - private func defineObjects() { - let object1 = InfoPopoverConstants.PrimaryRegistrationVC.Info2.object1 - TermDefinition.assignTermDefinitionsToLabels(term: object1, leftLabel: obj1Left, rightLabel: obj1Right) - - let object2 = InfoPopoverConstants.PrimaryRegistrationVC.Info2.object2 - TermDefinition.assignTermDefinitionsToLabels(term: object2, leftLabel: obj2Left, rightLabel: obj2Right) - - let object3 = InfoPopoverConstants.PrimaryRegistrationVC.Info2.object3 - TermDefinition.assignTermDefinitionsToLabels(term: object3, leftLabel: obj3Left, rightLabel: obj3Right) - - let object4 = InfoPopoverConstants.PrimaryRegistrationVC.Info2.object4 - TermDefinition.assignTermDefinitionsToLabels(term: object4, leftLabel: obj4Left, rightLabel: obj4Right) - - let object5 = InfoPopoverConstants.PrimaryRegistrationVC.Info2.object5 - TermDefinition.assignTermDefinitionsToLabels(term: object5, leftLabel: obj5Left, rightLabel: obj5Right) - - let object6 = InfoPopoverConstants.PrimaryRegistrationVC.Info2.object6 - TermDefinition.assignTermDefinitionsToLabels(term: object6, leftLabel: obj6Left, rightLabel: obj6Right) - } -} diff --git a/enrollment/enrollment/Controllers/PopOvers/Info4Popover.swift b/enrollment/enrollment/Controllers/PopOvers/Info4Popover.swift deleted file mode 100644 index 02f2fc1..0000000 --- a/enrollment/enrollment/Controllers/PopOvers/Info4Popover.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// Info4Popover.swift -// enrollment -// -// Created by Jay Latman on 7/27/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -class Info4Popover: NSViewController { - - // Left Column - @IBOutlet weak var obj1Left: NSTextField! - @IBOutlet weak var obj2Left: NSTextField! - @IBOutlet weak var obj3Left: NSTextField! - - - // Right Column - @IBOutlet weak var obj1Right: NSTextField! - @IBOutlet weak var obj2Right: NSTextField! - @IBOutlet weak var obj3Right: NSTextField! - - - override func viewDidLoad() { - super.viewDidLoad() - defineObjects() - } - - private func defineObjects() { - let object1 = InfoPopoverConstants.PrimaryRegistrationVC.Info4.object1 - TermDefinition.assignTermDefinitionsToLabels(term: object1, leftLabel: obj1Left, rightLabel: obj1Right) - - let object2 = InfoPopoverConstants.PrimaryRegistrationVC.Info4.object2 - TermDefinition.assignTermDefinitionsToLabels(term: object2, leftLabel: obj2Left, rightLabel: obj2Right) - - let object3 = InfoPopoverConstants.PrimaryRegistrationVC.Info4.object3 - TermDefinition.assignTermDefinitionsToLabels(term: object3, leftLabel: obj3Left, rightLabel: obj3Right) - } -} diff --git a/enrollment/enrollment/Controllers/PopOvers/OptionPopover.swift b/enrollment/enrollment/Controllers/PopOvers/OptionPopover.swift deleted file mode 100644 index 0fea972..0000000 --- a/enrollment/enrollment/Controllers/PopOvers/OptionPopover.swift +++ /dev/null @@ -1,57 +0,0 @@ -// -// OptionPopover.swift -// enrollment -// -// Created by Jay Latman on 7/31/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -class OptionPopover: NSViewController { - - // Left Column - @IBOutlet weak var obj1Left: NSTextField! - @IBOutlet weak var obj2Left: NSTextField! - @IBOutlet weak var obj3Left: NSTextField! - @IBOutlet weak var obj4Left: NSTextField! - @IBOutlet weak var obj5Left: NSTextField! - @IBOutlet weak var obj6Left: NSTextField! - - // Right Column - @IBOutlet weak var obj1Right: NSTextField! - @IBOutlet weak var obj2Right: NSTextField! - @IBOutlet weak var obj3Right: NSTextField! - @IBOutlet weak var obj4Right: NSTextField! - @IBOutlet weak var obj5Right: NSTextField! - @IBOutlet weak var obj6Right: NSTextField! - - - - override func viewDidLoad() { - super.viewDidLoad() - defineObjects() - } - - func defineObjects() { - let object1 = InfoPopoverConstants.SecondaryRegistrationVC.Option.object1 - TermDefinition.assignTermDefinitionsToLabels(term: object1, leftLabel: obj1Left, rightLabel: obj1Right) - - let object2 = InfoPopoverConstants.SecondaryRegistrationVC.Option.object2 - TermDefinition.assignTermDefinitionsToLabels(term: object2, leftLabel: obj2Left, rightLabel: obj2Right) - - let object3 = InfoPopoverConstants.SecondaryRegistrationVC.Option.object3 - TermDefinition.assignTermDefinitionsToLabels(term: object3, leftLabel: obj3Left, rightLabel: obj3Right) - - let object4 = InfoPopoverConstants.SecondaryRegistrationVC.Option.object4 - TermDefinition.assignTermDefinitionsToLabels(term: object4, leftLabel: obj4Left, rightLabel: obj4Right) - - let object5 = InfoPopoverConstants.SecondaryRegistrationVC.Option.object5 - TermDefinition.assignTermDefinitionsToLabels(term: object5, leftLabel: obj5Left, rightLabel: obj5Right) - - let object6 = InfoPopoverConstants.SecondaryRegistrationVC.Option.object6 - TermDefinition.assignTermDefinitionsToLabels(term: object6, leftLabel: obj6Left, rightLabel: obj6Right) - } - -} diff --git a/enrollment/enrollment/Controllers/PopOvers/SecurityDescriptionPopover.swift b/enrollment/enrollment/Controllers/PopOvers/SecurityDescriptionPopover.swift deleted file mode 100644 index 7aa63ce..0000000 --- a/enrollment/enrollment/Controllers/PopOvers/SecurityDescriptionPopover.swift +++ /dev/null @@ -1,62 +0,0 @@ -// -// SecurityDescriptionPopover.swift -// enrollment -// -// Created by Jay Latman on 7/26/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -class SecurityDescriptionPopover: NSViewController { - - - // Left Column - @IBOutlet weak var obj1Left: NSTextField! - @IBOutlet weak var obj2Left: NSTextField! - @IBOutlet weak var obj3Left: NSTextField! - @IBOutlet weak var obj4Left: NSTextField! - @IBOutlet weak var obj5Left: NSTextField! - @IBOutlet weak var obj6Left: NSTextField! - @IBOutlet weak var obj7Left: NSTextField! - - // Right Column - @IBOutlet weak var obj1Right: NSTextField! - @IBOutlet weak var obj2Right: NSTextField! - @IBOutlet weak var obj3Right: NSTextField! - @IBOutlet weak var obj4Right: NSTextField! - @IBOutlet weak var obj5Right: NSTextField! - @IBOutlet weak var obj6Right: NSTextField! - @IBOutlet weak var obj7Right: NSTextField! - - - override func viewDidLoad() { - super.viewDidLoad() - defineObjects() - } - - - private func defineObjects() { - let object1 = InfoPopoverConstants.PrimaryRegistrationVC.SecuritySettings.object1 - TermDefinition.assignTermDefinitionsToLabels(term: object1, leftLabel: obj1Left, rightLabel: obj1Right) - - let object2 = InfoPopoverConstants.PrimaryRegistrationVC.SecuritySettings.object2 - TermDefinition.assignTermDefinitionsToLabels(term: object2, leftLabel: obj2Left, rightLabel: obj2Right) - - let object3 = InfoPopoverConstants.PrimaryRegistrationVC.SecuritySettings.object3 - TermDefinition.assignTermDefinitionsToLabels(term: object3, leftLabel: obj3Left, rightLabel: obj3Right) - - let object4 = InfoPopoverConstants.PrimaryRegistrationVC.SecuritySettings.object4 - TermDefinition.assignTermDefinitionsToLabels(term: object4, leftLabel: obj4Left, rightLabel: obj4Right) - - let object5 = InfoPopoverConstants.PrimaryRegistrationVC.SecuritySettings.object5 - TermDefinition.assignTermDefinitionsToLabels(term: object5, leftLabel: obj5Left, rightLabel: obj5Right) - - let object6 = InfoPopoverConstants.PrimaryRegistrationVC.SecuritySettings.object6 - TermDefinition.assignTermDefinitionsToLabels(term: object6, leftLabel: obj6Left, rightLabel: obj6Right) - - let object7 = InfoPopoverConstants.PrimaryRegistrationVC.SecuritySettings.object7 - TermDefinition.assignTermDefinitionsToLabels(term: object7, leftLabel: obj7Left, rightLabel: obj7Right) - } -} diff --git a/enrollment/enrollment/Models/Extensions/NSButton+TextColor.swift b/enrollment/enrollment/Extensions/NSButton+TextColor.swift similarity index 94% rename from enrollment/enrollment/Models/Extensions/NSButton+TextColor.swift rename to enrollment/enrollment/Extensions/NSButton+TextColor.swift index 379afb7..99faf94 100644 --- a/enrollment/enrollment/Models/Extensions/NSButton+TextColor.swift +++ b/enrollment/enrollment/Extensions/NSButton+TextColor.swift @@ -7,7 +7,6 @@ // SPDX-License-Identifier: GPL-3.0-only // - import AppKit extension NSButton { @@ -15,7 +14,7 @@ extension NSButton { /** Extension method for NSButton to change the text color and underline style. An example would be a button that mirrors an underlined URL link with no border. - - Parameter color : NSColor for the string attributed to the button title + - Parameter color : NSColor for the attributed to the button title - Parameter underlineStyle : NSUnderlineStyle */ func set(textColor color: NSColor, underline underlineStyle: NSUnderlineStyle.RawValue) { diff --git a/enrollment/enrollment/Models/Extensions/NSTextField+Attributes.swift b/enrollment/enrollment/Extensions/NSTextField+Attributes.swift similarity index 96% rename from enrollment/enrollment/Models/Extensions/NSTextField+Attributes.swift rename to enrollment/enrollment/Extensions/NSTextField+Attributes.swift index 94be726..388aab1 100644 --- a/enrollment/enrollment/Models/Extensions/NSTextField+Attributes.swift +++ b/enrollment/enrollment/Extensions/NSTextField+Attributes.swift @@ -7,7 +7,6 @@ // SPDX-License-Identifier: GPL-3.0-only // -import Foundation import Cocoa extension NSTextField { @@ -23,4 +22,3 @@ extension NSTextField { self.textColor = color } } - diff --git a/enrollment/enrollment/Models/Extensions/NSView+FadeTransition.swift b/enrollment/enrollment/Extensions/NSView+FadeTransition.swift similarity index 90% rename from enrollment/enrollment/Models/Extensions/NSView+FadeTransition.swift rename to enrollment/enrollment/Extensions/NSView+FadeTransition.swift index c92c0b0..c3735c5 100644 --- a/enrollment/enrollment/Models/Extensions/NSView+FadeTransition.swift +++ b/enrollment/enrollment/Extensions/NSView+FadeTransition.swift @@ -26,6 +26,6 @@ extension NSView { } // Helper function inserted by Swift 4.2 migrator. -fileprivate func convertFromCATransitionType(_ input: CATransitionType) -> String { +private func convertFromCATransitionType(_ input: CATransitionType) -> String { return input.rawValue } diff --git a/enrollment/enrollment/Extensions/String-Extensions.swift b/enrollment/enrollment/Extensions/String-Extensions.swift new file mode 100644 index 0000000..7cb02e9 --- /dev/null +++ b/enrollment/enrollment/Extensions/String-Extensions.swift @@ -0,0 +1,16 @@ +// +// String-Extensions.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 2/5/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Foundation + +extension String { + var localized: String { + return NSLocalizedString(self, comment: "") + } +} diff --git a/enrollment/enrollment/Info.plist b/enrollment/enrollment/Info.plist index 3f71156..191537e 100644 --- a/enrollment/enrollment/Info.plist +++ b/enrollment/enrollment/Info.plist @@ -9,21 +9,36 @@ CFBundleIconFile CFBundleIdentifier - com.ibm.enrollment + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName - enrollment + Mac@IBM Enrollment CFBundlePackageType APPL CFBundleShortVersionString - 1.0 + $(MARKETING_VERSION) + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLName + enrollmentapp + CFBundleURLSchemes + + enrollmentapp + + + CFBundleVersion - 1 + 76 + LSApplicationCategoryType + public.app-category.utilities LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright - Copyright © 2018 IBM. All rights reserved. SPDX-License-Identifier: GPL-3.0-only + Copyright © 2018 IBM. All rights reserved. SPDX-License-Identifier: GPL-3.0-only. NSMainStoryboardFile Main NSPrincipalClass diff --git a/enrollment/enrollment/Model/Constants.swift b/enrollment/enrollment/Model/Constants.swift new file mode 100644 index 0000000..59f0d8b --- /dev/null +++ b/enrollment/enrollment/Model/Constants.swift @@ -0,0 +1,14 @@ +// +// Constants.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 07/01/2021. +// Copyright © 2021 IBM. All rights reserved. +// + +import Foundation + +struct Constants { + static let NewMessageReceivedNotification = Notification.Name("NewMessageReceivedNotification") + static let NewStatusReceivedNotification = Notification.Name("NewStatusReceivedNotification") +} diff --git a/enrollment/enrollment/Model/Context.swift b/enrollment/enrollment/Model/Context.swift new file mode 100644 index 0000000..805651c --- /dev/null +++ b/enrollment/enrollment/Model/Context.swift @@ -0,0 +1,59 @@ +// +// Context.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 2/18/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Foundation +import MoreCodable +import os.log + +class Context { + + static var main = Context() + var dataSet: EnrollmentDataSet! + + init?() { + do { + let decoder = DictionaryDecoder() + dataSet = try decoder.decode(EnrollmentDataSet.self, from: UserDefaults.standard.dictionaryRepresentation()) + } catch { + os_log("Decoding error during context creation. Error: %@", error.localizedDescription) + return nil + } + } + + func receivedNewStatus(for key: String, newStatus: EnrollmentBundle.InstallationStatus) { + guard dataSet != nil else { return } + + for bundle in dataSet.bundleSelectionPage?.bundles ?? [] { + if bundle.key == key { + bundle.status = newStatus + NotificationCenter.default.post(name: Constants.NewStatusReceivedNotification, object: nil, userInfo: ["key": key, "newStatus": newStatus]) + return + } else { + for app in bundle.apps where app.key == key { + var newAppInstances = app + newAppInstances.status = newStatus + bundle.apps.remove(at: bundle.apps.firstIndex(where: { $0.key == key })!) + bundle.apps.append(newAppInstances) + NotificationCenter.default.post(name: Constants.NewStatusReceivedNotification, object: nil, userInfo: ["key": key, "newStatus": newStatus]) + return + } + } + } + } + + func receivedNewMessage(for key: String, newMessage: String) { + guard dataSet != nil else { return } + + for bundle in dataSet.bundleSelectionPage?.bundles ?? [] where bundle.key == key { + bundle.bundleMessaging = newMessage + NotificationCenter.default.post(name: Constants.NewMessageReceivedNotification, object: nil, userInfo: ["key": key, "newMessage": newMessage]) + return + } + } +} diff --git a/enrollment/enrollment/Model/ContextModel/BundleInstallationPage.swift b/enrollment/enrollment/Model/ContextModel/BundleInstallationPage.swift new file mode 100644 index 0000000..86b0f8c --- /dev/null +++ b/enrollment/enrollment/Model/ContextModel/BundleInstallationPage.swift @@ -0,0 +1,73 @@ +// +// BundleInstallationPage.swift +// enrollment +// +// Created by Simone Martorelli on 2/17/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Foundation + +public final class BundleInstallationPage: Codable { + var title: InfoLabel + var subtitle: InfoLabel? + var bundleInstallationNeedsRestartBefore: Bool + var bundleInstallationNeedsRestartAfter: Bool + var automaticRestartCountdownSeconds: Int + var bundleInstallationStatus: Bool { + didSet { + UserDefaults.standard.set(bundleInstallationStatus, forKey: UserDefaultHelper.Bundles.AppInstallScreen.status) + } + } + var bundleInstallationWarning: Bool { + didSet { + UserDefaults.standard.set(bundleInstallationWarning, forKey: UserDefaultHelper.Bundles.AppInstallScreen.warning) + } + } + + init(_ title: InfoLabel, subtitle: InfoLabel? = nil, bundleInstallationNeedsRestartBefore: Bool, bundleInstallationNeedsRestartAfter: Bool, automaticRestartCountdownSeconds: Int, bundleInstallationStatus: Bool, bundleInstallationWarning: Bool) { + self.title = title + self.subtitle = subtitle + self.bundleInstallationNeedsRestartBefore = bundleInstallationNeedsRestartBefore + self.bundleInstallationNeedsRestartAfter = bundleInstallationNeedsRestartAfter + self.automaticRestartCountdownSeconds = automaticRestartCountdownSeconds + self.bundleInstallationStatus = bundleInstallationStatus + self.bundleInstallationWarning = bundleInstallationWarning + } + + enum BundleInstallationPageCodingKeys: String, CodingKey { + case title + case subtitle + case bundleInstallationNeedsRestartBefore + case bundleInstallationNeedsRestartAfter + case automaticRestartCountdownSeconds + case bundleInstallationStatus + case bundleInstallationWarning + } + + public init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: BundleInstallationPageCodingKeys.self) + + title = try values.decode(InfoLabel.self, forKey: .title) + subtitle = try values.decodeIfPresent(InfoLabel.self, forKey: .subtitle) + bundleInstallationNeedsRestartBefore = try values.decodeIfPresent(Bool.self, forKey: .bundleInstallationNeedsRestartBefore) ?? true + bundleInstallationNeedsRestartAfter = try values.decodeIfPresent(Bool.self, forKey: .bundleInstallationNeedsRestartAfter) ?? false + automaticRestartCountdownSeconds = try values.decodeIfPresent(Int.self, forKey: .automaticRestartCountdownSeconds) ?? 300 + bundleInstallationStatus = try values.decodeIfPresent(Bool.self, forKey: .bundleInstallationStatus) ?? false + bundleInstallationWarning = try values.decodeIfPresent(Bool.self, forKey: .bundleInstallationWarning) ?? false + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: BundleInstallationPageCodingKeys.self) + + try container.encode(title, forKey: .title) + try container.encode(subtitle, forKey: .subtitle) + try container.encode(bundleInstallationNeedsRestartBefore, forKey: .bundleInstallationNeedsRestartBefore) + try container.encode(bundleInstallationNeedsRestartAfter, forKey: .bundleInstallationNeedsRestartAfter) + try container.encode(automaticRestartCountdownSeconds, forKey: .automaticRestartCountdownSeconds) + try container.encode(bundleInstallationStatus, forKey: .bundleInstallationStatus) + try container.encode(bundleInstallationWarning, forKey: .bundleInstallationWarning) + } + +} diff --git a/enrollment/enrollment/Model/ContextModel/BundleSelectionPage.swift b/enrollment/enrollment/Model/ContextModel/BundleSelectionPage.swift new file mode 100644 index 0000000..5fdb192 --- /dev/null +++ b/enrollment/enrollment/Model/ContextModel/BundleSelectionPage.swift @@ -0,0 +1,22 @@ +// +// BundleSelectionPage.swift +// enrollment +// +// Created by Simone Martorelli on 2/17/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Foundation + +public final class BundleSelectionPage: Codable { + var title: InfoLabel + var subtitle: InfoLabel? + var bundles: [EnrollmentBundle] + + init(_ title: InfoLabel, subtitle: InfoLabel? = nil, bundles: [EnrollmentBundle]) { + self.title = title + self.subtitle = subtitle + self.bundles = bundles + } +} diff --git a/enrollment/enrollment/Model/ContextModel/EnrollmentBundle.swift b/enrollment/enrollment/Model/ContextModel/EnrollmentBundle.swift new file mode 100644 index 0000000..4775d7a --- /dev/null +++ b/enrollment/enrollment/Model/ContextModel/EnrollmentBundle.swift @@ -0,0 +1,92 @@ +// +// EnrollmentBundle.swift +// enrollment +// +// Created by Simone Martorelli on 2/17/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Foundation + +public final class EnrollmentBundle: Codable { + public struct App: Codable { + var title: String + var description: String + var key: String + var status: InstallationStatus + var icon: String + } + + public enum InstallationStatus: Int, Codable { + case installationPending = 0 + case installationInProgress = 1 + case installed = 2 + case errorDuringInstallation = 3 + case unknown = -1 + + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + let rawValue = try container.decode(Int.self) + self = InstallationStatus(rawValue: rawValue) ?? .unknown + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + switch self { + case .installationPending: + try container.encode(0) + case .installationInProgress: + try container.encode(1) + case .installed: + try container.encode(2) + case .errorDuringInstallation: + try container.encode(3) + default: + try container.encode(-1) + } + } + } + + var title: String + var extendedTitle: String + var description: String + var key: String + var icon: String + var status: InstallationStatus + var bundleMessaging: String? + var time: String? + var size: String? + var recommended: Bool + var apps: [App] + + init(_ title: String, + extendedTitle: String, + description: String, + key: String, + icon: String, + status: InstallationStatus, + warningMessage: String? = nil, + time: String? = nil, + size: String? = nil, + recommended: Bool, + apps: [App]) { + self.title = title + self.extendedTitle = extendedTitle + self.description = description + self.key = key + self.icon = icon + self.status = status + self.bundleMessaging = warningMessage + self.time = time + self.size = size + self.recommended = recommended + self.apps = apps + } +} + +extension EnrollmentBundle: Equatable { + public static func == (lhs: EnrollmentBundle, rhs: EnrollmentBundle) -> Bool { + return lhs.key == rhs.key + } +} diff --git a/enrollment/enrollment/Model/ContextModel/EnrollmentDataSet.swift b/enrollment/enrollment/Model/ContextModel/EnrollmentDataSet.swift new file mode 100644 index 0000000..be4bcd4 --- /dev/null +++ b/enrollment/enrollment/Model/ContextModel/EnrollmentDataSet.swift @@ -0,0 +1,127 @@ +// +// EnrollmentDataSet.swift +// enrollment +// +// Created by Simone Martorelli on 2/17/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Foundation + +public class EnrollmentDataSet: Codable { + struct UserInfo: Codable { + var hrFirstName: String? + } + + struct NetworkInfo: Codable { + var speedTestResult: String? + var jpsCommSeconds: String? + } + + var phase: String { + didSet { + UserDefaults.standard.set(phase, forKey: UserDefaultHelper.Keys.phase) + } + } + var userInfo: UserInfo + var networkInfo: NetworkInfo? + var selectedBundles: [String] { + didSet { + UserDefaults.standard.set(selectedBundles, forKey: UserDefaultHelper.Keys.selectedBundles) + } + } + var selectedRegistrationInfo: [RegistrationChoice] { + didSet { + for info in selectedRegistrationInfo { + if !info.isMultipleChoiseAllowed { + UserDefaults.standard.set(info.selectedOptionKeys.first!, forKey: info.fieldKey) + } else { + UserDefaults.standard.set(info.selectedOptionKeys, forKey: info.fieldKey) + } + } + } + } + var policies: JamfPoliciesStore + var registration: RegistrationData? + var bundleSelectionPage: BundleSelectionPage? + var bundleInstallationPage: BundleInstallationPage? + var postRegistrationPage: PostRegistrationPage + var postInstallationPage: PostInstallationPage + var environment: String? + + init(_ phase: String, + userInfo: UserInfo, + networkInfo: NetworkInfo? = nil, + selectedBundles: [String] = [], + selectedRegistrationInfo: [RegistrationChoice] = [], + policies: JamfPoliciesStore, + registration: RegistrationData? = nil, + bundleSelectionPage: BundleSelectionPage? = nil, + bundleInstallationPage: BundleInstallationPage? = nil, + postInstallationPage: PostInstallationPage, + postRegistrationPage: PostRegistrationPage, + environment: String) { + self.phase = phase + self.userInfo = userInfo + self.networkInfo = networkInfo + self.selectedBundles = selectedBundles + self.selectedRegistrationInfo = selectedRegistrationInfo + self.policies = policies + self.registration = registration + self.bundleSelectionPage = bundleSelectionPage + self.bundleInstallationPage = bundleInstallationPage + self.postInstallationPage = postInstallationPage + self.postRegistrationPage = postRegistrationPage + self.environment = environment + } + + enum EnrollmentDataSetCodingKey: String, CodingKey { + case phase + case userInfo + case networkInfo + case selectedBundles + case selectedRegistrationInfo + case policies + case registration + case bundleSelectionPage + case bundleInstallationPage + case postInstallationPage + case postRegistrationPage + case environment + } + + required public init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: EnrollmentDataSetCodingKey.self) + + phase = try values.decode(String.self, forKey: .phase) + userInfo = try values.decode(UserInfo.self, forKey: .userInfo) + networkInfo = try values.decodeIfPresent(NetworkInfo.self, forKey: .networkInfo) + selectedBundles = try values.decodeIfPresent([String].self, forKey: .selectedBundles) ?? [] + selectedRegistrationInfo = try values.decodeIfPresent([RegistrationChoice].self, forKey: .selectedRegistrationInfo) ?? [] + policies = try values.decode(JamfPoliciesStore.self, forKey: .policies) + registration = try values.decodeIfPresent(RegistrationData.self, forKey: .registration) + bundleSelectionPage = try values.decodeIfPresent(BundleSelectionPage.self, forKey: .bundleSelectionPage) + bundleInstallationPage = try values.decodeIfPresent(BundleInstallationPage.self, forKey: .bundleInstallationPage) + postRegistrationPage = try values.decode(PostRegistrationPage.self, forKey: .postRegistrationPage) + postInstallationPage = try values.decode(PostInstallationPage.self, forKey: .postInstallationPage) + environment = try values.decodeIfPresent(String.self, forKey: .environment) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: EnrollmentDataSetCodingKey.self) + + try container.encode(phase, forKey: .phase) + try container.encodeIfPresent(userInfo, forKey: .userInfo) + try container.encodeIfPresent(networkInfo, forKey: .networkInfo) + try container.encode(selectedBundles, forKey: .selectedBundles) + try container.encodeIfPresent(selectedRegistrationInfo, forKey: .selectedRegistrationInfo) + try container.encodeIfPresent(policies, forKey: .policies) + try container.encode(registration, forKey: .registration) + try container.encodeIfPresent(bundleSelectionPage, forKey: .bundleSelectionPage) + try container.encodeIfPresent(bundleInstallationPage, forKey: .bundleInstallationPage) + try container.encodeIfPresent(postRegistrationPage, forKey: .postRegistrationPage) + try container.encodeIfPresent(postInstallationPage, forKey: .postInstallationPage) + try container.encodeIfPresent(environment, forKey: .environment) + } +} diff --git a/enrollment/enrollment/Model/ContextModel/InfoLabel.swift b/enrollment/enrollment/Model/ContextModel/InfoLabel.swift new file mode 100644 index 0000000..39f1b55 --- /dev/null +++ b/enrollment/enrollment/Model/ContextModel/InfoLabel.swift @@ -0,0 +1,57 @@ +// +// InfoLabel.swift +// enrollment +// +// Created by Simone Martorelli on 2/17/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Foundation + +public struct InfoField: Codable { + var label: String + var description: String? + var iconName: String? +} + +public struct InfoSection: Codable { + var fields: [InfoField] +} + +public final class InfoLabel: Codable, Equatable { + var label: String + var attributedLabel: NSAttributedString? // Convenience variables not present in the .plist + var infoSection: InfoSection? + + init(_ label: String, alternateLabel: String? = nil, attributedLabel: NSAttributedString? = nil, attributedAlternateLabel: NSAttributedString? = nil, withHelpSection help: InfoSection? = nil) { + self.label = label + self.attributedLabel = attributedLabel + self.infoSection = help + } + + public static func == (lhs: InfoLabel, rhs: InfoLabel) -> Bool { + return lhs.label == rhs.label + } + + enum InfoLabelCodingKeys: String, CodingKey { + case label + case alternateLabel + case infoSection + } + + public init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: InfoLabelCodingKeys.self) + + label = try values.decode(String.self, forKey: .label) + infoSection = try values.decodeIfPresent(InfoSection.self, forKey: .infoSection) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: InfoLabelCodingKeys.self) + + try container.encode(label, forKey: .label) + try container.encodeIfPresent(infoSection, forKey: .infoSection) + } + +} diff --git a/enrollment/enrollment/Model/ContextModel/JamfPoliciesStore.swift b/enrollment/enrollment/Model/ContextModel/JamfPoliciesStore.swift new file mode 100644 index 0000000..c3e7839 --- /dev/null +++ b/enrollment/enrollment/Model/ContextModel/JamfPoliciesStore.swift @@ -0,0 +1,24 @@ +// +// Policies.swift +// enrollment +// +// Created by Simone Martorelli on 2/17/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Foundation + +public final class JamfPoliciesStore: Codable { + var registrationPolicy: String + var bundleInstallationPolicy: String + var removeFramework: String + + init(_ registrationPolicy: String, + bundleInstallationPolicy: String, + removeFramework: String) { + self.registrationPolicy = registrationPolicy + self.bundleInstallationPolicy = bundleInstallationPolicy + self.removeFramework = removeFramework + } +} diff --git a/enrollment/enrollment/Model/ContextModel/PostInstallationPage.swift b/enrollment/enrollment/Model/ContextModel/PostInstallationPage.swift new file mode 100644 index 0000000..229d5b3 --- /dev/null +++ b/enrollment/enrollment/Model/ContextModel/PostInstallationPage.swift @@ -0,0 +1,76 @@ +// +// PostInstallationPage.swift +// enrollment +// +// Created by Simone Martorelli on 2/17/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Foundation + +public final class PostInstallationPage: Codable { + + public struct Item: Codable { + enum CTAType: String { + case none + case url + case policy + } + var title: String + var description: String + var iconName: String + var iconURL: URL? + var ctaType: CTAType + var ctaPayload: String? + + enum SummaryItemCodingKey: String, CodingKey { + case title + case description + case iconName + case iconURL + case alternateDescription + case ctaType + case ctaPayload + } + + public init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: SummaryItemCodingKey.self) + + title = try values.decode(String.self, forKey: .title) + description = try values.decode(String.self, forKey: .description) + iconName = try values.decode(String.self, forKey: .iconName) + if let urlString = try values.decodeIfPresent(String.self, forKey: .iconURL) { + iconURL = URL(string: urlString) + } + let ctaPayloadRawValue = try values.decode(String.self, forKey: .ctaType) + ctaType = CTAType(rawValue: ctaPayloadRawValue) ?? .none + ctaPayload = try values.decodeIfPresent(String.self, forKey: .ctaPayload) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: SummaryItemCodingKey.self) + + try container.encode(title, forKey: .title) + try container.encode(description, forKey: .description) + try container.encode(iconName, forKey: .iconName) + try container.encodeIfPresent(iconURL?.absoluteString, forKey: .iconURL) + try container.encode(ctaType.rawValue, forKey: .ctaType) + try container.encodeIfPresent(ctaPayload, forKey: .ctaPayload) + } + } + + var title: InfoLabel + var subtitle: InfoLabel? + var items: [Item] + var needsRestart: Bool? + var restartTimeout: Int? + + init(_ title: InfoLabel, subtitle: InfoLabel? = nil, items: [Item], needsRestart: Bool? = false, restartTimeout: Int? = 300) { + self.title = title + self.subtitle = subtitle + self.items = items + self.needsRestart = needsRestart + self.restartTimeout = restartTimeout + } +} diff --git a/enrollment/enrollment/Model/ContextModel/PostRegistrationPage.swift b/enrollment/enrollment/Model/ContextModel/PostRegistrationPage.swift new file mode 100644 index 0000000..b5d0926 --- /dev/null +++ b/enrollment/enrollment/Model/ContextModel/PostRegistrationPage.swift @@ -0,0 +1,18 @@ +// +// PostRegistrationPage.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 16/12/2020. +// Copyright © 2020 IBM. All rights reserved. +// + +import Foundation + +final class PostRegistrationPage: Codable { + var title: InfoLabel + var subtitle: InfoLabel? + var body: String + var needsRestart: Bool? + var restartTimeout: Int? + var footer: InfoLabel? +} diff --git a/enrollment/enrollment/Model/ContextModel/RegistrationChoice.swift b/enrollment/enrollment/Model/ContextModel/RegistrationChoice.swift new file mode 100644 index 0000000..9599f97 --- /dev/null +++ b/enrollment/enrollment/Model/ContextModel/RegistrationChoice.swift @@ -0,0 +1,34 @@ +// +// RegistrationChoice.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 4/8/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Foundation + +public final class RegistrationChoice: Codable, Hashable { + var fieldKey: String + var fieldTitle: String + var selectedOptionKeys: [String] + var selectedOptionTitles: [String] + var isMultipleChoiseAllowed: Bool + + init(_ fieldKey: String, fieldTitle: String, selectedOptionKeys: [String], selectedOptionTitles: [String], isMultipleChoiseAllowed: Bool = false) { + self.fieldKey = fieldKey + self.fieldTitle = fieldTitle + self.selectedOptionKeys = selectedOptionKeys + self.selectedOptionTitles = selectedOptionTitles + self.isMultipleChoiseAllowed = isMultipleChoiseAllowed + } + + public static func == (lhs: RegistrationChoice, rhs: RegistrationChoice) -> Bool { + return lhs.fieldKey == rhs.fieldKey + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(fieldKey) + } +} diff --git a/enrollment/enrollment/Model/ContextModel/RegistrationData.swift b/enrollment/enrollment/Model/ContextModel/RegistrationData.swift new file mode 100644 index 0000000..f066fea --- /dev/null +++ b/enrollment/enrollment/Model/ContextModel/RegistrationData.swift @@ -0,0 +1,28 @@ +// +// RegistrationData.swift +// enrollment +// +// Created by Simone Martorelli on 2/17/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Foundation + +/// This object contains the information needed to present the registration phase to the end user. +public final class RegistrationData: Codable { + /// Array of the registration page that should be exposed to the user in the registration phase. + var pages: [RegistrationPage] + /// True if the registration process has been completed, false if not. (Default: false). + var registrationStatus: Bool? { + didSet { + UserDefaults.standard.set(registrationStatus, forKey: UserDefaultHelper.Keys.registrationStatus) + } + } + + init(_ pages: [RegistrationPage], + registrationStatus: Bool? = nil) { + self.pages = pages + self.registrationStatus = registrationStatus + } +} diff --git a/enrollment/enrollment/Model/ContextModel/RegistrationField.swift b/enrollment/enrollment/Model/ContextModel/RegistrationField.swift new file mode 100644 index 0000000..31f49b5 --- /dev/null +++ b/enrollment/enrollment/Model/ContextModel/RegistrationField.swift @@ -0,0 +1,52 @@ +// +// RegistrationField.swift +// enrollment +// +// Created by Simone Martorelli on 2/17/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Foundation + +public final class RegistrationField: Codable, Equatable { + public struct Option: Codable { + var key: String + var label: String + var isExclusive: Bool? + } + + var title: InfoLabel + var key: String + var multipleChoiseAllowed: Bool + var showTitle: Bool? + var options: [Option] + + var optionKeys: [String] { + var array: [String] = [] + for option in options { + array.append(option.key) + } + return array + } + + var optionLabels: [String] { + var array: [String] = [] + for option in options { + array.append(option.label) + } + return array + } + + init(_ title: InfoLabel, key: String, options: [Option], multipleChoiseAllowed: Bool, showTitle: Bool? = nil) { + self.title = title + self.key = key + self.options = options + self.multipleChoiseAllowed = multipleChoiseAllowed + self.showTitle = showTitle + } + + public static func == (lhs: RegistrationField, rhs: RegistrationField) -> Bool { + return lhs.key == rhs.key + } +} diff --git a/enrollment/enrollment/Model/ContextModel/RegistrationPage.swift b/enrollment/enrollment/Model/ContextModel/RegistrationPage.swift new file mode 100644 index 0000000..3544d52 --- /dev/null +++ b/enrollment/enrollment/Model/ContextModel/RegistrationPage.swift @@ -0,0 +1,28 @@ +// +// RegistrationPage.swift +// enrollment +// +// Created by Simone Martorelli on 2/17/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Foundation + +public final class RegistrationPage: Codable, Equatable { + var title: InfoLabel + var subtitle: InfoLabel? + var fields: [RegistrationField] + var footer: InfoLabel? + + init(_ title: InfoLabel, subtitle: InfoLabel? = nil, fields: [RegistrationField], footer: InfoLabel? = nil) { + self.title = title + self.subtitle = subtitle + self.fields = fields + self.footer = footer + } + + public static func == (lhs: RegistrationPage, rhs: RegistrationPage) -> Bool { + return lhs.fields == rhs.fields && lhs.title == rhs.title && lhs.subtitle == rhs.subtitle && lhs.footer == rhs.footer + } +} diff --git a/enrollment/enrollment/Controllers/CrossfadeStoryBoardSegue.swift b/enrollment/enrollment/Model/CrossfadeStoryBoardSegue.swift similarity index 56% rename from enrollment/enrollment/Controllers/CrossfadeStoryBoardSegue.swift rename to enrollment/enrollment/Model/CrossfadeStoryBoardSegue.swift index 8a0dbcb..43bde09 100644 --- a/enrollment/enrollment/Controllers/CrossfadeStoryBoardSegue.swift +++ b/enrollment/enrollment/Model/CrossfadeStoryBoardSegue.swift @@ -9,22 +9,11 @@ import Cocoa -/* - Override for StoryBoardSegue to control the animation of transitioning between views. Full string values or stored in `DestinationIDConstants` referenced from interface builder. - */ - +/// Override for StoryBoardSegue to control the animation of transitioning between views. class CrossfadeStoryBoardSegue: NSStoryboardSegue { - override init(identifier: NSStoryboardSegue.Identifier, source sourceController: Any, destination destinationController: Any) { - var myIdentifier: String - - myIdentifier = identifier - - super.init(identifier: myIdentifier, source: sourceController, destination: destinationController) - } - override func perform() { - let sourceViewController = self.sourceController as! NSViewController - let destinationViewController = self.destinationController as! NSViewController + guard let sourceViewController = self.sourceController as? NSViewController, + let destinationViewController = self.destinationController as? NSViewController else { return } let destinationID = self.identifier let containerViewController = sourceViewController.parent @@ -40,9 +29,25 @@ class CrossfadeStoryBoardSegue: NSStoryboardSegue { var transitionOption = NSViewController.TransitionOptions.slideForward switch destinationID { - case SegueDestinationID.ReturnTo.primaryRegistrationChildViewController? : + case "goToPage" : + transitionOption = NSViewController.TransitionOptions.slideForward + case "backFromPage" : transitionOption = NSViewController.TransitionOptions.slideBackward - case SegueDestinationID.SkipTo.setupCompleteChildViewConroller? : + case "goToFirstRegistrationPage" : + transitionOption = NSViewController.TransitionOptions.slideForward + case "backToRegistrationFinalPage" : + transitionOption = NSViewController.TransitionOptions.slideBackward + case "goToPostRegistrationPage": + transitionOption = NSViewController.TransitionOptions.slideForward + case "goToInstallationPage": + transitionOption = NSViewController.TransitionOptions.slideForward + case "goToPostInstallationPage": + transitionOption = NSViewController.TransitionOptions.slideForward + case "goToFilePickerPage": + transitionOption = NSViewController.TransitionOptions.slideUp + case "backFromFilePickerPage": + transitionOption = NSViewController.TransitionOptions.slideDown + case "goToInstallationPhase": transitionOption = NSViewController.TransitionOptions.crossfade default : transitionOption = NSViewController.TransitionOptions.slideForward diff --git a/enrollment/enrollment/Models/BundleInstallButtonVisibility.swift b/enrollment/enrollment/Models/BundleInstallButtonVisibility.swift deleted file mode 100644 index c6436f3..0000000 --- a/enrollment/enrollment/Models/BundleInstallButtonVisibility.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// BundleInstallButtonVisibility.swift -// enrollment -// -// Created by Jay Latman on 8/8/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Foundation -import Cocoa - -struct BundleInstallButtonVisibility { - /** - Method for handling the UI controls for the Bundle Selection view - - - Parameter label : NSTextField for the `totalDownloadTime` - - Parameter labelState : Boolean value for whether the label should be displayed - - Parameter installButton : NSButton for advancing to the installation screen - - Parameter installButtonState : Boolean value for whether the `installButton` should be displayed - - Parameter skipButton : NSButton for advancing to the SetupComplete / education view - - Parameter skipButtonState : Boolean value for whether the `skipButton` should be displayed - */ - static func displayButtons(label: NSTextField, labelState: Bool, installButton: NSButton, installButtonState: Bool, skipButton: NSButton, skipButtonState: Bool) { - - label.isHidden = labelState - installButton.isHidden = installButtonState - skipButton.isHidden = skipButtonState - } -} diff --git a/enrollment/enrollment/Models/DefineBundleInfoPopover.swift b/enrollment/enrollment/Models/DefineBundleInfoPopover.swift deleted file mode 100644 index 36b1b59..0000000 --- a/enrollment/enrollment/Models/DefineBundleInfoPopover.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// DefineBundleInfoPopover.swift -// enrollment -// -// Created by Jay on 8/30/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import AppKit - -/** - Class definition for defining a software bundle info popover - */ -class DefineBundleInfoPopover { - - var bundleTitle = String() - var descriptionText = String() - var appTitles = [String]() - var appDescriptions = [String]() - var appIcons = [NSImage]() - - /** - Class initializer for defining a bundle info popover. - - The appTitles, appDescriptions, and appIcons construct individual application cards based on array index position. - - - Parameter bundleTitle : string value for the bundle's name - - Parameter bundleDescription : string value for a short description about the bundle (size is limited) - - Parameter appTitles : [Array] of strings containing all the apps in a bundle - - Parameter appDescriptions : [Array] of strings containing short descriptions for each app in the bundle (size is limited) - - Parameter appIcons : [Array] of images from the asset catalog - */ - init(bundleTitle: String, bundleDescription: String, appTitles: [String], appDescriptions: [String], appIcons: [NSImage]) { - self.bundleTitle = String(bundleTitle) - self.descriptionText = String(bundleDescription) - self.appTitles = appTitles - self.appDescriptions = appDescriptions - self.appIcons = appIcons - } -} diff --git a/enrollment/enrollment/Models/Extensions/NSView+Rotation.swift b/enrollment/enrollment/Models/Extensions/NSView+Rotation.swift deleted file mode 100644 index 3610a63..0000000 --- a/enrollment/enrollment/Models/Extensions/NSView+Rotation.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// NSView+Rotation.swift -// enrollment -// -// Created by Jay Latman on 9/2/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import AppKit - -extension NSView { - private static let kRotationAnimationKey = "rotationanimationkey" - - /** - Extension method for locating the anchor point of a NSView to allow for proper rotation - - - Parameter indicator : `CircularStatus` indicator - */ - func determineAnchorPoint(indicator: CircularStatus) { - indicator.layer?.anchorPoint = CGPoint(x: 0.5, y: 0.5) - let frame : CGRect = (indicator.layer?.frame)! - let xCoord = Float(frame.origin.x + frame.size.width) - let yCoord = Float(frame.origin.y + frame.size.height) - let myPoint = CGPoint(x: CGFloat(xCoord), y: CGFloat(yCoord)) - indicator.layer?.position = myPoint - } - - /** - Extension method for rotating a NSView over a period of time - - - Parameter duration : Double value representing the seconds of rotation - */ - func rotate(duration: Double = 1.0) { - if layer?.animation(forKey: NSView.kRotationAnimationKey) == nil { - let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation") - - rotationAnimation.fromValue = 0.0 - rotationAnimation.toValue = Float.pi * -2.0 - rotationAnimation.duration = duration - rotationAnimation.repeatCount = Float.infinity - - layer?.add(rotationAnimation, forKey: NSView.kRotationAnimationKey) - } - } - - /** - Extension method for stopping the rotation animation of a NSView - */ - func stopRotation() { - if layer?.animation(forKey: NSView.kRotationAnimationKey) != nil { - layer?.removeAnimation(forKey: NSView.kRotationAnimationKey) - } - } -} diff --git a/enrollment/enrollment/Models/Hyperlink.swift b/enrollment/enrollment/Models/Hyperlink.swift deleted file mode 100644 index 100874e..0000000 --- a/enrollment/enrollment/Models/Hyperlink.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// Hyperlink.swift -// enrollment -// -// Created by Jay Latman on 8/16/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -/** - Class definition for converting a NSTextField to accept mount input to open a url - - href : string value of a url to be appled to the textfield for openning in a web browser - */ -class Hyperlink: NSTextField { - - @IBInspectable var href: String = "" - - override func resetCursorRects() { - discardCursorRects() - addCursorRect(self.bounds, cursor: NSCursor.pointingHand) - } - - override func awakeFromNib() { - super.awakeFromNib() - } - - override func mouseDown(with theEvent: NSEvent) { - if let localHref = URL(string: href) { - NSWorkspace.shared.open(localHref) - } - } -} diff --git a/enrollment/enrollment/Models/Images/InfoBubble.swift b/enrollment/enrollment/Models/Images/InfoBubble.swift deleted file mode 100644 index ca71e86..0000000 --- a/enrollment/enrollment/Models/Images/InfoBubble.swift +++ /dev/null @@ -1,143 +0,0 @@ -// -// InfoBubble.swift -// enrollment -// -// Created by Jay Latman on 7/24/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - - -import Cocoa - -public class InfoBubble : NSObject { - - //// Cache - private struct Cache { - static var imageOfInfo_bubble: NSImage? - } - - //// Drawing Methods - @objc dynamic public class func drawInfo_bubble(frame targetFrame: NSRect = NSRect(x: 0, y: 0, width: 18, height: 18), resizing: ResizingBehavior = .aspectFit) { - //// General Declarations - let context = NSGraphicsContext.current!.cgContext - - //// Resize to Target Frame - NSGraphicsContext.saveGraphicsState() - let resizedFrame: NSRect = resizing.apply(rect: NSRect(x: 0, y: 0, width: 18, height: 18), target: targetFrame) - context.translateBy(x: resizedFrame.minX, y: resizedFrame.minY) - context.scaleBy(x: resizedFrame.width / 18, y: resizedFrame.height / 18) - - - //// Color Declarations - let infoButtonStroke = ColorConstants.InfoButton.stroke - let infoButtonBackground = ColorConstants.InfoButton.background - let infoButtonColor = ColorConstants.InfoButton.color - //// Group 2 - //// Group 3 - //// b Drawing - let bPath = NSBezierPath(ovalIn: NSRect(x: 1.5, y: 1.34, width: 15, height: 15)) - infoButtonStroke?.setFill() - bPath.fill() - NSColor.black.setStroke() - bPath.lineWidth = 1 - bPath.lineCapStyle = .round - bPath.stroke() - - //// b 2 Drawing - let b2Path = NSBezierPath(ovalIn: NSRect(x: 1.5, y: 1.34, width: 15, height: 15)) - infoButtonBackground?.setFill() - b2Path.fill() - infoButtonColor?.setStroke() - b2Path.lineWidth = 1 - b2Path.stroke() - - //// Group 4 - //// Bezier Drawing - let bezierPath = NSBezierPath() - bezierPath.move(to: NSPoint(x: 10.25, y: 10.38)) - bezierPath.line(to: NSPoint(x: 6.5, y: 10.38)) - bezierPath.line(to: NSPoint(x: 6.5, y: 9.25)) - bezierPath.line(to: NSPoint(x: 7.75, y: 9.25)) - bezierPath.line(to: NSPoint(x: 7.75, y: 5.88)) - bezierPath.line(to: NSPoint(x: 6.5, y: 5.88)) - bezierPath.line(to: NSPoint(x: 6.5, y: 4.75)) - bezierPath.line(to: NSPoint(x: 11.5, y: 4.75)) - bezierPath.line(to: NSPoint(x: 11.5, y: 5.88)) - bezierPath.line(to: NSPoint(x: 10.25, y: 5.88)) - bezierPath.line(to: NSPoint(x: 10.25, y: 10.38)) - bezierPath.close() - bezierPath.move(to: NSPoint(x: 10.25, y: 12.62)) - bezierPath.line(to: NSPoint(x: 10.25, y: 12.62)) - bezierPath.curve(to: NSPoint(x: 9, y: 11.5), controlPoint1: NSPoint(x: 10.25, y: 12), controlPoint2: NSPoint(x: 9.69, y: 11.5)) - bezierPath.curve(to: NSPoint(x: 7.75, y: 12.62), controlPoint1: NSPoint(x: 8.31, y: 11.5), controlPoint2: NSPoint(x: 7.75, y: 12)) - bezierPath.line(to: NSPoint(x: 7.75, y: 12.62)) - bezierPath.curve(to: NSPoint(x: 9, y: 13.75), controlPoint1: NSPoint(x: 7.75, y: 13.25), controlPoint2: NSPoint(x: 8.31, y: 13.75)) - bezierPath.curve(to: NSPoint(x: 10.25, y: 12.62), controlPoint1: NSPoint(x: 9.69, y: 13.75), controlPoint2: NSPoint(x: 10.25, y: 13.25)) - bezierPath.close() - bezierPath.windingRule = .evenOdd - infoButtonColor?.setFill() - bezierPath.fill() - - NSGraphicsContext.restoreGraphicsState() - - } - - //// Generated Images - - @objc dynamic public class var imageOfInfo_bubble: NSImage { - if Cache.imageOfInfo_bubble != nil { - return Cache.imageOfInfo_bubble! - } - - Cache.imageOfInfo_bubble = NSImage(size: NSSize(width: 18, height: 18), flipped: false) { _ in - InfoBubble.drawInfo_bubble() - - return true - } - - return Cache.imageOfInfo_bubble! - } - - - - - @objc(InfoBubbleResizingBehavior) - public enum ResizingBehavior: Int { - case aspectFit /// The content is proportionally resized to fit into the target rectangle. - case aspectFill /// The content is proportionally resized to completely fill the target rectangle. - case stretch /// The content is stretched to match the entire target rectangle. - case center /// The content is centered in the target rectangle, but it is NOT resized. - - public func apply(rect: NSRect, target: NSRect) -> NSRect { - if rect == target || target == NSRect.zero { - return rect - } - - var scales = NSSize.zero - scales.width = abs(target.width / rect.width) - scales.height = abs(target.height / rect.height) - - switch self { - case .aspectFit: - scales.width = min(scales.width, scales.height) - scales.height = scales.width - case .aspectFill: - scales.width = max(scales.width, scales.height) - scales.height = scales.width - case .stretch: - break - case .center: - scales.width = 1 - scales.height = 1 - } - - var result = rect.standardized - result.size.width *= scales.width - result.size.height *= scales.height - result.origin.x = target.minX + (target.width - result.width) / 2 - result.origin.y = target.minY + (target.height - result.height) / 2 - return result - } - } -} diff --git a/enrollment/enrollment/Models/Images/SetupCompleteButtons.swift b/enrollment/enrollment/Models/Images/SetupCompleteButtons.swift deleted file mode 100644 index d531c7d..0000000 --- a/enrollment/enrollment/Models/Images/SetupCompleteButtons.swift +++ /dev/null @@ -1,754 +0,0 @@ -// -// SetupCompleteButtons.swift -// enrollment -// -// Created by Jay Latman on 8/13/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -public class SetupCompleteButtons: NSObject { - - //// Cache - private struct Cache { - static var imageOfMigrationButton: NSImage? - static var imageOfURLButton: NSImage? - static var imageOfSelfServiceButton: NSImage? - static var imageOfBackupButton: NSImage? - static var imageOfQnAButton: NSImage? - } - - //// Drawing Methods - - @objc dynamic public class func drawMigration(frame: NSRect = NSRect(x: 0, y: 0, width: 85, height: 81)) { - //// General Declarations - let context = NSGraphicsContext.current!.cgContext - - //// Color Declarations - let screenBezelColor = ColorConstants.SetupComplete.MigrationButton.screenBezel - let screenBackgroundColor = ColorConstants.SetupComplete.MigrationButton.laptopScreenBackground - let arrowColor = ColorConstants.SetupComplete.MigrationButton.arrow_and_Keyboard - let innerRingColor = ColorConstants.SetupComplete.MigrationButton.innerRing - - //// outer_ring Drawing - let outer_button_ringPath = NSBezierPath(ovalIn: NSRect(x: frame.minX + 4, y: frame.minY + frame.height - 79, width: 77, height: 77)) - ColorConstants.SetupComplete.outerRing.setStroke() - outer_button_ringPath.lineWidth = 1.5 - outer_button_ringPath.lineCapStyle = .round - outer_button_ringPath.lineJoinStyle = .round - outer_button_ringPath.stroke() - - //// inner_button_ring Drawing - let inner_button_ringPath = NSBezierPath(ovalIn: NSRect(x: frame.minX + 5, y: frame.minY + frame.height - 78, width: 75, height: 75)) - NSColor.white.setFill() - inner_button_ringPath.fill() - innerRingColor?.setStroke() - inner_button_ringPath.lineWidth = 1.5 - inner_button_ringPath.lineCapStyle = .round - inner_button_ringPath.lineJoinStyle = .round - inner_button_ringPath.stroke() - - //// Screen Drawing - let screenPath = NSBezierPath(roundedRect: NSRect(x: frame.minX + 28, y: frame.minY + frame.height - 53, width: 40, height: 29), xRadius: 8, yRadius: 8) - screenBackgroundColor?.setFill() - screenPath.fill() - screenBezelColor?.setStroke() - screenPath.lineWidth = 4 - screenPath.stroke() - - //// Keyboard Drawing - let keyboardPath = NSBezierPath(roundedRect: NSRect(x: frame.minX + 25.5, y: frame.minY + frame.height - 59.5, width: 45, height: 3), xRadius: 1.5, yRadius: 1.5) - arrowColor?.setFill() - keyboardPath.fill() - screenBezelColor?.setStroke() - keyboardPath.lineWidth = 1 - keyboardPath.stroke() - - //// Arrow Drawing - let arrowPath = NSBezierPath() - arrowPath.move(to: NSPoint(x: frame.minX + 23.13, y: frame.maxY - 40.67)) - arrowPath.line(to: NSPoint(x: frame.minX + 15.16, y: frame.maxY - 35.83)) - arrowPath.line(to: NSPoint(x: frame.minX + 15.16, y: frame.maxY - 45.51)) - arrowPath.line(to: NSPoint(x: frame.minX + 23.13, y: frame.maxY - 40.67)) - arrowPath.close() - arrowPath.move(to: NSPoint(x: frame.minX + 4.75, y: frame.maxY - 41.3)) - arrowPath.line(to: NSPoint(x: frame.minX + 15.66, y: frame.maxY - 41.3)) - arrowPath.curve(to: NSPoint(x: frame.minX + 16.16, y: frame.maxY - 40.67), controlPoint1: NSPoint(x: frame.minX + 15.93, y: frame.maxY - 41.3), controlPoint2: NSPoint(x: frame.minX + 16.16, y: frame.maxY - 41.02)) - arrowPath.curve(to: NSPoint(x: frame.minX + 15.66, y: frame.maxY - 40.04), controlPoint1: NSPoint(x: frame.minX + 16.16, y: frame.maxY - 40.32), controlPoint2: NSPoint(x: frame.minX + 15.93, y: frame.maxY - 40.04)) - arrowPath.line(to: NSPoint(x: frame.minX + 4.75, y: frame.maxY - 40.04)) - arrowPath.curve(to: NSPoint(x: frame.minX + 4.25, y: frame.maxY - 40.67), controlPoint1: NSPoint(x: frame.minX + 4.47, y: frame.maxY - 40.04), controlPoint2: NSPoint(x: frame.minX + 4.25, y: frame.maxY - 40.32)) - arrowPath.curve(to: NSPoint(x: frame.minX + 4.75, y: frame.maxY - 41.3), controlPoint1: NSPoint(x: frame.minX + 4.25, y: frame.maxY - 41.02), controlPoint2: NSPoint(x: frame.minX + 4.47, y: frame.maxY - 41.3)) - arrowPath.close() - arrowColor?.setFill() - arrowPath.fill() - - //// AppleLogo Drawing - let appleLogoRect = NSRect(x: frame.minX + 38, y: frame.minY + frame.height - 48, width: 19, height: 19) - NSGraphicsContext.saveGraphicsState() - appleLogoRect.clip() - context.translateBy(x: appleLogoRect.minX, y: appleLogoRect.minY) - - SetupCompleteButtons.drawAppleLogo(frame: CGRect(origin: .zero, size: appleLogoRect.size), resizing: .stretch) - NSGraphicsContext.restoreGraphicsState() - - - } - - - @objc dynamic public class func drawHelp(frame: NSRect = NSRect(x: 0, y: 0, width: 85, height: 81)) { - //// General Declarations - let context = NSGraphicsContext.current!.cgContext - - //// Color Declarations - let windowStrokeColor = ColorConstants.SetupComplete.WebURLButton.windowStroke - let windowBackgroundColor = ColorConstants.SetupComplete.WebURLButton.windowBackground - let closeColor = ColorConstants.SetupComplete.WebURLButton.closeButton - let minimizeColor = ColorConstants.SetupComplete.WebURLButton.minimizeButton - let maximizeColor = ColorConstants.SetupComplete.WebURLButton.maximizeButton - let innerRingColor = ColorConstants.SetupComplete.WebURLButton.innerRing - - //// outer_ring Drawing - let outer_button_ringPath = NSBezierPath(ovalIn: NSRect(x: frame.minX + 4, y: frame.minY + frame.height - 79, width: 77, height: 77)) - ColorConstants.SetupComplete.outerRing.setStroke() - outer_button_ringPath.lineWidth = 1.5 - outer_button_ringPath.lineCapStyle = .round - outer_button_ringPath.lineJoinStyle = .round - outer_button_ringPath.stroke() - - - //// inner_button_ring Drawing - let inner_button_ringPath = NSBezierPath(ovalIn: NSRect(x: frame.minX + 5, y: frame.minY + frame.height - 78, width: 75, height: 75)) - NSColor.white.setFill() - inner_button_ringPath.fill() - innerRingColor?.setStroke() - inner_button_ringPath.lineWidth = 1.5 - inner_button_ringPath.lineCapStyle = .round - inner_button_ringPath.lineJoinStyle = .round - inner_button_ringPath.stroke() - - //// App Screen Window Drawing - let rectanglePath = NSBezierPath(roundedRect: NSRect(x: frame.minX + 16, y: frame.minY + frame.height - 59, width: 55, height: 38), xRadius: 8, yRadius: 8) - windowBackgroundColor?.setFill() - rectanglePath.fill() - windowStrokeColor?.setStroke() - rectanglePath.lineWidth = 4 - rectanglePath.stroke() - - //// Close Control Oval Drawing - let closeOvalPath = NSBezierPath(ovalIn: NSRect(x: frame.minX + 20.75, y: frame.minY + frame.height - 28.75, width: 4.25, height: 4.25)) - closeColor?.setFill() - closeOvalPath.fill() - windowStrokeColor?.setStroke() - closeOvalPath.lineWidth = 0.5 - closeOvalPath.stroke() - - //// Minimize Oval Drawing - let minimizeOvalPath = NSBezierPath(ovalIn: NSRect(x: frame.minX + 26.25, y: frame.minY + frame.height - 28.75, width: 4.25, height: 4.25)) - minimizeColor?.setFill() - minimizeOvalPath.fill() - windowStrokeColor?.setStroke() - minimizeOvalPath.lineWidth = 0.5 - minimizeOvalPath.stroke() - - //// Maximize Oval Drawing - let maximizeOvalPath = NSBezierPath(ovalIn: NSRect(x: frame.minX + 31.75, y: frame.minY + frame.height - 28.75, width: 4.25, height: 4.25)) - maximizeColor?.setFill() - maximizeOvalPath.fill() - windowStrokeColor?.setStroke() - maximizeOvalPath.lineWidth = 0.5 - maximizeOvalPath.stroke() - - //// Webaddress Text Drawing - let webaddressRect = NSRect(x: frame.minX + 25, y: frame.minY + frame.height - 47, width: 37, height: 11) - NSGraphicsContext.saveGraphicsState() - webaddressRect.clip() - context.translateBy(x: webaddressRect.minX, y: webaddressRect.minY) - - SetupCompleteButtons.drawWebURL(frame: CGRect(origin: .zero, size: webaddressRect.size), resizing: .stretch) - NSGraphicsContext.restoreGraphicsState() - - - } - - @objc dynamic public class func drawBackup(frame: NSRect = NSRect(x: 0, y: 0, width: 85, height: 81)) { - //// General Declarations - let context = NSGraphicsContext.current!.cgContext - - //// Color Declarations - let arrowTailColor = ColorConstants.SetupComplete.BackupButton.arrowTail - let clockhandsArrowheadColor = ColorConstants.SetupComplete.BackupButton.clockhands_and_Arrowhead - let innerRingColor = ColorConstants.SetupComplete.BackupButton.innerRing - - //// outer_button_ringPath Drawing - let outer_button_ringPath = NSBezierPath(ovalIn: NSRect(x: frame.minX + 4, y: frame.minY + frame.height - 79, width: 77, height: 77)) - ColorConstants.SetupComplete.outerRing.setStroke() - outer_button_ringPath.lineWidth = 1.5 - outer_button_ringPath.lineCapStyle = .round - outer_button_ringPath.lineJoinStyle = .round - outer_button_ringPath.stroke() - - - //// inner_button_ring Drawing - let inner_button_ringPath = NSBezierPath(ovalIn: NSRect(x: frame.minX + 5, y: frame.minY + frame.height - 78, width: 75, height: 75)) - NSColor.white.setFill() - inner_button_ringPath.fill() - innerRingColor?.setStroke() - inner_button_ringPath.lineWidth = 1.5 - inner_button_ringPath.lineCapStyle = .round - inner_button_ringPath.lineJoinStyle = .round - inner_button_ringPath.stroke() - - //// Group - NSGraphicsContext.saveGraphicsState() - context.translateBy(x: frame.minX + 34.29, y: frame.maxY - 33.75) - context.rotate(by: 38.09 * CGFloat.pi/180) - - context.beginTransparencyLayer(auxiliaryInfo: nil) - - //// Arrow Drawing - NSGraphicsContext.saveGraphicsState() - context.translateBy(x: 2.89, y: -11.25) - context.rotate(by: -519.72 * CGFloat.pi/180) - - let ovalRect = NSRect(x: -27.78, y: -29.06, width: 55.55, height: 58.11) - let ovalPath = NSBezierPath() - ovalPath.appendArc(withCenter: NSPoint(x: 0, y: 0), radius: ovalRect.width / 2, startAngle: -91, endAngle: -39, clockwise: true) - - var ovalTransform = AffineTransform() - ovalTransform.translate(x: ovalRect.midX, y: ovalRect.midY) - ovalTransform.scale(x: 1, y: ovalRect.height / ovalRect.width) - ovalPath.transform(using: ovalTransform) - - ColorConstants.SetupComplete.BackupButton.arrowTail?.setStroke() - ovalPath.lineWidth = 3 - ovalPath.lineCapStyle = .round - ovalPath.lineJoinStyle = .bevel - ovalPath.stroke() - - NSGraphicsContext.restoreGraphicsState() - - //// Polygon Drawing - NSGraphicsContext.saveGraphicsState() - context.translateBy(x: -9.65, y: 15.01) - context.rotate(by: 110.98 * CGFloat.pi/180) - - NSGraphicsContext.saveGraphicsState() - context.setBlendMode(.darken) - - let polygonPath = NSBezierPath() - polygonPath.move(to: NSPoint(x: 0, y: 7.39)) - polygonPath.line(to: NSPoint(x: 7.08, y: -3.7)) - polygonPath.line(to: NSPoint(x: -7.08, y: -3.7)) - polygonPath.close() - clockhandsArrowheadColor?.setFill() - polygonPath.fill() - - NSGraphicsContext.restoreGraphicsState() - - NSGraphicsContext.restoreGraphicsState() - - context.endTransparencyLayer() - - NSGraphicsContext.restoreGraphicsState() - - //// Clockhand drawing - let rectanglePath = NSBezierPath(rect: NSRect(x: frame.minX + 39, y: frame.minY + frame.height - 45, width: 3, height: 21)) - clockhandsArrowheadColor?.setFill() - rectanglePath.fill() - arrowTailColor?.setStroke() - rectanglePath.lineWidth = 0.5 - rectanglePath.lineCapStyle = .round - rectanglePath.lineJoinStyle = .bevel - rectanglePath.stroke() - - - //// Clockhand Drawing - let rectangle2Path = NSBezierPath(rect: NSRect(x: frame.minX + 42, y: frame.minY + frame.height - 48, width: 16.75, height: 3)) - clockhandsArrowheadColor?.setFill() - rectangle2Path.fill() - clockhandsArrowheadColor?.setStroke() - rectangle2Path.lineWidth = 0.5 - rectangle2Path.lineCapStyle = .round - rectangle2Path.lineJoinStyle = .bevel - rectangle2Path.stroke() - - - //// Clock Center / Clockhand joining Nut Drawing - let oval2Path = NSBezierPath(ovalIn: NSRect(x: frame.minX + 38, y: frame.minY + frame.height - 49, width: 6, height: 6)) - clockhandsArrowheadColor?.setFill() - oval2Path.fill() - - - } - - @objc dynamic public class func drawSelfService(frame: NSRect = NSRect(x: 0, y: 0, width: 85, height: 81)) { - //// General Declarations - let context = NSGraphicsContext.current!.cgContext - - //// Color Declarations - let upperLeftColor = ColorConstants.SetupComplete.SelfServiceButton.upperLeft - let lowerLeftColor = ColorConstants.SetupComplete.SelfServiceButton.lowerLeft - let lowerRightColor = ColorConstants.SetupComplete.SelfServiceButton.lowerRight - let upperRightColor = ColorConstants.SetupComplete.SelfServiceButton.upperRight - let innerRingColor = ColorConstants.SetupComplete.SelfServiceButton.innerRing - - //// outer_button_ringPath Drawing - let outer_button_ringPath = NSBezierPath(ovalIn: NSRect(x: frame.minX + 4, y: frame.minY + frame.height - 79, width: 77, height: 77)) - ColorConstants.SetupComplete.outerRing.setStroke() - outer_button_ringPath.lineWidth = 1.5 - outer_button_ringPath.lineCapStyle = .round - outer_button_ringPath.lineJoinStyle = .round - outer_button_ringPath.stroke() - - //// inner_button_ring Drawing - let inner_button_ringPath = NSBezierPath(ovalIn: NSRect(x: frame.minX + 5, y: frame.minY + frame.height - 78, width: 75, height: 75)) - NSColor.white.setFill() - inner_button_ringPath.fill() - innerRingColor?.setStroke() - inner_button_ringPath.lineWidth = 1.5 - inner_button_ringPath.lineCapStyle = .round - inner_button_ringPath.lineJoinStyle = .round - inner_button_ringPath.stroke() - - //// Group - //// Upper Left Corner Shape Drawing - let bezierPath = NSBezierPath() - bezierPath.move(to: NSPoint(x: frame.minX + 48.56, y: frame.maxY - 16.38)) - bezierPath.line(to: NSPoint(x: frame.minX + 44.43, y: frame.maxY - 27.83)) - bezierPath.line(to: NSPoint(x: frame.minX + 35.67, y: frame.maxY - 24.69)) - bezierPath.curve(to: NSPoint(x: frame.minX + 34.48, y: frame.maxY - 24.69), controlPoint1: NSPoint(x: frame.minX + 35.67, y: frame.maxY - 24.69), controlPoint2: NSPoint(x: frame.minX + 35.06, y: frame.maxY - 24.39)) - bezierPath.curve(to: NSPoint(x: frame.minX + 33.36, y: frame.maxY - 25.92), controlPoint1: NSPoint(x: frame.minX + 33.9, y: frame.maxY - 25), controlPoint2: NSPoint(x: frame.minX + 33.36, y: frame.maxY - 25.92)) - bezierPath.line(to: NSPoint(x: frame.minX + 30.34, y: frame.maxY - 34.09)) - bezierPath.line(to: NSPoint(x: frame.minX + 18.57, y: frame.maxY - 29.94)) - bezierPath.line(to: NSPoint(x: frame.minX + 23.55, y: frame.maxY - 16.38)) - bezierPath.curve(to: NSPoint(x: frame.minX + 27.54, y: frame.maxY - 12.3), controlPoint1: NSPoint(x: frame.minX + 23.55, y: frame.maxY - 16.38), controlPoint2: NSPoint(x: frame.minX + 24.6, y: frame.maxY - 13.86)) - bezierPath.curve(to: NSPoint(x: frame.minX + 33.36, y: frame.maxY - 11.07), controlPoint1: NSPoint(x: frame.minX + 30.48, y: frame.maxY - 10.73), controlPoint2: NSPoint(x: frame.minX + 33.36, y: frame.maxY - 11.07)) - bezierPath.line(to: NSPoint(x: frame.minX + 48.56, y: frame.maxY - 16.38)) - upperLeftColor?.setFill() - bezierPath.fill() - upperLeftColor?.setStroke() - bezierPath.lineWidth = 1 - bezierPath.lineCapStyle = .round - bezierPath.lineJoinStyle = .round - bezierPath.stroke() - - //// Lower Left Corner Shape Drawing - NSGraphicsContext.saveGraphicsState() - context.translateBy(x: frame.minX + 35.28, y: frame.maxY - 63.51) - context.rotate(by: 89.3 * CGFloat.pi/180) - - let bezier2Path = NSBezierPath() - bezier2Path.move(to: NSPoint(x: 29.14, y: 18.21)) - bezier2Path.line(to: NSPoint(x: 25.12, y: 6.44)) - bezier2Path.line(to: NSPoint(x: 16.61, y: 9.67)) - bezier2Path.curve(to: NSPoint(x: 15.46, y: 9.67), controlPoint1: NSPoint(x: 16.61, y: 9.67), controlPoint2: NSPoint(x: 16.02, y: 9.98)) - bezier2Path.curve(to: NSPoint(x: 14.37, y: 8.41), controlPoint1: NSPoint(x: 14.89, y: 9.35), controlPoint2: NSPoint(x: 14.37, y: 8.41)) - bezier2Path.line(to: NSPoint(x: 11.44, y: 0)) - bezier2Path.line(to: NSPoint(x: -0, y: 4.27)) - bezier2Path.line(to: NSPoint(x: 4.83, y: 18.21)) - bezier2Path.curve(to: NSPoint(x: 8.72, y: 22.41), controlPoint1: NSPoint(x: 4.83, y: 18.21), controlPoint2: NSPoint(x: 5.86, y: 20.8)) - bezier2Path.curve(to: NSPoint(x: 14.37, y: 23.67), controlPoint1: NSPoint(x: 11.58, y: 24.02), controlPoint2: NSPoint(x: 14.37, y: 23.67)) - bezier2Path.line(to: NSPoint(x: 29.14, y: 18.21)) - lowerLeftColor?.setFill() - bezier2Path.fill() - lowerLeftColor?.setStroke() - bezier2Path.lineWidth = 1 - bezier2Path.lineCapStyle = .round - bezier2Path.lineJoinStyle = .round - bezier2Path.stroke() - - NSGraphicsContext.restoreGraphicsState() - - //// Lower Right Corner Shape Drawing - NSGraphicsContext.saveGraphicsState() - context.translateBy(x: frame.minX + 65.66, y: frame.maxY - 47.41) - context.rotate(by: 179.96 * CGFloat.pi/180) - - let bezier3Path = NSBezierPath() - bezier3Path.move(to: NSPoint(x: 29.99, y: 17.71)) - bezier3Path.line(to: NSPoint(x: 25.86, y: 6.27)) - bezier3Path.line(to: NSPoint(x: 17.1, y: 9.4)) - bezier3Path.curve(to: NSPoint(x: 15.91, y: 9.4), controlPoint1: NSPoint(x: 17.1, y: 9.4), controlPoint2: NSPoint(x: 16.49, y: 9.71)) - bezier3Path.curve(to: NSPoint(x: 14.79, y: 8.17), controlPoint1: NSPoint(x: 15.33, y: 9.09), controlPoint2: NSPoint(x: 14.79, y: 8.17)) - bezier3Path.line(to: NSPoint(x: 11.77, y: -0)) - bezier3Path.line(to: NSPoint(x: -0, y: 4.15)) - bezier3Path.line(to: NSPoint(x: 4.98, y: 17.71)) - bezier3Path.curve(to: NSPoint(x: 8.97, y: 21.8), controlPoint1: NSPoint(x: 4.98, y: 17.71), controlPoint2: NSPoint(x: 6.03, y: 20.23)) - bezier3Path.curve(to: NSPoint(x: 14.79, y: 23.02), controlPoint1: NSPoint(x: 11.91, y: 23.36), controlPoint2: NSPoint(x: 14.79, y: 23.02)) - bezier3Path.line(to: NSPoint(x: 29.99, y: 17.71)) - lowerRightColor?.setFill() - bezier3Path.fill() - lowerRightColor?.setStroke() - bezier3Path.lineWidth = 1 - bezier3Path.lineCapStyle = .round - bezier3Path.lineJoinStyle = .round - bezier3Path.stroke() - - NSGraphicsContext.restoreGraphicsState() - - //// Upper Right Corner Shape Drawing - NSGraphicsContext.saveGraphicsState() - context.translateBy(x: frame.minX + 48.74, y: frame.maxY - 18.16) - context.rotate(by: -90.27 * CGFloat.pi/180) - - let bezier4Path = NSBezierPath() - bezier4Path.move(to: NSPoint(x: 29.15, y: 18.22)) - bezier4Path.line(to: NSPoint(x: 25.13, y: 6.45)) - bezier4Path.line(to: NSPoint(x: 16.62, y: 9.67)) - bezier4Path.curve(to: NSPoint(x: 15.46, y: 9.67), controlPoint1: NSPoint(x: 16.62, y: 9.67), controlPoint2: NSPoint(x: 16.02, y: 9.98)) - bezier4Path.curve(to: NSPoint(x: 14.37, y: 8.41), controlPoint1: NSPoint(x: 14.9, y: 9.35), controlPoint2: NSPoint(x: 14.37, y: 8.41)) - bezier4Path.line(to: NSPoint(x: 11.44, y: 0)) - bezier4Path.line(to: NSPoint(x: -0, y: 4.27)) - bezier4Path.line(to: NSPoint(x: 4.84, y: 18.22)) - bezier4Path.curve(to: NSPoint(x: 8.72, y: 22.42), controlPoint1: NSPoint(x: 4.84, y: 18.22), controlPoint2: NSPoint(x: 5.86, y: 20.81)) - bezier4Path.curve(to: NSPoint(x: 14.37, y: 23.68), controlPoint1: NSPoint(x: 11.58, y: 24.03), controlPoint2: NSPoint(x: 14.37, y: 23.68)) - bezier4Path.line(to: NSPoint(x: 29.15, y: 18.22)) - upperRightColor?.setFill() - bezier4Path.fill() - upperRightColor?.setStroke() - bezier4Path.lineWidth = 1 - bezier4Path.lineCapStyle = .round - bezier4Path.lineJoinStyle = .round - bezier4Path.stroke() - - NSGraphicsContext.restoreGraphicsState() - - //// Upper Left Oval Drawing - let upperLeftOvalPath = NSBezierPath(ovalIn: NSRect(x: frame.minX + 36.5, y: frame.minY + frame.height - 36.5, width: 4, height: 4)) - upperLeftColor?.setFill() - upperLeftOvalPath.fill() - upperLeftColor?.setStroke() - upperLeftOvalPath.lineWidth = 1 - upperLeftOvalPath.stroke() - - //// Upper Right Oval Drawing - let upperRightOvalPath = NSBezierPath(ovalIn: NSRect(x: frame.minX + 46.5, y: frame.minY + frame.height - 40, width: 4, height: 4)) - upperRightColor?.setFill() - upperRightOvalPath.fill() - upperRightColor?.setStroke() - upperRightOvalPath.lineWidth = 1 - upperRightOvalPath.stroke() - - //// Oval 6 Drawing - let lowerLeftOvalPath = NSBezierPath(ovalIn: NSRect(x: frame.minX + 32.5, y: frame.minY + frame.height - 46, width: 4, height: 4)) - lowerLeftColor?.setFill() - lowerLeftOvalPath.fill() - lowerLeftColor?.setStroke() - lowerLeftOvalPath.lineWidth = 1 - lowerLeftOvalPath.stroke() - - //// Oval 7 Drawing - let lowerRightOvalPath = NSBezierPath(ovalIn: NSRect(x: frame.minX + 43, y: frame.minY + frame.height - 50, width: 4, height: 4)) - lowerRightColor?.setFill() - lowerRightOvalPath.fill() - lowerRightColor?.setStroke() - lowerRightOvalPath.lineWidth = 1 - lowerRightOvalPath.stroke() - - - } - - - @objc dynamic public class func qna(frame: NSRect = NSRect(x: 0, y: 0, width: 85, height: 81)) { - //// General Declarations - let context = NSGraphicsContext.current!.cgContext - - //// Color Declarations - let helpBubbleStrokeColor = ColorConstants.SetupComplete.HelpButton.bubbleStroke - let windowBackgroundColor = ColorConstants.SetupComplete.HelpButton.windowBackground - let checkmarkColor = ColorConstants.SetupComplete.HelpButton.checkmark - let innerRingColor = ColorConstants.SetupComplete.HelpButton.innerRing - - //// outer_button_ring Drawing - let outer_button_ringPath = NSBezierPath(ovalIn: NSRect(x: frame.minX + 4, y: frame.minY + frame.height - 79, width: 77, height: 77)) - ColorConstants.SetupComplete.outerRing.setStroke() - outer_button_ringPath.lineWidth = 1.5 - outer_button_ringPath.lineCapStyle = .round - outer_button_ringPath.lineJoinStyle = .round - outer_button_ringPath.stroke() - - //// inner_button_ring Drawing - let inner_button_ringPath = NSBezierPath(ovalIn: NSRect(x: frame.minX + 5, y: frame.minY + frame.height - 78, width: 75, height: 75)) - NSColor.white.setFill() - inner_button_ringPath.fill() - innerRingColor?.setStroke() - inner_button_ringPath.lineWidth = 1.5 - inner_button_ringPath.lineCapStyle = .round - inner_button_ringPath.lineJoinStyle = .round - inner_button_ringPath.stroke() - - //// Rectangle Drawing - let rectanglePath = NSBezierPath() - rectanglePath.move(to: NSPoint(x: frame.minX + 18, y: frame.maxY - 30.66)) - rectanglePath.curve(to: NSPoint(x: frame.minX + 21.19, y: frame.maxY - 33.83), controlPoint1: NSPoint(x: frame.minX + 18, y: frame.maxY - 32.41), controlPoint2: NSPoint(x: frame.minX + 19.43, y: frame.maxY - 33.83)) - rectanglePath.line(to: NSPoint(x: frame.minX + 43.53, y: frame.maxY - 33.83)) - rectanglePath.line(to: NSPoint(x: frame.minX + 49.51, y: frame.maxY - 37)) - rectanglePath.curve(to: NSPoint(x: frame.minX + 46.72, y: frame.maxY - 30.66), controlPoint1: NSPoint(x: frame.minX + 51.51, y: frame.maxY - 35.81), controlPoint2: NSPoint(x: frame.minX + 46.72, y: frame.maxY - 32.41)) - rectanglePath.line(to: NSPoint(x: frame.minX + 46.72, y: frame.maxY - 17.17)) - rectanglePath.curve(to: NSPoint(x: frame.minX + 43.53, y: frame.maxY - 14), controlPoint1: NSPoint(x: frame.minX + 46.72, y: frame.maxY - 15.42), controlPoint2: NSPoint(x: frame.minX + 45.29, y: frame.maxY - 14)) - rectanglePath.line(to: NSPoint(x: frame.minX + 21.19, y: frame.maxY - 14)) - rectanglePath.curve(to: NSPoint(x: frame.minX + 18, y: frame.maxY - 17.17), controlPoint1: NSPoint(x: frame.minX + 19.43, y: frame.maxY - 14), controlPoint2: NSPoint(x: frame.minX + 18, y: frame.maxY - 15.42)) - rectanglePath.line(to: NSPoint(x: frame.minX + 18, y: frame.maxY - 30.66)) - rectanglePath.close() - windowBackgroundColor?.setFill() - rectanglePath.fill() - helpBubbleStrokeColor?.setStroke() - rectanglePath.lineWidth = 2 - rectanglePath.stroke() - - //// Bezier Drawing - let bezierPath = NSBezierPath() - windowBackgroundColor?.setFill() - bezierPath.fill() - helpBubbleStrokeColor?.setStroke() - bezierPath.lineWidth = 2 - bezierPath.stroke() - - //// Rectangle 3 Drawing - let rectangle3Path = NSBezierPath() - rectangle3Path.move(to: NSPoint(x: frame.minX + 69, y: frame.maxY - 59.38)) - rectangle3Path.curve(to: NSPoint(x: frame.minX + 65.91, y: frame.maxY - 62.69), controlPoint1: NSPoint(x: frame.minX + 69, y: frame.maxY - 61.21), controlPoint2: NSPoint(x: frame.minX + 67.62, y: frame.maxY - 62.69)) - rectangle3Path.line(to: NSPoint(x: frame.minX + 44.27, y: frame.maxY - 62.69)) - rectangle3Path.line(to: NSPoint(x: frame.minX + 38.47, y: frame.maxY - 66)) - rectangle3Path.curve(to: NSPoint(x: frame.minX + 41.18, y: frame.maxY - 59.38), controlPoint1: NSPoint(x: frame.minX + 36.54, y: frame.maxY - 64.76), controlPoint2: NSPoint(x: frame.minX + 41.18, y: frame.maxY - 61.21)) - rectangle3Path.line(to: NSPoint(x: frame.minX + 41.18, y: frame.maxY - 45.31)) - rectangle3Path.curve(to: NSPoint(x: frame.minX + 44.27, y: frame.maxY - 42), controlPoint1: NSPoint(x: frame.minX + 41.18, y: frame.maxY - 43.48), controlPoint2: NSPoint(x: frame.minX + 42.56, y: frame.maxY - 42)) - rectangle3Path.line(to: NSPoint(x: frame.minX + 65.91, y: frame.maxY - 42)) - rectangle3Path.curve(to: NSPoint(x: frame.minX + 69, y: frame.maxY - 45.31), controlPoint1: NSPoint(x: frame.minX + 67.62, y: frame.maxY - 42), controlPoint2: NSPoint(x: frame.minX + 69, y: frame.maxY - 43.48)) - rectangle3Path.line(to: NSPoint(x: frame.minX + 69, y: frame.maxY - 59.38)) - rectangle3Path.close() - windowBackgroundColor?.setFill() - rectangle3Path.fill() - helpBubbleStrokeColor?.setStroke() - rectangle3Path.lineWidth = 2 - rectangle3Path.stroke() - - //// checkmark Drawing - let checkmarkPath = NSBezierPath() - checkmarkPath.move(to: NSPoint(x: frame.minX + 49, y: frame.maxY - 54.33)) - checkmarkPath.line(to: NSPoint(x: frame.minX + 54.6, y: frame.maxY - 59)) - checkmarkPath.line(to: NSPoint(x: frame.minX + 61, y: frame.maxY - 45)) - checkmarkColor?.setStroke() - checkmarkPath.lineWidth = 2 - checkmarkPath.lineCapStyle = .round - checkmarkPath.lineJoinStyle = .round - checkmarkPath.stroke() - - //// questionMark Drawing - let questionMarkRect = NSRect(x: frame.minX + 28, y: frame.minY + frame.height - 33, width: 11, height: 18) - NSGraphicsContext.saveGraphicsState() - questionMarkRect.clip() - context.translateBy(x: questionMarkRect.minX, y: questionMarkRect.minY) - - SetupCompleteButtons.drawQuestion(frame: CGRect(origin: .zero, size: questionMarkRect.size), resizing: .stretch) - NSGraphicsContext.restoreGraphicsState() - - - } - - - @objc dynamic public class func drawQuestion(frame targetFrame: NSRect = NSRect(x: 0, y: 0, width: 11, height: 18), resizing: ResizingBehavior = .aspectFit) { - //// General Declarations - let context = NSGraphicsContext.current!.cgContext - - //// Resize to Target Frame - NSGraphicsContext.saveGraphicsState() - let resizedFrame: NSRect = resizing.apply(rect: NSRect(x: 0, y: 0, width: 11, height: 18), target: targetFrame) - context.translateBy(x: resizedFrame.minX, y: resizedFrame.minY) - context.scaleBy(x: resizedFrame.width / 11, y: resizedFrame.height / 18) - - //// Color Declarations - let questionMarkColor = ColorConstants.SetupComplete.HelpButton.questionMark - - //// Text Drawing - let textRect = NSRect(x: 0, y: 0, width: 11, height: 18) - let textTextContent = "?" - let textStyle = NSMutableParagraphStyle() - textStyle.alignment = .left - let textFontAttributes = [ - .font: NSFont.boldSystemFont(ofSize: 17), - .foregroundColor: questionMarkColor as Any, - .paragraphStyle: textStyle, - ] as [NSAttributedString.Key: Any] - - let textTextHeight: CGFloat = textTextContent.boundingRect(with: NSSize(width: textRect.width, height: CGFloat.infinity), options: .usesLineFragmentOrigin, attributes: textFontAttributes).height - let textTextRect: NSRect = NSRect(x: textRect.minX, y: textRect.minY + (textRect.height - textTextHeight) / 2, width: textRect.width, height: textTextHeight) - NSGraphicsContext.saveGraphicsState() - textRect.clip() - textTextContent.draw(in: textTextRect.offsetBy(dx: 0, dy: 0.5), withAttributes: textFontAttributes) - NSGraphicsContext.restoreGraphicsState() - - NSGraphicsContext.restoreGraphicsState() - } - - @objc dynamic public class func drawAppleLogo(frame targetFrame: NSRect = NSRect(x: 0, y: 0, width: 24, height: 24), resizing: ResizingBehavior = .aspectFit) { - //// General Declarations - let context = NSGraphicsContext.current!.cgContext - - //// Resize to Target Frame - NSGraphicsContext.saveGraphicsState() - let resizedFrame: NSRect = resizing.apply(rect: NSRect(x: 0, y: 0, width: 24, height: 24), target: targetFrame) - context.translateBy(x: resizedFrame.minX, y: resizedFrame.minY) - context.scaleBy(x: resizedFrame.width / 24, y: resizedFrame.height / 24) - - //// Color Declarations - let apple_logo_color = ColorConstants.SetupComplete.appleLogo - //// Label Drawing - let labelRect = NSRect(x: 0, y: 0, width: 24, height: 24) - let labelStyle = NSMutableParagraphStyle() - labelStyle.alignment = .left - let labelFontAttributes = [ - .font: NSFont(name: "Helvetica-Light", size: 24)!, - .foregroundColor: apple_logo_color as Any, - .paragraphStyle: labelStyle, - ] as [NSAttributedString.Key: Any] - - "".draw(in: labelRect.offsetBy(dx: 0, dy: 0), withAttributes: labelFontAttributes) - - NSGraphicsContext.restoreGraphicsState() - } - - @objc dynamic public class func drawWebURL(frame targetFrame: NSRect = NSRect(x: 0, y: 0, width: 52, height: 15), resizing: ResizingBehavior = .aspectFit) { - //// General Declarations - let context = NSGraphicsContext.current!.cgContext - - //// Resize to Target Frame - NSGraphicsContext.saveGraphicsState() - let resizedFrame: NSRect = resizing.apply(rect: NSRect(x: 0, y: 0, width: 52, height: 15), target: targetFrame) - context.translateBy(x: resizedFrame.minX, y: resizedFrame.minY) - context.scaleBy(x: resizedFrame.width / 52, y: resizedFrame.height / 15) - - - //// Color Declarations - let textForeground = NSColor(red: 0.592, green: 0.592, blue: 0.592, alpha: 1) - - //// Text Drawing - let textRect = NSRect(x: 0, y: 0, width: 52, height: 15) - let textTextContent = "https://" - let textStyle = NSMutableParagraphStyle() - textStyle.alignment = .left - let textFontAttributes = [ - .font: NSFont.boldSystemFont(ofSize: NSFont.systemFontSize), - .foregroundColor: textForeground, - .paragraphStyle: textStyle, - ] as [NSAttributedString.Key: Any] - - let textTextHeight: CGFloat = textTextContent.boundingRect(with: NSSize(width: textRect.width, height: CGFloat.infinity), options: .usesLineFragmentOrigin, attributes: textFontAttributes).height - let textTextRect: NSRect = NSRect(x: textRect.minX, y: textRect.minY + (textRect.height - textTextHeight) / 2, width: textRect.width, height: textTextHeight) - NSGraphicsContext.saveGraphicsState() - textRect.clip() - textTextContent.draw(in: textTextRect.offsetBy(dx: 0, dy: 0.5), withAttributes: textFontAttributes) - NSGraphicsContext.restoreGraphicsState() - - NSGraphicsContext.restoreGraphicsState() - } - - - @objc(SetupCompleteScreenButtonsResizingBehavior) - public enum ResizingBehavior: Int { - case aspectFit /// The content is proportionally resized to fit into the target rectangle. - case aspectFill /// The content is proportionally resized to completely fill the target rectangle. - case stretch /// The content is stretched to match the entire target rectangle. - case center /// The content is centered in the target rectangle, but it is NOT resized. - - public func apply(rect: NSRect, target: NSRect) -> NSRect { - if rect == target || target == NSRect.zero { - return rect - } - - var scales = NSSize.zero - scales.width = abs(target.width / rect.width) - scales.height = abs(target.height / rect.height) - - switch self { - case .aspectFit: - scales.width = min(scales.width, scales.height) - scales.height = scales.width - case .aspectFill: - scales.width = max(scales.width, scales.height) - scales.height = scales.width - case .stretch: - break - case .center: - scales.width = 1 - scales.height = 1 - } - - var result = rect.standardized - result.size.width *= scales.width - result.size.height *= scales.height - result.origin.x = target.minX + (target.width - result.width) / 2 - result.origin.y = target.minY + (target.height - result.height) / 2 - return result - } - } - - @objc dynamic public class var imageOfMigrationButton: NSImage { - if Cache.imageOfMigrationButton != nil { - return Cache.imageOfMigrationButton! - } - - Cache.imageOfMigrationButton = NSImage(size: NSSize(width: 85, height: 81), flipped: false) { _ in - SetupCompleteButtons.drawMigration() - - return true - } - - return Cache.imageOfMigrationButton! - } - - @objc dynamic public class var imageOfSelfServiceButton: NSImage { - if Cache.imageOfSelfServiceButton != nil { - return Cache.imageOfSelfServiceButton! - } - - Cache.imageOfSelfServiceButton = NSImage(size: NSSize(width: 85, height: 81), flipped: false) { _ in - SetupCompleteButtons.drawSelfService() - - return true - } - - return Cache.imageOfSelfServiceButton! - } - - @objc dynamic public class var imageOfBackupButton: NSImage { - if Cache.imageOfBackupButton != nil { - return Cache.imageOfBackupButton! - } - - Cache.imageOfBackupButton = NSImage(size: NSSize(width: 85, height: 81), flipped: false) { _ in - SetupCompleteButtons.drawBackup() - return true - } - - return Cache.imageOfBackupButton! - } - - @objc dynamic public class var imageOfURLButton: NSImage { - if Cache.imageOfURLButton != nil { - return Cache.imageOfURLButton! - } - - Cache.imageOfURLButton = NSImage(size: NSSize(width: 85, height: 81), flipped: false) { _ in - SetupCompleteButtons.drawHelp() - return true - } - - return Cache.imageOfURLButton! - } - - @objc dynamic public class var imageOfQnAButton: NSImage { - if Cache.imageOfQnAButton != nil { - return Cache.imageOfQnAButton! - } - - Cache.imageOfQnAButton = NSImage(size: NSSize(width: 85, height: 81), flipped: false) { _ in - SetupCompleteButtons.qna() - return true - } - - return Cache.imageOfQnAButton! - } -} diff --git a/enrollment/enrollment/Models/MainStoryboardConstants.swift b/enrollment/enrollment/Models/MainStoryboardConstants.swift deleted file mode 100644 index 955027f..0000000 --- a/enrollment/enrollment/Models/MainStoryboardConstants.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// MainStoryboardConstants.swift -// enrollment -// -// Created by Jay Latman on 12/4/17. -// Copyright © 2017 IBM. All rights reserved. -// - -import Cocoa - -enum MainStoryboard { - static let name = "Main" - - static func storyboard() -> NSStoryboard { - return NSStoryboard(name: name, bundle: nil) - } - - enum SegueIdentifier: String { - case contentContainerSegue - } - - enum WindowControllerIdentifier : String { - case PrimaryRegistrationChildViewController - - func instatiateWindowController() -> NSWindowController? { - return MainStoryboard.storyboard().instantiateController(withIdentifier: self.rawValue) as? NSWindowController - } - } -} diff --git a/enrollment/enrollment/Models/ProgressStates.swift b/enrollment/enrollment/Models/ProgressStates.swift deleted file mode 100644 index e014d9c..0000000 --- a/enrollment/enrollment/Models/ProgressStates.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// ProgressStates.swift -// enrollment -// -// Created by Jay Latman on 8/7/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Foundation - -/** - Enumeration of progress states for bund and app installations - - - waiting: Waiting, not running - - inProgress: In Progress - - success: Successfull completed - - failure: Completed with error - */ -enum StatusState: Int { - case appInQueue - case appInProgress - case appInProgressAnimated - case appSuccess - case appFailure - case inQueue - case inProgress - case inProgressAnimated - case success - case partial - case failure - - - /// Indicates whether the state indicates completion - var isComplete: Bool { - get { - return self == .success || self == .failure || self == .partial - } - } -} diff --git a/enrollment/enrollment/Models/TermDefinition.swift b/enrollment/enrollment/Models/TermDefinition.swift deleted file mode 100644 index a716f63..0000000 --- a/enrollment/enrollment/Models/TermDefinition.swift +++ /dev/null @@ -1,48 +0,0 @@ -// -// TermDefinition.swift -// enrollment -// -// Created by Jay Latman on 7/26/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Foundation -import Cocoa - -/** - Structure definition to create a term / definition paired listing for info popover views - */ -struct TermDefinition: Equatable { - var term: String - var definition: String - - static func ==(lhs: TermDefinition, rhs: TermDefinition) -> Bool { - return lhs.term == rhs.term && lhs.definition == rhs.definition - } - - /** - Method for applying a `TermDefinition` to labels for info popover views - - - Parameter term : equatable `TermDefinition` comprised of two strings - - Parameter leftLabel : NSTextField in the left position - - Parameter rightLabel : NSTextField in the right position - */ - static func assignTermDefinitionsToLabels(term: TermDefinition, leftLabel: NSTextField, rightLabel: NSTextField) { - leftLabel.stringValue = term.term - rightLabel.stringValue = term.definition - leftLabel.textColor = .headerTextColor - rightLabel.textColor = .headerTextColor - } -} - -/** - Structure definition containing the string equivalents for state of settings used in SecurityDescriptionPopover - */ -struct State { - let enabled = "Enabled" - let disabled = "Disabled" - let required = "Required" -} - - diff --git a/enrollment/enrollment/Models/UpdateAppBundleInstallationUI.swift b/enrollment/enrollment/Models/UpdateAppBundleInstallationUI.swift deleted file mode 100644 index 1f9e8ea..0000000 --- a/enrollment/enrollment/Models/UpdateAppBundleInstallationUI.swift +++ /dev/null @@ -1,62 +0,0 @@ -// -// UpdateAppBundleInstallationUI.swift -// enrollment -// -// Created by Jay Latman on 9/4/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa - -/** - Class definition for updating the UI with the app installation progress used on the Bundle Installation Child View Controller - */ -class UpdateUIForAppStatus{ - var appStatusKey = String() - var appIndicator = CircularStatus() - var anchorStop = Int() - var totalBundleResult = [Double]() - var index = Int() - - /** - Class initializer for updating the installation progress UI - - - Parameter appStatusKey : string value for referencing the app bundle status property list key and value - - Parameter appIndicator : `CircularStatus` indicator - - Parameter anchorStop : integer value for anchoring the indicator to keep it positioned properly - - Parameter totalBundleResult : [Array] of doubles containing the values of 0.0 or 1.0 for each item in the bundle (0.0 = failure and 1.0 success) - - Parameter index : integer value pertaining to the index value for the paricular app in the bundle array - */ - init(appStatusKey: String, appIndicator: CircularStatus, anchorStop: inout Int, totalBundleResult: inout [Double], index: Int) { - self.appStatusKey = appStatusKey - self.appIndicator = appIndicator - self.anchorStop = anchorStop - self.totalBundleResult = totalBundleResult - self.index = index - - if let appObject = UserDefaults.standard.value(forKey: appStatusKey) { - switch String(describing: appObject) { - case "0" : - appIndicator.state = .appInQueue - case "1" : - appIndicator.state = .appInProgressAnimated - if anchorStop == 0 { - appIndicator.determineAnchorPoint(indicator: appIndicator) - } - anchorStop = 1 - appIndicator.rotate() - case "2" : - appIndicator.stopRotation() - appIndicator.state = .appSuccess - totalBundleResult[index] = 1.0 - case "3" : - appIndicator.stopRotation() - appIndicator.state = .appFailure - totalBundleResult[index] = 0.0 - default: - appIndicator.state = .appInQueue - } - } - } -} diff --git a/enrollment/enrollment/Protocols/LoadableNib.swift b/enrollment/enrollment/Protocols/LoadableNib.swift new file mode 100644 index 0000000..b255cf7 --- /dev/null +++ b/enrollment/enrollment/Protocols/LoadableNib.swift @@ -0,0 +1,32 @@ +// +// LoadableNib.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 3/5/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Cocoa + +protocol LoadableNib { + var contentView: NSView! { get } +} + +extension LoadableNib where Self: NSView { + + func loadViewFromNib() { + let bundle = Bundle(for: type(of: self)) + let nib = NSNib(nibNamed: .init(String(describing: type(of: self))), bundle: bundle)! + _ = nib.instantiate(withOwner: self, topLevelObjects: nil) + + let contentConstraints = contentView.constraints + contentView.subviews.forEach({ addSubview($0) }) + + for constraint in contentConstraints { + let firstItem = (constraint.firstItem as? NSView == contentView) ? self : constraint.firstItem + let secondItem = (constraint.secondItem as? NSView == contentView) ? self : constraint.secondItem + addConstraint(NSLayoutConstraint(item: firstItem as Any, attribute: constraint.firstAttribute, relatedBy: constraint.relation, toItem: secondItem, attribute: constraint.secondAttribute, multiplier: constraint.multiplier, constant: constraint.constant)) + } + } +} diff --git a/enrollment/enrollment/Models/Images/AnimatedGIFImageView.swift b/enrollment/enrollment/Resources/Images/AnimatedGIFImageView.swift similarity index 88% rename from enrollment/enrollment/Models/Images/AnimatedGIFImageView.swift rename to enrollment/enrollment/Resources/Images/AnimatedGIFImageView.swift index 3b10672..4c6d108 100644 --- a/enrollment/enrollment/Models/Images/AnimatedGIFImageView.swift +++ b/enrollment/enrollment/Resources/Images/AnimatedGIFImageView.swift @@ -30,12 +30,9 @@ class AnimatedGIFImageView: NSView { return } - guard - let image = NSImage(data: imageData), + guard let image = NSImage(data: imageData), let imageSource = CGImageSourceCreateWithData(imageData as CFData, nil), - let containerType = CGImageSourceGetType(imageSource), UTTypeConformsTo(containerType, kUTTypeGIF) - else - { + let containerType = CGImageSourceGetType(imageSource), UTTypeConformsTo(containerType, kUTTypeGIF) else { NSLog("ERROR: \(#file):\(#file)): Image data is not a valid GIF file.") return } @@ -45,10 +42,8 @@ class AnimatedGIFImageView: NSView { var lastFrameDelay = 0.0 for imageRepresentation in image.representations { - guard - let bitmapRepresentation = imageRepresentation as? NSBitmapImageRep, - let frameCount = bitmapRepresentation.value(forProperty: NSBitmapImageRep.PropertyKey.frameCount) as? Int - else { continue } + guard let bitmapRepresentation = imageRepresentation as? NSBitmapImageRep, + let frameCount = bitmapRepresentation.value(forProperty: NSBitmapImageRep.PropertyKey.frameCount) as? Int else { continue } var imageFrames = [CGImage]() var totalDuration = 0.0 as TimeInterval @@ -84,9 +79,7 @@ class AnimatedGIFImageView: NSView { } override var intrinsicContentSize: NSSize { - get { - return self.image?.size ?? NSSize.zero - } + return self.image?.size ?? NSSize.zero } override var frame: NSRect { @@ -109,7 +102,4 @@ class AnimatedGIFImageView: NSView { self.wantsLayer = true self.layer?.addSublayer(self.animationLayer) } - } - - diff --git a/enrollment/enrollment/Models/Images/Indicators.swift b/enrollment/enrollment/Resources/Images/Indicators.swift similarity index 99% rename from enrollment/enrollment/Models/Images/Indicators.swift rename to enrollment/enrollment/Resources/Images/Indicators.swift index 778882e..2617a1f 100644 --- a/enrollment/enrollment/Models/Images/Indicators.swift +++ b/enrollment/enrollment/Resources/Images/Indicators.swift @@ -82,7 +82,6 @@ class Indicators: NSView { oval2Path.fill() - //// Rectangle Drawing let rectanglePath = NSBezierPath(rect: NSRect(x: frame.minX + 5, y: frame.minY + frame.height - 11, width: 10, height: 2)) diff --git a/enrollment/enrollment/Resources/bee-blue.gif b/enrollment/enrollment/Resources/bee-blue.gif new file mode 100755 index 0000000..e25da77 Binary files /dev/null and b/enrollment/enrollment/Resources/bee-blue.gif differ diff --git a/enrollment/enrollment/Resources/bee-lowlight.gif b/enrollment/enrollment/Resources/bee-lowlight.gif new file mode 100755 index 0000000..08a61b7 Binary files /dev/null and b/enrollment/enrollment/Resources/bee-lowlight.gif differ diff --git a/enrollment/enrollment/Services/AppleInterfaceStyleMonitor.swift b/enrollment/enrollment/Services/AppleInterfaceStyleMonitor.swift new file mode 100644 index 0000000..e477b08 --- /dev/null +++ b/enrollment/enrollment/Services/AppleInterfaceStyleMonitor.swift @@ -0,0 +1,26 @@ +// +// AppleInterfaceStyleMonitor.swift +// Mac@IBM Enrollment +// +// Created by Jay on 12/5/18. +// Copyright © 2018 IBM. All rights reserved. +// + +//import Foundation +import AppKit + +extension NSViewController { + enum InterfaceStyle: String { + case dark = "Dark" + case light = "Light" + + init() { + let type = UserDefaults.standard.string(forKey: "AppleInterfaceStyle") ?? "Light" + self = InterfaceStyle(rawValue: type)! + } + } + + func currentInterfaceStyle() -> InterfaceStyle { + return InterfaceStyle() + } +} diff --git a/enrollment/enrollment/Services/IssueAlertService.swift b/enrollment/enrollment/Services/IssueAlertService.swift index c69f073..fa5cdb4 100644 --- a/enrollment/enrollment/Services/IssueAlertService.swift +++ b/enrollment/enrollment/Services/IssueAlertService.swift @@ -6,6 +6,7 @@ // Copyright © 2018 IBM. All rights reserved. // SPDX-License-Identifier: GPL-3.0-only // +// swiftlint:disable function_parameter_count import Cocoa @@ -27,9 +28,15 @@ class IssueAlertService: NSObject { - Parameter button1 : string value for the cancel button label - Parameter button2 : string value for the proceed / action button label - Parameter jamfEvent : string value for the jamf event trigger - - Parameter button1LogText : string value for the logging of the cancel button being used - */ - func displaySheetWithJAMFAction(header messageText: String?, message informativeText: String?, style: NSAlert.Style, cancelButtonLabel button1: String?, actionButtonLabel button2: String?, jamfPolicyEvent jamfEvent: String?, button1LogText: String?) { + - Parameter button1LogText : string value for logging of cancel button being used + */ + func displaySheetWithJAMFAction(header messageText: String?, + message informativeText: String?, + style: NSAlert.Style, + cancelButtonLabel button1: String?, + actionButtonLabel button2: String?, + jamfPolicyEvent jamfEvent: String?, + button1LogText: String?) { let alert = NSAlert() if let message = messageText { @@ -52,7 +59,7 @@ class IssueAlertService: NSObject { alert.beginSheetModal(for: NSApp.keyWindow!) { (returnCode) -> Void in if returnCode == NSApplication.ModalResponse.alertSecondButtonReturn { - XPCService.sharedInstance.processJAMFAction(event: JAMFPolicyEventID.removeFramework) + PrivilegedHelperController.shared.processJAMFPolicy(Context.main?.dataSet.policies.removeFramework ?? "") exit(0) } else { if button1LogText != nil { @@ -69,7 +76,7 @@ class IssueAlertService: NSObject { - Parameter informativeText : string value for the central part of the alert - Parameter style : NSAlert.style (critical, informational, warning) - Parameter button1 : string value for the cancel button label - */ + */ func displayModalFailureToLaunch(header messageText: String?, message informativeText: String?, style: NSAlert.Style, cancelButtonLabel button1: String?) { let appLaunchFailure = NSAlert() @@ -95,14 +102,14 @@ class IssueAlertService: NSObject { Method for displaying an alert sheet in the event the network is unreachable - Parameter message : string value for the alert text to be displayed - */ + */ func displaySheetNetworkUnreachable(message: String?) { let alert = NSAlert() if let message = message { alert.messageText = message } alert.alertStyle = .critical - alert.addButton(withTitle: "OK") + alert.addButton(withTitle: "buttonLabelOk".localized) alert.beginSheetModal(for: NSApp.keyWindow!) } } diff --git a/enrollment/enrollment/Services/NetworkValidationService.swift b/enrollment/enrollment/Services/NetworkValidationService.swift index c34d0e4..88522ca 100644 --- a/enrollment/enrollment/Services/NetworkValidationService.swift +++ b/enrollment/enrollment/Services/NetworkValidationService.swift @@ -13,7 +13,7 @@ import SystemConfiguration /** Shared service class for extending network validation to the enrollment app -*/ + */ class NetworkValidationService: NSObject { static let sharedInstance: NetworkValidationService = { @@ -51,8 +51,8 @@ class NetworkValidationService: NSObject { Method for validating if the system is able to reach an internal url / intranet - Parameter urlPath : string value containing the internal testing url - */ - func verifyInternalURL(urlPath: String, completion: @escaping (_ isValid: Bool)->()) { + */ + func verifyInternalURL(urlPath: String, completion: @escaping (_ isValid: Bool) -> Void) { if let url = NSURL(string: urlPath) { let request = NSMutableURLRequest(url: url as URL) request.httpMethod = "HEAD" @@ -74,12 +74,12 @@ class NetworkValidationService: NSObject { Method for validating if the system is able to reach the Jamf Pro Server - Parameter jpsURL : string value containing the health check url for the Jamf Pro Server - */ + */ func checkForJPSAvailability(jpsURL: String, completion: @escaping (_ result: Int) -> Void) { let url = URL(string: jpsURL)! let request = URLRequest(url: url) - let task = URLSession.shared.dataTask(with: request) {data, response, error in + let task = URLSession.shared.dataTask(with: request) {_, response, _ in if let httpResponse = response as? HTTPURLResponse { let responseCode = httpResponse.statusCode @@ -91,14 +91,14 @@ class NetworkValidationService: NSObject { } /** - Private method for displaying an alert sheet in the event the network validation returns a false state + Method for displaying a alert sheet to the user in the event that the any network validation has a failure state */ private func displayInternalNetworkValidationWarning() { DispatchQueue.main.async { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = AlertText.NetworkValidationMessaging.Internal.warning - alert.addButton(withTitle: "OK") + alert.addButton(withTitle: "buttonLabelOk".localized) alert.beginSheetModal(for: NSApp.keyWindow!) } } diff --git a/enrollment/enrollment/Services/PrivilegedHelperController.swift b/enrollment/enrollment/Services/PrivilegedHelperController.swift new file mode 100644 index 0000000..5e5a117 --- /dev/null +++ b/enrollment/enrollment/Services/PrivilegedHelperController.swift @@ -0,0 +1,182 @@ +// +// PrivilegedHelperController.swift +// Mac@IBM +// +// Created by Simone Martorelli on 8/24/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// +// swiftlint:disable line_length + +import Cocoa +import ServiceManagement +import os.log + +class PrivilegedHelperController: NSObject, NSXPCListenerDelegate { + + // MARK: - Static variables + + static let shared = PrivilegedHelperController() + + // MARK: - Private variables + + private var helperMachServiceName = "com.ibm.cio.be.PrivilegedCommandsHelper" + private var xpcHelperConnection: NSXPCConnection? + private var authRef: AuthorizationRef? + + // MARK: - Private methods + + private func prepareConnection() { + guard self.xpcHelperConnection == nil else { + os_log("XPC Connection ready") + return + } + os_log("Preparing XPC Connection") + self.xpcHelperConnection = NSXPCConnection(machServiceName: helperMachServiceName, options: [.privileged]) + self.xpcHelperConnection?.remoteObjectInterface = NSXPCInterface(with: RemoteProcessProtocol.self) + self.xpcHelperConnection?.invalidationHandler = { + self.xpcHelperConnection?.invalidationHandler = nil + OperationQueue.main.addOperation { + self.xpcHelperConnection = nil + os_log("XPC Connection invalidated") + } + } + self.xpcHelperConnection?.resume() + os_log("Resuming XPC Connection") + } + + private func helper(_ errorHandler: @escaping (Error) -> Void) -> RemoteProcessProtocol? { + return self.xpcHelperConnection?.remoteObjectProxyWithErrorHandler({ (error) in + errorHandler(error) + }) as? RemoteProcessProtocol + } + + private func initAuthorizationRef() { + var authorizationExtForm = AuthorizationExternalForm() + os_log("Requesting priviledged authorizations") + var authStatus = AuthorizationCreate(nil, nil, AuthorizationFlags(), &authRef) + guard authStatus == errAuthorizationSuccess, authRef != nil else { + os_log(.error, "Authorization failure: %{public}@", authStatus.description) + return + } + authStatus = AuthorizationMakeExternalForm(authRef!, &authorizationExtForm) + guard authStatus == errAuthorizationSuccess else { + os_log(.error, "Authorization failure: %{public}@", authStatus.description) + return + } + guard authRef != nil else { + os_log(.error, "Authorization failure: %{public}@", authStatus.description) + return + } + let authName = kSMRightBlessPrivilegedHelper + var blockErr = OSStatus() + + blockErr = AuthorizationRightGet(authName, nil) + if blockErr == errAuthorizationDenied { + blockErr = AuthorizationRightSet(authRef!, + authName, + kAuthorizationRuleAuthenticateAsAdmin as CFTypeRef, + "Localizable" as CFString, + nil, + "Localizable" as CFString) + guard blockErr == errAuthorizationSuccess else { + os_log(.error, "Authorization failure: %{public}@", blockErr.description) + return + } + } + os_log("Authorization success: %{public}@", blockErr.description) + } + + private func installHelperDaemon() { + var error: Unmanaged? + var success: Bool = false + + success = SMJobBless(kSMDomainSystemLaunchd, helperMachServiceName as CFString, authRef, &error) + + if success { + os_log("%{public}@ installed successfully", helperMachServiceName) + } else { + let blessError = error!.takeRetainedValue() as Error + os_log(.error, "Bless Error: %{public}@", blessError.localizedDescription) + } + } + + private func checkIfHelperDaemonExists() -> Bool { + let fileManager = FileManager.default + + if !fileManager.fileExists(atPath: "/Library/PrivilegedHelperTools/\(helperMachServiceName)") { + os_log("Helper not found") + return false + } else { + os_log("Helper found") + return true + } + } + + private func checkHelperVersionAndUpdateIfNecessary() { + let helperURL = Bundle.main.bundleURL.appendingPathComponent("Contents/Library/LaunchServices/\(helperMachServiceName)") + guard let helperBundleInfo = CFBundleCopyInfoDictionaryForURL(helperURL as CFURL), + let helperVersion = (helperBundleInfo as NSDictionary)["CFBundleVersion"] as? String else { + os_log(.error, "Failed to obtain Helper's new version value") + return + } + + os_log("PrivilegedCommandsHelper Bundle Version: %{public}@", helperVersion) + os_log("Preparing XPC Service") + self.prepareConnection() + + guard let xpcService = self.helper({ error in + os_log(.error, "XPC Error: %{public}@", error.localizedDescription) + }) else { + os_log(.error, "XPC Service failed to obtain object's proxy") + return + } + + xpcService.getVersion(reply: { (installedVersion) in + guard let installedVersion = installedVersion else { + os_log(.error, "Failed to obtain Helper's installed version value") + return + } + os_log("Helper Installed Version: %{public}@", installedVersion) + if installedVersion != helperVersion { + os_log("Starting installation of the latest version") + self.installHelperDaemon() + } else { + os_log("Helper version is up to date!") + } + }) + } + + // MARK: - Public methods + + func setupHelperController() { + initAuthorizationRef() + if !checkIfHelperDaemonExists() { + installHelperDaemon() + } else { + checkHelperVersionAndUpdateIfNecessary() + } + } + + func releaseAuthorizationRef() { + AuthorizationFree(authRef!, AuthorizationFlags.destroyRights) + } + + func processJAMFPolicy(_ policy: String) { + #if !DEBUG + self.prepareConnection() + guard let xpcService = self.helper({ error in + os_log(.error, "XPC Error: %{public}@", error.localizedDescription) + }) else { + os_log(.error, "XPC Service failed to obtain object's proxy") + return + } + os_log("XPCService will run event: %{public}@", policy) + xpcService.runPolicy(event: policy) { output in + os_log("Jamf event execution completed with output: %@", output ?? "") + } + #else + os_log(.debug, "User requested to run policy: %@", policy) + #endif + } +} diff --git a/enrollment/enrollment/Services/XPCService.swift b/enrollment/enrollment/Services/XPCService.swift deleted file mode 100644 index b57ca84..0000000 --- a/enrollment/enrollment/Services/XPCService.swift +++ /dev/null @@ -1,184 +0,0 @@ -// -// XPCService.swift -// enrollment -// -// Created by Jay Latman on 10/12/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Cocoa -import ServiceManagement - -/** - Shared service class for extending XPC operations to the enrollment app. - */ -class XPCService: NSObject, NSXPCListenerDelegate { - - private var xpcHelperConnection: NSXPCConnection? - - private var authRef: AuthorizationRef? - private var connection: NSXPCConnection? - private var listener: NSXPCListener? - - static let sharedInstance: XPCService = { - let instance = XPCService() - return instance - }() - - private override init() { - self.listener = NSXPCListener(machServiceName: JAMFHelperConstants.machServiceName) - super.init() - self.listener?.delegate = self - } - - private func prepareXPC() -> NSXPCConnection? { - if (connection == nil) { - connection = NSXPCConnection(machServiceName: JAMFHelperConstants.machServiceName, options: NSXPCConnection.Options.privileged) - connection?.remoteObjectInterface = NSXPCInterface(with: RemoteProcessProtocol.self) - connection?.invalidationHandler = { - OperationQueue.main.addOperation { - self.connection = nil - NSLog("Enrollment: XPC Connection Invalidated") - } - } - connection?.resume() - } - - return connection - } - - private func helper(_ completion: ((Bool) -> Void)?) -> RemoteProcessProtocol? { - guard let helper = self.xpcHelperConnection?.remoteObjectProxyWithErrorHandler({ (error) in - NSLog("Error : \(error)") - if let onCompletion = completion { onCompletion(false) } - }) as? RemoteProcessProtocol else { return nil } - return helper - } - - /** - Method for initializing authorization - */ - func initAuthorizationRef() { - let status = AuthorizationCreate(nil, nil, AuthorizationFlags(), &authRef) - if (status != OSStatus(errAuthorizationSuccess)) { - NSLog("Enrollment JAMFIntegrationHelper: Authorization failure") - return - } - } - - /** - Method for releasing authorization - */ - func releaseAuthorizationRef() { - AuthorizationFree(authRef!, AuthorizationFlags.destroyRights) - } - - /** - Method for installing the Jamf Integration Helper / daemon from teh app bundle. The customer will be prompted for authorization. - */ - func installHelperDaemon() { - NSLog("Enrollment: Privileged Helper daemon not found, installing a new one......") - - var authRef: AuthorizationRef? - var authStatus = AuthorizationCreate(nil, nil, [], &authRef) - - guard authStatus == errAuthorizationSuccess else { - NSLog("Enrollment: Authorization failure: \(authStatus)") - return - } - - var authItem = AuthorizationItem(name: kSMRightBlessPrivilegedHelper, valueLength: 0, value: nil, flags: 0) - var authRights = AuthorizationRights(count: 1, items: &authItem) - let flags: AuthorizationFlags = [[], .interactionAllowed, .extendRights, .preAuthorize] - authStatus = AuthorizationCreate(&authRights, nil, flags, &authRef) - - guard authStatus == errAuthorizationSuccess else { - NSLog("Enrollment: could not obtain admin privileges: \(authStatus)") - return - } - - var error: Unmanaged? = nil - - if (SMJobBless(kSMDomainSystemLaunchd, JAMFHelperConstants.machServiceName as CFString, authRef, &error) == false) { - let blessError = error!.takeRetainedValue() as Error - NSLog("Enrollment: Bless Error: \(blessError)") - } else { - NSLog("Enrollment: \(JAMFHelperConstants.machServiceName) installed successfully") - } - - AuthorizationFree(authRef!, []) - } - - /** - Method for validating if Jamf Integration Helper daemon exists - */ - func checkIfHelperDaemonExists() -> Bool { - let fileManager = FileManager.default - - if (!fileManager.fileExists(atPath: "/Library/PrivilegedHelperTools/\(JAMFHelperConstants.machServiceName)")) { - return false - } else { - return true - } - } - - /** - Method for comparing the app's helper binary version to installed daemon's version and update if not equal - */ - func checkHelperVersionAndUpdateIfNecessary() { - let helperURL = Bundle.main.bundleURL.appendingPathComponent("Contents/Library/LaunchServices/\(JAMFHelperConstants.machServiceName)") - let helperBundleInfo = CFBundleCopyInfoDictionaryForURL(helperURL as CFURL) - let helperInfo = helperBundleInfo! as NSDictionary - let helperVersion = helperInfo["CFBundleVersion"] as! String - - NSLog("Enrollment: JAMFIntegrationHelper Bundle Version => \(helperVersion)") - - let xpcService = prepareXPC()?.remoteObjectProxyWithErrorHandler() { error -> Void in - NSLog("XPC error: \(error)") - } as? RemoteProcessProtocol - - xpcService?.getVersion(reply: { (installedVersion) in - NSLog("Enrollment: JAMFIntegrationHelper Installed Version => \(installedVersion)") - if (installedVersion != helperVersion) { - self.installHelperDaemon() - } else { - NSLog("Enrollment: Bundle version matches privileged helper version") - } - }) - } - - func helperConnection() -> NSXPCConnection? { - guard self.xpcHelperConnection == nil else { - return self.xpcHelperConnection - } - let connection = NSXPCConnection(machServiceName: JAMFHelperConstants.machServiceName, options:[.privileged]) - connection.exportedObject = self - connection.remoteObjectInterface = NSXPCInterface(with: RemoteProcessProtocol.self) - connection.invalidationHandler = { - self.xpcHelperConnection?.invalidationHandler = nil - OperationQueue.main.addOperation { - self.xpcHelperConnection = nil - } - } - - self.xpcHelperConnection = connection - self.xpcHelperConnection?.resume() - return self.xpcHelperConnection - } - - /** - Method for executing a Jamf policy event trigger - - - Parameter event : string value for event trigger - */ - func processJAMFAction(event: String) { - let xpcConnection = prepareXPC()?.remoteObjectProxyWithErrorHandler() { error -> Void in - print("XPCService error: ", error) } as? RemoteProcessProtocol - - xpcConnection?.runCommand(event: event, reply: { (exitCode) in - print(exitCode) - } - ) - } -} diff --git a/enrollment/enrollment/Shared/JAMFHelperConstants.swift b/enrollment/enrollment/Shared/JAMFHelperConstants.swift deleted file mode 100644 index 43a50b1..0000000 --- a/enrollment/enrollment/Shared/JAMFHelperConstants.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// JAMFHelperConstants.swift -// enrollment -// -// Created by Jay Latman on 10/9/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Foundation - -struct JAMFHelperConstants { - static let machServiceName = "com.ibm.jamf.IntegrationHelper" -} diff --git a/enrollment/enrollment/Shared/JAMFIntegrationHelper.swift b/enrollment/enrollment/Shared/JAMFIntegrationHelper.swift deleted file mode 100644 index 0405d93..0000000 --- a/enrollment/enrollment/Shared/JAMFIntegrationHelper.swift +++ /dev/null @@ -1,59 +0,0 @@ -// -// JAMFIntegrationHelper.swift -// com.ibm.enrollmentJAMFIntegrationHelper -// -// Created by Jay Latman on 10/11/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Foundation -import AppKit - -class JAMFIntegrationHelper: NSObject, RemoteProcessProtocol, NSXPCListenerDelegate { - - var listener: NSXPCListener - - override init() { - self.listener = NSXPCListener(machServiceName:JAMFHelperConstants.machServiceName) - super.init() - self.listener.delegate = self - } - - func run() { - self.listener.resume() - RunLoop.current.run() - } - - func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool { - newConnection.exportedInterface = NSXPCInterface(with: RemoteProcessProtocol.self) - newConnection.exportedObject = self - newConnection.resume() - - return true - } - - func runPolicy(path: String, arguments: Array, reply: @escaping ((NSNumber) -> Void)) -> Void { - print("runPolicy \(arguments)") - let jamfTask : Process = Process() - - jamfTask.launchPath = path - jamfTask.arguments = arguments - - jamfTask.launch() - } - - func getVersion(reply: @escaping (String) -> Void) { - reply(Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as! String) - } - - func runCommand(event: String, reply: @escaping (NSNumber) -> Void) { - let jamfLaunchPath = "/usr/local/jamf/bin/jamf" - let jamfArguments = ["policy", "-event", event] - - NSLog("User: \(NSUserName())") - NSLog("jamf command line: \(String(describing: jamfLaunchPath )) \(String(describing: jamfArguments.joined(separator: " ")))") - - runPolicy(path: jamfLaunchPath, arguments: jamfArguments, reply: reply) - } -} diff --git a/enrollment/enrollment/Shared/RemoteProcessProtocol.swift b/enrollment/enrollment/Shared/RemoteProcessProtocol.swift index c7a75c0..a455cf1 100644 --- a/enrollment/enrollment/Shared/RemoteProcessProtocol.swift +++ b/enrollment/enrollment/Shared/RemoteProcessProtocol.swift @@ -11,6 +11,6 @@ import Foundation @objc(RemoteProcessProtocol) protocol RemoteProcessProtocol { - func runCommand(event: String, reply: @escaping (NSNumber) -> Void) - func getVersion(reply: @escaping (String) -> Void) + func runPolicy(event: String, reply: @escaping (String?) -> Void) + func getVersion(reply: @escaping (String?) -> Void) } diff --git a/enrollment/enrollment/ViewControllers/Configuration/ConfigurationErrorViewController.swift b/enrollment/enrollment/ViewControllers/Configuration/ConfigurationErrorViewController.swift new file mode 100644 index 0000000..c02b90c --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Configuration/ConfigurationErrorViewController.swift @@ -0,0 +1,44 @@ +// +// ConfigurationErrorViewController.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 5/21/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Cocoa + +class ConfigurationErrorViewController: NSViewController { + + // MARK: Variables + + private var errorMessage: String + @IBOutlet weak var errorLabel: NSTextField! + @IBOutlet weak var bottomRightButton: NSButton! + + // MARK: Initializers + + init(with errorMessage: String) { + self.errorMessage = errorMessage + super.init(nibName: "ConfigurationErrorViewController", bundle: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: Instance methods + + override func viewWillAppear() { + super.viewWillAppear() + errorLabel.stringValue = errorMessage + bottomRightButton.title = "buttonLabelClose".localized + } + + // MARK: Actions + + @IBAction func didPressedBottomRightButton(_ sender: NSButton) { + exit(0) + } +} diff --git a/enrollment/enrollment/ViewControllers/Configuration/ConfigurationErrorViewController.xib b/enrollment/enrollment/ViewControllers/Configuration/ConfigurationErrorViewController.xib new file mode 100644 index 0000000..9f11d19 --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Configuration/ConfigurationErrorViewController.xib @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/enrollment/enrollment/Controllers/MainWindow/EnrollmentWindowController.swift b/enrollment/enrollment/ViewControllers/EnrollmentWindowController.swift similarity index 79% rename from enrollment/enrollment/Controllers/MainWindow/EnrollmentWindowController.swift rename to enrollment/enrollment/ViewControllers/EnrollmentWindowController.swift index a2f6736..f62612a 100644 --- a/enrollment/enrollment/Controllers/MainWindow/EnrollmentWindowController.swift +++ b/enrollment/enrollment/ViewControllers/EnrollmentWindowController.swift @@ -9,14 +9,13 @@ import Cocoa +/// The main window controller for the application. class EnrollmentWindowController: NSWindowController { - override func windowDidLoad() { super.windowDidLoad() window?.isMovableByWindowBackground = true window?.level = .normal - window?.setAccessibilityIdentifier("Enrollment") + window?.setAccessibilityIdentifier("Mac@IBM Enrollment") window?.titleVisibility = .visible } } - diff --git a/enrollment/enrollment/ViewControllers/Installation/BundleInstallationViewController.swift b/enrollment/enrollment/ViewControllers/Installation/BundleInstallationViewController.swift new file mode 100644 index 0000000..ce61c7a --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Installation/BundleInstallationViewController.swift @@ -0,0 +1,202 @@ +// +// BundleInstallationViewController.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 4/9/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Cocoa +import Combine + +/// This class manage the bundle installation page. +class BundleInstallationViewController: NSViewController { + + struct CellLayout { + var bundle: EnrollmentBundle + var isExpanded: Bool + var height: CGFloat + } + + // MARK: - Outlets + + @IBOutlet weak var titleLabel: InfoLabelView! + @IBOutlet weak var subtitleLabel: InfoLabelView! + @IBOutlet weak var bundlesStackView: CustomStackView! + @IBOutlet weak var bottomRightButton: NSButton! + @IBOutlet weak var bottomLeftLabel: NSTextField! + @IBOutlet weak var subtitleHeight: NSLayoutConstraint! + + // MARK: - Variables + + private var viewModel = BundleInstallationViewModel() + private var timer: Timer? + private var timeLeft: Double = 0 + private var installationProcessController: InstallationProcessController? + private var bundleStackViewItems: [BundleInstallationStackViewItem] = [] + private var appStackViewItems: [[AppInstallationStackViewItem]] = [] + private var restartNeeded: Bool { + return Context.main?.dataSet.bundleInstallationPage?.bundleInstallationNeedsRestartAfter ?? true + } + + // MARK: - Instance methods + + override func viewDidLoad() { + super.viewDidLoad() + configureStackView() + } + + override func viewWillAppear() { + super.viewWillAppear() + configureLabels() + configureButtons() + configureTimer() + configureController() + } + + override func viewDidAppear() { + super.viewDidAppear() + PrivilegedHelperController.shared.processJAMFPolicy(Context.main?.dataSet.policies.bundleInstallationPolicy ?? "") + } + + override func viewWillDisappear() { + super.viewWillDisappear() + timer?.invalidate() + timer = nil + installationProcessController?.stopListeningForUpdate() + } + + // MARK: - Private methods + + private func configureLabels() { + titleLabel.labelledInfo = Context.main?.dataSet.bundleInstallationPage?.title + titleLabel.font = .systemFont(ofSize: 28) + if Context.main?.dataSet.bundleInstallationPage?.subtitle == nil { + subtitleHeight.constant = 0 + subtitleLabel.isHidden = true + } else { + subtitleLabel.labelledInfo = Context.main?.dataSet.bundleInstallationPage?.subtitle + } + timeLeft = viewModel.getEstimatedTime() + bottomLeftLabel.stringValue = "installationBundleInstallationPageSubtitle".localized + "\n" + viewModel.formatTimeInterval(for: timeLeft) + } + + private func configureButtons() { + bottomRightButton.title = "buttonLabelNext".localized + bottomRightButton.set(textColor: .white, underline: .zero) + bottomRightButton.isEnabled = false + } + + private func configureStackView() { + bundlesStackView.setHuggingPriority(NSLayoutConstraint.Priority.defaultHigh, for: .horizontal) + bundlesStackView.enclosingScrollView?.scrollerStyle = .overlay + viewModel.selectedBundles.forEach({ bundle in + let bundleStackViewItem = BundleInstallationStackViewItem(frame: .zero) + bundleStackViewItem.configure(with: bundle, isExpanded: false) + bundleStackViewItem.delegate = self + bundleStackViewItems.append(bundleStackViewItem) + bundlesStackView.addArrangedSubview(bundleStackViewItem) + + var bundleAppStackViewItems: [AppInstallationStackViewItem] = [] + bundle.apps.forEach({ app in + let appStackViewItem = AppInstallationStackViewItem(frame: .zero) + appStackViewItem.configure(with: app) + bundleAppStackViewItems.append(appStackViewItem) + bundlesStackView.addArrangedSubview(appStackViewItem) + }) + appStackViewItems.append(bundleAppStackViewItems) + }) + } + + private func configureTimer() { + timer = Timer.scheduledTimer(withTimeInterval: 60.0, repeats: true) { _ in + self.updateCounter() + } + } + + private func configureController() { + installationProcessController = InstallationProcessController(with: viewModel.selectedBundles) + installationProcessController?.delegate = self + installationProcessController?.startListeningForUpdate() + } + + private func updateCounter() { + timeLeft -= 60 + bottomLeftLabel.stringValue = "installationBundleInstallationPageSubtitle".localized + "\n" + viewModel.formatTimeInterval(for: timeLeft) + view.needsDisplay = true + } + + private func checkInstallationStatus() { + var completed: Bool = true + for bundle in viewModel.selectedBundles { + completed = completed && (bundle.status == .installed || bundle.status == .errorDuringInstallation) + } + bottomRightButton.isEnabled = completed + bottomLeftLabel.isHidden = completed + } + + // MARK: - Actions + + @IBAction func didSelectBottomRightButton(_ sender: NSButton) { + Context.main?.dataSet.phase = "2" + guard !restartNeeded else { + var systemProcessPSN = ProcessSerialNumber(highLongOfPSN: 0, lowLongOfPSN: UInt32(kSystemProcess)) + let systemProcessDescriptor = NSAppleEventDescriptor(descriptorType: DescType(typeProcessSerialNumber), + bytes: &systemProcessPSN, + length: MemoryLayout.size(ofValue: systemProcessPSN)) + let rebootEvent = NSAppleEventDescriptor(eventClass: AEEventClass(kCoreEventClass), + eventID: AEEventID(kAERestart), + targetDescriptor: systemProcessDescriptor, + returnID: AEReturnID(kAutoGenerateReturnID), + transactionID: AETransactionID(kAnyTransactionID)) + let err = AESendMessage(rebootEvent.aeDesc, nil, AESendMode(kAENoReply), kAEDefaultTimeout) + if err != noErr { + let failureAlert = NSAlert() + failureAlert.messageText = NSLocalizedString("restartFailureMessage".localized, comment: "restartFailureComment".localized) + failureAlert.runModal() + } + return + } + self.performSegue(withIdentifier: "goToPostInstallationPage", sender: self) + } +} + +// MARK: - Bundle cell delegate + +extension BundleInstallationViewController: BundleInstallationStackViewItemDelegate { + func didPressShowHideButton(_ sender: BundleInstallationStackViewItem) { + guard let bundleIndex = self.viewModel.selectedBundles.firstIndex(of: sender.bundle) else { return } + for appView in appStackViewItems[bundleIndex] { + appView.isVisible.toggle() + } + } +} + +// MARK: - Installation process controller delegate + +extension BundleInstallationViewController: InstallationProcessControllerDelegate { + func bundleStatusUpdated(_ bundleKey: String, newStatus: EnrollmentBundle.InstallationStatus) { + guard let index = viewModel.index(forBundleKey: bundleKey) else { return } + DispatchQueue.main.async { + self.bundleStackViewItems[index].updateBundle(with: newStatus) + self.checkInstallationStatus() + } + } + + func bundleMessageUpdated(_ bundleKey: String, newMessage: String) { + guard let index = viewModel.index(forBundleKey: bundleKey) else { return } + DispatchQueue.main.async { + self.bundleStackViewItems[index].updateBundle(with: newMessage) + self.checkInstallationStatus() + } + } + + func appStatusUpdated(_ appKey: String, newStatus: EnrollmentBundle.InstallationStatus) { + guard let (bundleIndex, appIndex) = viewModel.index(forAppKey: appKey) else { return } + DispatchQueue.main.async { + self.appStackViewItems[bundleIndex][appIndex].updateApp(with: newStatus) + self.checkInstallationStatus() + } + } +} diff --git a/enrollment/enrollment/ViewControllers/Installation/BundleInstallationViewModel.swift b/enrollment/enrollment/ViewControllers/Installation/BundleInstallationViewModel.swift new file mode 100644 index 0000000..aee3c29 --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Installation/BundleInstallationViewModel.swift @@ -0,0 +1,108 @@ +// +// BundleInstallationViewModel.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 4/14/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Foundation +import Combine + +/// This class handle the logic behind the update of the views of the Installation process and provide usefull methods to the viewController. +class BundleInstallationViewModel { + + // MARK: - Enums + + enum State { + case readyToStart + case started(bundle: EnrollmentBundle) + case updated(bundle: EnrollmentBundle) + case completed(bundle: EnrollmentBundle) + case ended + } + + // MARK: - Variables + + var selectedBundles: [EnrollmentBundle] { + guard let context = Context.main?.dataSet else { return [] } + return context.bundleSelectionPage?.bundles.filter({ context.selectedBundles.contains($0.key) }) ?? [] + } + var installationProcessState: State + + // MARK: - Initializer + + init() { + installationProcessState = .readyToStart + } + + // MARK: - Public methods + + /// This method translate the total size and time of selected bundles to download and install in a user friendly estimated time string. + /// - Returns: the string that show the estimated time needed to download and install the bundle. + func getEstimatedTime() -> Double { + guard let speedTestRateString = Context.main?.dataSet.networkInfo?.speedTestResult, let speedTestRate = Double(speedTestRateString), + let jamfComBufferTimeInSecondsString = Context.main?.dataSet.networkInfo?.jpsCommSeconds, let jamfComBufferTimeInSeconds = Double(jamfComBufferTimeInSecondsString), + let bundlesSize = self.getSelectedBundlesSize(), + let bundlesInstallTimeInSeconds = self.getSelectedBundlesTime() else { + return 0 + } + + return ((bundlesSize / speedTestRate) + bundlesInstallTimeInSeconds + jamfComBufferTimeInSeconds) + } + + func formatTimeInterval(for timeLeft: Double) -> String { + guard timeLeft > 0 else { return "installationBundleSelectionPageNoTime".localized } + let formatter = DateComponentsFormatter() + formatter.unitsStyle = .full + formatter.allowedUnits = [ .day, .hour, .minute] + formatter.zeroFormattingBehavior = [.dropAll] + + let formattedDuration = formatter.string(from: timeLeft) + return formattedDuration! + } + + /// This method return the index of the bundle in the "selectedBundles" array that contain the app with the given app key. + /// - Parameter appKey: the given app key. + /// - Returns: the indexes of the bundle and of the app in the bundle (bundleIndex, appIndex), nil if not present. + func index(forAppKey appKey: String) -> (bundleIndex: Int, appIndex: Int)? { + for (bundleIndex, bundle) in selectedBundles.enumerated() { + if let appIndex = bundle.apps.firstIndex(where: { $0.key == appKey }) { + return (bundleIndex, appIndex) + } + } + return nil + } + + /// This method return the index of the bundle in the "selectedBundles" array with the given bundle key. + /// - Parameter bundleKey: the given bundle key. + /// - Returns: the index of the bundle, nil if not present. + func index(forBundleKey bundleKey: String) -> Int? { + return selectedBundles.firstIndex(where: { $0.key == bundleKey }) + } + + // MARK: - Private methods + + private func getSelectedBundlesSize() -> Double? { + var size: Double = 0 + + for bundle in selectedBundles { + guard let bundleSizeString = bundle.size, let bundleSize = Double(bundleSizeString) else { return nil } + size += bundleSize + } + + return size > 0 ? size : nil + } + + private func getSelectedBundlesTime() -> Double? { + var time: Double = 0 + + for bundle in selectedBundles { + guard let bundleTimeString = bundle.time, let bundletime = Double(bundleTimeString) else { return nil } + time += bundletime + } + + return time > 0 ? time : nil + } +} diff --git a/enrollment/enrollment/Controllers/PopOvers/Bundles/BundleItemCell.swift b/enrollment/enrollment/ViewControllers/Installation/BundlePopOver/BundleItemCell.swift similarity index 52% rename from enrollment/enrollment/Controllers/PopOvers/Bundles/BundleItemCell.swift rename to enrollment/enrollment/ViewControllers/Installation/BundlePopOver/BundleItemCell.swift index ef24540..8d01dab 100644 --- a/enrollment/enrollment/Controllers/PopOvers/Bundles/BundleItemCell.swift +++ b/enrollment/enrollment/ViewControllers/Installation/BundlePopOver/BundleItemCell.swift @@ -9,25 +9,46 @@ import Cocoa +/// This class manage the cell that represent the bundle app. class BundleItemCell: NSCollectionViewItem { + // MARK: - Outlets + @IBOutlet weak var bundleItemImage: NSImageView! @IBOutlet weak var bundleItemTitleLabel: NSTextField! @IBOutlet weak var bundleItemDescriptionLabel: NSTextField! + // MARK: - Instance methods + override func viewDidLoad() { super.viewDidLoad() } override func viewWillAppear() { super.viewWillAppear() - layoutSetup() + configureView() + configureLabels() } - private func layoutSetup() { - self.view.wantsLayer = true - self.view.layer?.cornerRadius = 5 + // MARK: - Public methods + + /// Thsi method configure the cell with the ginven app informations. + /// - Parameter app: the given app. + func configure(with app: EnrollmentBundle.App) { + bundleItemTitleLabel.stringValue = app.title.localized + bundleItemImage.image = NSImage(named: app.icon) + bundleItemDescriptionLabel.stringValue = app.description.localized + } + + // MARK: - Private methods + + private func configureLabels() { bundleItemTitleLabel.textColor = .headerTextColor bundleItemDescriptionLabel.textColor = .controlTextColor } + + private func configureView() { + self.view.wantsLayer = true + self.view.layer?.cornerRadius = 5 + } } diff --git a/enrollment/enrollment/Views/BundleItemCell.xib b/enrollment/enrollment/ViewControllers/Installation/BundlePopOver/BundleItemCell.xib similarity index 86% rename from enrollment/enrollment/Views/BundleItemCell.xib rename to enrollment/enrollment/ViewControllers/Installation/BundlePopOver/BundleItemCell.xib index 1f8f648..39f430f 100644 --- a/enrollment/enrollment/Views/BundleItemCell.xib +++ b/enrollment/enrollment/ViewControllers/Installation/BundlePopOver/BundleItemCell.xib @@ -1,8 +1,8 @@ - + - + @@ -14,24 +14,26 @@ - + - - - + + + + + + - + - - + @@ -71,7 +73,7 @@ - + diff --git a/enrollment/enrollment/Controllers/PopOvers/Bundles/BundlePopOverViewController.swift b/enrollment/enrollment/ViewControllers/Installation/BundlePopOver/BundlePopOverViewController.swift similarity index 53% rename from enrollment/enrollment/Controllers/PopOvers/Bundles/BundlePopOverViewController.swift rename to enrollment/enrollment/ViewControllers/Installation/BundlePopOver/BundlePopOverViewController.swift index 52d4c68..8b519a6 100644 --- a/enrollment/enrollment/Controllers/PopOvers/Bundles/BundlePopOverViewController.swift +++ b/enrollment/enrollment/ViewControllers/Installation/BundlePopOver/BundlePopOverViewController.swift @@ -9,66 +9,73 @@ import Cocoa - +/// This class manage the view controller that should show the bundle information as popover. class BundlePopOverViewController: NSViewController { + // MARK: - Outlets + @IBOutlet var headerTextLabel: NSTextField! @IBOutlet var descriptionTextLabel: NSTextField! @IBOutlet var collectionView: NSCollectionView! - var recievedBundleTitleString = String() - var recievedBundleDescriptionString = String() - var recievedListOfTitles = [String]() - var recievedListOfIcons = [NSImage]() - var recievedListOfDescriptions = [String]() + // MARK: - Variables + + var bundle: EnrollmentBundle - var listOfIcons = [NSImage]() - var listOfTitles = [String]() - var listOfDescriptions = [String]() + // MARK: - Instance methods override func viewDidLoad() { super.viewDidLoad() + configureLabels() + configureCollectionView() } - override func viewWillAppear() { - super.viewWillAppear() - layoutSetup() + // MARK: - Initializers + + /// Initialize the popover viewcontroller with the bundle that needs to be showed. + /// - Parameter bundle: the given bundle. + init(with bundle: EnrollmentBundle) { + self.bundle = bundle + super.init(nibName: .init("BundlePopOverViewController"), bundle: nil) } - private func layoutSetup() { - collectionView.backgroundColors = ColorConstants.BackgroundColor.popover + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Private methods + + private func configureCollectionView() { + collectionView.register(NSNib(nibNamed: "BundleItemCell", bundle: nil), forItemWithIdentifier: NSUserInterfaceItemIdentifier("BundleItemCell")) + collectionView.dataSource = self + collectionView.delegate = self + } + + private func configureLabels() { headerTextLabel.alignment = .center headerTextLabel.textColor = .headerTextColor descriptionTextLabel.alignment = .center descriptionTextLabel.textColor = .headerTextColor - headerTextLabel.stringValue = recievedBundleTitleString.capitalized - descriptionTextLabel.stringValue = recievedBundleDescriptionString - listOfIcons = recievedListOfIcons - listOfTitles = recievedListOfTitles - listOfDescriptions = recievedListOfDescriptions - collectionView.dataSource = self - collectionView.delegate = self + headerTextLabel.stringValue = bundle.title.localized + descriptionTextLabel.stringValue = bundle.description.localized } } +// MAKR: - Collection View delegate, data source and flow layout delegate. + extension BundlePopOverViewController: NSCollectionViewDelegate, NSCollectionViewDataSource, NSCollectionViewDelegateFlowLayout { - func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem { + guard let cell = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "BundleItemCell"), for: indexPath as IndexPath) as? BundleItemCell, + indexPath.item < bundle.apps.count else { return NSCollectionViewItem() } - let bundleItem = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "BundleItemCell"), for: indexPath as IndexPath) as? BundleItemCell + let app = bundle.apps[indexPath.item] + cell.configure(with: app) - bundleItem?.bundleItemTitleLabel.stringValue = self.listOfTitles[indexPath.item] - bundleItem?.bundleItemImage.image = self.listOfIcons[indexPath.item] - bundleItem?.bundleItemDescriptionLabel.stringValue = self.listOfDescriptions[indexPath.item] - return bundleItem! - } - - func numberOfSections(in collectionView: NSCollectionView) -> Int { - return 1 + return cell } func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int { - return listOfTitles.count + return self.bundle.apps.count } func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> NSSize { diff --git a/enrollment/enrollment/Views/BundlePopOverViewController.xib b/enrollment/enrollment/ViewControllers/Installation/BundlePopOver/BundlePopOverViewController.xib similarity index 73% rename from enrollment/enrollment/Views/BundlePopOverViewController.xib rename to enrollment/enrollment/ViewControllers/Installation/BundlePopOver/BundlePopOverViewController.xib index af644f4..c331293 100644 --- a/enrollment/enrollment/Views/BundlePopOverViewController.xib +++ b/enrollment/enrollment/ViewControllers/Installation/BundlePopOver/BundlePopOverViewController.xib @@ -1,16 +1,18 @@ - + - + + - + - - - + + + + @@ -20,7 +22,7 @@ - + @@ -28,46 +30,48 @@ - + - - - + + + + + + - - - + + + - - + + - + - - @@ -85,6 +89,12 @@ + + + + + + diff --git a/enrollment/enrollment/ViewControllers/Installation/BundleSelectionViewController.swift b/enrollment/enrollment/ViewControllers/Installation/BundleSelectionViewController.swift new file mode 100644 index 0000000..399f535 --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Installation/BundleSelectionViewController.swift @@ -0,0 +1,245 @@ +// +// BundleSelectionViewController.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 3/31/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Cocoa + +/// This class manage the bundle selection page. +class BundleSelectionViewController: NSViewController { + + // MARK: - Outlets + + @IBOutlet weak var titleLabel: InfoLabelView! + @IBOutlet weak var subtitleLabel: InfoLabelView! + @IBOutlet weak var bundlesCollectionView: NSCollectionView! + @IBOutlet weak var bottomRightButton: NSButton! + @IBOutlet weak var bottomLeftButton: NSButton! + @IBOutlet weak var bottomRightLabel: NSTextField! + + // MARK: - Variables + + static let controllerID = "BundleSelectionViewController" + private var selectedBundles: Set = .init() { + didSet { + bottomLeftButton.isHidden = !selectedBundles.isEmpty + bottomRightButton.isHidden = selectedBundles.isEmpty + bottomRightLabel.isHidden = selectedBundles.isEmpty + bottomRightLabel.stringValue = !selectedBundles.isEmpty ? "+ \(getEstimatedTime())" : "" + } + } + private var pageInfo: BundleSelectionPage? + var jpsCheckResult: Int? + var jpsHealthCheckServiceURL: String = Environment.current.healthCheckURL + + // MARK: - Instance methods + + override func viewDidLoad() { + super.viewDidLoad() + pageInfo = Context.main?.dataSet.bundleSelectionPage + setValuesToFactoryDefaults() + configureCollectionView() + configureLabels() + configureButtons() + } + + // MARK: - Private methods + + private func setValuesToFactoryDefaults() { + Context.main?.dataSet.bundleInstallationPage?.bundleInstallationStatus = false + Context.main?.dataSet.bundleInstallationPage?.bundleInstallationWarning = false + Context.main?.dataSet.selectedBundles = [] + + Context.main?.dataSet.bundleSelectionPage?.bundles.forEach({ bundle in + bundle.status = .installationPending + bundle.bundleMessaging = "" + let appArray = bundle.apps + bundle.apps = appArray.map({ app in + var updatedApp = app + updatedApp.status = .installationPending + return updatedApp + }) + }) + } + + private func configureCollectionView() { + bundlesCollectionView.register(NSNib(nibNamed: "SelectableBundleCell", bundle: nil), forItemWithIdentifier: SelectableBundleCell.reuseIdentifier) + bundlesCollectionView.enclosingScrollView?.scrollerStyle = .overlay + } + + private func configureLabels() { + titleLabel.labelledInfo = pageInfo?.title + titleLabel.font = .systemFont(ofSize: 28) + subtitleLabel.labelledInfo = pageInfo?.subtitle + bottomRightLabel.placeholderString = "installationBundleSelectionPageNoTime".localized + bottomRightLabel.isHidden = true + } + + private func configureButtons() { + bottomLeftButton.title = "buttonLabelSkip".localized + bottomRightButton.title = "buttonLabelNext".localized + bottomRightButton.set(textColor: .white, underline: .zero) + bottomRightButton.isHidden = true + } + + /// This method translate the total bundles size and time to download and install in a user friendly estimated time string. + /// - Returns: the string that show the estimated time needed to download and install the bundle. + private func getEstimatedTime() -> String { + let duration: TimeInterval = getEstimatedTimeInSeconds() + + let formatter = DateComponentsFormatter() + formatter.unitsStyle = .full + formatter.allowedUnits = [ .day, .hour, .minute] + formatter.zeroFormattingBehavior = [.dropAll] + + let formattedDuration = formatter.string(from: duration) + return formattedDuration! + } + + /// This method translate the total bundles size and time to download and install in a double value that rapresent the total time in seconds needed. + /// - Returns: the double value that rapresent the estimated time in seconds needed to download and install the bundle. + private func getEstimatedTimeInSeconds() -> Double { + guard let speedTestRateString = Context.main?.dataSet.networkInfo?.speedTestResult, let speedTestRate = Double(speedTestRateString), + let jamfComBufferTimeInSecondsString = Context.main?.dataSet.networkInfo?.jpsCommSeconds, let jamfComBufferTimeInSeconds = Double(jamfComBufferTimeInSecondsString), + let bundleSizes = self.getSelectedBundlesSize(), + let bundlesInstallTimeInSeconds = self.getSelectedBundlesTime() else { + return 1 + } + + let totalJAMFBufferTime = jamfComBufferTimeInSeconds * Double(selectedBundles.count) + + let duration: TimeInterval = ((bundleSizes / speedTestRate) + bundlesInstallTimeInSeconds + totalJAMFBufferTime) + + return duration + } + + private func getSelectedBundlesSize() -> Double? { + var size: Double = 0 + + for bundle in selectedBundles { + guard let bundleSizeString = self.pageInfo?.bundles.first(where: { $0.key == bundle })?.size, let bundleSize = Double(bundleSizeString) else { return nil } + size += bundleSize + } + + return size > 0 ? size : nil + } + + private func getSelectedBundlesTime() -> Double? { + var time: Double = 0 + + for bundle in selectedBundles { + guard let bundleTimeString = self.pageInfo?.bundles.first(where: { $0.key == bundle })?.time, let bundletime = Double(bundleTimeString) else { return nil } + time += bundletime + } + + return time > 0 ? time : nil + } + + private func checkNetwork(_ completion: @escaping () -> Void, error: @escaping (String) -> Void) { + let dispatchGroup = DispatchGroup() + if NetworkValidationService.sharedInstance.isConnectedToNetwork() { + dispatchGroup.enter() + NetworkValidationService.sharedInstance.checkForJPSAvailability(jpsURL: jpsHealthCheckServiceURL) { result in + self.jpsCheckResult = result + dispatchGroup.leave() + } + + dispatchGroup.notify(queue: .main) { + if self.jpsCheckResult != 200 { + error(AlertText.NetworkValidationMessaging.External.jps) + } else { + completion() + } + } + } else { + error(AlertText.NetworkValidationMessaging.External.network) + } + } + + // MARK: - Actions + + @IBAction func didPressBottomLeftButton(_ sender: NSButton) { + self.performSegue(withIdentifier: "skipToSummaryPage", sender: self) + } + + @IBAction func didPressBottomRightButton(_ sender: NSButton) { + bottomRightButton.isEnabled = false + Context.main?.dataSet.selectedBundles = selectedBundles.map({ $0 }) + checkNetwork({ + if self.selectedBundles.count >= 1 { + if self.getEstimatedTimeInSeconds() > 3000.0 { + let alert = NSAlert() + alert.messageText = "bundleSelectionAlertTitle".localized + alert.alertStyle = .critical + alert.informativeText = String(format: "estimatedInstallTimeMessage".localized, "bundleSelectionAlertMessage".localized, self.getEstimatedTime()) + alert.addButton(withTitle: "labelNo".localized) + alert.addButton(withTitle: "labelYes".localized) + alert.beginSheetModal(for: NSApp.keyWindow!, completionHandler: { [unowned self] (returnCode) -> Void in + if returnCode == NSApplication.ModalResponse.alertSecondButtonReturn { + self.performSegue(withIdentifier: "goToInstallationPage", sender: self) + } else { + self.bottomRightButton.isEnabled = true + } + }) + } else { + self.performSegue(withIdentifier: "goToInstallationPage", sender: self) + } + } + }, error: { error in + let alert = NSAlert() + alert.messageText = error + alert.alertStyle = .critical + alert.addButton(withTitle: "buttonLabelOk".localized) + alert.beginSheetModal(for: NSApp.keyWindow!) + self.bottomRightButton.isEnabled = true + }) + + } +} + +// MARK: - Collection View delegate and data source. + +extension BundleSelectionViewController: NSCollectionViewDelegate, NSCollectionViewDataSource { + func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int { + return pageInfo?.bundles.count ?? 0 + } + + func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem { + guard let item = bundlesCollectionView.makeItem(withIdentifier: SelectableBundleCell.reuseIdentifier, for: indexPath) as? SelectableBundleCell, + let bundle = pageInfo?.bundles[indexPath.item] else { return NSCollectionViewItem() } + item.configure(with: bundle) + item.delegate = self + return item + } +} + +// MARK: - Collection View flow layout delegate. + +extension BundleSelectionViewController: NSCollectionViewDelegateFlowLayout { + func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> NSSize { + guard let bundle = pageInfo?.bundles[indexPath.item] else { return CGSize(width: 0, height: 0) } + let label = NSTextField(labelWithAttributedString: NSAttributedString(string: bundle.description.localized, attributes: [NSAttributedString.Key.font: NSFont.systemFont(ofSize: 11)])) + return CGSize(width: 471, height: 62+((CGFloat(Int(label.bounds.width/445)+1))*14)) + } +} + +// MARK: - Bundle cell delegate + +extension BundleSelectionViewController: SelectableBundleCollectionViewItemDelegate { + func didPressedInfoButton(_ sender: NSButton, infos: EnrollmentBundle) { + let appsPopupViewController = BundlePopOverViewController(with: infos) + self.present(appsPopupViewController, asPopoverRelativeTo: sender.convert(sender.bounds, to: self.view), of: self.view, preferredEdge: .maxX, behavior: .semitransient) + } + + func didSelectedBundle(_ bundleKey: String) { + self.selectedBundles.insert(bundleKey) + } + + func didDeselectBundle(_ bundleKey: String) { + self.selectedBundles.remove(bundleKey) + } +} diff --git a/enrollment/enrollment/ViewControllers/Installation/Cells/BundleInstallationCell/AppInstallationStackViewItem.swift b/enrollment/enrollment/ViewControllers/Installation/Cells/BundleInstallationCell/AppInstallationStackViewItem.swift new file mode 100644 index 0000000..9c812d1 --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Installation/Cells/BundleInstallationCell/AppInstallationStackViewItem.swift @@ -0,0 +1,91 @@ +// +// AppInstallationStackViewItem.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 4/16/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Cocoa + +class AppInstallationStackViewItem: NSView, LoadableNib { + + // MARK: - Outlets + + @IBOutlet weak var loaderView: LoaderView! + @IBOutlet weak var appNameLabel: NSTextField! + @IBOutlet weak var heightConstraint: NSLayoutConstraint! + @IBOutlet weak var topMargin: NSLayoutConstraint! + @IBOutlet weak var bottomMargin: NSLayoutConstraint! + @IBOutlet weak var contentView: NSView! + + // MARK: - Variables + + var app: EnrollmentBundle.App! + public var isVisible: Bool = false { + didSet { + NSAnimationContext.runAnimationGroup({ (context) -> Void in + context.duration = 0.10 + context.allowsImplicitAnimation = true + heightConstraint.animator().constant = isVisible ? 16 : 0 + topMargin.animator().constant = isVisible ? 4 : 0 + bottomMargin.animator().constant = isVisible ? 4 : 0 + layoutSubtreeIfNeeded() + }, completionHandler: { + if self.isVisible { + DispatchQueue.main.async { + self.loaderView.state = self.translatedBundleStatus() + } + } + }) + } + } + + // MARK: - Initializers + + override init(frame frameRect: NSRect) { + super.init(frame: frameRect) + loadViewFromNib() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + loadViewFromNib() + } + + // MARK: - Public methods + + func configure(with app: EnrollmentBundle.App) { + self.app = app + appNameLabel.stringValue = app.title.localized + loaderView.state = translatedBundleStatus() + heightConstraint.constant = 0 + topMargin.constant = 0 + bottomMargin.constant = 0 + layoutSubtreeIfNeeded() + } + + func updateApp(with newStatus: EnrollmentBundle.InstallationStatus) { + guard app.status != newStatus else { return } + app.status = newStatus + loaderView.state = translatedBundleStatus() + } + + // MARK: - Private methods + + private func translatedBundleStatus() -> LoaderView.State { + switch app.status { + case .installationPending: + return .inQueue + case .installationInProgress: + return .inProgress + case .installed: + return .success + case .errorDuringInstallation: + return .failure + default: + return .inQueue + } + } +} diff --git a/enrollment/enrollment/ViewControllers/Installation/Cells/BundleInstallationCell/AppInstallationStackViewItem.xib b/enrollment/enrollment/ViewControllers/Installation/Cells/BundleInstallationCell/AppInstallationStackViewItem.xib new file mode 100644 index 0000000..7b3bbd8 --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Installation/Cells/BundleInstallationCell/AppInstallationStackViewItem.xib @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/enrollment/enrollment/ViewControllers/Installation/Cells/BundleInstallationCell/BundleInstallationStackViewItem.swift b/enrollment/enrollment/ViewControllers/Installation/Cells/BundleInstallationCell/BundleInstallationStackViewItem.swift new file mode 100644 index 0000000..ca29780 --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Installation/Cells/BundleInstallationCell/BundleInstallationStackViewItem.swift @@ -0,0 +1,99 @@ +// +// BundleInstallationCell.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 4/14/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Cocoa + +/// This protocol provide an interface between the bundle cell and the collection view controller. +protocol BundleInstallationStackViewItemDelegate: class { + func didPressShowHideButton(_ sender: BundleInstallationStackViewItem) +} + +class BundleInstallationStackViewItem: NSView, LoadableNib { + + // MARK: - Outlets + @IBOutlet weak var loaderView: LoaderView! + @IBOutlet weak var bundleTitleLabel: NSTextField! + @IBOutlet weak var bundleMessageLabel: NSTextField! + @IBOutlet weak var showHideButton: NSButton! + @IBOutlet weak var contentView: NSView! + @IBOutlet weak var headerContainerView: NSView! + + // MARK: - Variables + + var bundle: EnrollmentBundle! + weak var delegate: BundleInstallationStackViewItemDelegate? + var isExpanded: Bool = false + + // MARK: - Initializers + + override init(frame frameRect: NSRect) { + super.init(frame: frameRect) + loadViewFromNib() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + loadViewFromNib() + } + + // MARK: - Public methods + + /// This method configure the cell with the information of the given bundle. + /// - Parameter bundle: the given bundle. + func configure(with bundle: EnrollmentBundle, isExpanded: Bool = false) { + self.bundle = bundle + self.isExpanded = isExpanded + configureView() + } + + func updateBundle(with newStatus: EnrollmentBundle.InstallationStatus) { + bundle.status = newStatus + loaderView.state = translatedBundleStatus() + } + + func updateBundle(with newMessage: String) { + bundle.bundleMessaging = newMessage + bundleMessageLabel.stringValue = newMessage + } + + // MARK: - Private methods + + private func configureView() { + bundleTitleLabel.stringValue = bundle.title.localized + configureBundleInstallationStatus() + } + + private func configureBundleInstallationStatus() { + bundleMessageLabel.stringValue = bundle.bundleMessaging ?? "" + showHideButton.title = isExpanded ? "HideApp" : "ShowApp" + loaderView.state = translatedBundleStatus() + } + + private func translatedBundleStatus() -> LoaderView.State { + switch bundle.status { + case .installationPending: + return .inQueue + case .installationInProgress: + return .inProgress + case .installed, .errorDuringInstallation: + let bundleAppStatus = bundle.apps.map({ $0.status }) + return (bundleAppStatus.contains(.errorDuringInstallation) ? (bundleAppStatus.contains(.installed) ? .partial : .failure) : .success) + default: + return .inQueue + } + } + + // MARK: - Actions + + @IBAction func didPressShowHideButton(_ sender: NSButton) { + isExpanded.toggle() + showHideButton.title = isExpanded ? "HideApp" : "ShowApp" + delegate?.didPressShowHideButton(self) + } +} diff --git a/enrollment/enrollment/ViewControllers/Installation/Cells/BundleInstallationCell/BundleInstallationStackViewItem.xib b/enrollment/enrollment/ViewControllers/Installation/Cells/BundleInstallationCell/BundleInstallationStackViewItem.xib new file mode 100644 index 0000000..c1c3bb7 --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Installation/Cells/BundleInstallationCell/BundleInstallationStackViewItem.xib @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/enrollment/enrollment/ViewControllers/Installation/Cells/SelectableBundleCell/SelectableBundleCell.swift b/enrollment/enrollment/ViewControllers/Installation/Cells/SelectableBundleCell/SelectableBundleCell.swift new file mode 100644 index 0000000..6e5725e --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Installation/Cells/SelectableBundleCell/SelectableBundleCell.swift @@ -0,0 +1,102 @@ +// +// SelectableBundleCell.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 3/31/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Cocoa + +/// This protocol provide an interface between the bundle selection page and the bundle cell. +protocol SelectableBundleCollectionViewItemDelegate: class { + func didPressedInfoButton(_ sender: NSButton, infos: EnrollmentBundle) + func didSelectedBundle(_ bundleKey: String) + func didDeselectBundle(_ bundleKey: String) +} + +/// This class manage the cell that represent the bundle inside the bundle selection page. +class SelectableBundleCell: NSCollectionViewItem, LoadableNib { + + // MARK: - Outlets + + @IBOutlet weak var checkBox: NSButton! + @IBOutlet weak var titleHelpLabel: InfoLabelView! + @IBOutlet weak var descriptionLabel: NSTextField! + @IBOutlet weak var timeLabel: NSTextField! + + // MARK: - Variables + + var contentView: NSView! { + return self.view + } + private var bundle: EnrollmentBundle? + static var reuseIdentifier = NSUserInterfaceItemIdentifier("SelectableBundleCell") + public weak var delegate: SelectableBundleCollectionViewItemDelegate? + + // MARK: - Public methods + + /// This method configure the cell with the information of the given bundle. + /// - Parameter bundle: the given bundle. + func configure(with bundle: EnrollmentBundle) { + self.bundle = bundle + self.descriptionLabel.placeholderString = "installationBundleSelectionPageNoDescription".localized + self.timeLabel.placeholderString = "installationBundleSelectionPageNoTime".localized + self.descriptionLabel.stringValue = bundle.description.localized + var attributedTitle: NSMutableAttributedString? + if bundle.recommended { + attributedTitle = NSMutableAttributedString(string: bundle.title.localized) + attributedTitle?.append(NSAttributedString(string: " " + "installationBundleSelectionPageRecommended".localized, attributes: [.foregroundColor: NSColor.red, .font: NSFont.systemFont(ofSize: 11), .baselineOffset: 3])) + } + var infoSection = InfoSection(fields: []) + for app in bundle.apps { + infoSection.fields.append(InfoField(label: app.title.localized, description: app.description.localized, iconName: app.icon)) + } + let infoLabel = InfoLabel(bundle.title.localized, + attributedLabel: attributedTitle, + withHelpSection: infoSection) + self.titleHelpLabel.labelledInfo = infoLabel + self.titleHelpLabel.onInfoButtonPressed = { button in + self.delegate?.didPressedInfoButton(button, infos: bundle) + } + self.timeLabel.stringValue = self.estimatedTime() + } + + // MARK: - Private methods + + /// This method translate the bundle size and time to download and install in a user friendly estimated time string. + /// - Returns: the string that show the estimated time needed to download and install the bundle. + private func estimatedTime() -> String { + guard let speedTestRateString = Context.main?.dataSet.networkInfo?.speedTestResult, let speedTestRate = Double(speedTestRateString), + let jamfComBufferTimeInSecondsString = Context.main?.dataSet.networkInfo?.jpsCommSeconds, let jamfComBufferTimeInSeconds = Double(jamfComBufferTimeInSecondsString), + let bundleSizeString = self.bundle?.size, let bundleSize = Double(bundleSizeString), + let bundleInstallTimeInSecondsString = self.bundle?.time, let bundleInstallTimeInSeconds = Double(bundleInstallTimeInSecondsString) else { + return "" + } + + let duration: TimeInterval = ((bundleSize / speedTestRate) + bundleInstallTimeInSeconds + jamfComBufferTimeInSeconds) + + let formatter = DateComponentsFormatter() + formatter.unitsStyle = .full + formatter.allowedUnits = [ .day, .hour, .minute] + formatter.zeroFormattingBehavior = [.dropAll] + + let formattedDuration = formatter.string(from: duration) + return "+ " + formattedDuration! + } + + // MARK: - Actions + + @IBAction func didSelectedBundle(_ sender: NSButton) { + guard let bundleKey = self.bundle?.key else { return } + switch sender.state { + case .on: + delegate?.didSelectedBundle(bundleKey) + case .off: + delegate?.didDeselectBundle(bundleKey) + default: + break + } + } +} diff --git a/enrollment/enrollment/ViewControllers/Installation/Cells/SelectableBundleCell/SelectableBundleCell.xib b/enrollment/enrollment/ViewControllers/Installation/Cells/SelectableBundleCell/SelectableBundleCell.xib new file mode 100644 index 0000000..f274a6b --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Installation/Cells/SelectableBundleCell/SelectableBundleCell.xib @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/enrollment/enrollment/ViewControllers/Installation/Cells/SummaryItemCell/SummaryItemCell.swift b/enrollment/enrollment/ViewControllers/Installation/Cells/SummaryItemCell/SummaryItemCell.swift new file mode 100644 index 0000000..a3c210b --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Installation/Cells/SummaryItemCell/SummaryItemCell.swift @@ -0,0 +1,51 @@ +// +// SummaryItemCell.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 4/23/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Cocoa + +protocol SummaryItemCellDelegate: class { + func didPressItem(_ item: PostInstallationPage.Item) +} + +/// This class handle the summary item. +class SummaryItemCell: NSCollectionViewItem { + + // MARK: - Outlets + + @IBOutlet weak var iconImageView: NSImageView! + @IBOutlet weak var titleButton: LabelButton! + @IBOutlet weak var descriptionLabel: NSTextField! + + // MARK: - Variables + + static var reuseIdentifier = NSUserInterfaceItemIdentifier("SummaryItemCell") + weak var delegate: SummaryItemCellDelegate? + var rapresentedItem: PostInstallationPage.Item! + + // MARK: - Instance methods + + override func viewDidLoad() { + super.viewDidLoad() + } + + // MARK: - Public methods + + func configure(with item: PostInstallationPage.Item) { + rapresentedItem = item + iconImageView.image = NSImage(named: item.iconName) + titleButton.title = item.title.localized + descriptionLabel.stringValue = item.description.localized + } + + // MARK: - Action + + @IBAction func didPressOnTitleButton(_ sender: LabelButton) { + delegate?.didPressItem(rapresentedItem) + } +} diff --git a/enrollment/enrollment/ViewControllers/Installation/Cells/SummaryItemCell/SummaryItemCell.xib b/enrollment/enrollment/ViewControllers/Installation/Cells/SummaryItemCell/SummaryItemCell.xib new file mode 100644 index 0000000..fa8c769 --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Installation/Cells/SummaryItemCell/SummaryItemCell.xib @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/enrollment/enrollment/ViewControllers/Installation/Installation.storyboard b/enrollment/enrollment/ViewControllers/Installation/Installation.storyboard new file mode 100644 index 0000000..8a18518 --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Installation/Installation.storyboard @@ -0,0 +1,370 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/enrollment/enrollment/ViewControllers/Installation/PostInstallationPageViewController.swift b/enrollment/enrollment/ViewControllers/Installation/PostInstallationPageViewController.swift new file mode 100644 index 0000000..7768c84 --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Installation/PostInstallationPageViewController.swift @@ -0,0 +1,177 @@ +// +// PostInstallationPageViewController.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 4/9/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Cocoa +import ServiceManagement + +/// This class handle the summary page. +class PostInstallationPageViewController: NSViewController { + + // MARK: - Outlets + + @IBOutlet weak var titleLabel: InfoLabelView! + @IBOutlet weak var subtitleLabel: InfoLabelView! + @IBOutlet weak var subtitleHeightAnchor: NSLayoutConstraint! + @IBOutlet weak var summaryCollectionView: NSCollectionView! + @IBOutlet weak var checkBottomLeftButton: NSButton! + @IBOutlet weak var bottomRightButton: NSButton! + + // MARK: - Variables + + static let controllerID = "PostInstallationPageViewController" + private let postInstallationPageData = Context.main?.dataSet.postInstallationPage + private var timeout: Int { + return postInstallationPageData?.restartTimeout ?? 300 + } + private var countdown: Int = 0 + private var timer: Timer? + private var needsRestart: Bool { + return postInstallationPageData?.needsRestart ?? false + } + + // MARK: - Instances methods + + override func viewDidLoad() { + super.viewDidLoad() + configureLabels() + configureButtons() + configureCollectionView() + configureTimerIfNeeded() + } + + override func viewWillDisappear() { + super.viewWillDisappear() + timer?.invalidate() + timer = nil + } + + // MARK: - Private methods + + private func configureLabels() { + titleLabel.labelledInfo = postInstallationPageData?.title + titleLabel.font = .systemFont(ofSize: 28) + guard postInstallationPageData?.subtitle != nil else { + subtitleLabel.isHidden = true + return + } + subtitleLabel.labelledInfo = postInstallationPageData?.subtitle + } + + private func configureCollectionView() { + summaryCollectionView.register(NSNib(nibNamed: .init("SummaryItemCell"), bundle: nil), forItemWithIdentifier: NSUserInterfaceItemIdentifier(rawValue: "SummaryItemCell")) + summaryCollectionView.enclosingScrollView?.scrollerStyle = .overlay + } + + private func configureButtons() { + checkBottomLeftButton.title = "postInstallationPageFooterLabel".localized + bottomRightButton.title = needsRestart ? "buttonLabelRestart".localized : "buttonLabelClose".localized + bottomRightButton.set(textColor: .white, underline: .zero) + } + + private func configureTimerIfNeeded() { + if needsRestart { + countdown = timeout + } + timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in + self.updateCounter() + } + } + + private func updateCounter() { + if countdown >= 1 { + bottomRightButton.title = "buttonLabelRestart".localized + " (\(countdown))" + countdown -= 1 + } else { + self.restartComputer() + } + } + + private func restartComputer() { + var systemProcessPSN = ProcessSerialNumber(highLongOfPSN: 0, lowLongOfPSN: UInt32(kSystemProcess)) + let systemProcessDescriptor = NSAppleEventDescriptor(descriptorType: DescType(typeProcessSerialNumber), + bytes: &systemProcessPSN, + length: MemoryLayout.size(ofValue: systemProcessPSN)) + let rebootEvent = NSAppleEventDescriptor(eventClass: AEEventClass(kCoreEventClass), + eventID: AEEventID(kAERestart), + targetDescriptor: systemProcessDescriptor, + returnID: AEReturnID(kAutoGenerateReturnID), + transactionID: AETransactionID(kAnyTransactionID)) + let err = AESendMessage(rebootEvent.aeDesc, nil, AESendMode(kAENoReply), kAEDefaultTimeout) + if err != noErr { + let failureAlert = NSAlert() + failureAlert.messageText = NSLocalizedString("restartFailureMessage".localized, comment: "restartFailureComment".localized) + failureAlert.runModal() + } + } + + // MARK: - Actions + + @IBAction func didPressBottomLeftButton(_ sender: NSButton) { + let autoLaunch = sender.state == .on + if SMLoginItemSetEnabled("com.ibm.EnrollmentLoginHelper" as CFString, autoLaunch) { + if autoLaunch { + NSLog("Login item added") + } else { + NSLog("Login item removed") + } + } + } + + @IBAction func didPressBottomRightButton(_ sender: NSButton) { + if needsRestart { + restartComputer() + } else { + exit(0) + } + } +} + +// MARK: - Collection view delegate and data source + +extension PostInstallationPageViewController: NSCollectionViewDelegate, NSCollectionViewDataSource { + func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int { + return postInstallationPageData?.items.count ?? 0 + } + + func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem { + guard let item = collectionView.makeItem(withIdentifier: SummaryItemCell.reuseIdentifier, for: indexPath) as? SummaryItemCell, + let itemData = postInstallationPageData?.items[indexPath.item] else { return NSCollectionViewItem() } + item.configure(with: itemData) + item.delegate = self + return item + } +} + +// MARK: - Collection view flow layout delegate + +extension PostInstallationPageViewController: NSCollectionViewDelegateFlowLayout { + func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> NSSize { + return CGSize(width: 230, height: 90) + } +} + +// MARK: - Collection view item delegate + +extension PostInstallationPageViewController: SummaryItemCellDelegate { + func didPressItem(_ item: PostInstallationPage.Item) { + switch item.ctaType { + case .url: + guard let string = item.ctaPayload else { return } + NetworkValidationService.sharedInstance.verifyInternalURL(urlPath: string, completion: { isValid in + guard isValid, let url = URL(string: string) else { return } + NSWorkspace.shared.open(url) + }) + case .policy: + guard let policy = item.ctaPayload else { return } + PrivilegedHelperController.shared.processJAMFPolicy(policy) + case .none: + break + } + } +} diff --git a/enrollment/enrollment/ViewControllers/Main.storyboard b/enrollment/enrollment/ViewControllers/Main.storyboard new file mode 100644 index 0000000..448cf3e --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Main.storyboard @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/enrollment/enrollment/Controllers/MainWindow/MainViewController.swift b/enrollment/enrollment/ViewControllers/MainViewController.swift similarity index 75% rename from enrollment/enrollment/Controllers/MainWindow/MainViewController.swift rename to enrollment/enrollment/ViewControllers/MainViewController.swift index faebe29..c5acc0a 100644 --- a/enrollment/enrollment/Controllers/MainWindow/MainViewController.swift +++ b/enrollment/enrollment/ViewControllers/MainViewController.swift @@ -4,25 +4,14 @@ // // Created by Jay Latman on 7/20/18. // Copyright © 2017 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only // import Cocoa +/// Main view controller for the application. class MainViewController: NSViewController { - /** - Enumeration for errors generated by the MainViewController - - - noViewControllerForSegue: The view controller could not locate a segue - - invalidAppSupportConfiguration: Could not create a valid reference for resources with AppConfiguration - */ - enum MainError : Error { - /// The view controller could not locate a segue - case noViewControllerForSegue - /// Could not create a valid reference for resources with AppConfiguration - case invalidAppSupportConfiguration - } - /// Image view for displaying art @IBOutlet weak var sidePanelImageView: NSImageView! @@ -45,8 +34,10 @@ class MainViewController: NSViewController { IssueAlertService.sharedInstance.displayModalFailureToLaunch(header: AlertText.FailureToLaunch.header, message: AlertText.FailureToLaunch.message, style: .critical, - cancelButtonLabel: UserInteractionButtons.quit) + cancelButtonLabel: "buttonLabelQuit".localized) } + + guard Context.main?.dataSet != nil else { return } } override func viewWillAppear() { @@ -58,5 +49,3 @@ class MainViewController: NSViewController { self.currentConfigurationViewController?.view.setFrameSize(self.contentContainerView.bounds.size) } } - - diff --git a/enrollment/enrollment/ViewControllers/Registration/AnimatedGIFProgressViewController.swift b/enrollment/enrollment/ViewControllers/Registration/AnimatedGIFProgressViewController.swift new file mode 100644 index 0000000..da0a080 --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Registration/AnimatedGIFProgressViewController.swift @@ -0,0 +1,93 @@ +// +// AnimatedGIFProgressViewController.swift +// enrollment +// +// Created by Jay Latman on 8/1/18. +// Copyright © 2018 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Cocoa + +/// This class manage the registration loading page. +class AnimatedGIFProgressViewController: NSViewController { + + // MARK: - Outlets + + @IBOutlet weak var animatedGIFView: NSImageView! + @IBOutlet weak var progressAlertTextLabel: NSTextField! + + // MAKR: - Variables + + var progressCounter: Int! + var timer: Timer? + private var isRegistrationOnlyPhase: Bool { + return Context.main?.dataSet.phase == "3" + } + + // MARK: - Instance methods + + override func viewWillAppear() { + super.viewWillAppear() + configureGIFView() + configureLabels() + configureTimer() + } + override func viewDidAppear() { + super.viewDidAppear() + PrivilegedHelperController.shared.processJAMFPolicy(Context.main?.dataSet.policies.registrationPolicy ?? "") + } + + override func viewWillDisappear() { + super.viewWillDisappear() + timer?.invalidate() + timer = nil + } + + // MARK: - Private methods + + private func configureTimer() { + progressCounter = isRegistrationOnlyPhase ? 10 : 20 + timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in + self.updateProgressCounter() + } + } + + private func configureLabels() { + progressAlertTextLabel.stringValue = isRegistrationOnlyPhase ? "registrationLoadingPageStateForPhaseThree".localized : "registrationLoadingPageStateOne".localized + progressAlertTextLabel.textColor = .headerTextColor + } + + private func configureGIFView() { + animatedGIFView.canDrawSubviewsIntoLayer = true + animatedGIFView.imageScaling = .scaleProportionallyUpOrDown + if currentInterfaceStyle() == .light { + animatedGIFView.image = NSImage(named: "bee-blue.gif") + } else { + animatedGIFView.image = NSImage(named: "bee-lowlight.gif") + } + animatedGIFView.animates = true + } + + /// This method called by the timer implement a fake loading. + private func updateProgressCounter() { + if progressCounter >= 0 { + progressCounter -= 1 + } + switch progressCounter! { + case 2...10 : + progressAlertTextLabel.fadeTransition(0.10) + progressAlertTextLabel.stringValue = isRegistrationOnlyPhase ? "registrationLoadingPageStateForPhaseThree".localized : "registrationLoadingPageStateTwo".localized + case 11...20 : + progressAlertTextLabel.fadeTransition(0.10) + progressAlertTextLabel.stringValue = "registrationLoadingPageStateOne".localized + case 1 : + progressAlertTextLabel.fadeTransition(0.10) + progressAlertTextLabel.isHidden = true + case 0 : + self.performSegue(withIdentifier: "goToPostRegistrationPage", sender: self) + default: + break + } + } +} diff --git a/enrollment/enrollment/ViewControllers/Registration/Cells/CompactRegistrationField/CompactRegistrationField.swift b/enrollment/enrollment/ViewControllers/Registration/Cells/CompactRegistrationField/CompactRegistrationField.swift new file mode 100644 index 0000000..6c3e4f7 --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Registration/Cells/CompactRegistrationField/CompactRegistrationField.swift @@ -0,0 +1,72 @@ +// +// CompactRegistrationField.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 3/3/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Cocoa + +/// This protocol describe the interface between the page viewController and the field items +protocol SelectableRegistrationCollectionViewItemDelegate: class { + func didPressedInfoButton(_ view: NSButton, infos: InfoSection) + func didSelectedOption(_ sender: NSCollectionViewItem, option: RegistrationChoice) + func didDeselectOption(_ option: RegistrationChoice) +} + +/// This class manage the compact registration field. +class CompactRegistrationField: NSCollectionViewItem { + + // MARK: - Outlets + + @IBOutlet weak var fieldOptionsMenu: NSPopUpButton! + @IBOutlet weak var fieldLabel: InfoLabelView! + + // MARK: - Variables + + weak var delegate: SelectableRegistrationCollectionViewItemDelegate? + static var reuseIdentifier = NSUserInterfaceItemIdentifier("CompactRegistrationField") + var selectedOption: String? { + didSet { + if let option = selectedOption { + self.fieldOptionsMenu.selectItem(withTitle: option.localized) + } + } + } + var fieldInfo: RegistrationField? { + didSet { + guard let info = fieldInfo else { return } + self.fieldLabel.labelledInfo = info.title + self.fieldOptionsMenu.addItem(withTitle: "") + self.fieldOptionsMenu.addItems(withTitles: info.optionLabels.map({ $0.localized })) + guard let help = info.title.infoSection else { return } + self.fieldLabel.onInfoButtonPressed = { view in + self.delegate?.didPressedInfoButton(view, infos: help) + } + } + } + + // MARK: - Actions + + @IBAction func didSelectedOption(_ sender: NSPopUpButton) { + guard let fieldInfo = fieldInfo, + let selectedOptionTitle = sender.selectedItem?.title, + !selectedOptionTitle.isEmpty, + let selectedOptionTitleIndex = fieldInfo.optionLabels.map({ $0.localized }).firstIndex(of: selectedOptionTitle), + selectedOptionTitleIndex < fieldInfo.optionKeys.count else { + delegate?.didDeselectOption(RegistrationChoice(self.fieldInfo?.key ?? "", + fieldTitle: "", + selectedOptionKeys: [], + selectedOptionTitles: [])) + return + } + let selectedOptionKey = fieldInfo.optionKeys[selectedOptionTitleIndex] + let registrationChoise = RegistrationChoice(fieldInfo.key, + fieldTitle: fieldInfo.title.label, + selectedOptionKeys: [selectedOptionKey], + selectedOptionTitles: [selectedOptionTitle]) + delegate?.didSelectedOption(self, option: registrationChoise) + } +} diff --git a/enrollment/enrollment/ViewControllers/Registration/Cells/CompactRegistrationField/CompactRegistrationField.xib b/enrollment/enrollment/ViewControllers/Registration/Cells/CompactRegistrationField/CompactRegistrationField.xib new file mode 100644 index 0000000..7b18ec0 --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Registration/Cells/CompactRegistrationField/CompactRegistrationField.xib @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/enrollment/enrollment/ViewControllers/Registration/Cells/ExtendedRegistrationField/ExtendedRegistrationField.swift b/enrollment/enrollment/ViewControllers/Registration/Cells/ExtendedRegistrationField/ExtendedRegistrationField.swift new file mode 100644 index 0000000..2cca37f --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Registration/Cells/ExtendedRegistrationField/ExtendedRegistrationField.swift @@ -0,0 +1,105 @@ +// +// ExtendedRegistrationField.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 3/25/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Cocoa + +/// This class manage the extended registration field cell. This kind of cell is used when the user needs to display field where multiple option selection is allowed. +class ExtendedRegistrationField: NSCollectionViewItem { + + // MARK: - Outlets + + @IBOutlet var fieldTitle: InfoLabelView! + @IBOutlet var optionsStackView: NSStackView! + + // MARK: - Variables + + weak var delegate: SelectableRegistrationCollectionViewItemDelegate? + static var reuseIdentifier = NSUserInterfaceItemIdentifier("ExtendedRegistrationField") + + private var selectedChoises: [RegistrationField.Option] = [] + private var isExclusiveOptionSelected: Bool = false + + var selectedOptions: [String] = [] + var fieldInfo: RegistrationField? + + // MARK: - Public methods + + /// Use this method to configure the cell with the given field and the selected options if applicable. + /// - Parameters: + /// - field: the registration field that the cell should show. + /// - selectedOptions: the already selected option keys if applicable (default value: empty array). + func configure(with field: RegistrationField, selectedOptions: [String] = []) { + self.fieldInfo = field + self.selectedOptions = selectedOptions + + fieldTitle.labelledInfo = field.title + if let helpInfos = field.title.infoSection { + fieldTitle.onInfoButtonPressed = { view in + self.delegate?.didPressedInfoButton(view, infos: helpInfos) + } + } + fieldTitle.isHidden = !(fieldInfo?.showTitle ?? false) + + for option in field.options { + let optionView = ExtendedRegistrationFieldItem(frame: .zero) + optionView.fieldOption = option + optionView.isSelected = selectedOptions.contains(option.label) + if (option.isExclusive ?? false) && optionView.isSelected { + isExclusiveOptionSelected = true + } + optionView.onSelection = { option, newState in + switch newState { + case .on: + if (option.isExclusive ?? false) || self.isExclusiveOptionSelected { + self.isExclusiveOptionSelected.toggle() + self.resetSelectedOptions(except: option.label) + } + self.selectedOptions.append(option.label) + case .off: + self.selectedOptions.removeAll(where: { $0 == option.label }) + default: + break + } + self.callOptionsUpdate() + } + self.optionsStackView.addArrangedSubview(optionView) + } + } + + // MARK: - Private methods + + /// Use this method to reset the array of the selected options when the caller (exclusive selection field option) is selected. + /// - Parameter caller: the exclusive selected option. + private func resetSelectedOptions(except caller: String) { + selectedOptions.removeAll() + for item in optionsStackView.arrangedSubviews { + guard let item = item as? ExtendedRegistrationFieldItem, + item.fieldOption?.label != caller else { continue } + item.isSelected = false + } + } + + /// This method is called when a new selection is made on the field. + private func callOptionsUpdate() { + guard let info = fieldInfo else { return } + if selectedOptions.isEmpty { + delegate?.didDeselectOption(RegistrationChoice.init(info.key, fieldTitle: info.title.label, selectedOptionKeys: [], selectedOptionTitles: [])) + } else { + let selectedOptionTitles = selectedOptions + var selectedOptionKeys: [String] = [] + for title in selectedOptionTitles { + guard let index = info.optionLabels.firstIndex(of: title), + index < info.optionKeys.count else { continue } + selectedOptionKeys.append(info.optionKeys[index]) + } + delegate?.didSelectedOption(self, option: RegistrationChoice(info.key, fieldTitle: info.title.label, selectedOptionKeys: selectedOptionKeys, selectedOptionTitles: selectedOptionTitles, isMultipleChoiseAllowed: true)) + } + } + +} diff --git a/enrollment/enrollment/ViewControllers/Registration/Cells/ExtendedRegistrationField/ExtendedRegistrationField.xib b/enrollment/enrollment/ViewControllers/Registration/Cells/ExtendedRegistrationField/ExtendedRegistrationField.xib new file mode 100644 index 0000000..28e1fd2 --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Registration/Cells/ExtendedRegistrationField/ExtendedRegistrationField.xib @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/enrollment/enrollment/ViewControllers/Registration/Cells/ExtendedRegistrationField/ExtendedRegistrationFieldItem.swift b/enrollment/enrollment/ViewControllers/Registration/Cells/ExtendedRegistrationField/ExtendedRegistrationFieldItem.swift new file mode 100644 index 0000000..a67be8b --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Registration/Cells/ExtendedRegistrationField/ExtendedRegistrationFieldItem.swift @@ -0,0 +1,54 @@ +// +// ExtendedRegistrationFieldItem.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 3/25/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Cocoa + +/// This class manage the single option item of the extended registration field. +class ExtendedRegistrationFieldItem: NSView, LoadableNib { + + // MARK: - Outlets + + @IBOutlet var contentView: NSView! + @IBOutlet weak var optionItem: NSButton! + + // MARK: - Variables + + var fieldOption: RegistrationField.Option? { + didSet { + guard let option = fieldOption else { return } + optionItem.title = option.label.localized + } + } + var isSelected: Bool = false { + didSet { + optionItem.state = isSelected ? .on : .off + } + } + /// Call back that pass the option and the checkBox state to the parent class. + var onSelection: (RegistrationField.Option, NSControl.StateValue) -> Void = { _, _ in } + + // MARK: - Initializers + + override init(frame frameRect: NSRect) { + super.init(frame: frameRect) + loadViewFromNib() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + loadViewFromNib() + } + + // MARK: - Actions + + @IBAction func didSelectOption(_ sender: NSButton) { + guard let option = fieldOption else { return } + self.onSelection(option, sender.state) + } +} diff --git a/enrollment/enrollment/ViewControllers/Registration/Cells/ExtendedRegistrationField/ExtendedRegistrationFieldItem.xib b/enrollment/enrollment/ViewControllers/Registration/Cells/ExtendedRegistrationField/ExtendedRegistrationFieldItem.xib new file mode 100644 index 0000000..52731f1 --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Registration/Cells/ExtendedRegistrationField/ExtendedRegistrationFieldItem.xib @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/enrollment/enrollment/ViewControllers/Registration/InfoPopOver/InfoPopOverStackItem.swift b/enrollment/enrollment/ViewControllers/Registration/InfoPopOver/InfoPopOverStackItem.swift new file mode 100644 index 0000000..e272df8 --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Registration/InfoPopOver/InfoPopOverStackItem.swift @@ -0,0 +1,69 @@ +// +// InfoPopOverStackItem.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 3/16/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Cocoa + +/// This class manage the stack item that will be showd in an infoPopover. +class InfoPopOverStackItem: NSView, LoadableNib { + + // MARK: - Outlets + + @IBOutlet var contentView: NSView! + @IBOutlet weak var containerView: NSView! + @IBOutlet var leftText: NSTextField! { + didSet { + guard let text = infoLabel else { return } + leftText.stringValue = text + } + } + @IBOutlet var rightText: NSTextField! { + didSet { + guard let text = infoDescription else { return } + rightText.stringValue = text + } + } + @IBOutlet var separatorCenter: NSLayoutConstraint! { + didSet { + separatorCenter.isActive = false + separatorCenter = NSLayoutConstraint(item: separator!, attribute: .centerX, relatedBy: .equal, toItem: separator.superview!, attribute: .centerX, multiplier: separatorMultiplierValue!, constant: 0) + separatorCenter.isActive = true + } + } + @IBOutlet weak var separator: NSBox! + + // MARK: - Variables + + var infoLabel: String? + var infoDescription: String? + var separatorMultiplierValue: CGFloat? + + // MARK: - Initializers + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + /// Initialize the stack item with the information of the infoSection row. + /// - Parameters: + /// - label: the label of the row. + /// - description: the description of the row. If nil or not set the row will display only the label in full size. + /// - separatorMultiplierValue: the multiplier value that handle the position of an hidden separator between the label and the description. + init(with field: InfoField, separatorMultiplierValue: CGFloat? = 0.60) { + self.infoLabel = field.label.localized + if let description = field.description?.localized, !description.isEmpty { + self.infoDescription = description + self.separatorMultiplierValue = separatorMultiplierValue + } else { + self.infoDescription = "" + self.separatorMultiplierValue = 1.9 + } + super.init(frame: .zero) + loadViewFromNib() + } +} diff --git a/enrollment/enrollment/ViewControllers/Registration/InfoPopOver/InfoPopOverStackItem.xib b/enrollment/enrollment/ViewControllers/Registration/InfoPopOver/InfoPopOverStackItem.xib new file mode 100644 index 0000000..f42720c --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Registration/InfoPopOver/InfoPopOverStackItem.xib @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/enrollment/enrollment/ViewControllers/Registration/InfoPopOver/InfoPopOverViewController.swift b/enrollment/enrollment/ViewControllers/Registration/InfoPopOver/InfoPopOverViewController.swift new file mode 100644 index 0000000..3a7080a --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Registration/InfoPopOver/InfoPopOverViewController.swift @@ -0,0 +1,53 @@ +// +// InfoPopOverViewController.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 3/16/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Cocoa + +/// This class manage the popover that shows the informations related to a label. +class InfoPopOverViewController: NSViewController { + + // MAKR: - Outlets + + @IBOutlet var mainStackView: NSStackView! + + // MARK: - Variables + + var infoSection: InfoSection + + // MARK: - Initializers + + /// Initialize the popover with the infoSection that needs to be showed. + /// - Parameter info: the InfoSection object that needs to be displayed ad popover. + init(with info: InfoSection) { + self.infoSection = info + super.init(nibName: .init("InfoPopOverViewController"), bundle: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Instance methods + + override func viewDidLoad() { + super.viewDidLoad() + for (index, field) in infoSection.fields.enumerated() { + let itemView = InfoPopOverStackItem(with: field) + self.mainStackView.insertArrangedSubview(itemView, at: index*2) + guard index+1 < infoSection.fields.count else { return } + let horizontalLine = HorizontalLine() + let widthConstraint = NSLayoutConstraint(item: horizontalLine, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1, constant: mainStackView.frame.width-16) + let heightConstraint = NSLayoutConstraint(item: horizontalLine, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 1) + horizontalLine.addConstraints([widthConstraint, heightConstraint]) + widthConstraint.isActive = true + heightConstraint.isActive = true + self.mainStackView.insertArrangedSubview(horizontalLine, at: (index*2)+1) + } + } +} diff --git a/enrollment/enrollment/ViewControllers/Registration/InfoPopOver/InfoPopOverViewController.xib b/enrollment/enrollment/ViewControllers/Registration/InfoPopOver/InfoPopOverViewController.xib new file mode 100644 index 0000000..20354d5 --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Registration/InfoPopOver/InfoPopOverViewController.xib @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/enrollment/enrollment/ViewControllers/Registration/MultipleRegistrationFieldsViewController.swift b/enrollment/enrollment/ViewControllers/Registration/MultipleRegistrationFieldsViewController.swift new file mode 100644 index 0000000..a6f0ee4 --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Registration/MultipleRegistrationFieldsViewController.swift @@ -0,0 +1,264 @@ +// +// MultipleRegistrationFieldsViewController.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 3/3/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Cocoa + +/// This class manage the view controller that shows multiple registration fields to the user. +class MultipleRegistrationFieldsViewController: NSViewController { + + // MARK: - Outlets + + @IBOutlet weak var contentView: NSView! + @IBOutlet weak var titleLabel: InfoLabelView! + @IBOutlet weak var subtitleLabel: InfoLabelView! + @IBOutlet weak var footerLabel: InfoLabelView! + @IBOutlet weak var fieldsCollectionView: NSCollectionView! + @IBOutlet weak var bottomLeftButton: NSButton! + @IBOutlet weak var bottomRightButton: NSButton! { + didSet { + bottomRightButton?.isEnabled = canGoThrough() + } + } + + // MARK: - Variables + + static let controllerID = "MultipleRegistrationFieldsViewController" + private var _page: RegistrationPage? + var page: RegistrationPage! { + get { + guard _page != nil else { + return Context.main!.dataSet.registration?.pages.first! // If the page was not setted at the viewController init it takes the first registration page of the main context. + } + return _page + } + set { + _page = newValue + } + } + var registrationChoices: Set = .init() { + didSet { + bottomRightButton?.isEnabled = canGoThrough() + } + } + + // MARK: - Instance methods + + override func viewDidLoad() { + super.viewDidLoad() + configureCollectionView() + loadChoices() + } + + override func viewWillAppear() { + super.viewWillAppear() + configureLabels() + configureButtons() + } + + // MARK: - Overriding methods + + override func prepare(for segue: NSStoryboardSegue, sender: Any?) { + switch segue.identifier { + case "goToPage": + guard let nexVC = segue.destinationController as? MultipleRegistrationFieldsViewController else { return } + guard let context = Context.main, + let currentIndexPage = context.dataSet.registration?.pages.firstIndex(of: self.page), + let count = context.dataSet.registration?.pages.count, count > currentIndexPage+1 else { return } + let nextPage = context.dataSet.registration?.pages[currentIndexPage+1] + nexVC.page = nextPage + nexVC.registrationChoices = self.registrationChoices + case "backFromPage": + guard let nexVC = segue.destinationController as? MultipleRegistrationFieldsViewController else { return } + guard let context = Context.main, + let currentIndexPage = context.dataSet.registration?.pages.firstIndex(of: self.page), + currentIndexPage > 0 else { return } + let nextPage = context.dataSet.registration?.pages[currentIndexPage-1] + nexVC.page = nextPage + nexVC.registrationChoices = self.registrationChoices + default: + break + } + } + + // MARK: - Private methods + + private func configureCollectionView() { + fieldsCollectionView.register(NSNib(nibNamed: "CompactRegistrationField", bundle: nil), forItemWithIdentifier: CompactRegistrationField.reuseIdentifier) + fieldsCollectionView.register(NSNib(nibNamed: "ExtendedRegistrationField", bundle: nil), forItemWithIdentifier: ExtendedRegistrationField.reuseIdentifier) + } + + private func configureLabels() { + titleLabel.labelledInfo = page.title + titleLabel.font = .systemFont(ofSize: 28) + if let titleHelp = page.title.infoSection { + titleLabel.onInfoButtonPressed = { view in + self.didPressedInfoButton(view, infos: titleHelp) + } + } + + if let subtitle = page.subtitle { + subtitleLabel.labelledInfo = subtitle + if let subtitleHelp = subtitle.infoSection { + subtitleLabel.onInfoButtonPressed = { view in + self.didPressedInfoButton(view, infos: subtitleHelp) + } + } + } + + if let footer = page.footer { + footerLabel.labelledInfo = footer + if let footerHelp = footer.infoSection { + footerLabel.onInfoButtonPressed = { view in + self.didPressedInfoButton(view, infos: footerHelp) + } + } + } else { + footerLabel.isHidden = true + } + } + + private func configureButtons() { + guard let context = Context.main, + let currentIndexPage = context.dataSet.registration?.pages.firstIndex(of: self.page)else { return } + + switch context.dataSet.phase { + case "3": + bottomLeftButton.isHidden = !(context.dataSet.registration?.registrationStatus ?? false) + bottomLeftButton.title = "buttonLabelBack".localized + bottomRightButton.title = "buttonLabelNext".localized + default: + bottomLeftButton.title = currentIndexPage > 0 ? "buttonLabelBack".localized : "buttonLabelUnenroll".localized + bottomRightButton.title = "buttonLabelNext".localized + } + } + + /// If not defined at viewController init it load the user registration choices from the main context. + private func loadChoices() { + guard registrationChoices.isEmpty, let choices = Context.main?.dataSet.selectedRegistrationInfo else { return } + choices.forEach({ self.registrationChoices.insert($0) }) + } + + /// Check if all the fields have a selected choice. + /// - Returns: bool value. + private func canGoThrough() -> Bool { + let regChoisesKeys = registrationChoices.map({ $0.fieldKey }) + let pageFieldKeys = page.fields.map({ $0.key }) + for key in pageFieldKeys { + guard regChoisesKeys.contains(key) else { return false } + } + return true + } + + private func didRequestCancelFramework() { + IssueAlertService.sharedInstance.displaySheetWithJAMFAction(header: AlertText.RegistrationCancelAlert.header, + message: AlertText.RegistrationCancelAlert.message, + style: .critical, + cancelButtonLabel: "labelNo".localized, + actionButtonLabel: "labelYes".localized, + jamfPolicyEvent: Context.main?.dataSet.policies.removeFramework ?? "", + button1LogText: "unenrollmentCancelled".localized) + } + + // MARK: - Actions + + @IBAction func didPressedBottomLeftButton(_ sender: Any) { + guard let context = Context.main else { return } + guard let currentIndexPage = context.dataSet.registration?.pages.firstIndex(of: self.page), + currentIndexPage > 0 else { + if context.dataSet.phase == "3" { + self.performSegue(withIdentifier: .init("backToRegistrationFinalPage"), sender: nil) + } else { + didRequestCancelFramework() + } + return + } + self.performSegue(withIdentifier: .init("backFromPage"), sender: nil) + } + + @IBAction func didPressedBottomRightButton(_ sender: Any) { + + guard let context = Context.main, + let currentIndexPage = context.dataSet.registration?.pages.firstIndex(of: self.page) else { return } + + guard let count = context.dataSet.registration?.pages.count, count > currentIndexPage+1 else { + context.dataSet.selectedRegistrationInfo = registrationChoices.map({ $0 }) + self.performSegue(withIdentifier: .init("goToLoadingPage"), sender: nil) + return + } + self.performSegue(withIdentifier: .init("goToPage"), sender: nil) + } +} + +// MARK: - Collection View delegate and data source + +extension MultipleRegistrationFieldsViewController: NSCollectionViewDelegate, NSCollectionViewDataSource { + func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int { + return page.fields.count + } + + func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem { + let field = page.fields[indexPath.item] + if field.multipleChoiseAllowed { + guard let item = fieldsCollectionView.makeItem(withIdentifier: ExtendedRegistrationField.reuseIdentifier, for: indexPath) as? ExtendedRegistrationField else { return NSCollectionViewItem() } + item.configure(with: field, selectedOptions: registrationChoices.first(where: { $0.fieldKey == field.key })?.selectedOptionTitles ?? []) + item.delegate = self + return item + } else { + guard let item = fieldsCollectionView.makeItem(withIdentifier: CompactRegistrationField.reuseIdentifier, for: indexPath) as? CompactRegistrationField else { return NSCollectionViewItem() } + item.fieldInfo = field + item.selectedOption = registrationChoices.first(where: { $0.fieldKey == field.key })?.selectedOptionTitles.first + item.delegate = self + return item + } + + } +} + +// MARK: - Collection View flow layout delegate + +extension MultipleRegistrationFieldsViewController: NSCollectionViewDelegateFlowLayout { + func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> NSSize { + let field = page.fields[indexPath.item] + if field.multipleChoiseAllowed { + let height: CGFloat = CGFloat(field.optionLabels.count)*25+25 + return NSSize(width: collectionView.bounds.size.width/1.10, height: height) + } else { + return NSSize(width: collectionView.bounds.size.width/2.20, height: 60) + } + } +} + +// MARK: - Registration Field Cell delegate + +extension MultipleRegistrationFieldsViewController: SelectableRegistrationCollectionViewItemDelegate { + func didSelectedOption(_ sender: NSCollectionViewItem, option: RegistrationChoice) { + self.registrationChoices.remove(option) + self.registrationChoices.insert(option) + } + + func didDeselectOption(_ option: RegistrationChoice) { + self.registrationChoices.remove(option) + } + + func didPressedInfoButton(_ sender: NSButton, infos: InfoSection) { + let infoPopupViewController = InfoPopOverViewController(with: infos) + self.present(infoPopupViewController, asPopoverRelativeTo: sender.convert(sender.bounds, to: self.contentView), of: self.contentView, preferredEdge: .maxX, behavior: .semitransient) + } +} + +class MyScroller: NSScroller { + override var scrollerStyle: NSScroller.Style { + get { + return .overlay + } + set { + super.scrollerStyle = newValue + } + } +} diff --git a/enrollment/enrollment/ViewControllers/Registration/PostRegistrationPageViewController.swift b/enrollment/enrollment/ViewControllers/Registration/PostRegistrationPageViewController.swift new file mode 100644 index 0000000..65f5d5c --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Registration/PostRegistrationPageViewController.swift @@ -0,0 +1,206 @@ +// +// PostRegistrationPageViewController.swift +// enrollment +// +// Created by Simone Martorelli on 4/5/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Cocoa + +/// This class manage the last page of the registration process. +class PostRegistrationPageViewController: NSViewController { + + // MARK: - Outlets + + @IBOutlet weak var titleInfoLabel: InfoLabelView! + @IBOutlet weak var subTitleInfoLabel: InfoLabelView! + @IBOutlet weak var countdownLabel: NSTextField! + @IBOutlet weak var bodyLabel: NSTextField! + @IBOutlet weak var footerMessageInfoLabel: InfoLabelView! + @IBOutlet weak var restartCloseButton: NSButton! + @IBOutlet weak var updateInfoButton: NSButton! + + // MARK: - Variables + + static let controllerID = "PostRegistrationPageViewController" + private var countdown = Context.main?.dataSet.postRegistrationPage.restartTimeout ?? 300 + private var isRegistrationOnlyPhase: Bool { + return Context.main?.dataSet.phase == "3" + } + private var isInstallationOnlyPhase: Bool { + return Context.main?.dataSet.phase == "4" + } + private var restartNeeded: Bool { + return Context.main?.dataSet.bundleInstallationPage?.bundleInstallationNeedsRestartBefore ?? true + } + private var timer: Timer? + private var postRegistrationPageData: PostRegistrationPage = (Context.main?.dataSet.postRegistrationPage)! + + // MARK: - Instance methods + + override func viewDidLoad() { + super.viewDidLoad() + configureTimer() + configureUIElements() + updateRegistrationStatus() + } + + override func viewWillDisappear() { + super.viewWillDisappear() + timer?.invalidate() + timer = nil + } + + // MARK: - Private methods + + private func configureTimer() { + guard restartNeeded else { return } + timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in + self.updateCounter() + } + } + + private func configureUIElements() { + self.titleInfoLabel.labelledInfo = postRegistrationPageData.title + titleInfoLabel.font = .systemFont(ofSize: 28) + if let infos = titleInfoLabel.labelledInfo?.infoSection { + titleInfoLabel.onInfoButtonPressed = { view in + self.didPressedInfoButton(view, infos: infos) + } + } + if let subtitle = postRegistrationPageData.subtitle { + self.subTitleInfoLabel.labelledInfo = subtitle + if let infos = subTitleInfoLabel.labelledInfo?.infoSection { + subTitleInfoLabel.onInfoButtonPressed = { view in + self.didPressedInfoButton(view, infos: infos) + } + } + } else { + self.subTitleInfoLabel.isHidden = true + } + if let footer = postRegistrationPageData.footer { + self.footerMessageInfoLabel.labelledInfo = footer + if let infos = footerMessageInfoLabel.labelledInfo?.infoSection { + footerMessageInfoLabel.onInfoButtonPressed = { view in + self.didPressedInfoButton(view, infos: infos) + } + } + } else { + self.footerMessageInfoLabel.isHidden = true + } + if isRegistrationOnlyPhase { + self.bodyLabel.attributedStringValue = self.getSelectedInfo() + } else { + self.bodyLabel.set(label: postRegistrationPageData.body.localized, color: .controlTextColor) + } + if restartNeeded { + restartCloseButton.title = "buttonLabelRestart".localized + countdownLabel.set(label: String(format: "postRegistrationPageCountdownMessage".localized, countdown), color: .controlTextColor) + } else if isRegistrationOnlyPhase { + restartCloseButton.title = "buttonLabelClose".localized + } else { + restartCloseButton.title = "buttonLabelNext".localized + } + } + + private func updateRegistrationStatus() { + Context.main?.dataSet.registration?.registrationStatus = true + } + + private func restartComputer() { + if isRegistrationOnlyPhase { + Context.main?.dataSet.phase = "2" + } else { + Context.main?.dataSet.phase = "1" + } + + var systemProcessPSN = ProcessSerialNumber(highLongOfPSN: 0, lowLongOfPSN: UInt32(kSystemProcess)) + let systemProcessDescriptor = NSAppleEventDescriptor(descriptorType: DescType(typeProcessSerialNumber), + bytes: &systemProcessPSN, + length: MemoryLayout.size(ofValue: systemProcessPSN)) + let rebootEvent = NSAppleEventDescriptor(eventClass: AEEventClass(kCoreEventClass), + eventID: AEEventID(kAERestart), + targetDescriptor: systemProcessDescriptor, + returnID: AEReturnID(kAutoGenerateReturnID), + transactionID: AETransactionID(kAnyTransactionID)) + let err = AESendMessage(rebootEvent.aeDesc, nil, AESendMode(kAENoReply), kAEDefaultTimeout) + if err != noErr { + let failureAlert = NSAlert() + failureAlert.messageText = NSLocalizedString("restartFailureMessage".localized, comment: "restartFailureComment".localized) + failureAlert.runModal() + } + } + + private func updateCounter() { + if countdown >= 1 { + countdownLabel.stringValue = String(format: "postRegistrationPageCountdownMessage".localized, countdown) + countdown -= 1 + } else { + self.restartComputer() + } + } + + /// This method get the registration info selected by the user and build up an attributed string with the follow row "schema": + /// "FieldTitle": "selected option" + /// - Returns: attributed string. + private func getSelectedInfo() -> NSMutableAttributedString { + guard let selectedRegistrationInfo = Context.main?.dataSet.selectedRegistrationInfo else { + return NSMutableAttributedString() + } + + let composedString = NSMutableAttributedString() + for info in selectedRegistrationInfo { + let infoString = NSMutableAttributedString(string: info.fieldTitle.localized, attributes: [NSAttributedString.Key.font: NSFont.boldSystemFont(ofSize: 13)]) + if info.isMultipleChoiseAllowed { + infoString.append(NSAttributedString(string: ": ")) + for (index, title) in info.selectedOptionTitles.enumerated() { + infoString.append(NSAttributedString(string: title.localized)) + if index < (info.selectedOptionTitles.count - 1) { + infoString.append(NSAttributedString(string: ", ")) + } + } + infoString.append(NSAttributedString(string: "\n\n")) + } else { + infoString.append(NSAttributedString(string: ": " + (info.selectedOptionTitles.first?.localized ?? "") + "\n\n")) + } + composedString.append(infoString) + } + composedString.addAttributes([NSAttributedString.Key.foregroundColor: NSColor.controlTextColor], range: NSRange(location: 0, length: composedString.string.utf16.count)) + return composedString + } + + // MARK: - Actions + + @IBAction func didPressBottomRightButton(_ sender: NSButton) { + if isRegistrationOnlyPhase { + NSApplication.shared.terminate(self) + } else if isInstallationOnlyPhase && restartNeeded { + self.restartComputer() + } else if restartNeeded { + self.restartComputer() + } else { + self.performSegue(withIdentifier: "goToInstallationPhase", sender: self) + } + } + + @IBAction func didPressBottomLeftButton(_ sender: NSButton) { + if isRegistrationOnlyPhase { + self.performSegue(withIdentifier: "goToFirstRegistrationPage", sender: nil) + } else if isInstallationOnlyPhase { + IssueAlertService.sharedInstance.displaySheetWithJAMFAction(header: AlertText.RegistrationCancelAlert.header, + message: AlertText.RegistrationCancelAlert.message, + style: .critical, + cancelButtonLabel: "labelNo".localized, + actionButtonLabel: "labelYes".localized, + jamfPolicyEvent: Context.main?.dataSet.policies.removeFramework ?? "", + button1LogText: "unenrollmentCancelled".localized) + } + } + + func didPressedInfoButton(_ sender: NSButton, infos: InfoSection) { + let infoPopupViewController = InfoPopOverViewController(with: infos) + self.present(infoPopupViewController, asPopoverRelativeTo: sender.convert(sender.bounds, to: self.view), of: self.view, preferredEdge: .maxX, behavior: .semitransient) + } +} diff --git a/enrollment/enrollment/ViewControllers/Registration/Registration.storyboard b/enrollment/enrollment/ViewControllers/Registration/Registration.storyboard new file mode 100644 index 0000000..179d097 --- /dev/null +++ b/enrollment/enrollment/ViewControllers/Registration/Registration.storyboard @@ -0,0 +1,344 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/enrollment/enrollment/ViewControllers/SubViewControllerManagerViewController.swift b/enrollment/enrollment/ViewControllers/SubViewControllerManagerViewController.swift new file mode 100644 index 0000000..fc9d59b --- /dev/null +++ b/enrollment/enrollment/ViewControllers/SubViewControllerManagerViewController.swift @@ -0,0 +1,162 @@ +// +// SubViewControllerManagerViewController.swift +// enrollment +// +// Created by Simone Martorelli on 20/07/2020. +// Copyright © 2018 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// +// swiftlint:disable function_body_length + +import Cocoa + +/// Parent view controller for the main window of the application. +class SubViewControllerManagerViewController: NSViewController { + + // MARK: - Variables + + static let registrationStoryboardName = "Registration" + static let installationStoryboardName = "Installation" + + // MARK: - Instance methods + + override func viewDidLoad() { + super.viewDidLoad() + layoutSetup() + } + + // MARK: - Private methods + + /// Define the target VC based on the phase defined in the context object. + private func layoutSetup() { + checkContextConsistency({ phase in + var controllerID: String! + var storyboardName: String! + + switch phase { + case "0" : + storyboardName = Self.registrationStoryboardName + controllerID = MultipleRegistrationFieldsViewController.controllerID + case "1" : + storyboardName = Self.installationStoryboardName + controllerID = BundleSelectionViewController.controllerID + case "2" : + storyboardName = Self.installationStoryboardName + controllerID = PostInstallationPageViewController.controllerID + case "3": + storyboardName = Self.registrationStoryboardName + controllerID = Context.main?.dataSet.registration?.registrationStatus ?? false ? PostRegistrationPageViewController.controllerID : MultipleRegistrationFieldsViewController.controllerID + case "4": + storyboardName = Self.registrationStoryboardName + controllerID = PostRegistrationPageViewController.controllerID + default: + storyboardName = Self.registrationStoryboardName + controllerID = MultipleRegistrationFieldsViewController.controllerID + } + + let mainStoryboard: NSStoryboard = NSStoryboard(name: storyboardName, bundle: nil) + guard let sourceViewController = mainStoryboard.instantiateController(withIdentifier: controllerID) as? NSViewController else { return } + + self.insertChild(sourceViewController, at: 0) + self.view.addSubview(sourceViewController.view) + self.view.frame = sourceViewController.view.frame + + }, errorHandler: { errorMessage in + let sourceViewController = ConfigurationErrorViewController(with: errorMessage) + self.insertChild(sourceViewController, at: 0) + self.view.addSubview(sourceViewController.view) + self.view.frame = sourceViewController.view.frame + }) + } + + /// This methods check the context informations consistency based on the defined phase. + /// - Parameters: + /// - completion: return the available phase (the defined one if possible). + /// - errorHandler: return an error message if no available phases for the defined informations. + private func checkContextConsistency(_ completion: @escaping (_ phase: String) -> Void, errorHandler: @escaping (_ errorMessage: String) -> Void) { + guard let context = Context.main else { + errorHandler("Impossible to parse configuration file, please contact an administrator.") + return + } + + func testForPhase0() -> Bool { + guard let registrationData = context.dataSet.registration, !registrationData.pages.isEmpty else { return false } + for page in registrationData.pages { + guard !page.fields.isEmpty else { return false } + } + return true + } + + func testForPhase1() -> Bool { + guard let bundleSelectionData = context.dataSet.bundleSelectionPage, + !bundleSelectionData.bundles.isEmpty else { return false } + for bundle in bundleSelectionData.bundles { + guard !bundle.apps.isEmpty else { return false } + } + return true + } + + func testForPhase2() -> Bool { + guard !context.dataSet.postInstallationPage.items.isEmpty else { return false } + return true + } + + func testForPhase3() -> Bool { + return testForPhase0() + } + + func testForPhase4() -> Bool { + return testForPhase1() + } + + switch context.dataSet.phase { + case "0": + guard testForPhase0() else { + guard testForPhase1() else { + guard testForPhase2() else { + errorHandler("Impossible to find the information needed, please contact an administrator.") + return + } + context.dataSet.phase = "2" + completion(context.dataSet.phase) + return + } + context.dataSet.phase = "1" + completion(context.dataSet.phase) + return + } + completion(context.dataSet.phase) + case "1": + guard testForPhase1() else { + guard testForPhase2() else { + errorHandler("Impossible to find the information needed, please contact an administrator.") + return + } + context.dataSet.phase = "2" + completion(context.dataSet.phase) + return + } + completion(context.dataSet.phase) + case "2": + guard testForPhase2() else { + errorHandler("Impossible to find the information needed, please contact an administrator.") + return + } + completion(context.dataSet.phase) + case "3": + guard testForPhase3() else { + errorHandler("Impossible to find the information needed, please contact an administrator.") + return + } + completion(context.dataSet.phase) + case "4": + guard testForPhase4() else { + errorHandler("Impossible to find the information needed, please contact an administrator.") + return + } + completion(context.dataSet.phase) + default: + errorHandler("Impossible to find the information needed, please contact an administrator.") + } + } +} diff --git a/enrollment/enrollment/Views/Constants/AlertConstants.swift b/enrollment/enrollment/Views/Constants/AlertConstants.swift new file mode 100644 index 0000000..6cde2b3 --- /dev/null +++ b/enrollment/enrollment/Views/Constants/AlertConstants.swift @@ -0,0 +1,103 @@ +// +// AlertConstants.swift +// enrollment +// +// Created by Jay Latman on 7/30/18. +// Copyright © 2018 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Cocoa + +struct AlertText { + /** + Structure definition containing reference assignments of stored values or property list key names for retrieving values. + + String values used for displaying alert sheet to user upon cancelling / opting out of enrollment. + + • header : header message string + + • message : body message string + */ + struct RegistrationCancelAlert { + static let header: String = "unenrollmentAlertTitle".localized + static let message: String = "unenrollmentAlertMessage".localized + } + + /** + Structure definition containing reference assignments of stored values or property list key names for retrieving values. + + String values used for displaying alert sheet to user when attempting to install bundles where the estimated download time exceeds the `estimatedDownloadTimeInSecondsThreshold`. + + • header : header message string + + • message : body message string + */ + struct BundleSelectionWarning { + static let header: String = "bundleSelectionAlertTitle".localized + static let message: String = "bundleSelectionAlertMessage".localized + } + + /** + Structure definition containing reference assignments of stored values or property list key names for retrieving values. + + String value used for displaying alert string to user if any bundle app installations experienced failures. + + • message : string value to be displayed below the header string of the bundle installation view + */ + struct BundleInstallationWarning { + static let message: String = "bundleInstallationalertMessage".localized + } + + /** + Structure definition containing reference assignments of stored values or property list key names for retrieving values. + + String values used for displaying alert window to user in the event that the application is launched and can not locate the jamf binary. + + • header : header message string + + • message : body message string + */ + struct FailureToLaunch { + static let header: String = "launchFailureAlertTitle".localized + static let message: String = "launchFailureAlertMessage".localized + } + + /** + Structure definition containing reference assignments of stored values or property list key names for retrieving values. + + String values used for displaying alert sheet to user if the internal or external network is not available. + + child structs: + + External, Internal + */ + struct NetworkValidationMessaging { + /** + Structure definition containing reference assignments of stored values or property list key names for retrieving values. + - Note: string values used for displaying alert sheet to user should the public network not be reachable or the JPS is not available. + + • network : network alert string + + • jps : jps unreachable alert string + */ + struct External { + static let network: String = "externalNetworkAlertMessage".localized + static let jps: String = "externalNetworkJspMessage".localized + } + + /** + Structure definition containing reference assignments of stored values or property list key names for retrieving values. + + String values used for displaying alert sheet to user should the intranet not be reachable. + + • url : string value of an internal URL for validation + + • warning : message displayed to the user + */ + struct Internal { + static let url = "https://w3.ibm.com/" + static let warning = "internalNetworkProblemAlertMessage".localized + } + } +} diff --git a/enrollment/enrollment/Constants/ColorConstants.swift b/enrollment/enrollment/Views/Constants/ColorConstants.swift similarity index 91% rename from enrollment/enrollment/Constants/ColorConstants.swift rename to enrollment/enrollment/Views/Constants/ColorConstants.swift index ed7315e..0733cc2 100644 --- a/enrollment/enrollment/Constants/ColorConstants.swift +++ b/enrollment/enrollment/Views/Constants/ColorConstants.swift @@ -11,6 +11,7 @@ import Cocoa /** Structure definition containing reference assignments of stored constants mapped to color swatches in the asset catalog + child structs: @@ -72,7 +73,7 @@ struct ColorConstants { /// General background color assignment for backing layers struct BackgroundColor { static let standard = "standard_bg_color" - static let popover = ([NSColor(named: "popover_bg_color")] as! [NSColor]) + static let popover = NSColor(named: "popover_bg_color") } /// Stored color assignments for interface elements in the Registration phase of the application @@ -92,15 +93,15 @@ struct ColorConstants { Color references for drawn objects used in the SetupComplete view: - • appleLogo : color for apple logo displayed in `MigrationButton` + • appleLogo : color for apple logo displayed in `MigrationButton` - • outerRing : universal outer ring color + • outerRing : universal outer ring color - • weblinkTextColor : color applied to `Hyperlink` text buttons for LinkOuts + • weblinkTextColor : color applied to `Hyperlink` text buttons for LinkOuts - • descriptionTextColor : color applied to description text for each web link + • descriptionTextColor : color applied to description text for each web link - child structs - + child structs : WebURLButton, MigrationButton, SelfServiceButton, HelpButton, BackupButton */ @@ -122,7 +123,7 @@ struct ColorConstants { /// MigrationButton color assignments for each part of the drawn shape struct MigrationButton { - static let arrow_and_Keyboard = NSColor(named: "arrow_and_keyboard") + static let arrowAndKeyboard = NSColor(named: "arrow_and_keyboard") static let screenBezel = NSColor(named: "screen_bezel") static let laptopScreenBackground = NSColor(named: "laptop_screen_background") static let innerRing = NSColor(named: "migration_inner_ring") @@ -149,7 +150,7 @@ struct ColorConstants { /// BackupButton color assignments for each part of the drawn shape struct BackupButton { static let innerRing = NSColor(named: "backup_inner_ring") - static let clockhands_and_Arrowhead = NSColor(named: "clockhands_and_arrowhead") + static let clockhandsAndArrowhead = NSColor(named: "clockhands_and_arrowhead") static let arrowTail = NSColor(named: "arrow_tail") } } diff --git a/enrollment/enrollment/Views/Constants/JAMFConstants.swift b/enrollment/enrollment/Views/Constants/JAMFConstants.swift new file mode 100644 index 0000000..828eef0 --- /dev/null +++ b/enrollment/enrollment/Views/Constants/JAMFConstants.swift @@ -0,0 +1,35 @@ +// +// JAMFConstants.swift +// enrollment +// +// Created by Simone Martorelli on 12/10/20. +// Copyright © 2018 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// +// swiftlint:disable identifier_name + +import Foundation + +struct JPSPaths { + static let binaryPath = "/usr/local/jamf/bin/jamf" +} + +enum Environment: String { + case eng + case qa + case prod + + static var current: Environment { + return Environment(rawValue: Context.main?.dataSet.environment ?? "prod") ?? .prod + } + var healthCheckURL: String { + switch self { + case .eng: + return "" + case .qa: + return "" + case .prod: + return "" + } + } +} diff --git a/enrollment/enrollment/Views/Constants/UserDefaultHelper.swift b/enrollment/enrollment/Views/Constants/UserDefaultHelper.swift new file mode 100644 index 0000000..782ba78 --- /dev/null +++ b/enrollment/enrollment/Views/Constants/UserDefaultHelper.swift @@ -0,0 +1,69 @@ +// +// UserDefaultHelper.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 2/20/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Foundation + +struct UserDefaultHelper { + struct Keys { + static let phase = "phase" + static let registrationStatus = "registrationStatus" + static let hrFirstName = "hrFirstName" + static let environment = "environment" + static let selectedBundles = "SelectedBundles" + } + + struct Bundles { + struct AppInstallScreen { + static let status = "appScreenStatus" + static let warning = "appScreenWarning" + } + + struct Connectivity { + static let messaging = "connectivityMessaging" + static let status = "connectivityBundleStatus" + struct AppStatus { + static let app1 = "anyconnectInstallStatus" + } + struct DownloadTime { + static let size = "connectivitySize" + static let time = "connectivityInstallSeconds" + } + } + + struct Essentials { + static let messaging = "essentialsMessaging" + static let status = "essentialsBundleStatus" + struct AppStatus { + static let app1 = "notesInstallStatus" + static let app2 = "webexmeetingsInstallStatus" + static let app3 = "code42InstallStatus" + static let app4 = "bluepagesInstallStatus" + static let app5 = "safariBookmarksInstallStatus" + } + struct DownloadTime { + static let size = "essentialsSize" + static let time = "essentialsInstallSeconds" + } + } + + struct Productivity { + static let messaging = "productivityMessaging" + static let status = "productivityBundleStatus" + struct AppStatus { + static let app1 = "officeInstallStatus" + static let app2 = "slackInstallStatus" + static let app3 = "boxInstallStatus" + } + struct DownloadTime { + static let size = "productivitySize" + static let time = "productivityInstallSeconds" + } + } + } +} diff --git a/enrollment/enrollment/Views/CustomStackView.swift b/enrollment/enrollment/Views/CustomStackView.swift new file mode 100644 index 0000000..da13b16 --- /dev/null +++ b/enrollment/enrollment/Views/CustomStackView.swift @@ -0,0 +1,15 @@ +// +// CustomStackView.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 5/11/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Foundation +import Cocoa + +class CustomStackView: NSStackView { + override var isFlipped: Bool { return true } +} diff --git a/enrollment/enrollment/Views/HeaderViewController.storyboard b/enrollment/enrollment/Views/HeaderViewController.storyboard deleted file mode 100644 index e9fc174..0000000 --- a/enrollment/enrollment/Views/HeaderViewController.storyboard +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/enrollment/enrollment/Views/HorizontalLine.swift b/enrollment/enrollment/Views/HorizontalLine.swift new file mode 100644 index 0000000..5b428a2 --- /dev/null +++ b/enrollment/enrollment/Views/HorizontalLine.swift @@ -0,0 +1,18 @@ +// +// HorizontalLine.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 3/17/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Cocoa + +/// This class provide a simple horizontal line. +class HorizontalLine: NSView { + override func draw(_ dirtyRect: NSRect) { + NSColor.darkGray.set() + NSRect(x: 0, y: 0, width: dirtyRect.width, height: 1).fill() + } +} diff --git a/enrollment/enrollment/Views/InfoLabelView.swift b/enrollment/enrollment/Views/InfoLabelView.swift new file mode 100644 index 0000000..a458a26 --- /dev/null +++ b/enrollment/enrollment/Views/InfoLabelView.swift @@ -0,0 +1,56 @@ +// +// InfoLabelView.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 3/3/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Cocoa + +/// This class provide a label with a built in info button. +class InfoLabelView: NSView, LoadableNib { + + // MARK: - Outlets + + @IBOutlet var contentView: NSView! + @IBOutlet weak var labelText: NSTextField! + @IBOutlet weak var infoButton: NSButton! + + // MARK: - Variables + + /// This call back send to the parent view the reference of the button that triggered the action. + /// This reference will be used to obtain the correct rect to show the informations popover + var onInfoButtonPressed: ((NSButton) -> Void)? + var labelledInfo: InfoLabel? { + didSet { + guard let info = labelledInfo else { return } + if let attributedLabel = info.attributedLabel { + labelText.attributedStringValue = attributedLabel + } else { + labelText.stringValue = info.label.localized + } + infoButton.isHidden = info.infoSection == nil + } + } + /// The developer can define the different fonts for the label. + var font: NSFont? { + didSet { + labelText.font = font + } + } + + // MARK: - Initializer + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + loadViewFromNib() + } + + // MARK: - Actions + + @IBAction func infoButtonDidPressed(_ sender: NSButton) { + self.onInfoButtonPressed?(sender) + } +} diff --git a/enrollment/enrollment/Views/InfoLabelView.xib b/enrollment/enrollment/Views/InfoLabelView.xib new file mode 100644 index 0000000..f2af34c --- /dev/null +++ b/enrollment/enrollment/Views/InfoLabelView.xib @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/enrollment/enrollment/Views/LabelButton.swift b/enrollment/enrollment/Views/LabelButton.swift new file mode 100644 index 0000000..99edf95 --- /dev/null +++ b/enrollment/enrollment/Views/LabelButton.swift @@ -0,0 +1,52 @@ +// +// LabelButton.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 4/17/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import AppKit + +class LabelButton: NSControl { + var backgroundColor: NSColor = NSColor.clear { + didSet { + self.needsDisplay = true + } + } + var title: String = "" + var titleLabel: NSTextField! + + override func draw(_ dirtyRect: NSRect) { + super.draw(dirtyRect) + titleLabel?.removeFromSuperview() + titleLabel = NSTextField(wrappingLabelWithString: title) + titleLabel.translatesAutoresizingMaskIntoConstraints = false + addSubview(titleLabel) + titleLabel.topAnchor.constraint(equalTo: self.topAnchor).isActive = true + titleLabel.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true + titleLabel.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true + titleLabel.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true + titleLabel.isEditable = false + titleLabel.isSelectable = false + titleLabel.textColor = NSColor.linkColor + } + + override func mouseDown(with event: NSEvent) { + self.titleLabel.textColor = NSColor.selectedControlColor + } + + override func mouseUp(with event: NSEvent) { + self.titleLabel.textColor = NSColor.linkColor + guard let action = action else {return} + tryToPerform(action, with: self) + } + + override func resetCursorRects() { + super.resetCursorRects() + DispatchQueue.main.async { + self.addCursorRect(self.bounds, cursor: .pointingHand) + } + } +} diff --git a/enrollment/enrollment/Views/LinkOutItemCell.xib b/enrollment/enrollment/Views/LinkOutItemCell.xib index 5a1611a..9bdc457 100644 --- a/enrollment/enrollment/Views/LinkOutItemCell.xib +++ b/enrollment/enrollment/Views/LinkOutItemCell.xib @@ -1,19 +1,19 @@ - + - + - + - + @@ -33,8 +33,8 @@ - - + + @@ -42,9 +42,9 @@ - + - + @@ -58,6 +58,7 @@ + diff --git a/enrollment/enrollment/Views/LoaderView.swift b/enrollment/enrollment/Views/LoaderView.swift new file mode 100644 index 0000000..a3f1c91 --- /dev/null +++ b/enrollment/enrollment/Views/LoaderView.swift @@ -0,0 +1,100 @@ +// +// LoaderView.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 4/16/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import Cocoa + +class LoaderView: NSView { + + enum State { + case inQueue + case failure + case success + case inProgress + case partial + + var image: NSImage? { + switch self { + case .failure: + return NSImage(named: "failure") + case .inProgress: + return NSImage(named: "inProgress") + case .success: + return NSImage(named: "success") + case .inQueue: + return NSImage(named: "inQueue") + case .partial: + return NSImage(named: "partial") + } + } + + var isAnimationNeeded: Bool { + return self == .inProgress + } + } + + var imageView: RotableImageView! + var state: State { + didSet { + guard imageView != nil else { return } + updateView() + } + } + var animation: CABasicAnimation { + let rotation: CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation") + rotation.fromValue = 0.0 + rotation.toValue = Float(Double.pi * 2.0) + rotation.duration = 5 + rotation.repeatCount = Float.infinity + return rotation + } + + override init(frame frameRect: NSRect) { + state = .inQueue + super.init(frame: frameRect) + setupView() + } + + required init?(coder: NSCoder) { + state = .inQueue + super.init(coder: coder) + setupView() + } + + private func setupView() { + imageView = RotableImageView(image: state.image ?? NSImage()) + imageView.translatesAutoresizingMaskIntoConstraints = false + imageView.imageScaling = .scaleProportionallyUpOrDown + imageView.wantsLayer = true + self.addSubview(imageView) + + imageView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true + imageView.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true + imageView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true + imageView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true + } + + private func updateView() { + DispatchQueue.main.async { + self.imageView.image = self.state.image + guard self.state.isAnimationNeeded else { + self.stopAnimation() + return + } + self.startAnimation() + } + } + + private func startAnimation() { + imageView.rotate() + } + + private func stopAnimation() { + imageView.stopRotation() + } +} diff --git a/enrollment/enrollment/Views/Main.storyboard b/enrollment/enrollment/Views/Main.storyboard deleted file mode 100644 index 99a19c6..0000000 --- a/enrollment/enrollment/Views/Main.storyboard +++ /dev/null @@ -1,2231 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/enrollment/enrollment/Controllers/MainWindow/MainView.swift b/enrollment/enrollment/Views/MainView.swift similarity index 66% rename from enrollment/enrollment/Controllers/MainWindow/MainView.swift rename to enrollment/enrollment/Views/MainView.swift index 328d357..be434f9 100644 --- a/enrollment/enrollment/Controllers/MainWindow/MainView.swift +++ b/enrollment/enrollment/Views/MainView.swift @@ -1,19 +1,16 @@ // // MainView.swift -// enrollment +// Mac@IBM Enrollment // -// Created by Jay Latman on 12/14/18. +// Created by Jay Latman on 12/11/18. // Copyright © 2018 IBM. All rights reserved. // SPDX-License-Identifier: GPL-3.0-only // import Cocoa -/* - Through view hierarchy, this class uses the asset catalog color swatch to condition the background color for dark and light mode adoption. - */ +/// Through view hierarchy, this class uses the asset catalog color swatch to condition the background color for dark and light mode adoption class MainView: NSView { - override func updateLayer() { layer?.backgroundColor = backgroundColor?.cgColor } diff --git a/enrollment/enrollment/Views/RotableImageView.swift b/enrollment/enrollment/Views/RotableImageView.swift new file mode 100644 index 0000000..e651959 --- /dev/null +++ b/enrollment/enrollment/Views/RotableImageView.swift @@ -0,0 +1,48 @@ +// +// RotableImageView.swift +// Mac@IBM Enrollment +// +// Created by Simone Martorelli on 4/22/20. +// Copyright © 2020 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import AppKit + +class RotableImageView: NSImageView { + private let kRotationAnimationKey = "rotationanimationkey" + + /// This method locate the anchor point of the image view to allow for proper rotation. + func determineAnchorPoint() { + guard self.layer?.anchorPoint != CGPoint(x: 0.5, y: 0.5) else { return } + self.layer?.anchorPoint = CGPoint(x: 0.5, y: 0.5) + guard let frame = self.layer?.frame else { return } + let xCoord = Float(frame.origin.x + frame.size.width) + let yCoord = Float(frame.origin.y + frame.size.height) + let myPoint = CGPoint(x: CGFloat(xCoord), y: CGFloat(yCoord)) + self.layer?.position = myPoint + } + + /// This method start the rotation of the imageView. + /// - Parameter duration: double value representing the seconds of rotation. + func rotate(duration: Double = 1.0) { + determineAnchorPoint() + if layer?.animation(forKey: kRotationAnimationKey) == nil { + let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation") + + rotationAnimation.fromValue = 0.0 + rotationAnimation.toValue = Float.pi * -2.0 + rotationAnimation.duration = duration + rotationAnimation.repeatCount = Float.infinity + + layer?.add(rotationAnimation, forKey: kRotationAnimationKey) + } + } + + /// This method stop the rotation animation. + func stopRotation() { + if layer?.animation(forKey: kRotationAnimationKey) != nil { + layer?.removeAnimation(forKey: kRotationAnimationKey) + } + } +} diff --git a/enrollment/enrollment/Views/RotableView.swift b/enrollment/enrollment/Views/RotableView.swift new file mode 100644 index 0000000..f6f52af --- /dev/null +++ b/enrollment/enrollment/Views/RotableView.swift @@ -0,0 +1,46 @@ +// +// RotableView.swift +// enrollment +// +// Created by Simone Martorelli on 9/2/20. +// Copyright © 2018 IBM. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-only +// + +import AppKit + +class RotableView: NSView { + private let kRotationAnimationKey = "rotationanimationkey" + private var isAnchorPointDetermined: Bool = false + + func determineAnchorPoint() { + guard !isAnchorPointDetermined else { return } + self.layer?.anchorPoint = CGPoint(x: 0.5, y: 0.5) + guard let frame = self.layer?.frame else { return } + let xCoord = Float(frame.origin.x + frame.size.width) + let yCoord = Float(frame.origin.y + frame.size.height) + let myPoint = CGPoint(x: CGFloat(xCoord), y: CGFloat(yCoord)) + self.layer?.position = myPoint + isAnchorPointDetermined = true + } + + func rotate(duration: Double = 1.0) { + determineAnchorPoint() + if layer?.animation(forKey: kRotationAnimationKey) == nil { + let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation") + + rotationAnimation.fromValue = 0.0 + rotationAnimation.toValue = Float.pi * -2.0 + rotationAnimation.duration = duration + rotationAnimation.repeatCount = Float.infinity + + layer?.add(rotationAnimation, forKey: kRotationAnimationKey) + } + } + + func stopRotation() { + if layer?.animation(forKey: kRotationAnimationKey) != nil { + layer?.removeAnimation(forKey: kRotationAnimationKey) + } + } +} diff --git a/enrollment/enrollment/Views/StackItems.storyboard b/enrollment/enrollment/Views/StackItems.storyboard deleted file mode 100644 index f0827a6..0000000 --- a/enrollment/enrollment/Views/StackItems.storyboard +++ /dev/null @@ -1,386 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/enrollment/enrollment/de.lproj/Localizable.strings b/enrollment/enrollment/de.lproj/Localizable.strings new file mode 100644 index 0000000..d770820 --- /dev/null +++ b/enrollment/enrollment/de.lproj/Localizable.strings @@ -0,0 +1,272 @@ +/* + Localizable.strings + enrollment + + Created by Simone Martorelli on 2/5/20. + Copyright © 2020 IBM. All rights reserved. + SPDX-License-Identifier: GPL-3.0-only + */ + +/// MARK: - Note to the translation +/// +/// Pay attention to not modify, cancel or move the special characters: +/// - %d - This special character is substituted with a number at runtime; +/// - %@ - This special characted is substituted with a string at runtime; +/// - \n - This special characted works like the "return" key; +/// - \" - This special characted insert a "; + +// MARK: - Registration: page one + +// Header +"registrationPageOneTitleSimple" = "Willkommen als neue/r Mitarbeiter/in!"; +"registrationPageOneTitleComposed" = "Willkommen, %@!"; +"registrationPageOneSubtitleSimple" = "Ihr Name wird nicht angezeigt?"; +"registrationPageOneSubtitleComposed" = "Sie sind nicht %@?"; + +// Info popovers +"registrationPageOneSubtitle_info" = "Kein Problem, Sie können diese Angaben später aktualisieren, indem Sie den Mac@IBM App Store aufsuchen und nach \"Assign User\" (Benutzer zuordnen) suchen."; +"registrationPageOneDisclaimerPolicies_infoElementOne" = "Firewall"; +"registrationPageOneDisclaimerPolicies_infoElementTwo" = "Geheimer Modus"; +"registrationPageOneDisclaimerPolicies_infoElementThree" = "Gastbenutzerkonto"; +"registrationPageOneDisclaimerPolicies_infoElementFour" = "FileVault-Plattenverschlüsselung"; +"registrationPageOneDisclaimerPolicies_infoElementFive" = "Änderung des ursprünglichen Mac OS-Kennworts"; +"registrationPageOneDisclaimerPolicies_infoElementSix" = "ScreenSaver-Kennwort"; +"registrationPageOneDisclaimerPolicies_infoElementSeven_title" = "ScreenSaver-Startzeit"; +"registrationPageOneDisclaimerPolicies_infoElementSeven_description" = "Nach 30 Minuten Inaktivität"; +"registrationPageOneDisclaimerPolicies_infoElementEight_title" = "Endpunktschutzsoftware"; + +// Field labels +"registrationPageOneFieldRegion" = "Region"; +"registrationPageOneFieldComputer" = "Computertyp"; +"registrationPageOneFieldOwner" = "Asseteigner"; +"registrationPageOneFieldUser" = "Benutzertyp"; + +// Region field options +"registrationPageOneFieldRegionOptionOne" = "USA"; +"registrationPageOneFieldRegionOptionTwo" = "Kanada"; +"registrationPageOneFieldRegionOptionThree" = "EMEA (Europa, Naher und Mittlerer Osten, Afrika)"; +"registrationPageOneFieldRegionOptionFour" = "LA (Lateinamerika)"; +"registrationPageOneFieldRegionOptionFive" = "AP (Asien/Pazifik)"; + +// Computer Type options +"registrationPageOneFieldComputerOptionOne" = "Primär"; +"registrationPageOneFieldComputerOptionOne_info" = "für einen einzelnen Benutzer als Produktivitätsplattform für normale Büroarbeit (z. B. E-Mail, Web-Browsing/-Anwendungen, Instant Messaging, Dokumentation etc.)"; +"registrationPageOneFieldComputerOptionTwo" = "Sekundär"; +"registrationPageOneFieldComputerOptionTwo_info" = "für verschiedene Aufgaben, außer Büroarbeiten, einschließlich Kundenvorführungen und virtueller Maschinen"; +"registrationPageOneFieldComputerOptionThree" = "Gemeinsam"; +"registrationPageOneFieldComputerOptionThree_info" = "genutzt durch mehrere Benutzer für Schulung und Training"; +"registrationPageOneFieldComputerOptionFour" = "Leihweise"; +"registrationPageOneFieldComputerOptionFour_info" = "für Test- und/oder Entwicklungszwecke"; +"registrationPageOneFieldComputerOptionFive" = "Schulungsraum"; +"registrationPageOneFieldComputerOptionFive_info" = "für die kurzfristige Verwendung als Ersatz oder Ergänzung"; +"registrationPageOneFieldComputerOptionSix" = "Labor"; +"registrationPageOneFieldComputerOptionSix_info" = "für die Verwendung durch mehrere Benutzer für verschiedene Aufgaben, einschließlich Büroarbeiten"; + +// Asset Owner options +"registrationPageOneFieldOwnerOptionOne" = "Von IBM bereitgestellt"; +"registrationPageOneFieldOwnerOptionTwo" = "Im Eigentum"; +"registrationPageOneFieldOwnerOptionThree" = "Im Eigentum Dritter: vom Anbieter bereitgestellt"; +"registrationPageOneFieldOwnerOptionFour" = "Im Eigentum Dritter: von der Agentur des Auftragnehmers bereitgestellt"; +"registrationPageOneFieldOwnerOptionFive" = "Im Eigentum Dritter: vom Kunden bereitgestellt"; + +// User Type options +"registrationPageOneFieldUserOptionOne" = "Standard"; +"registrationPageOneFieldUserOptionOne_info" = "allgemeine Verwendung außerhalb der Pflichten im Rahmen von privilegierten oder Call-Center-Anwendungsfällen"; +"registrationPageOneFieldUserOptionTwo" = "Privilegiert"; +"registrationPageOneFieldUserOptionTwo_info" = "unter Zuordnung von Sicherheitsadministratorberechtigungen, Systemberechtigungen auf Netzeinheiten, Computersystemen, Middlewarekomponenten oder Anwendungen für IBM oder Kunden"; +"registrationPageOneFieldUserOptionThree" = "Service-/Call-Center"; +"registrationPageOneFieldUserOptionThree_info" = "einem Service-Center, Call-Center oder Help-Desk zugeordnet"; + +// Policies disclaimer +"registrationPageOneDisclaimerPolicies" = "IBM Sicherheitsrichtlinien werden automatisch angewendet."; + +// MARK: - Registration: page two + +// Header +"registrationPageTwoTitle" = "Informationen, auf die Sie zugreifen"; +"registrationPageTwoSubtitle" = "Wählen Sie die Datentypen aus, die auf diesem Computer gespeichert sind."; + +// Information options +"registrationPageTwoFieldInformationOptionOne_title" = "Sensible personenbezogene Daten"; +"registrationPageTwoFieldInformationOptionOne_description" = "Ihr Gerät speichert personenbezogene Daten"; +"registrationPageTwoFieldInformationOptionTwo_title" = "Kundendaten"; +"registrationPageTwoFieldInformationOptionTwo_description" = "Gerät speichert Daten, die sich im Eigentum eines Kunden befinden oder von einem Kunden erstellt wurden, oder wird verwendet, um darauf zuzugreifen"; +"registrationPageTwoFieldInformationOptionThree_title" = "Staatlich regulierte Daten"; +"registrationPageTwoFieldInformationOptionThree_description" = "Sie wurden von Ihrem Management, dem Dateneigner oder dem Datenverwalter informiert, dass die von Ihrem Gerät gespeicherten oder abgerufenen Daten staatlichen Beschränkungen oder Bestimmungen unterliegen, z. B. gelten für einige Gesundheitsdaten zusätzliche Schutzmaßnahmen"; +"registrationPageTwoFieldInformationOptionFour_title" = "FFIEC-Daten (Federal Financial Institutions Examination Council)"; +"registrationPageTwoFieldInformationOptionFour_description" = "Sie unterstützen Finanzumgebungen eines Kunden oder haben Zugriff darauf"; +"registrationPageTwoFieldInformationOptionFive_title" = "HIPAA-Daten (Health Insurance Portability and Accountability Act)"; +"registrationPageTwoFieldInformationOptionFive_description" = "Sie unterstützen ein durch HIPAA reguliertes Kundenkonto oder Multi-Tenant-Angebot"; +"registrationPageTwoFieldInformationOptionSix_title" = "PCI-Daten"; +"registrationPageTwoFieldInformationOptionSix_description" = "Gerät speichert sensible Zahlungskartendaten (z. B. Kreditkartendaten), die von einem Kunden erstellt wurden oder sich in dessen Eigentum befinden, oder greift darauf zu"; +"registrationPageTwoFieldInformationOptionSeven_title" = "Keine der vorstehenden Angaben"; +"registrationPageTwoFieldInformationOptionSeven_description" = ""; + +// MARK: - Registration: loading page + +// State labels +"registrationLoadingPageStateOne" = "Test der Netzgeschwindigkeit"; +"registrationLoadingPageStateTwo" = "Abschluss der Registrierung"; +"registrationLoadingPageStateForPhaseThree" = "Aktualisierung der Registrierung"; + +// MARK: - Registration: final page + +// Header +"registrationFinalPageTitle" = "Registrierung abgeschlossen"; +"registrationFinalPageTitlePhaseThree" = "Registrierungsdetails"; +"registrationFinalPageTitlePhaseFour" = "Willkommen!"; +"registrationFinalPageSubtitleStandard" = "Lassen Sie uns Ihren Mac einrichten!"; +"registrationFinalPageSubtitlePhaseThree" = ""; +"registrationFinalPageInstructionalMessage" = "Nach Ihrer nächsten Anmeldung werden Sie dazu aufgefordert, ein neues Mac OS-Anmeldekennwort einzugeben und FileVault-Plattenverschlüsselung zu aktivieren."; +"registrationFinalPageCountdownMessage" = "Ihr Mac wird in %d Sekunden automatisch erneut gestartet, um den Einrichtungsprozess fortzusetzen, oder Sie können jetzt \"Erneut starten\" auswählen."; + +// MARK: - Installation: bundle selection page + +// Header +"installationBundleSelectionPageTitle" = "App-Pakete für die ersten Schritte"; +"installationBundleSelectionPageSubtitle" = "Weitere Apps können jederzeit aus dem Mac@IBM App Store installiert werden."; + +// Labels +"installationBundleSelectionPageRecommended" = "(empfohlen)"; + +// Bundle one +"installationBundleSelectionPageBundleOneTitle" = "Konnektivität"; +"installationBundleSelectionPageBundleOneDescription" = "Stellen Sie mit den erforderlichen Softwarelösungen und Zertifikaten eine Verbindung zu IBM Netzen her"; +"installationBundleSelectionPageBundleOnePopoverTitle" = "Konnektivitätspaket"; +"installationBundleSelectionPageBundleOnePopoverDescription" = "Stellen Sie mit Zertifikaten und Software eine Verbindung zu unserem Netz her"; +"installationBundleSelectionPageBundleOneAppOneTitle" = "AnyConnect"; +"installationBundleSelectionPageBundleOneAppOneDescription" = "Ipsum lorem 1"; + +// Bundle two +"installationBundleSelectionPageBundleTwoTitle" = "Grundlagen"; +"installationBundleSelectionPageBundleTwoDescription" = "Schnell betriebsbereit mit den gängigsten IBM Tools"; +"installationBundleSelectionPageBundleTwoPopoverTitle" = "Grundlagenpaket"; +"installationBundleSelectionPageBundleTwoPopoverDescription" = "Die von den meisten Mitarbeitern verwendeten Apps"; +"installationBundleSelectionPageBundleTwoAppOneTitle" = "IBM Notes"; +"installationBundleSelectionPageBundleTwoAppOneDescription" = "IBM Mail senden und empfangen und mit Datenbanken interagieren"; +"installationBundleSelectionPageBundleTwoAppTwoTitle" = "Webex-Meetings"; +"installationBundleSelectionPageBundleTwoAppTwoDescription" = "Funktionalität für Video- und Audiokonferenzen sowie Web-Meetings miteinander kombinieren"; +"installationBundleSelectionPageBundleTwoAppThreeTitle" = "Code42 CrashPlan"; +"installationBundleSelectionPageBundleTwoAppThreeDescription" = "Sichere Sicherung und Wiederherstellung von Dateien auf Ihrem Mac"; +"installationBundleSelectionPageBundleTwoAppFourTitle" = "BluePages"; +"installationBundleSelectionPageBundleTwoAppFourDescription" = "Schnelle und bequeme Suchläufe im Mitarbeiterverzeichnis"; +"installationBundleSelectionPageBundleTwoAppFiveTitle" = "IBM Bookmarks"; +"installationBundleSelectionPageBundleTwoAppFiveDescription" = "Links zu gängigen IBM Websites"; + +// Bundle three +"installationBundleSelectionPageBundleThreeTitle" = "Produktivität"; +"installationBundleSelectionPageBundleThreeDescription" = "Steigern Sie Ihre Produktivität mit Textverarbeitung, Spreadsheets und mehr."; +"installationBundleSelectionPageBundleThreePopoverTitle" = "Produktivitätspaket"; +"installationBundleSelectionPageBundleThreePopoverDescription" = "Tools, um Sie bei Erstellung und Zusammenarbeit zu unterstützen."; +"installationBundleSelectionPageBundleThreeAppOneTitle" = "Office 365"; +"installationBundleSelectionPageBundleThreeAppOneDescription" = "Microsoft Word, Excel, PowerPoint, OneNote und Outlook"; +"installationBundleSelectionPageBundleThreeAppTwoTitle" = "Slack"; +"installationBundleSelectionPageBundleThreeAppTwoDescription" = "Kommunikation und Zusammenarbeit mit Teams bei IBM"; +"installationBundleSelectionPageBundleThreeAppThreeTitle" = "Box Drive"; +"installationBundleSelectionPageBundleThreeAppThreeDescription" = "Speicherung, gemeinsame Nutzung und Synchronisation von Dateien"; + +// MARK: - Installation: bundle installation page +"installationBundleInstallationPageTitle" = "Ausgewählte App-Pakete werden installiert …"; +"installationBundleInstallationPageSubtitle" = "Geschätzte verbleibende Zeit: "; +"installationBundleInstallationPageHideAppLabel" = "App ausblenden"; +"installationBundleInstallationPageShowAppLabel" = "App einblenden"; + +// MARK: - Installation: final page + +// Header +"installationFinalPageTitle" = "Erste Schritte mit Ihrem Mac"; + +// Elements +"installationFinalPageElementOneTitle" = "Rufen Sie Apps aus dem \nMac@IBM App Store ab"; +"installationFinalPageElementOneDescription" = "Microsoft Office, Slack, IBM Notes und mehr!"; +"installationFinalPageElementTwoTitle" = "Migrieren Sie Ihre Daten \nvon einem anderen Computer"; +"installationFinalPageElementTwoDescription" = "Übertragen Sie wichtige Informationen \nauf Ihren neuen Mac."; +"installationFinalPageElementThreeTitle" = "Sichern Sie Ihren Mac mit \nCode42 CrashPlan"; +"installationFinalPageElementThreeDescription" = "Installieren, ein Konto einrichten \nund entspannt arbeiten."; +"installationFinalPageElementThreeDescriptionAlternate" = "Ein Konto einrichten \nund entspannt arbeiten."; +"installationFinalPageElementFourTitle" = "Tipps, Lernprogramme und \nSupport in Help@IBM anzeigen"; +"installationFinalPageElementFourDescription" = "Profitieren Sie von IBM dedizierten Apple-Help-Desk-Beratern."; +"installationFinalPageElementFiveTitle" = "Sie arbeiten mit Notes? Installieren\nSie Ihre Notes-ID-Datei"; +"installationFinalPageElementFiveDescription" = "Installieren und richten Sie Notes als E-Mail-Client ein."; +"installationFinalPAgeElementSixTitle" = "Zur w3-Homepage"; +"installationFinalPageElementSixDescription" = "w3-Positionen und BluePages durchsuchen."; + +// Footer +"installationFinalPageFooterLabel" = " Erinnern Sie mich beim nächsten Neustart meines Mac."; + +// MARK: - Installation: Notes wizard page + +// Header +"filePickerPageTitle" = "Installieren Sie Ihre Notes-ID-Datei"; +"filePickerPageSubtitle" = "Ihre Notes-ID wird benötigt, um die Notes-Einrichtung abzuschließen. Sie können sie auch später hinzufügen."; + +// Messages +"filePickerPageMessageSuccess" = "Ihre Notes-ID wurde erfolgreich installiert!"; +"filePickerPageMessageFailure" = "Ihre Notes-ID-Datei konnte nicht installiert werden."; +"filePickerPageMessageAlreadyExist" = "Eine Notes-ID-Datei ist bereits vorhanden. Sie können eine neue installieren."; + +// Labels +"filePickerPageButtonBrowse" = "Notes-ID-Datei suchen"; +"filePickerPageButtonRemove" = "Entfernen"; +"filePickerPageCenterLabel" = "Notes-ID-Datei ziehen und ablegen"; +"filePickerPageAlertMessage" = "Datei ist bereits vorhanden"; +"filePickerPageAlertInformativeText" = "Die Datei ist am Ziel bereits vorhanden. Möchten Sie die bestehende Datei durch die ausgewählte Datei ersetzen?"; +"filePickerPageFileSelectionPanelTitle" = "Wählen Sie die ID-Datei aus, die Sie zur Konfiguration von Notes verwenden möchten"; +"filePickerPageButtonInstall" = "Notes-ID-Datei installieren"; + +// MARK: - Alert labels + +// Un-enrollment +"unenrollmentAlertTitle" = "Sind Sie sicher, dass Sie den Registrierungsprozess abbrechen möchten?"; +"unenrollmentAlertMessage" = "Wenn Sie jetzt abbrechen, werden alle Sicherheitseinstellungen aufgehoben und wird dieser Computer aus der Verwaltung entfernt."; +"unenrollmentCancelled" = "Aktion Framework entfernen wurde abgebrochen"; + +// Bundle selection +"bundleSelectionAlertTitle" = "Sind Sie sicher, dass Sie fortfahren möchten?"; +"bundleSelectionAlertMessage" = "Es sieht aus, als wäre die Netzgeschwindigkeit aktuell sehr langsam. Sie sollten weniger Pakete installieren."; + +// Bundle installation +"bundleInstallationalertMessage" = "Einige Anwendungen konnten nicht installiert werden – verwenden Sie Self-Service, um sie später zu installieren."; + +// Launch failure +"launchFailureAlertTitle" = "Für diese Anwendung ist Gerätemanagement erforderlich."; +"launchFailureAlertMessage" = "Bitte registrieren Sie dieses Gerät."; + +// External network problem +"externalNetworkAlertMessage" = "Sie sind nicht mit dem Internet verbunden. Stellen Sie sicher, dass Ihr Mac mit einem Netzwerk mit Internetzugang verbunden ist, bevor Sie fortfahren."; +"externalNetworkJspMessage" = "Self-Service ist derzeit nicht verfügbar. Bitte versuchen Sie es später noch einmal."; + +// Internal network problem +"internalNetworkProblemAlertMessage" = "\n\nSie müssen eine Intranetverbindung herstellen, um fortzufahren."; + +// Terms and conditions drop down +"termsAndConditionsTitle" = "IBM Vereinbarung zur Nutzung persönlicher Geräte"; +"termsAndConditionsBody" = "Sie haben sich dafür entschieden, dieses Gerät als „persönliches Eigentum“ zu registrieren. Die Verwendung eines eigenen Geräts zur Durchführung von IBM Geschäften unterliegt bestimmten Bestimmungen und Bedingungen.\n\nBitte lesen Sie die IBM Bedingungen und geben Sie an, ob Sie diese akzeptieren. "; +"termsAndConditionsButtonLink" = "IBM Bedingungen lesen"; +"termsAndConditionsButtonAccept" = "Akzeptieren"; + +// MARK: - Common button labels +"buttonLabelOk" = "OK"; +"buttonLabelCancel" = "Abbrechen"; +"buttonLabelNext" = "Weiter"; +"buttonLabelRestart" = "Erneut starten"; +"buttonLabelClose" = "Schließen"; +"buttonLabelBack" = "Zurück"; +"buttonLabelOkWithQuestionMark" = "Ok?"; +"buttonLabelQuit" = "Beenden"; +"buttonLabelReplace" = "Ersetzen"; +"buttonLabelUpdateInfo" = "Details bearbeiten"; +"buttonLabelUnenroll" = "Registrierung abbrechen"; + +// MARK: - Common labels +"labelEnabled" = "Aktiviert"; +"labelDisabled" = "Inaktiviert"; +"labelRequired" = "Erforderlich"; +"restartFailureMessage" = "Ihr Computer konnte nicht erneut gestartet werden"; +"restartFailureComment" = "Benachrichtigung über Fehler beim Neustart"; +"estimatedInstallTimeMessage" = "%@ \n \n Geschätzte Installationszeit: %@"; +"labelChooseAnswer" = "Antwort auswählen."; +"labelNo" = "Nein"; +"labelYes" = "Ja"; +"buttonLabelInstall" = "Ausgewählte Pakete installieren"; +"buttonLabelSkip" = "Überspringen"; diff --git a/enrollment/enrollment/en.lproj/Localizable.strings b/enrollment/enrollment/en.lproj/Localizable.strings new file mode 100644 index 0000000..ba9bbf3 --- /dev/null +++ b/enrollment/enrollment/en.lproj/Localizable.strings @@ -0,0 +1,252 @@ +/* + Localizable.strings + enrollment + + Created by Simone Martorelli on 2/5/20. + Copyright © 2020 IBM. All rights reserved. + SPDX-License-Identifier: GPL-3.0-only + */ + +/// MARK: - Note to the translation +/// +/// Pay attention to not modify, cancel or move the special characters: +/// - %d - This special character is substituted with a number at runtime; +/// - %@ - This special characted is substituted with a string at runtime; +/// - \n - This special characted works like the "return" key; +/// - \" - This special characted insert a "; + +// MARK: - Registration: page one + +// Header +"registrationPageOneTitleSimple" = "Welcome, new employee!"; +"registrationPageOneTitleComposed" = "Welcome, %@!"; +"registrationPageOneSubtitleSimple" = "Don't see your name?"; +"registrationPageOneSubtitleComposed" = "Not %@?"; + +// Info popovers +"registrationPageOneSubtitle_info" = "Don't worry, you can update this later by using the Mac@IBM App Store and searching for \"Assign User\"."; +"registrationPageOneDisclaimerPolicies_infoElementOne" = "Firewall"; +"registrationPageOneDisclaimerPolicies_infoElementTwo" = "Stealth Mode"; +"registrationPageOneDisclaimerPolicies_infoElementThree" = "Guest User Account"; +"registrationPageOneDisclaimerPolicies_infoElementFour" = "FileVault Disk Encryption"; +"registrationPageOneDisclaimerPolicies_infoElementFive" = "Initial macOS Password Change"; +"registrationPageOneDisclaimerPolicies_infoElementSix" = "ScreenSaver Password"; +"registrationPageOneDisclaimerPolicies_infoElementSeven_title" = "ScreenSaver Start Time"; +"registrationPageOneDisclaimerPolicies_infoElementSeven_description" = "30 minutes of inactivity"; +"registrationPageOneDisclaimerPolicies_infoElementEight_title" = "Endpoint Protection Software"; + +// Field labels +"registrationPageOneFieldRegion" = "Region"; +"registrationPageOneFieldComputer" = "Computer Type"; +"registrationPageOneFieldOwner" = "Asset Owner"; +"registrationPageOneFieldUser" = "User Type"; + +// Region field options +"registrationPageOneFieldRegionOptionOne" = "USA"; +"registrationPageOneFieldRegionOptionTwo" = "Canada"; +"registrationPageOneFieldRegionOptionThree" = "EMEA (Europe, Middle East, Africa)"; +"registrationPageOneFieldRegionOptionFour" = "LA (Latin America)"; +"registrationPageOneFieldRegionOptionFive" = "AP (Asia Pacific)"; + +// Computer Type options +"registrationPageOneFieldComputerOptionOne" = "Primary"; +"registrationPageOneFieldComputerOptionOne_info" = "for a single user as an office productivity platform for normal office work (e.g., email, web browsing/applications, instant messaging, documentation, etc.)"; +"registrationPageOneFieldComputerOptionTwo" = "Secondary"; +"registrationPageOneFieldComputerOptionTwo_info" = "for various tasks excluding office productivity activities including customer demo activities and Virtual Machines"; +"registrationPageOneFieldComputerOptionThree" = "Shared"; +"registrationPageOneFieldComputerOptionThree_info" = "used by multiple users for education and training"; +"registrationPageOneFieldComputerOptionFour" = "Loaner"; +"registrationPageOneFieldComputerOptionFour_info" = "for the purpose of testing and/or development"; +"registrationPageOneFieldComputerOptionFive" = "Classroom"; +"registrationPageOneFieldComputerOptionFive_info" = "used on a short term basis, as a replacement or supplement"; +"registrationPageOneFieldComputerOptionSix" = "Lab"; +"registrationPageOneFieldComputerOptionSix_info" = "for use by multiple users for various tasks including office productivity activities"; + +// Asset Owner options +"registrationPageOneFieldOwnerOptionOne" = "IBM Provided"; +"registrationPageOneFieldOwnerOptionTwo" = "Personally Owned"; +"registrationPageOneFieldOwnerOptionThree" = "3rd Party Owned: Vendor Provided"; +"registrationPageOneFieldOwnerOptionFour" = "3rd Party Owned: Contractor Agency Provided"; +"registrationPageOneFieldOwnerOptionFive" = "3rd Party Owned: Client Provided"; + +// User Type options +"registrationPageOneFieldUserOptionOne" = "Standard"; +"registrationPageOneFieldUserOptionOne_info" = "general use outside of duties performed by Privileged or Call Center use cases"; +"registrationPageOneFieldUserOptionTwo" = "Privileged"; +"registrationPageOneFieldUserOptionTwo_info" = "under assignment of security administrative authorities, system authorities on network devices, computer systems, middleware components or applications for IBM or clients"; +"registrationPageOneFieldUserOptionThree" = "Service / Call Center"; +"registrationPageOneFieldUserOptionThree_info" = "assigned to a Service Center, Call Center or Help Desk"; + +// Policies disclaimer +"registrationPageOneDisclaimerPolicies" = "IBM security policies will automatically be applied."; + +// MARK: - Registration: page two + +// Header +"registrationPageTwoTitle" = "Information you access"; +"registrationPageTwoSubtitle" = "Select the data type(s) stored on this computer."; + +// Information options +"registrationPageTwoFieldInformationOptionOne_title" = "Sensitive Personal Information (SPI)"; +"registrationPageTwoFieldInformationOptionOne_description" = "your device stores Personal Information (PI)"; +"registrationPageTwoFieldInformationOptionTwo_title" = "Client data"; +"registrationPageTwoFieldInformationOptionTwo_description" = "device stores or is used to access data owned or created by a client"; +"registrationPageTwoFieldInformationOptionThree_title" = "Government Regulated data"; +"registrationPageTwoFieldInformationOptionThree_description" = "you have been informed by your management, the owner of the data, or custodian of the data that the data stored or accessed by your device is subject to governmental restrictions or regulation, e.g., some health care data is subject to additional protections"; +"registrationPageTwoFieldInformationOptionFour_title" = "FFIEC (Federal Financial Institutions Examination Council) data"; +"registrationPageTwoFieldInformationOptionFour_description" = "you support or have access to client’s financial environments"; +"registrationPageTwoFieldInformationOptionFive_title" = "HIPAA (Health Insurance Portability and Accountability Act) data"; +"registrationPageTwoFieldInformationOptionFive_description" = "you support a HIPAA regulated client account or multi-tenant offering"; +"registrationPageTwoFieldInformationOptionSix_title" = "PCI data"; +"registrationPageTwoFieldInformationOptionSix_description" = "device stores or accesses sensitive payment card (e.g., credit card) data owned or created by a client"; +"registrationPageTwoFieldInformationOptionSeven_title" = "None of the above"; +"registrationPageTwoFieldInformationOptionSeven_description" = ""; + +// MARK: - Registration: loading page + +// State labels +"registrationLoadingPageStateOne" = "Testing network speed"; +"registrationLoadingPageStateTwo" = "Completing enrollment"; +"registrationLoadingPageStateForPhaseThree" = "Updating Registration"; + +// MARK: - Post registration page + +// Header +"postRegistrationPageTitle" = "Registration complete"; +"postRegistrationPageTitlePhaseThree" = "Registration Details"; +"postRegistrationPageTitlePhaseFour" = "Welcome!"; +"postRegistrationPageSubtitleStandard" = "Let's get your Mac set up!"; +"postRegistrationPageSubtitlePhaseThree" = ""; +"postRegistrationPageInstructionalMessage" = "After your next log in, you'll be prompted for a new macOS login password and to enable FileVault disk encryption."; +"postRegistrationPageCountdownMessage" = "Your Mac will be restarted automatically in %d seconds to continue the setup process or you can select \"Restart\" to continue now."; + +// MARK: - Installation: bundle selection page + +// Header +"installationBundleSelectionPageTitle" = "App bundles to get you started"; +"installationBundleSelectionPageSubtitle" = "Additional apps can be installed from the Mac@IBM App Store at any time."; + +// Labels +"installationBundleSelectionPageRecommended" = "(recommended)"; + +// Bundle one +"installationBundleSelectionPageBundleOneTitle" = "Connectivity"; +"installationBundleSelectionPageBundleOneDescription" = "Connect to IBM networks with the necessary software and certificates"; +"installationBundleSelectionPageBundleOnePopoverTitle" = "Connectivity bundle"; +"installationBundleSelectionPageBundleOnePopoverDescription" = "Get connected to our network with certificates and software"; +"installationBundleSelectionPageBundleOneAppOneTitle" = "AnyConnect"; +"installationBundleSelectionPageBundleOneAppOneDescription" = "Ipsum lorem 1"; + +// Bundle two +"installationBundleSelectionPageBundleTwoTitle" = "Essentials"; +"installationBundleSelectionPageBundleTwoDescription" = "Get up and running with the most common IBM tools."; +"installationBundleSelectionPageBundleTwoPopoverTitle" = "Essentials bundle"; +"installationBundleSelectionPageBundleTwoPopoverDescription" = "The apps used by most employees"; +"installationBundleSelectionPageBundleTwoAppOneTitle" = "IBM Notes"; +"installationBundleSelectionPageBundleTwoAppOneDescription" = "Send and receive IBM mail and interact with databases"; +"installationBundleSelectionPageBundleTwoAppTwoTitle" = "Webex Meetings"; +"installationBundleSelectionPageBundleTwoAppTwoDescription" = "Combine video and audio conference and web meeting capabilities"; +"installationBundleSelectionPageBundleTwoAppThreeTitle" = "Code42 CrashPlan"; +"installationBundleSelectionPageBundleTwoAppThreeDescription" = "Safely backup and restore files on your Mac"; +"installationBundleSelectionPageBundleTwoAppFourTitle" = "BluePages"; +"installationBundleSelectionPageBundleTwoAppFourDescription" = "Fast and convenient employee directory searches"; +"installationBundleSelectionPageBundleTwoAppFiveTitle" = "IBM Bookmarks"; +"installationBundleSelectionPageBundleTwoAppFiveDescription" = "Links to commonly used IBM websites"; + +// Bundle three +"installationBundleSelectionPageBundleThreeTitle" = "Productivity"; +"installationBundleSelectionPageBundleThreeDescription" = "Boost your productivity with word processing, spreadsheets and more."; +"installationBundleSelectionPageBundleThreePopoverTitle" = "Productivity bundle"; +"installationBundleSelectionPageBundleThreePopoverDescription" = "Tools to help you create and collaborate."; +"installationBundleSelectionPageBundleThreeAppOneTitle" = "Office 365"; +"installationBundleSelectionPageBundleThreeAppOneDescription" = "Microsoft Word, Excel, PowerPoint, OneNote and Outlook"; +"installationBundleSelectionPageBundleThreeAppTwoTitle" = "Slack"; +"installationBundleSelectionPageBundleThreeAppTwoDescription" = "Communicate and collaborate with teams across IBM"; +"installationBundleSelectionPageBundleThreeAppThreeTitle" = "Box Drive"; +"installationBundleSelectionPageBundleThreeAppThreeDescription" = "Store, Share and Syncronize files"; + +// MARK: - Installation: bundle installation page +"installationBundleInstallationPageTitle" = "Installing selected app bundles…"; +"installationBundleInstallationPageSubtitle" = "Estimated time remaining: "; +"installationBundleInstallationPageHideAppLabel" = "Hide App"; +"installationBundleInstallationPageShowAppLabel" = "Show App"; + +// MARK: - Post installation page + +// Header +"postInstallationPageTitle" = "Get started with your Mac"; + +// Elements +"postInstallationPageElementOneTitle" = "Get apps from the \nMac@IBM App Store"; +"postInstallationPageElementOneDescription" = "Microsoft Office, Slack, IBM Notes, and more!"; +"postInstallationPageElementTwoTitle" = "Migrate your data \nfrom another computer"; +"postInstallationPageElementTwoDescription" = "Transfer important information \nto your new Mac."; +"postInstallationPageElementThreeTitle" = "Back up your Mac with \nCode42 CrashPlan"; +"postInstallationPageElementThreeDescription" = "Install, set up an account,\nand enjoy peace of mind."; +"postInstallationPageElementThreeDescriptionAlternate" = "Set up an account,\nand enjoy peace of mind."; +"postInstallationPageElementFourTitle" = "View tips, tutorials and \nsupport on Help@IBM"; +"postInstallationPageElementFourDescription" = "Access IBM's dedicated Apple Help Desk advisors."; +"postInstallationPageElementFiveTitle" = "Use Notes? Install your \nNotes ID file"; +"postInstallationPageElementFiveDescription" = "Install and set up Notes as your email client."; +"postInstallationPageElementSixTitle" = "Go to w3 Homepage"; +"postInstallationPageElementSixDescription" = "Search w3 places and BluePages"; + +// Footer +"postInstallationPageFooterLabel" = " Remind me the next time I restart my Mac."; + +// MARK: - Alert labels + +// Un-enrollment +"unenrollmentAlertTitle" = "Are you sure you want to quit the enrollment process?"; +"unenrollmentAlertMessage" = "Cancelling now will undo all security settings and remove this computer from the management."; +"unenrollmentCancelled" = "Remove Framework action cancelled"; + +// Bundle selection +"bundleSelectionAlertTitle" = "Are you sure you want to proceed?"; +"bundleSelectionAlertMessage" = "It looks like your network speeds are slow at this time. We recommend installing fewer bundles."; + +// Bundle installation +"bundleInstallationalertMessage" = "We had trouble installing some applications - use Self Service to install them later."; + +// Launch failure +"launchFailureAlertTitle" = "This application requires device management."; +"launchFailureAlertMessage" = "Please enroll this device."; + +// External network problem +"externalNetworkAlertMessage" = "You are not connected to the Internet. Please make sure that your Mac is connected to a network with Internet access before continuing."; +"externalNetworkJspMessage" = "Self Service is not available at this time. Please try again later."; + +// Internal network problem +"internalNetworkProblemAlertMessage" = "\n\nYou must connect to the intranet to proceed."; + +// Terms and conditions drop down +"termsAndConditionsTitle" = "IBM Agreement for Personal Device Usage"; +"termsAndConditionsBody" = "You have chosen to register this device as “personally owned”. The use of a personally owned device to conduct IBM Business is governed by certain terms and conditions.\n\nPlease review the IBM terms and conditions and indicate whether you accept them."; +"termsAndConditionsButtonLink" = "Read IBM Terms and Conditions"; +"termsAndConditionsButtonAccept" = "Accept"; + +// MARK: - Common button labels +"buttonLabelOk" = "OK"; +"buttonLabelCancel" = "Cancel"; +"buttonLabelNext" = "Next"; +"buttonLabelRestart" = "Restart"; +"buttonLabelClose" = "Close"; +"buttonLabelBack" = "Back"; +"buttonLabelOkWithQuestionMark" = "Ok?"; +"buttonLabelQuit" = "Quit"; +"buttonLabelReplace" = "Replace"; +"buttonLabelUpdateInfo" = "Edit Details"; +"buttonLabelUnenroll" = "Cancel Enrollment"; + +// MARK: - Common labels +"labelEnabled" = "Enabled"; +"labelDisabled" = "Disabled"; +"labelRequired" = "Required"; +"restartFailureMessage" = "Your computer could not be restarted"; +"restartFailureComment" = "Restart failure alert"; +"estimatedInstallTimeMessage" = "%@ \n \n Estimated install time: %@"; +"labelChooseAnswer" = "Choose your answer."; +"labelNo" = "No"; +"labelYes" = "Yes"; +"buttonLabelInstall" = "Install Selected Bundles"; +"buttonLabelSkip" = "Skip"; diff --git a/enrollment/enrollment/es.lproj/Localizable.strings b/enrollment/enrollment/es.lproj/Localizable.strings new file mode 100644 index 0000000..ebf38c7 --- /dev/null +++ b/enrollment/enrollment/es.lproj/Localizable.strings @@ -0,0 +1,272 @@ +/* + Localizable.strings + enrollment + + Created by Simone Martorelli on 2/5/20. + Copyright © 2020 IBM. All rights reserved. + SPDX-License-Identifier: GPL-3.0-only + */ + +/// MARK: - Note to the translation +/// +/// Pay attention to not modify, cancel or move the special characters: +/// - %d - This special character is substituted with a number at runtime; +/// - %@ - This special characted is substituted with a string at runtime; +/// - \n - This special characted works like the "return" key; +/// - \" - This special characted insert a "; + +// MARK: - Registration: page one + +// Header +"registrationPageOneTitleSimple" = "¡Bienvenido, nuevo empleado!"; +"registrationPageOneTitleComposed" = "¡Bienvenido, %@!"; +"registrationPageOneSubtitleSimple" = "¿No ve su nombre?"; +"registrationPageOneSubtitleComposed" = "¿No aparece %@?"; + +// Info popovers +"registrationPageOneSubtitle_info" = "No se preocupe, puede actualizarlo más adelante utilizando la App Store de Mac@IBM mediante la búsqueda de \"Asignar usuario\"."; +"registrationPageOneDisclaimerPolicies_infoElementOne" = "Cortafuegos"; +"registrationPageOneDisclaimerPolicies_infoElementTwo" = "Modo Stealth"; +"registrationPageOneDisclaimerPolicies_infoElementThree" = "Cuando de usuario invitado"; +"registrationPageOneDisclaimerPolicies_infoElementFour" = "Cifrado de disco de FileVault"; +"registrationPageOneDisclaimerPolicies_infoElementFive" = "Cambio de contraseña de macOS inicial"; +"registrationPageOneDisclaimerPolicies_infoElementSix" = "Contraseña de protector de pantalla"; +"registrationPageOneDisclaimerPolicies_infoElementSeven_title" = "Hora de inicio de protector de pantalla"; +"registrationPageOneDisclaimerPolicies_infoElementSeven_description" = "30 minutos de inactividad"; +"registrationPageOneDisclaimerPolicies_infoElementEight_title" = "Software de protección de punto final"; + +// Field labels +"registrationPageOneFieldRegion" = "Región"; +"registrationPageOneFieldComputer" = "Tipo de sistema"; +"registrationPageOneFieldOwner" = "Propietario de activo"; +"registrationPageOneFieldUser" = "Tipo de usuario"; + +// Region field options +"registrationPageOneFieldRegionOptionOne" = "EE.UU."; +"registrationPageOneFieldRegionOptionTwo" = "Canadá"; +"registrationPageOneFieldRegionOptionThree" = "EMEA (Europa, Oriente Medio y África)"; +"registrationPageOneFieldRegionOptionFour" = "LA (Latinoamérica)"; +"registrationPageOneFieldRegionOptionFive" = "AP (Asia Pacífico)"; + +// Computer Type options +"registrationPageOneFieldComputerOptionOne" = "Primario"; +"registrationPageOneFieldComputerOptionOne_info" = "para un usuario individual como una plataforma de productividad de oficina para el trabajo normal de oficina (por ejemplo, correo electrónico, aplicaciones/navegador web, mensajería instantánea, documentación, etc.)"; +"registrationPageOneFieldComputerOptionTwo" = "Secundario"; +"registrationPageOneFieldComputerOptionTwo_info" = "para varias tareas, excepto las actividades de productividad de oficina, que incluyen las actividades de demo de cliente y las máquinas virtuales"; +"registrationPageOneFieldComputerOptionThree" = "Compartido"; +"registrationPageOneFieldComputerOptionThree_info" = "utilizado por varios usuarios para fines de formación y entrenamiento"; +"registrationPageOneFieldComputerOptionFour" = "Préstamo"; +"registrationPageOneFieldComputerOptionFour_info" = "para fines de prueba y/o desarrollo"; +"registrationPageOneFieldComputerOptionFive" = "Clase"; +"registrationPageOneFieldComputerOptionFive_info" = "utilizado a corto plazo, como sustitución o suplemento"; +"registrationPageOneFieldComputerOptionSix" = "Laboratorio"; +"registrationPageOneFieldComputerOptionSix_info" = "utilizado por varios usuarios para distintas tareas como, por ejemplo, actividades de productividad de oficina"; + +// Asset Owner options +"registrationPageOneFieldOwnerOptionOne" = "Proporcionado por IBM"; +"registrationPageOneFieldOwnerOptionTwo" = "Propiedad personal"; +"registrationPageOneFieldOwnerOptionThree" = "Propiedad de terceros: proporcionado por el proveedor"; +"registrationPageOneFieldOwnerOptionFour" = "Propiedad de terceros: proporcionado por el contratista"; +"registrationPageOneFieldOwnerOptionFive" = "Propiedad de terceros: proporcionado por el cliente"; + +// User Type options +"registrationPageOneFieldUserOptionOne" = "Estándar"; +"registrationPageOneFieldUserOptionOne_info" = "uso general aparte de las funciones desempeñadas por los casos de uso Privilegiado y de Centro de atención telefónica"; +"registrationPageOneFieldUserOptionTwo" = "Privilegiado"; +"registrationPageOneFieldUserOptionTwo_info" = "en virtud de la asignación de autoridades administrativas de seguridad, autoridades del sistema en dispositivos de red, sistemas, componentes de middleware o aplicaciones para IBM o clientes"; +"registrationPageOneFieldUserOptionThree" = "Centro de atención telefónica/servicio"; +"registrationPageOneFieldUserOptionThree_info" = "asignado a un Centro de servicio, un Centro de atención telefónica o un Centro de atención al cliente"; + +// Policies disclaimer +"registrationPageOneDisclaimerPolicies" = "Las políticas de seguridad de IBM se aplicarán automáticamente."; + +// MARK: - Registration: page two + +// Header +"registrationPageTwoTitle" = "Información a la que accede"; +"registrationPageTwoSubtitle" = "Seleccione los tipos de datos almacenados en este sistema."; + +// Information options +"registrationPageTwoFieldInformationOptionOne_title" = "Información personal sensible (SPI)"; +"registrationPageTwoFieldInformationOptionOne_description" = "su dispositivo almacena Información personal (PI)"; +"registrationPageTwoFieldInformationOptionTwo_title" = "Datos de cliente"; +"registrationPageTwoFieldInformationOptionTwo_description" = "el dispositivo almacena o se utiliza para acceder a datos propiedad de un cliente o creados por él"; +"registrationPageTwoFieldInformationOptionThree_title" = "Datos regulados por el gobierno"; +"registrationPageTwoFieldInformationOptionThree_description" = "ha sido informado por su director, el propietario de los datos o el vigilante de los datos de que los datos almacenados o accedidos por el dispositivo están sujetos a normativas o restricciones gubernamentales, por ejemplo, algunos datos de asistencia médica están sujetos a protecciones adicionales"; +"registrationPageTwoFieldInformationOptionFour_title" = "Datos de FFIEC (Federal Financial Institutions Examination Council)"; +"registrationPageTwoFieldInformationOptionFour_description" = "da soporte o tiene acceso a entornos financieros del cliente"; +"registrationPageTwoFieldInformationOptionFive_title" = "Datos de HIPAA (Health Insurance Portability and Accountability Act)"; +"registrationPageTwoFieldInformationOptionFive_description" = "da soporte a una oferta de varios arrendatarios o una cuente de cliente regulada por HIPAA"; +"registrationPageTwoFieldInformationOptionSix_title" = "Datos de PCI"; +"registrationPageTwoFieldInformationOptionSix_description" = "el dispositivo almacena o accede a datos de una tarjeta de pago sensible (por ejemplo, una tarjeta de crédito) propiedad o creados por un cliente"; +"registrationPageTwoFieldInformationOptionSeven_title" = "Ninguno de los anteriores"; +"registrationPageTwoFieldInformationOptionSeven_description" = ""; + +// MARK: - Registration: loading page + +// State labels +"registrationLoadingPageStateOne" = "Probando velocidad de red"; +"registrationLoadingPageStateTwo" = "Finalizando inscripción"; +"registrationLoadingPageStateForPhaseThree" = "Actualizando registro"; + +// MARK: - Registration: final page + +// Header +"registrationFinalPageTitle" = "Registro completo"; +"registrationFinalPageTitlePhaseThree" = "Detalles de registro"; +"registrationFinalPageTitlePhaseFour" = "¡Bienvenidos!"; +"registrationFinalPageSubtitleStandard" = "¡Vamos a configurar su Mac!"; +"registrationFinalPageSubtitlePhaseThree" = ""; +"registrationFinalPageInstructionalMessage" = "Después del siguiente inicio de sesión, se le solicitará una nueva contraseña de inicio de sesión de macOS y que active el cifrado de disco de FileVault."; +"registrationFinalPageCountdownMessage" = "El sistema Mac se reiniciará automáticamente en %d segundos para continuar el proceso de configuración, o bien puede seleccionar \"Reiniciar\" para continuar ahora."; + +// MARK: - Installation: bundle selection page + +// Header +"installationBundleSelectionPageTitle" = "Paquete de aplicaciones para empezar"; +"installationBundleSelectionPageSubtitle" = "Pueden instalarse aplicaciones adicionales desde la App Store de Mac@IBM en cualquier momento."; + +// Labels +"installationBundleSelectionPageRecommended" = "(recomendado)"; + +// Bundle one +"installationBundleSelectionPageBundleOneTitle" = "Conectividad"; +"installationBundleSelectionPageBundleOneDescription" = "Conectarse a redes de IBM con el software y los certificados necesarios"; +"installationBundleSelectionPageBundleOnePopoverTitle" = "Paquete de conectividad"; +"installationBundleSelectionPageBundleOnePopoverDescription" = "Conéctese a su red con el software y los certificados"; +"installationBundleSelectionPageBundleOneAppOneTitle" = "AnyConnect"; +"installationBundleSelectionPageBundleOneAppOneDescription" = "Ipsum lorem 1"; + +// Bundle two +"installationBundleSelectionPageBundleTwoTitle" = "Elementos básicos"; +"installationBundleSelectionPageBundleTwoDescription" = "Póngase en marcha utilizando las herramientas de IBM más comunes."; +"installationBundleSelectionPageBundleTwoPopoverTitle" = "Paquete de elementos básicos"; +"installationBundleSelectionPageBundleTwoPopoverDescription" = "Las aplicaciones utilizadas por la mayoría de empleados"; +"installationBundleSelectionPageBundleTwoAppOneTitle" = "IBM Notes"; +"installationBundleSelectionPageBundleTwoAppOneDescription" = "Enviar y recibir correo de IBM e interactuar con las bases de datos"; +"installationBundleSelectionPageBundleTwoAppTwoTitle" = "Webex Meetings"; +"installationBundleSelectionPageBundleTwoAppTwoDescription" = "Combinar prestaciones de videoconferencia, audioconferencias y web meeting"; +"installationBundleSelectionPageBundleTwoAppThreeTitle" = "Code42 CrashPlan"; +"installationBundleSelectionPageBundleTwoAppThreeDescription" = "Realizar copias de seguridad y restauraciones seguras de archivos en el Mac"; +"installationBundleSelectionPageBundleTwoAppFourTitle" = "BluePages"; +"installationBundleSelectionPageBundleTwoAppFourDescription" = "Búsquedas en directorios de empleados rápidas y sencillas"; +"installationBundleSelectionPageBundleTwoAppFiveTitle" = "IBM Bookmarks"; +"installationBundleSelectionPageBundleTwoAppFiveDescription" = "Enlaces a los sitios web de IBM más utilizados"; + +// Bundle three +"installationBundleSelectionPageBundleThreeTitle" = "Productividad"; +"installationBundleSelectionPageBundleThreeDescription" = "Aumente su productividad con el tratamiento de texto, las hojas de cálculo, etc."; +"installationBundleSelectionPageBundleThreePopoverTitle" = "Paquete de productividad"; +"installationBundleSelectionPageBundleThreePopoverDescription" = "Herramientas para ayudarle a crear y colaborar."; +"installationBundleSelectionPageBundleThreeAppOneTitle" = "Office 365"; +"installationBundleSelectionPageBundleThreeAppOneDescription" = "Microsoft Word, Excel, PowerPoint, OneNote y Outlook"; +"installationBundleSelectionPageBundleThreeAppTwoTitle" = "Slack"; +"installationBundleSelectionPageBundleThreeAppTwoDescription" = "Comunicarse y colaborar con equipos en IBM"; +"installationBundleSelectionPageBundleThreeAppThreeTitle" = "Box Drive"; +"installationBundleSelectionPageBundleThreeAppThreeDescription" = "Almacenar, compartir y sincronizar archivos"; + +// MARK: - Installation: bundle installation page +"installationBundleInstallationPageTitle" = "Instalando el paquete de aplicaciones seleccionado…"; +"installationBundleInstallationPageSubtitle" = "Tiempo restante estimado:"; +"installationBundleInstallationPageHideAppLabel" = "Ocultar aplicación"; +"installationBundleInstallationPageShowAppLabel" = "Mostrar aplicación"; + +// MARK: - Installation: final page + +// Header +"installationFinalPageTitle" = "Cómo empezar con el Mac"; + +// Elements +"installationFinalPageElementOneTitle" = "Obtenga aplicaciones de\nla App Store de Mac@IBM"; +"installationFinalPageElementOneDescription" = "¡Microsoft Office, Slack, IBM Notes y mucho más!"; +"installationFinalPageElementTwoTitle" = "Migre sus datos\ndesde otro sistema"; +"installationFinalPageElementTwoDescription" = "Transfiera la información importante\na su nuevo Mac."; +"installationFinalPageElementThreeTitle" = "Haga una copia de seguridad de\nsu Mac con Code42 CrashPlan"; +"installationFinalPageElementThreeDescription" = "Instale, configure una cuenta\ny disfrute de la tranquilidad."; +"installationFinalPageElementThreeDescriptionAlternate" = "Configure una cuenta\ny disfrute de la tranquilidad."; +"installationFinalPageElementFourTitle" = "Vea las sugerencias, las guías de\naprendizaje y el soporte en Help@IBM"; +"installationFinalPageElementFourDescription" = "Póngase en contacto con los asesores del Centro de atención al cliente de Apple dedicado de IBM."; +"installationFinalPageElementFiveTitle" = "¿Utiliza Notes? Instale su\narchivo de ID de Notes"; +"installationFinalPageElementFiveDescription" = "Instale y configure Notes como su cliente de correo electrónico."; +"installationFinalPAgeElementSixTitle" = "Vaya a la página inicial w3"; +"installationFinalPageElementSixDescription" = "Busque sitios w3 y BluePages"; + +// Footer +"installationFinalPageFooterLabel" = " Recordarme la próxima vez que reinicie mi Mac."; + +// MARK: - Installation: Notes wizard page + +// Header +"filePickerPageTitle" = "Instale su archivo de ID de Notes"; +"filePickerPageSubtitle" = "El ID de Notes es necesario para completar la configuración de Notes. También puede añadirlo más adelante."; + +// Messages +"filePickerPageMessageSuccess" = "¡Su ID de Notes se ha instalado correctamente!"; +"filePickerPageMessageFailure" = "No hemos podido instalar su archivo de ID de Notes."; +"filePickerPageMessageAlreadyExist" = "Ya existe un archivo de ID de Notes. Puede instalar otro nuevo."; + +// Labels +"filePickerPageButtonBrowse" = "Examine su archivo de ID de Notes"; +"filePickerPageButtonRemove" = "Eliminar"; +"filePickerPageCenterLabel" = "Arrastre y suelte su archivo de ID de Notes"; +"filePickerPageAlertMessage" = "El archivo ya existe"; +"filePickerPageAlertInformativeText" = "El archivo ya existe en el destino. ¿Desea sustituir el archivo existente por el archivo que ha seleccionado?"; +"filePickerPageFileSelectionPanelTitle" = "Seleccione el archivo de ID que desee utilizar para configurar Notes"; +"filePickerPageButtonInstall" = "Instalar archivo de ID de Notes"; + +// MARK: - Alert labels + +// Un-enrollment +"unenrollmentAlertTitle" = "¿Está seguro de que desea abandonar el proceso de inscripción?"; +"unenrollmentAlertMessage" = "Si cancela ahora, se deshará toda la configuración de seguridad y se eliminará este sistema de la administración."; +"unenrollmentCancelled" = "La acción de Eliminar infraestructura se ha cancelado"; + +// Bundle selection +"bundleSelectionAlertTitle" = "¿Está seguro de que desea continuar?"; +"bundleSelectionAlertMessage" = "Parece que sus velocidades de red son lentas actualmente. Se recomienda instalar menos paquetes."; + +// Bundle installation +"bundleInstallationalertMessage" = "Hemos tenido problemas para instalar algunas aplicaciones; utilice el Autoservicio para instalarlas más adelante."; + +// Launch failure +"launchFailureAlertTitle" = "Esta aplicación requiere la gestión de dispositivos."; +"launchFailureAlertMessage" = "Inscriba este dispositivo."; + +// External network problem +"externalNetworkAlertMessage" = "No está conectado a Internet. Asegúrese de que su Mac esté conectado a una red con acceso a Internet antes de continuar."; +"externalNetworkJspMessage" = "El Autoservicio no está disponible en estos momentos. Inténtelo de nuevo más adelante."; + +// Internal network problem +"internalNetworkProblemAlertMessage" = "\n\nDebe estar conectado a la intranet para poder continuar."; + +// Terms and conditions drop down +"termsAndConditionsTitle" = "Acuerdo de IBM para el Uso de Dispositivos Personales"; +"termsAndConditionsBody" = "Ha elegido registrar este dispositivo como \"propiedad personal\". El uso de un dispositivo de propiedad personal para llevar a cabo negocios de IBM se rige por ciertos términos y condiciones.\n\nRevise los términos y condiciones de IBM e indique si los acepta."; +"termsAndConditionsButtonLink" = "Lea los Términos y Condiciones de IBM"; +"termsAndConditionsButtonAccept" = "Aceptar"; + +// MARK: - Common button labels +"buttonLabelOk" = "Aceptar"; +"buttonLabelCancel" = "Cancelar"; +"buttonLabelNext" = "Siguiente"; +"buttonLabelRestart" = "Reiniciar"; +"buttonLabelClose" = "Cerrar"; +"buttonLabelBack" = "Atrás"; +"buttonLabelOkWithQuestionMark" = "¿Correcto?"; +"buttonLabelQuit" = "Abandonar"; +"buttonLabelReplace" = "Sustituir"; +"buttonLabelUpdateInfo" = "Editar detalles"; +"buttonLabelUnenroll" = "Cancelar inscripción"; + +// MARK: - Common labels +"labelEnabled" = "Activado"; +"labelDisabled" = "Desactivado"; +"labelRequired" = "Necesario"; +"restartFailureMessage" = "Su sistema no se ha podido reiniciar"; +"restartFailureComment" = "Alerta de error de reinicio"; +"estimatedInstallTimeMessage" = "%@ \n \n Tiempo de instalación estimado: %@"; +"labelChooseAnswer" = "Elija su respuesta."; +"labelNo" = "No"; +"labelYes" = "Sí"; +"buttonLabelInstall" = "Instalar paquetes seleccionados"; +"buttonLabelSkip" = "Omitir"; diff --git a/enrollment/enrollment/fr-CA.lproj/Localizable.strings b/enrollment/enrollment/fr-CA.lproj/Localizable.strings new file mode 100644 index 0000000..f1eb806 --- /dev/null +++ b/enrollment/enrollment/fr-CA.lproj/Localizable.strings @@ -0,0 +1,272 @@ +/* + Localizable.strings + enrollment + + Created by Simone Martorelli on 2/5/20. + Copyright © 2020 IBM. All rights reserved. + SPDX-License-Identifier: GPL-3.0-only + */ + +/// MARK: - Note to the translation +/// +/// Pay attention to not modify, cancel or move the special characters: +/// - %d - This special character is substituted with a number at runtime; +/// - %@ - This special characted is substituted with a string at runtime; +/// - \n - This special characted works like the "return" key; +/// - \" - This special characted insert a "; + +// MARK: - Registration: page one + +// Header +"registrationPageOneTitleSimple" = "Bienvenue parmi nous!"; +"registrationPageOneTitleComposed" = "Bienvenue, %@ !"; +"registrationPageOneSubtitleSimple" = "Vous ne voyez pas votre nom?"; +"registrationPageOneSubtitleComposed" = "Vous ne vous appelez pas %@?"; + +// Info popovers +"registrationPageOneSubtitle_info" = "Ne vous inquiétez pas, vous pourrez mettre cette information à jour plus tard en utilisant Mac@IBM App Store et en recherchant \"Assign User\"."; +"registrationPageOneDisclaimerPolicies_infoElementOne" = "Pare-feu"; +"registrationPageOneDisclaimerPolicies_infoElementTwo" = "Mode secret"; +"registrationPageOneDisclaimerPolicies_infoElementThree" = "Compte utilisateur invité"; +"registrationPageOneDisclaimerPolicies_infoElementFour" = "Chiffrement de disque avec FileVault"; +"registrationPageOneDisclaimerPolicies_infoElementFive" = "Changement du mot de passe macOS initial"; +"registrationPageOneDisclaimerPolicies_infoElementSix" = "Mot de passe de l’écran de veille"; +"registrationPageOneDisclaimerPolicies_infoElementSeven_title" = "Délai d’activation de l’écran de veille"; +"registrationPageOneDisclaimerPolicies_infoElementSeven_description" = "30 minutes d’inactivité"; +"registrationPageOneDisclaimerPolicies_infoElementEight_title" = "Logiciel de protection des points d'extrémité"; + +// Field labels +"registrationPageOneFieldRegion" = "Région"; +"registrationPageOneFieldComputer" = "Type d’ordinateur"; +"registrationPageOneFieldOwner" = "Propriétaire de l’équipement"; +"registrationPageOneFieldUser" = "Type d’utilisateur"; + +// Region field options +"registrationPageOneFieldRegionOptionOne" = "États-Unis"; +"registrationPageOneFieldRegionOptionTwo" = "Canada"; +"registrationPageOneFieldRegionOptionThree" = "EMOA (Europe, Moyen-Orient, Afrique)"; +"registrationPageOneFieldRegionOptionFour" = "AL (Amérique latine)"; +"registrationPageOneFieldRegionOptionFive" = "AP (Asie-Pacifique)"; + +// Computer Type options +"registrationPageOneFieldComputerOptionOne" = "Principal"; +"registrationPageOneFieldComputerOptionOne_info" = "pour un seul utilisateur en tant que plateforme de productivité pour l’exécution des tâches bureautiques courantes (par ex., courrier électronique, applications/navigateur Web, messagerie instantanée, documentation, etc.)"; +"registrationPageOneFieldComputerOptionTwo" = "Secondaire"; +"registrationPageOneFieldComputerOptionTwo_info" = "pour des tâches autres que la bureautique, y compris les tâches liées aux démonstrations destinées aux clients et les machines virtuelles"; +"registrationPageOneFieldComputerOptionThree" = "Partagé"; +"registrationPageOneFieldComputerOptionThree_info" = "utilisé par plusieurs personnes aux fins d’enseignement et de formation"; +"registrationPageOneFieldComputerOptionFour" = "Prêté"; +"registrationPageOneFieldComputerOptionFour_info" = "aux fins de test et/ou de développement"; +"registrationPageOneFieldComputerOptionFive" = "Classe"; +"registrationPageOneFieldComputerOptionFive_info" = "utilisation à court terme, en remplacement ou en complément"; +"registrationPageOneFieldComputerOptionSix" = "Laboratoire"; +"registrationPageOneFieldComputerOptionSix_info" = "utilisé par plusieurs personnes pour différentes tâches, y compris des tâches bureautiques"; + +// Asset Owner options +"registrationPageOneFieldOwnerOptionOne" = "Fourni par IBM"; +"registrationPageOneFieldOwnerOptionTwo" = "Équipement personnel"; +"registrationPageOneFieldOwnerOptionThree" = "Propriété d’un tiers : fourni par un fournisseur"; +"registrationPageOneFieldOwnerOptionFour" = "Propriété d’un tiers : fourni par une agence de sous-traitance"; +"registrationPageOneFieldOwnerOptionFive" = "Propriété d’un tiers : fourni par un client"; + +// User Type options +"registrationPageOneFieldUserOptionOne" = "Standard"; +"registrationPageOneFieldUserOptionOne_info" = "utilisation générale, à l’exclusion des tâches effectuées par les utilisateurs de type Privilégié ou Centre d’appels"; +"registrationPageOneFieldUserOptionTwo" = "Privilégié"; +"registrationPageOneFieldUserOptionTwo_info" = "utilisé par un détenteur de droits d’administration de la sécurité ou de droits système sur des équipements réseau, des systèmes informatiques, des composants intergiciels ou des applications pour IBM ou ses clients"; +"registrationPageOneFieldUserOptionThree" = "Centre d’appels ou de service"; +"registrationPageOneFieldUserOptionThree_info" = "utilisé dans un centre de service, d’appels ou d’assistance"; + +// Policies disclaimer +"registrationPageOneDisclaimerPolicies" = "Les règles de sécurité IBM seront automatiquement appliquées."; + +// MARK: - Registration: page two + +// Header +"registrationPageTwoTitle" = "Informations auxquelles vous avez accès"; +"registrationPageTwoSubtitle" = "Sélectionnez les types de données présents sur cet ordinateur."; + +// Information options +"registrationPageTwoFieldInformationOptionOne_title" = "Renseignements personnels sensibles (SPI)"; +"registrationPageTwoFieldInformationOptionOne_description" = "votre équipement contient des renseignements personnels"; +"registrationPageTwoFieldInformationOptionTwo_title" = "Données de clients"; +"registrationPageTwoFieldInformationOptionTwo_description" = "votre équipement contient des données appartenant à (ou créées par) un client ou sert à y accéder"; +"registrationPageTwoFieldInformationOptionThree_title" = "Données réglementées"; +"registrationPageTwoFieldInformationOptionThree_description" = "vous avez été informé par votre hiérarchie ou par le propriétaire ou le dépositaire des données que les données que votre ordinateur contient (ou auxquelles il accède) sont soumises à des restrictions ou à une réglementation gouvernementales; par exemple, certaines données de santé font l’objet d’une protection supplémentaire"; +"registrationPageTwoFieldInformationOptionFour_title" = "Données FFIEC (Federal Financial Institutions Examination Council)"; +"registrationPageTwoFieldInformationOptionFour_description" = "vous prenez en charge des environnements financiers de clients ou vous y accédez"; +"registrationPageTwoFieldInformationOptionFive_title" = "Données HIPAA (Health Insurance Portability and Accountability Act)"; +"registrationPageTwoFieldInformationOptionFive_description" = "vous prenez en charge un compte client ou une offre à service partagé réglementé(e) par la loi HIPAA"; +"registrationPageTwoFieldInformationOptionSix_title" = "Données de carte de paiement (PCI)"; +"registrationPageTwoFieldInformationOptionSix_description" = "votre équipement contient des données de carte de paiement sensibles (p. ex., carte de crédit) appartenant à (ou créées par) un client, ou y a accès "; +"registrationPageTwoFieldInformationOptionSeven_title" = "Aucun des types de données ci-dessus"; +"registrationPageTwoFieldInformationOptionSeven_description" = ""; + +// MARK: - Registration: loading page + +// State labels +"registrationLoadingPageStateOne" = "Test de la vitesse du réseau en cours"; +"registrationLoadingPageStateTwo" = "Inscription en cours"; +"registrationLoadingPageStateForPhaseThree" = "Mise à jour de l’inscription en cours"; + +// MARK: - Registration: final page + +// Header +"registrationFinalPageTitle" = "Inscription terminée"; +"registrationFinalPageTitlePhaseThree" = "Détails de l’inscription"; +"registrationFinalPageTitlePhaseFour" = "Bienvenue!"; +"registrationFinalPageSubtitleStandard" = "Configurons votre Mac!"; +"registrationFinalPageSubtitlePhaseThree" = ""; +"registrationFinalPageInstructionalMessage" = "Lors de votre prochaine ouverture de session, vous devrez entrer un nouveau mot de passe de connexion à macOS et activer le chiffrement de disque FileVault."; +"registrationFinalPageCountdownMessage" = "Votre Mac redémarrera automatiquement dans %d secondes pour poursuivre le processus de configuration. Vous pouvez aussi sélectionner \"Redémarrer\" pour poursuivre ce processus dès maintenant."; + +// MARK: - Installation: bundle selection page + +// Header +"installationBundleSelectionPageTitle" = "Groupes d’applications pour vous permettre de commencer à travailler"; +"installationBundleSelectionPageSubtitle" = "Vous pouvez à tout moment installer des applications supplémentaires à partir de Mac@IBM App Store."; + +// Labels +"installationBundleSelectionPageRecommended" = "(recommandé)"; + +// Bundle one +"installationBundleSelectionPageBundleOneTitle" = "Connectivité"; +"installationBundleSelectionPageBundleOneDescription" = "Pour vous connecter aux réseaux IBM, vous avez besoin de logiciels et de certificats."; +"installationBundleSelectionPageBundleOnePopoverTitle" = "Groupe de connectivité"; +"installationBundleSelectionPageBundleOnePopoverDescription" = "Connectez-vous à notre réseau avec les certificats et les logiciels appropriés"; +"installationBundleSelectionPageBundleOneAppOneTitle" = "AnyConnect"; +"installationBundleSelectionPageBundleOneAppOneDescription" = "Ipsum lorem 1"; + +// Bundle two +"installationBundleSelectionPageBundleTwoTitle" = "Outils indispensables"; +"installationBundleSelectionPageBundleTwoDescription" = "Commencez à utiliser les outils IBM les plus courants."; +"installationBundleSelectionPageBundleTwoPopoverTitle" = "Groupe d'outils indispensables"; +"installationBundleSelectionPageBundleTwoPopoverDescription" = "Applications utilisées par la plupart des employés"; +"installationBundleSelectionPageBundleTwoAppOneTitle" = "IBM Notes"; +"installationBundleSelectionPageBundleTwoAppOneDescription" = "Envoyez et recevez des courriels IBM et interagissez avec des bases de données"; +"installationBundleSelectionPageBundleTwoAppTwoTitle" = "Webex Meetings"; +"installationBundleSelectionPageBundleTwoAppTwoDescription" = "Combinez des fonctionnalités de visioconférence, d’audioconférence et de réunion Web"; +"installationBundleSelectionPageBundleTwoAppThreeTitle" = "Code42 CrashPlan"; +"installationBundleSelectionPageBundleTwoAppThreeDescription" = "Sauvegardez et restaurez en toute sécurité les fichiers de votre Mac"; +"installationBundleSelectionPageBundleTwoAppFourTitle" = "BluePages"; +"installationBundleSelectionPageBundleTwoAppFourDescription" = "Recherches rapides et pratiques dans l’annuaire des employés"; +"installationBundleSelectionPageBundleTwoAppFiveTitle" = "IBM Bookmarks"; +"installationBundleSelectionPageBundleTwoAppFiveDescription" = "Liens vers les sites Web IBM couramment utilisés"; + +// Bundle three +"installationBundleSelectionPageBundleThreeTitle" = "Productivité"; +"installationBundleSelectionPageBundleThreeDescription" = "Augmentez votre productivité avec des outils de traitement de texte, de calcul, etc."; +"installationBundleSelectionPageBundleThreePopoverTitle" = "Groupe de productivité"; +"installationBundleSelectionPageBundleThreePopoverDescription" = "Des outils pour vous aider à créer et à collaborer."; +"installationBundleSelectionPageBundleThreeAppOneTitle" = "Office 365"; +"installationBundleSelectionPageBundleThreeAppOneDescription" = "Microsoft Word, Excel, PowerPoint, OneNote et Outlook"; +"installationBundleSelectionPageBundleThreeAppTwoTitle" = "Slack"; +"installationBundleSelectionPageBundleThreeAppTwoDescription" = "Communiquez et collaborez avec les autres équipes d’IBM"; +"installationBundleSelectionPageBundleThreeAppThreeTitle" = "Box Drive"; +"installationBundleSelectionPageBundleThreeAppThreeDescription" = "Stockez, partagez et synchronisez des fichiers"; + +// MARK: - Installation: bundle installation page +"installationBundleInstallationPageTitle" = "Installation des groupes d’applications sélectionnés en cours"; +"installationBundleInstallationPageSubtitle" = "Estimation du temps restant : "; +"installationBundleInstallationPageHideAppLabel" = "Masquer l’application"; +"installationBundleInstallationPageShowAppLabel" = "Afficher l’application"; + +// MARK: - Installation: final page + +// Header +"installationFinalPageTitle" = "Commencez à utiliser votre Mac"; + +// Elements +"installationFinalPageElementOneTitle" = "Téléchargez des applications\nà partir de Mac@IBM App Store"; +"installationFinalPageElementOneDescription" = "Microsoft Office, Slack, IBM Notes, etc.!"; +"installationFinalPageElementTwoTitle" = "Transférez vos données à partir \nd’un autre ordinateur"; +"installationFinalPageElementTwoDescription" = "Transférez vos informations importantes \nvers votre nouveau Mac."; +"installationFinalPageElementThreeTitle" = "Faites la sauvegarde de votre\nMac avec Code42 CrashPlan"; +"installationFinalPageElementThreeDescription" = "Installez, configurez un compte \net travaillez sans aucun souci."; +"installationFinalPageElementThreeDescriptionAlternate" = "Configurez un compte \net travaillez sans aucun souci."; +"installationFinalPageElementFourTitle" = "Accédez à des conseils, à des\ntutoriels et à de l'assistance\nsur Help@IBM"; +"installationFinalPageElementFourDescription" = "Accédez aux conseillers du centre d’assistance IBM spécialisés dans les ordinateurs Apple."; +"installationFinalPageElementFiveTitle" = "Vous utilisez Notes? Installez votre \nfichier ID Notes"; +"installationFinalPageElementFiveDescription" = "Installez et configurez Notes comme client de courrier électronique."; +"installationFinalPAgeElementSixTitle" = "Allez à la page d’accueil w3"; +"installationFinalPageElementSixDescription" = "Faites des recherches dans les emplacements w3 et dans BluePages"; + +// Footer +"installationFinalPageFooterLabel" = " Rappelez-le-moi lors du prochain redémarrage de mon Mac."; + +// MARK: - Installation: Notes wizard page + +// Header +"filePickerPageTitle" = "Installez votre fichier ID Notes"; +"filePickerPageSubtitle" = "Vous avez besoin de votre ID Notes pour terminer la configuration de Notes. Vous pouvez aussi l’ajouter plus tard."; + +// Messages +"filePickerPageMessageSuccess" = "Votre ID Notes a été installé!"; +"filePickerPageMessageFailure" = "Nous n’avons pas pu installer votre fichier ID Notes."; +"filePickerPageMessageAlreadyExist" = "Un fichier ID Notes existe déjà. Vous pouvez en installer un nouveau."; + +// Labels +"filePickerPageButtonBrowse" = "Rechercher votre fichier ID Notes"; +"filePickerPageButtonRemove" = "Supprimer"; +"filePickerPageCenterLabel" = "Glissez-déposez votre fichier ID Notes"; +"filePickerPageAlertMessage" = "Un fichier existe déjà."; +"filePickerPageAlertInformativeText" = "La destination choisie contient déjà ce fichier. Voulez-vous le remplacer par le fichier sélectionné?"; +"filePickerPageFileSelectionPanelTitle" = "Sélectionnez le fichier d’ID à utiliser pour configurer Notes"; +"filePickerPageButtonInstall" = "Installer le fichier ID Notes"; + +// MARK: - Alert labels + +// Un-enrollment +"unenrollmentAlertTitle" = "Voulez-vous vraiment mettre fin au processus d’inscription?"; +"unenrollmentAlertMessage" = "Si vous annulez maintenant, tous les réglages de sécurité seront annulés et cet ordinateur sera supprimé du système de gestion."; +"unenrollmentCancelled" = "La demande de suppression de l’infrastructure de gestion a été annulée."; + +// Bundle selection +"bundleSelectionAlertTitle" = "Voulez-vous vraiment poursuivre?"; +"bundleSelectionAlertMessage" = "Il semble que votre réseau soit lent actuellement. Nous vous recommandons d’installer moins de groupes d'applications."; + +// Bundle installation +"bundleInstallationalertMessage" = "Nous n’avons pas pu installer certaines applications. Utilisez le libre-service pour les installer plus tard."; + +// Launch failure +"launchFailureAlertTitle" = "Cette application nécessite que l’appareil soit géré."; +"launchFailureAlertMessage" = "Veuillez inscrire cet appareil."; + +// External network problem +"externalNetworkAlertMessage" = "Vous n’êtes pas connecté à Internet. Avant de poursuivre, assurez-vous que votre Mac est connecté à un réseau et a accès à Internet."; +"externalNetworkJspMessage" = "Le libre-service n'est pas disponible en ce moment. Réessayez plus tard."; + +// Internal network problem +"internalNetworkProblemAlertMessage" = "\n\nPour pouvoir poursuivre, vous devez vous connecter à l’intranet."; + +// Terms and conditions drop down +"termsAndConditionsTitle" = "Convention d'IBM relative à l'utilisation d'appareils personnels"; +"termsAndConditionsBody" = "Vous avez choisi d'enregistrer cet appareil comme étant votre «propriété personnelle». L'utilisation d'un appareil personnel dans la conduite des affaires d'IBM est régie par certaines modalités particulières.\n\nVeuillez lire les modalités d'IBM et indiquer si vous les acceptez."; +"termsAndConditionsButtonLink" = "Lire les modalités d'IBM"; +"termsAndConditionsButtonAccept" = "Accepter"; + +// MARK: - Common button labels +"buttonLabelOk" = "OK"; +"buttonLabelCancel" = "Annuler"; +"buttonLabelNext" = "Suivant"; +"buttonLabelRestart" = "Redémarrer"; +"buttonLabelClose" = "Fermer"; +"buttonLabelBack" = "Précédent"; +"buttonLabelOkWithQuestionMark" = "OK?"; +"buttonLabelQuit" = "Quitter"; +"buttonLabelReplace" = "Remplacer"; +"buttonLabelUpdateInfo" = "Modifier les informations"; +"buttonLabelUnenroll" = "Annuler l’inscription"; + +// MARK: - Common labels +"labelEnabled" = "Activé"; +"labelDisabled" = "Désactivé"; +"labelRequired" = "Requis"; +"restartFailureMessage" = "Votre ordinateur n’a pas pu être redémarré"; +"restartFailureComment" = "Alerte d’échec du redémarrage"; +"estimatedInstallTimeMessage" = "%@ \n \n Estimation du temps requis pour l’installation : %@"; +"labelChooseAnswer" = "Choisissez votre réponse."; +"labelNo" = "Non"; +"labelYes" = "Oui"; +"buttonLabelInstall" = "Installer les groupes sélectionnés"; +"buttonLabelSkip" = "Ignorer"; diff --git a/enrollment/enrollment/fr.lproj/Localizable.strings b/enrollment/enrollment/fr.lproj/Localizable.strings new file mode 100644 index 0000000..ce8ee8d --- /dev/null +++ b/enrollment/enrollment/fr.lproj/Localizable.strings @@ -0,0 +1,273 @@ +/* + Localizable.strings + enrollment + + Created by Simone Martorelli on 2/5/20. + Copyright © 2020 IBM. All rights reserved. + SPDX-License-Identifier: GPL-3.0-only + */ + +/// MARK: - Note to the translation +/// +/// Pay attention to not modify, cancel or move the special characters: +/// - %d - This special character is substituted with a number at runtime; +/// - %@ - This special characted is substituted with a string at runtime; +/// - \n - This special characted works like the "return" key; +/// - \" - This special characted insert a "; + +// MARK: - Registration: page one + +// Header +"registrationPageOneTitleSimple" = "Bienvenue parmi nous !"; +"registrationPageOneTitleComposed" = "Bienvenue, %@ !"; +"registrationPageOneSubtitleSimple" = "Vous ne voyez pas votre nom ?"; +"registrationPageOneSubtitleComposed" = "Vous ne vous appelez pas %@ ?"; + +// Info popovers +"registrationPageOneSubtitle_info" = "Ne vous inquiétez pas, vous pourrez mettre cette information à jour plus tard en utilisant Mac@IBM App Store et en recherchant \"Assign User\"."; +"registrationPageOneDisclaimerPolicies_infoElementOne" = "Pare-feu"; +"registrationPageOneDisclaimerPolicies_infoElementTwo" = "Mode secret"; +"registrationPageOneDisclaimerPolicies_infoElementThree" = "Compte utilisateur invité"; +"registrationPageOneDisclaimerPolicies_infoElementFour" = "Chiffrement de disque avec FileVault"; +"registrationPageOneDisclaimerPolicies_infoElementFive" = "Changement du mot de passe macOS initial"; +"registrationPageOneDisclaimerPolicies_infoElementSix" = "Mot de passe de l’écran de veille"; +"registrationPageOneDisclaimerPolicies_infoElementSeven_title" = "Délai d’activation de l’écran de veille"; +"registrationPageOneDisclaimerPolicies_infoElementSeven_description" = "30 minutes d’inactivité"; +"registrationPageOneDisclaimerPolicies_infoElementEight_title" = "Logiciel de protection des nœuds finaux"; + +// Field labels +"registrationPageOneFieldRegion" = "Région "; +"registrationPageOneFieldComputer" = "Type d’ordinateur "; +"registrationPageOneFieldOwner" = "Propriétaire de l’équipement "; +"registrationPageOneFieldUser" = "Type d’utilisateur "; + +// Region field options +"registrationPageOneFieldRegionOptionOne" = "États-Unis"; +"registrationPageOneFieldRegionOptionTwo" = "Canada"; +"registrationPageOneFieldRegionOptionThree" = "EMOA (Europe, Moyen-Orient, Afrique)"; +"registrationPageOneFieldRegionOptionFour" = "AL (Amérique latine)"; +"registrationPageOneFieldRegionOptionFive" = "AP (Asie-Pacifique)"; + +// Computer Type options +"registrationPageOneFieldComputerOptionOne" = "Principal"; +"registrationPageOneFieldComputerOptionOne_info" = "pour un utilisateur unique, en tant que plateforme de productivité pour l’exécution des tâches bureautiques courantes (par ex. : courrier électronique, applications/navigateur Web, messagerie instantanée, documentation, etc.)"; +"registrationPageOneFieldComputerOptionTwo" = "Secondaire"; +"registrationPageOneFieldComputerOptionTwo_info" = "pour des tâches autres que les tâches bureautiques, y compris les tâches liées aux démonstrations destinées aux clients et les machines virtuelles"; +"registrationPageOneFieldComputerOptionThree" = "Partagé"; +"registrationPageOneFieldComputerOptionThree_info" = "utilisé par plusieurs personnes aux fins d’enseignement et de formation"; +"registrationPageOneFieldComputerOptionFour" = "Prêté"; +"registrationPageOneFieldComputerOptionFour_info" = "aux fins de test ou de développement"; +"registrationPageOneFieldComputerOptionFive" = "Classe"; +"registrationPageOneFieldComputerOptionFive_info" = "utilisation de courte durée, en tant que remplacement ou complément"; +"registrationPageOneFieldComputerOptionSix" = "Labo"; +"registrationPageOneFieldComputerOptionSix_info" = "utilisé par plusieurs personnes pour différentes tâches, y compris des tâches bureautiques"; + +// Asset Owner options +"registrationPageOneFieldOwnerOptionOne" = "Fourni par IBM"; +"registrationPageOneFieldOwnerOptionTwo" = "Équipement personnel"; +"registrationPageOneFieldOwnerOptionThree" = "Propriété d’un tiers : fourni par un fournisseur"; +"registrationPageOneFieldOwnerOptionFour" = "Propriété d’un tiers : fourni par une agence de sous-traitance"; +"registrationPageOneFieldOwnerOptionFive" = "Propriété d’un tiers : fourni par un client"; + +// User Type options +"registrationPageOneFieldUserOptionOne" = "Standard"; +"registrationPageOneFieldUserOptionOne_info" = "utilisation générale, à l’exclusion des tâches effectuées par les utilisateurs de type Privilégié ou Centre d’appel"; +"registrationPageOneFieldUserOptionTwo" = "Privilégié"; +"registrationPageOneFieldUserOptionTwo_info" = "utilisé par un détenteur de droits d’administration de la sécurité ou de droits système sur des équipements réseau, des systèmes informatiques, des composants middleware ou des applications pour IBM ou ses clients"; +"registrationPageOneFieldUserOptionThree" = "Centre d’appel ou de service"; +"registrationPageOneFieldUserOptionThree_info" = "utilisé dans un centre de service, d’appel ou d’assistance"; + +// Policies disclaimer +"registrationPageOneDisclaimerPolicies" = "Les règles de sécurité IBM seront automatiquement appliquées."; + +// MARK: - Registration: page two + +// Header +"registrationPageTwoTitle" = "Informations auxquelles vous avez accès "; +"registrationPageTwoSubtitle" = "Sélectionnez les types de données présents sur cet ordinateur."; + +// Information options +"registrationPageTwoFieldInformationOptionOne_title" = "Informations personnelles sensibles"; +"registrationPageTwoFieldInformationOptionOne_description" = "votre équipement contient des informations personnelles"; +"registrationPageTwoFieldInformationOptionTwo_title" = "Données de clients"; +"registrationPageTwoFieldInformationOptionTwo_description" = "votre équipement contient (ou accède à) des données appartenant à (ou créées par) des clients"; +"registrationPageTwoFieldInformationOptionThree_title" = "Données réglementées"; +"registrationPageTwoFieldInformationOptionThree_description" = "vous avez été informé par votre hiérarchie, leur propriétaire ou leur conservateur, que les données que votre ordinateur contient (ou auxquelles il accède) sont soumises à des restrictions ou à une réglementation gouvernementales ; par exemple, certaines données de santé font l’objet d’une protection supplémentaire"; +"registrationPageTwoFieldInformationOptionFour_title" = "Données FFIEC (Federal Financial Institutions Examination Council)"; +"registrationPageTwoFieldInformationOptionFour_description" = "vous supportez les (ou accédez aux) environnements financiers de clients"; +"registrationPageTwoFieldInformationOptionFive_title" = "Données HIPAA (Health Insurance Portability and Accountability Act)"; +"registrationPageTwoFieldInformationOptionFive_description" = "vous supportez un compte client ou une offre à service partagé réglementés par la loi HIPAA"; +"registrationPageTwoFieldInformationOptionSix_title" = "Données de carte de paiement"; +"registrationPageTwoFieldInformationOptionSix_description" = "votre équipement contient (ou accède à) des données de carte de paiement sensibles (par exemple : carte bancaire) appartenant à (ou créées par) des clients"; +"registrationPageTwoFieldInformationOptionSeven_title" = "Aucun des types de données ci-dessus"; +"registrationPageTwoFieldInformationOptionSeven_description" = ""; + +// MARK: - Registration: loading page + +// State labels +"registrationLoadingPageStateOne" = "Test de la vitesse du réseau..."; +"registrationLoadingPageStateTwo" = "Inscription en cours..."; +"registrationLoadingPageStateForPhaseThree" = "Mise à jour de l’inscription..."; + +// MARK: - Registration: final page + +// Header +"registrationFinalPageTitle" = "Inscription terminée"; +"registrationFinalPageTitlePhaseThree" = "Détails de l’inscription"; +"registrationFinalPageTitlePhaseFour" = "Bienvenue !"; +"registrationFinalPageSubtitleStandard" = "Configurons votre Mac !"; +"registrationFinalPageSubtitlePhaseThree" = ""; +"registrationFinalPageInstructionalMessage" = "Lors de votre prochaine ouverture de session, vous serez invité à entrer un nouveau mot de passe de connexion à macOS et à activer le chiffrement de disque FileVault."; +"registrationFinalPageCountdownMessage" = "Votre Mac redémarrera automatiquement dans %d secondes pour poursuivre le processus de configuration. Vous pouvez aussi sélectionner \"Redémarrer\" pour poursuivre ce processus dès maintenant."; + +// MARK: - Installation: bundle selection page + +// Header +"installationBundleSelectionPageTitle" = "Quelques bundles d’application pour vous permettre de commencer à travailler"; +"installationBundleSelectionPageSubtitle" = "Vous pouvez à tout moment installer des applications supplémentaires à l’aide de Mac@IBM App Store."; + +// Labels +"installationBundleSelectionPageRecommended" = "(recommandé)"; + +// Bundle one +"installationBundleSelectionPageBundleOneTitle" = "Connectivité"; +"installationBundleSelectionPageBundleOneDescription" = "Pour vous connecter aux réseaux IBM, vous avez besoin de logiciels et de certificats."; +"installationBundleSelectionPageBundleOnePopoverTitle" = "Bundle de connectivité"; +"installationBundleSelectionPageBundleOnePopoverDescription" = "Connectez-vous à notre réseau avec les certificats et les logiciels appropriés."; +"installationBundleSelectionPageBundleOneAppOneTitle" = "AnyConnect"; +"installationBundleSelectionPageBundleOneAppOneDescription" = "Client de réseau privé virtuel (VPN)."; + +// Bundle two +"installationBundleSelectionPageBundleTwoTitle" = "Indispensables"; +"installationBundleSelectionPageBundleTwoDescription" = "Soyez opérationnel grâce aux outils IBM les plus courants."; +"installationBundleSelectionPageBundleTwoPopoverTitle" = "Bundle d’outils indispensables"; +"installationBundleSelectionPageBundleTwoPopoverDescription" = "Applications utilisées par la plupart des employés"; +"installationBundleSelectionPageBundleTwoAppOneTitle" = "IBM Notes"; +"installationBundleSelectionPageBundleTwoAppOneDescription" = "Envoyez et recevez des courriels IBM et interagissez avec des bases de données"; +"installationBundleSelectionPageBundleTwoAppTwoTitle" = "Webex Meetings"; +"installationBundleSelectionPageBundleTwoAppTwoDescription" = "Combinez des fonctionnalités de visioconférence, d’audioconférence et de réunion Web"; +"installationBundleSelectionPageBundleTwoAppThreeTitle" = "Code42 CrashPlan"; +"installationBundleSelectionPageBundleTwoAppThreeDescription" = "Sauvegardez et restaurez en toute sécurité les fichiers de votre Mac"; +"installationBundleSelectionPageBundleTwoAppFourTitle" = "BluePages"; +"installationBundleSelectionPageBundleTwoAppFourDescription" = "Recherches rapides et pratiques dans l’annuaire des employés"; +"installationBundleSelectionPageBundleTwoAppFiveTitle" = "IBM Bookmarks"; +"installationBundleSelectionPageBundleTwoAppFiveDescription" = "Liens vers les sites Web IBM couramment utilisés"; + +// Bundle three +"installationBundleSelectionPageBundleThreeTitle" = "Productivité"; +"installationBundleSelectionPageBundleThreeDescription" = "Boostez votre productivité grâce à des outils de traitement de texte, de calcul, etc."; +"installationBundleSelectionPageBundleThreePopoverTitle" = "Bundle de productivité"; +"installationBundleSelectionPageBundleThreePopoverDescription" = "Des outils pour vous aider à créer et collaborer."; +"installationBundleSelectionPageBundleThreeAppOneTitle" = "Office 365"; +"installationBundleSelectionPageBundleThreeAppOneDescription" = "Microsoft Word, Excel, PowerPoint, OneNote et Outlook"; +"installationBundleSelectionPageBundleThreeAppTwoTitle" = "Slack"; +"installationBundleSelectionPageBundleThreeAppTwoDescription" = "Communiquez et collaborez avec les autres équipes d’IBM"; +"installationBundleSelectionPageBundleThreeAppThreeTitle" = "Box Drive"; +"installationBundleSelectionPageBundleThreeAppThreeDescription" = "Stockez, partagez et synchronisez des fichiers"; + +// MARK: - Installation: bundle installation page +"installationBundleInstallationPageTitle" = "Installation des bundles d’applications sélectionnés…"; +"installationBundleInstallationPageSubtitle" = "Estimation du temps restant : "; +"installationBundleInstallationPageHideAppLabel" = "Masquer l’application"; +"installationBundleInstallationPageShowAppLabel" = "Afficher l’application"; + +// MARK: - Installation: final page + +// Header +"installationFinalPageTitle" = "Commencez à utiliser votre Mac"; + +// Elements +"installationFinalPageElementOneTitle" = "Télécharger des applications à \npartir de Mac@IBM App Store"; +"installationFinalPageElementOneDescription" = "Microsoft Office, Slack, IBM Notes, etc. !"; +"installationFinalPageElementTwoTitle" = "Transférer vos données à partir \nd’un autre ordinateur"; +"installationFinalPageElementTwoDescription" = "Transférez vos informations importantes \nvers votre nouveau Mac."; +"installationFinalPageElementThreeTitle" = "Sauvegarder votre Mac \navec Code42 CrashPlan"; +"installationFinalPageElementThreeDescription" = "Installez, configurez un compte \net travaillez sans aucun souci."; +"installationFinalPageElementThreeDescriptionAlternate" = "Configurez un compte et \ntravaillez sans aucun souci."; +"installationFinalPageElementFourTitle" = "Accéder à des conseils, des tutoriels \net une assistance sur Help@IBM"; +"installationFinalPageElementFourDescription" = "Accédez aux conseillers du centre d’assistance IBM dédiés aux ordinateurs Apple."; +"installationFinalPageElementFiveTitle" = "Vous utilisez Notes ? Installer votre \nfichier d’ID Notes"; +"installationFinalPageElementFiveDescription" = "Installez et configurez Notes comme client de messagerie."; +"installationFinalPAgeElementSixTitle" = "Aller à la page d’accueil w3"; +"installationFinalPageElementSixDescription" = "Recherchez dans les emplacements w3 et dans BluePages"; + +// Footer +"installationFinalPageFooterLabel" = " Me le rappeler lors du prochain redémarrage de mon Mac."; + +// MARK: - Installation: Notes wizard page + +// Header +"filePickerPageTitle" = "Installer votre fichier d’ID Notes"; +"filePickerPageSubtitle" = "Vous avez besoin de votre ID Notes pour terminer la configuration de Notes. Vous pouvez aussi l’ajouter ultérieurement."; + +// Messages +"filePickerPageMessageSuccess" = "Votre ID Notes a été installé !"; +"filePickerPageMessageFailure" = "Nous n’avons pas pu installer votre fichier d’ID Notes."; +"filePickerPageMessageAlreadyExist" = "Un fichier d’ID Notes existe déjà. Vous pouvez en installer un nouveau."; + +// Labels +"filePickerPageButtonBrowse" = "Rechercher votre fichier d’ID Notes"; +"filePickerPageButtonRemove" = "Supprimer"; +"filePickerPageCenterLabel" = "Glisser-déposer votre fichier d’ID Notes"; +"filePickerPageAlertMessage" = "Un fichier existe déjà."; +"filePickerPageAlertInformativeText" = "La destination choisie contient déjà un fichier. Voulez-vous le remplacer par le fichier sélectionné ?"; +"filePickerPageFileSelectionPanelTitle" = "Sélectionner le fichier d’ID à utiliser pour configurer Notes"; +"filePickerPageButtonInstall" = "Installer le fichier d’ID Notes"; + +// MARK: - Alert labels + +// Un-enrollment +"unenrollmentAlertTitle" = "Voulez-vous vraiment mettre fin au processus d’inscription ?"; +"unenrollmentAlertMessage" = "Si vous annulez maintenant, tous les réglages de sécurité seront annulés et cet ordinateur sera supprimé du système de gestion."; +"unenrollmentCancelled" = "La demande de suppression de l’infrastructure de gestion a été annulée."; + +// Bundle selection +"bundleSelectionAlertTitle" = "Voulez-vous vraiment poursuivre ?"; +"bundleSelectionAlertMessage" = "Il semble que votre réseau soit actuellement lent. Nous vous recommandons d’installer moins de bundles."; + +// Bundle installation +"bundleInstallationalertMessage" = "Nous n’avons pas pu installer certaines applications. Utilisez Self Service pour les installer ultérieurement."; + +// Launch failure +"launchFailureAlertTitle" = "Cette application nécessite que l’appareil soit géré."; +"launchFailureAlertMessage" = "Veuillez inscrire cet appareil."; + +// External network problem +"externalNetworkAlertMessage" = "Vous n’êtes pas connecté à Internet. Avant de poursuivre, assurez-vous que votre Mac est connecté à un réseau et a accès à Internet."; +"externalNetworkJspMessage" = "Self Service est actuellement indisponible. Réessayez plus tard."; + +// Internal network problem +"internalNetworkProblemAlertMessage" = "\n\nPour pouvoir poursuivre, vous devez vous connecter à l’intranet."; + +// Terms and conditions drop down +"termsAndConditionsTitle" = "Contrat IBM relatif à l'utilisation des équipements personnels"; +"termsAndConditionsBody" = "Vous avez choisi d'enregistrer cet appareil en tant qu'“équipement personnel”. L'utilisation d'un équipement personnel à des fins professionnelles pour IBM est régie par des dispositions particulières.\n\nVeuillez prendre connaissance des conditions générales IBM et préciser si vous les acceptez."; +"termsAndConditionsButtonLink" = "Lire les conditions générales IBM"; +"termsAndConditionsButtonAccept" = "Accepter"; + + +// MARK: - Common button labels +"buttonLabelOk" = "OK"; +"buttonLabelCancel" = "Annuler"; +"buttonLabelNext" = "Suivant"; +"buttonLabelRestart" = "Redémarrer"; +"buttonLabelClose" = "Fermer"; +"buttonLabelBack" = "Précédent"; +"buttonLabelOkWithQuestionMark" = "OK ?"; +"buttonLabelQuit" = "Quitter"; +"buttonLabelReplace" = "Remplacer"; +"buttonLabelUpdateInfo" = "Modifier les informations"; +"buttonLabelUnenroll" = "Annuler l’inscription"; + +// MARK: - Common labels +"labelEnabled" = "Activé"; +"labelDisabled" = "Désactivé"; +"labelRequired" = "Requis"; +"restartFailureMessage" = "Votre ordinateur n’a pas pu être redémarré."; +"restartFailureComment" = "Alerte d’échec du redémarrage"; +"estimatedInstallTimeMessage" = "%@ \n \n Estimation du temps requis pour l’installation : %@"; +"labelChooseAnswer" = "Choisissez votre réponse."; +"labelNo" = "Non"; +"labelYes" = "Oui"; +"buttonLabelInstall" = "Installer les bundles sélectionnés"; +"buttonLabelSkip" = "Ignorer"; diff --git a/enrollment/enrollment/it.lproj/Localizable.strings b/enrollment/enrollment/it.lproj/Localizable.strings new file mode 100644 index 0000000..fd0f874 --- /dev/null +++ b/enrollment/enrollment/it.lproj/Localizable.strings @@ -0,0 +1,272 @@ +/* + Localizable.strings + enrollment + + Created by Simone Martorelli on 2/5/20. + Copyright © 2020 IBM. All rights reserved. + SPDX-License-Identifier: GPL-3.0-only + */ + +/// MARK: - Note to the translation +/// +/// Pay attention to not modify, cancel or move the special characters: +/// - %d - This special character is substituted with a number at runtime; +/// - %@ - This special characted is substituted with a string at runtime; +/// - \n - This special characted works like the "return" key; +/// - \" - This special characted insert a "; + +// MARK: - Registration: page one + +// Header +"registrationPageOneTitleSimple" = "Benvenuto, nuovo dipendente!"; +"registrationPageOneTitleComposed" = "Benvenuto/a, %@!"; +"registrationPageOneSubtitleSimple" = "Non vedi il tuo nome?"; +"registrationPageOneSubtitleComposed" = "Non sei %@?"; + +// Info popovers +"registrationPageOneSubtitle_info" = "Non ti preoccupare, lo potrai correggere più tardi con Mac@IBM App Store e cercando \"Assign User\"."; +"registrationPageOneDisclaimerPolicies_infoElementOne" = "Firewall"; +"registrationPageOneDisclaimerPolicies_infoElementTwo" = "Modalità Mascheramento"; +"registrationPageOneDisclaimerPolicies_infoElementThree" = "Account Utente Guest"; +"registrationPageOneDisclaimerPolicies_infoElementFour" = "Crittografia Disco FileVault"; +"registrationPageOneDisclaimerPolicies_infoElementFive" = "Modifica Password macOS Iniziale"; +"registrationPageOneDisclaimerPolicies_infoElementSix" = "Password Screen Saver "; +"registrationPageOneDisclaimerPolicies_infoElementSeven_title" = "Tempo di avvio dello Screen Saver "; +"registrationPageOneDisclaimerPolicies_infoElementSeven_description" = "30 minuti di inattività"; +"registrationPageOneDisclaimerPolicies_infoElementEight_title" = "Software di protezione dell'endpoint"; + +// Field labels +"registrationPageOneFieldRegion" = "Area"; +"registrationPageOneFieldComputer" = "Tipo di Computer"; +"registrationPageOneFieldOwner" = "Proprietario Asset"; +"registrationPageOneFieldUser" = "Tipo di Utente"; + +// Region field options +"registrationPageOneFieldRegionOptionOne" = "USA"; +"registrationPageOneFieldRegionOptionTwo" = "Canada"; +"registrationPageOneFieldRegionOptionThree" = "EMEA (Europa, Medio Oriente e Africa)"; +"registrationPageOneFieldRegionOptionFour" = "LA (America Latina)"; +"registrationPageOneFieldRegionOptionFive" = "AP (Asia Pacifico)"; + +// Computer Type options +"registrationPageOneFieldComputerOptionOne" = "Primario"; +"registrationPageOneFieldComputerOptionOne_info" = "per singolo utente, funge da piattaforma produttiva per le normali attività di ufficio (ad es., email, esplorazione/applicazioni web, messaggistica istantanea, documentazione, etc.)"; +"registrationPageOneFieldComputerOptionTwo" = "Secondario"; +"registrationPageOneFieldComputerOptionTwo_info" = "per diverse attività ad eccezione di quelle operative per l'ufficio, incluse attività dimostrative per il cliente e Macchine Virtuali"; +"registrationPageOneFieldComputerOptionThree" = "Condiviso"; +"registrationPageOneFieldComputerOptionThree_info" = "utilizzato da più utenti per formazione e addestramento"; +"registrationPageOneFieldComputerOptionFour" = "In prestito"; +"registrationPageOneFieldComputerOptionFour_info" = "per attività di test e/o sviluppo"; +"registrationPageOneFieldComputerOptionFive" = "Classe"; +"registrationPageOneFieldComputerOptionFive_info" = "utilizzato per brevi periodi in sostituzione o in aggiunta"; +"registrationPageOneFieldComputerOptionSix" = "Lab"; +"registrationPageOneFieldComputerOptionSix_info" = "destinato all'utilizzo da parte di diversi utenti per svariate attività incluse quelle di produttività dell'ufficio"; + +// Asset Owner options +"registrationPageOneFieldOwnerOptionOne" = "Fornito da IBM"; +"registrationPageOneFieldOwnerOptionTwo" = "Di proprietà personale"; +"registrationPageOneFieldOwnerOptionThree" = "Di proprietà di terzi: Fornito dal Vendor"; +"registrationPageOneFieldOwnerOptionFour" = "Di proprietà di terzi: Fornito da Agenzia Appaltatrice"; +"registrationPageOneFieldOwnerOptionFive" = "Di proprietà di terzi: Fornito dal Cliente"; + +// User Type options +"registrationPageOneFieldUserOptionOne" = "Standard"; +"registrationPageOneFieldUserOptionOne_info" = "uso generale al di fuori delle attività svolte negli scenari di utilizzo Privilegiato o Call Center"; +"registrationPageOneFieldUserOptionTwo" = "Privilegiato"; +"registrationPageOneFieldUserOptionTwo_info" = "assegnato ad incarichi per autorità amministrative di sicurezza, autorità di sistema su dispositivi di rete, sistemi informatici, componenti middleware applicazioni per IBM o per i clienti"; +"registrationPageOneFieldUserOptionThree" = "Assistenza / Call Center"; +"registrationPageOneFieldUserOptionThree_info" = "assegnato ad un Service Center, Call Center o Help Desk"; + +// Policies disclaimer +"registrationPageOneDisclaimerPolicies" = "Le policy di sicurezza IBM verranno applicate automaticamente."; + +// MARK: - Registration: page two + +// Header +"registrationPageTwoTitle" = "Informazioni a cui l'utente accede"; +"registrationPageTwoSubtitle" = "Selezionare il tipo di dati memorizzato su questo computer."; + +// Information options +"registrationPageTwoFieldInformationOptionOne_title" = "Dati Personali Sensibili (Sensitive Personal Information, SPI)"; +"registrationPageTwoFieldInformationOptionOne_description" = "questo dispositivo memorizza Informazioni Personali (Personal Information, PI)"; +"registrationPageTwoFieldInformationOptionTwo_title" = "Dati del Cliente"; +"registrationPageTwoFieldInformationOptionTwo_description" = "il dispositivo memorizza o viene utilizzato per accedere ai dati di proprietà o creati da un cliente "; +"registrationPageTwoFieldInformationOptionThree_title" = "Dati Regolamentati dal Governo"; +"registrationPageTwoFieldInformationOptionThree_description" = "si è stati informati dalla propria dirigenza, dal proprietario dei dati o dal custode dei dati che i dati archiviati o accessibili dal dispositivo sono soggetti a restrizioni o normative governative, ad esempio alcuni dati sanitari sono soggetti ad ulteriori protezioni "; +"registrationPageTwoFieldInformationOptionFour_title" = "Dati FFIEC (Federal Financial Institutions Examination Council)"; +"registrationPageTwoFieldInformationOptionFour_description" = "si fornisce supporto o si ha accesso agli ambienti finanziari del cliete"; +"registrationPageTwoFieldInformationOptionFive_title" = "Dati HIPAA (Health Insurance Portability and Accountability Act)"; +"registrationPageTwoFieldInformationOptionFive_description" = "si fornisce supporto ad un account o ad un'offerta multi-tenant del cliente regolamentati dall'HIPAA"; +"registrationPageTwoFieldInformationOptionSix_title" = "Dati PCI"; +"registrationPageTwoFieldInformationOptionSix_description" = "il dispositivo archivia o accede ai dati sensibili delle carte di pagamento (ad es. carte di credito) di proprietà o create da un cliente "; +"registrationPageTwoFieldInformationOptionSeven_title" = "Nessuna delle precedenti"; +"registrationPageTwoFieldInformationOptionSeven_description" = ""; + +// MARK: - Registration: loading page + +// State labels +"registrationLoadingPageStateOne" = "Test della velocità di rete"; +"registrationLoadingPageStateTwo" = "Completamento iscrizione"; +"registrationLoadingPageStateForPhaseThree" = "Aggiornamento Registrazione"; + +// MARK: - Registration: final page + +// Header +"registrationFinalPageTitle" = "Registrazione completata"; +"registrationFinalPageTitlePhaseThree" = "Dettagli Registrazione"; +"registrationFinalPageTitlePhaseFour" = "Benvenuto!"; +"registrationFinalPageSubtitleStandard" = "Configurazione del Mac."; +"registrationFinalPageSubtitlePhaseThree" = ""; +"registrationFinalPageInstructionalMessage" = "Al prossimo accesso, verrà richiesto l'inserimento di una nuova password di accesso a macOS e di abilitare la crittografia del disco FileVault. "; +"registrationFinalPageCountdownMessage" = "Il Mac verrà riavviato automaticamente tra %d secondi per continuare la procedura di configurazione oppure è possibile selezionare \"Riavvia\" per continuare ora. "; + +// MARK: - Installation: bundle selection page + +// Header +"installationBundleSelectionPageTitle" = "Bundle di app per iniziare"; +"installationBundleSelectionPageSubtitle" = "È possibile installare in qualsiasi momento altre app da Mac@IBM App Store."; + +// Labels +"installationBundleSelectionPageRecommended" = "(consigliato)"; + +// Bundle one +"installationBundleSelectionPageBundleOneTitle" = "Connettività"; +"installationBundleSelectionPageBundleOneDescription" = "Collegati alle reti IBM con il software ed i certificati necessari"; +"installationBundleSelectionPageBundleOnePopoverTitle" = "Bundle Connettività"; +"installationBundleSelectionPageBundleOnePopoverDescription" = "Collegati alla nostra rete con certificati e software"; +"installationBundleSelectionPageBundleOneAppOneTitle" = "AnyConnect"; +"installationBundleSelectionPageBundleOneAppOneDescription" = "Ipsum lorem 1"; + +// Bundle two +"installationBundleSelectionPageBundleTwoTitle" = "Essentials"; +"installationBundleSelectionPageBundleTwoDescription" = "Parti con i tool più comuni di IBM."; +"installationBundleSelectionPageBundleTwoPopoverTitle" = "Bundle Essentials "; +"installationBundleSelectionPageBundleTwoPopoverDescription" = "Queste sono le app utilizzate dalla maggior parte dei dipendenti"; +"installationBundleSelectionPageBundleTwoAppOneTitle" = "IBM Notes"; +"installationBundleSelectionPageBundleTwoAppOneDescription" = "Invia e ricevi posta IBM e interagisci con i database"; +"installationBundleSelectionPageBundleTwoAppTwoTitle" = "Webex Meetings"; +"installationBundleSelectionPageBundleTwoAppTwoDescription" = "Combina le funzionalità delle conferenze video e audio e dei web meeting "; +"installationBundleSelectionPageBundleTwoAppThreeTitle" = "Code42 CrashPlan"; +"installationBundleSelectionPageBundleTwoAppThreeDescription" = "Esegui in sicurezza il backup ed il ripristino dei file sul tuo Mac in completa"; +"installationBundleSelectionPageBundleTwoAppFourTitle" = "BluePages"; +"installationBundleSelectionPageBundleTwoAppFourDescription" = "Effettua ricerche ricerche rapide e comode nell'elenco dei dipendenti"; +"installationBundleSelectionPageBundleTwoAppFiveTitle" = "IBM Bookmarks"; +"installationBundleSelectionPageBundleTwoAppFiveDescription" = "Collegamenti ai siti web IBM utilizzati più di frequente"; + +// Bundle three +"installationBundleSelectionPageBundleThreeTitle" = "Productivity"; +"installationBundleSelectionPageBundleThreeDescription" = "Aumenta la tua produttività con word processing, fogli di calcolo e altro ancora. "; +"installationBundleSelectionPageBundleThreePopoverTitle" = "Bundle Productivity"; +"installationBundleSelectionPageBundleThreePopoverDescription" = "Tool che ti aiutano a creare e collaborare."; +"installationBundleSelectionPageBundleThreeAppOneTitle" = "Office 365"; +"installationBundleSelectionPageBundleThreeAppOneDescription" = "Microsoft Word, Excel, PowerPoint, OneNote e Outlook"; +"installationBundleSelectionPageBundleThreeAppTwoTitle" = "Slack"; +"installationBundleSelectionPageBundleThreeAppTwoDescription" = "Comunica e collabora con i team in tutto il mondo IBM"; +"installationBundleSelectionPageBundleThreeAppThreeTitle" = "Box Drive"; +"installationBundleSelectionPageBundleThreeAppThreeDescription" = "Archivia, Condividi e Sincronizza file"; + +// MARK: - Installation: bundle installation page +"installationBundleInstallationPageTitle" = "Installazione di bundle selezionati di app…"; +"installationBundleInstallationPageSubtitle" = "Tempo rimanente stimato: "; +"installationBundleInstallationPageHideAppLabel" = "Nascondi App"; +"installationBundleInstallationPageShowAppLabel" = "Mostra App"; + +// MARK: - Installation: final page + +// Header +"installationFinalPageTitle" = "Introduzione al Mac"; + +// Elements +"installationFinalPageElementOneTitle" = "Scarica le app dal \nMac@IBM App Store"; +"installationFinalPageElementOneDescription" = "Microsoft Office, Slack, IBM Notes e altro!"; +"installationFinalPageElementTwoTitle" = "Migra i tuoi dati \nda un altro computer"; +"installationFinalPageElementTwoDescription" = "Trasferisci informazioni importanti \nnel tuo nuovo Mac."; +"installationFinalPageElementThreeTitle" = "Esegui il backup del tuo Mac con \nCode42 CrashPlan"; +"installationFinalPageElementThreeDescription" = "Installa, imposta un account,\ne rilassati."; +"installationFinalPageElementThreeDescriptionAlternate" = "Imposta un account,\ne rilassati."; +"installationFinalPageElementFourTitle" = "Visualizza suggerimenti, esercitazioni\ne supporto su Help@IBM"; +"installationFinalPageElementFourDescription" = "Entra in contatto con consulenti Apple Help Desk dedicati di IBM."; +"installationFinalPageElementFiveTitle" = "Utilizzi Notes? Installa il tuo \nfile Notes ID"; +"installationFinalPageElementFiveDescription" = "Installa e imposta Notes come tuo client email."; +"installationFinalPAgeElementSixTitle" = "Accedi alla homepage di w3"; +"installationFinalPageElementSixDescription" = "Cerca siti w3 e nelle BluePages"; + +// Footer +"installationFinalPageFooterLabel" = " Ricordamelo al prossimo avvio del mio Mac."; + +// MARK: - Installation: Notes wizard page + +// Header +"filePickerPageTitle" = "Installa il tuo file Notes ID"; +"filePickerPageSubtitle" = "Il Notes ID serve a completare l'impostazione di Notes. È anche possibile aggiungerlo in un secondo momento."; + +// Messages +"filePickerPageMessageSuccess" = "Il Notes ID è stato installato correttamente."; +"filePickerPageMessageFailure" = "Non è stato possibile installare il file Notes ID."; +"filePickerPageMessageAlreadyExist" = "È già presente un file Notes ID. È possibile installarne un altro."; + +// Labels +"filePickerPageButtonBrowse" = "Cerca il tuo file Notes ID"; +"filePickerPageButtonRemove" = "Rimuovi"; +"filePickerPageCenterLabel" = "Trascina e rilascia il tuo file Notes ID"; +"filePickerPageAlertMessage" = "Il file esiste già"; +"filePickerPageAlertInformativeText" = "Il file è già presente nel percorso di destinazione. Si desidera sostituire il file esistente con il file selezionato?"; +"filePickerPageFileSelectionPanelTitle" = "Selezionare il file ID che si desidera utilizzare per configurare Notes"; +"filePickerPageButtonInstall" = "Installa il file Notes ID"; + +// MARK: - Alert labels + +// Un-enrollment +"unenrollmentAlertTitle" = "Si è certi di voler interrompere il processo di iscrizione?"; +"unenrollmentAlertMessage" = "L'annullamento del processo in questo momento determinerà l'annullamento di tutte le impostazioni di sicurezza e la rimozione di questo computer dalla gestione."; +"unenrollmentCancelled" = "Azione Rimuovi Framework annullata"; + +// Bundle selection +"bundleSelectionAlertTitle" = "Si è certi di voler proseguire?"; +"bundleSelectionAlertMessage" = "La velocità di rete al momento è bassa. Si consiglia di installare un numero minore di bundle."; + +// Bundle installation +"bundleInstallationalertMessage" = "Si sono verificati degli errori durante l'installazione di alcune applicazioni, utilizzare Self Service per installarle in un secondo momento."; + +// Launch failure +"launchFailureAlertTitle" = "Questa applicazione richiede la gestione dei dispositivi."; +"launchFailureAlertMessage" = "Iscrivere questo dispositivo."; + +// External network problem +"externalNetworkAlertMessage" = "Non si è collegati a Internet. Prima di proseguire verificare che il Mac sia connesso ad una rete con accesso a Internet. "; +"externalNetworkJspMessage" = "Self Service non è disponibile al momento. Riprovare più tardi."; + +// Internal network problem +"internalNetworkProblemAlertMessage" = "\n\nÈ necessario collegarsi a intranet per procedere."; + +// Terms and conditions drop down +"termsAndConditionsTitle" = "Accordo IBM per l'Utilizzo dei dispositivi personali"; +"termsAndConditionsBody" = "Si è scelto di registrare questo dispositivo come “di proprietà personale”. L'utilizzo di un dispositivo di proprietà personale per condurre attività IBM è regolato da determinati termini e condizioni.\n\nConsultare i termini e le condizioni IBM e indicare se li si accetta. "; +"termsAndConditionsButtonLink" = "Leggi i Termini e le Condizioni IBM"; +"termsAndConditionsButtonAccept" = "Accetto"; + +// MARK: - Common button labels +"buttonLabelOk" = "OK"; +"buttonLabelCancel" = "Annulla"; +"buttonLabelNext" = "Avanti"; +"buttonLabelRestart" = "Riavvia"; +"buttonLabelClose" = "Chiudi"; +"buttonLabelBack" = "Indietro"; +"buttonLabelOkWithQuestionMark" = "Ok?"; +"buttonLabelQuit" = "Esci"; +"buttonLabelReplace" = "Sostituisci"; +"buttonLabelUpdateInfo" = "Modifica dettagli"; +"buttonLabelUnenroll" = "Annulla iscrizione"; + +// MARK: - Common labels +"labelEnabled" = "Abilitato"; +"labelDisabled" = "Disabilitato"; +"labelRequired" = "Obbligatorio"; +"restartFailureMessage" = "Il computer non può essere riavviato"; +"restartFailureComment" = "Avviso di errore nel riavvio"; +"estimatedInstallTimeMessage" = "%@ \n \n Tempo di installazione stimanto: %@"; +"labelChooseAnswer" = "Scegli la tua risposta."; +"labelNo" = "No"; +"labelYes" = "Sì"; +"buttonLabelInstall" = "Installa bundle selezionati"; +"buttonLabelSkip" = "Ignora"; diff --git a/enrollment/enrollment/ja-JP.lproj/Localizable.strings b/enrollment/enrollment/ja-JP.lproj/Localizable.strings new file mode 100644 index 0000000..8485d4a --- /dev/null +++ b/enrollment/enrollment/ja-JP.lproj/Localizable.strings @@ -0,0 +1,272 @@ +/* + Localizable.strings + enrollment + + Created by Simone Martorelli on 2/5/20. + Copyright © 2020 IBM. All rights reserved. + SPDX-License-Identifier: GPL-3.0-only + */ + +/// MARK: - Note to the translation +/// +/// Pay attention to not modify, cancel or move the special characters: +/// - %d - This special character is substituted with a number at runtime; +/// - %@ - This special characted is substituted with a string at runtime; +/// - \n - This special characted works like the "return" key; +/// - \" - This special characted insert a "; + +// MARK: - Registration: page one + +// Header +"registrationPageOneTitleSimple" = "新入社員の方へ、ようこそ"; +"registrationPageOneTitleComposed" = "%@ さん、ようこそ"; +"registrationPageOneSubtitleSimple" = "ご自身の名前が表示されませんか?"; +"registrationPageOneSubtitleComposed" = "%@ さんではありませんか?"; + +// Info popovers +"registrationPageOneSubtitle_info" = "ご安心ください。Mac@IBM App Store にある「Assign User」で、いつでも情報を更新できます。"; +"registrationPageOneDisclaimerPolicies_infoElementOne" = "ファイアウォール"; +"registrationPageOneDisclaimerPolicies_infoElementTwo" = "ステルス・モード"; +"registrationPageOneDisclaimerPolicies_infoElementThree" = "ゲスト・ユーザー・アカウント"; +"registrationPageOneDisclaimerPolicies_infoElementFour" = "FileVault ディスク暗号化"; +"registrationPageOneDisclaimerPolicies_infoElementFive" = "macOS の初期パスワードの変更"; +"registrationPageOneDisclaimerPolicies_infoElementSix" = "スクリーン・セーバーのパスワード"; +"registrationPageOneDisclaimerPolicies_infoElementSeven_title" = "スクリーン・セーバーの開始時間"; +"registrationPageOneDisclaimerPolicies_infoElementSeven_description" = "30 分間の非アクティブ状態"; +"registrationPageOneDisclaimerPolicies_infoElementEight_title" = "エンドポイント保護ソフトウェア"; + +// Field labels +"registrationPageOneFieldRegion" = "地域"; +"registrationPageOneFieldComputer" = "コンピューター・タイプ"; +"registrationPageOneFieldOwner" = "資産所有者"; +"registrationPageOneFieldUser" = "ユーザー・タイプ"; + +// Region field options +"registrationPageOneFieldRegionOptionOne" = "米国"; +"registrationPageOneFieldRegionOptionTwo" = "カナダ"; +"registrationPageOneFieldRegionOptionThree" = "EMEA (ヨーロッパ、中東、アフリカ)"; +"registrationPageOneFieldRegionOptionFour" = "LA (ラテンアメリカ)"; +"registrationPageOneFieldRegionOptionFive" = "AP (アジア太平洋)"; + +// Computer Type options +"registrationPageOneFieldComputerOptionOne" = "プライマリー"; +"registrationPageOneFieldComputerOptionOne_info" = "単一ユーザーが通常の業務でオフィス生産性プラットフォームとして使用 (E メール、Web ブラウザー/Web アプリケーション、インスタント・メッセージ、ドキュメンテーションなど)。"; +"registrationPageOneFieldComputerOptionTwo" = "セカンダリー"; +"registrationPageOneFieldComputerOptionTwo_info" = "オフィス生産性業務以外の各種作業 (お客様へのデモ業務を含む) および仮想マシンに使用"; +"registrationPageOneFieldComputerOptionThree" = "共有"; +"registrationPageOneFieldComputerOptionThree_info" = "複数ユーザーへの教育と研修に使用"; +"registrationPageOneFieldComputerOptionFour" = "貸出"; +"registrationPageOneFieldComputerOptionFour_info" = "テストまたは開発に使用"; +"registrationPageOneFieldComputerOptionFive" = "クラスルーム"; +"registrationPageOneFieldComputerOptionFive_info" = "交換品や補充品として短期間使用"; +"registrationPageOneFieldComputerOptionSix" = "ラボ"; +"registrationPageOneFieldComputerOptionSix_info" = "複数ユーザーがオフィス生産性業務を含む各種作業に使用"; + +// Asset Owner options +"registrationPageOneFieldOwnerOptionOne" = "IBM 提供"; +"registrationPageOneFieldOwnerOptionTwo" = "個人所有"; +"registrationPageOneFieldOwnerOptionThree" = "第三者所有: ベンダー提供"; +"registrationPageOneFieldOwnerOptionFour" = "第三者所有: 契約業者提供"; +"registrationPageOneFieldOwnerOptionFive" = "第三者所有: お客様提供"; + +// User Type options +"registrationPageOneFieldUserOptionOne" = "標準"; +"registrationPageOneFieldUserOptionOne_info" = "特権またはコール・センターのユース・ケースにおける職務を除く、一般的な使用"; +"registrationPageOneFieldUserOptionTwo" = "特権"; +"registrationPageOneFieldUserOptionTwo_info" = "IBM またはお客様のネットワーク・デバイス、コンピューター・システム、ミドルウェア・コンポーネントまたはアプリケーションに対し、セキュリティー管理権限、システム権限を用いて行う業務に使用"; +"registrationPageOneFieldUserOptionThree" = "サービス/コール・センター"; +"registrationPageOneFieldUserOptionThree_info" = "サービス・センター、コール・センター、またはヘルプ・デスクの業務に使用"; + +// Policies disclaimer +"registrationPageOneDisclaimerPolicies" = "IBM のセキュリティー・ポリシーが自動的に適用されます。"; + +// MARK: - Registration: page two + +// Header +"registrationPageTwoTitle" = "あなたがアクセスする情報"; +"registrationPageTwoSubtitle" = "このコンピューターに保管されるデータのタイプを選択してください。"; + +// Information options +"registrationPageTwoFieldInformationOptionOne_title" = "機密個人情報 (SPI)"; +"registrationPageTwoFieldInformationOptionOne_description" = "このデバイスに個人情報 (PI) を保管する場合"; +"registrationPageTwoFieldInformationOptionTwo_title" = "お客様のデータ"; +"registrationPageTwoFieldInformationOptionTwo_description" = "このデバイスで、お客様所有またはお客様作成のデータを保管、またはそのようなデータにアクセスする場合"; +"registrationPageTwoFieldInformationOptionThree_title" = "政府による規制データ"; +"registrationPageTwoFieldInformationOptionThree_description" = "このデバイスで保管またはアクセスするデータは政府による規制の対象となるものであるという連絡を経営上層部、データ所有者、またはデータ管理人から受けている場合 (例えば、一部の医療データは追加的保護の対象となります)"; +"registrationPageTwoFieldInformationOptionFour_title" = "FFIEC (米国連邦金融機関検査協議会) データ"; +"registrationPageTwoFieldInformationOptionFour_description" = "お客様の金融環境を支援しているか、お客様の金融環境にアクセスできる場合"; +"registrationPageTwoFieldInformationOptionFive_title" = "HIPAA (医療保険の積算と責任に関する法律) データ"; +"registrationPageTwoFieldInformationOptionFive_description" = "HIPAA による規制の対象となる顧客アカウントまたはマルチテナント・オファリングをサポートする場合"; +"registrationPageTwoFieldInformationOptionSix_title" = "PCI データ"; +"registrationPageTwoFieldInformationOptionSix_description" = "このデバイスがお客様所有またはお客様作成の機密性の高い支払カード (クレジット・カードなど) データを保管するか、そのようなデータにアクセスする場合"; +"registrationPageTwoFieldInformationOptionSeven_title" = "上記のいずれにも該当しない"; +"registrationPageTwoFieldInformationOptionSeven_description" = ""; + +// MARK: - Registration: loading page + +// State labels +"registrationLoadingPageStateOne" = "ネットワークの速度をテストしています"; +"registrationLoadingPageStateTwo" = "登録を完了しています"; +"registrationLoadingPageStateForPhaseThree" = "登録を更新しています"; + +// MARK: - Registration: final page + +// Header +"registrationFinalPageTitle" = "登録が完了しました"; +"registrationFinalPageTitlePhaseThree" = "登録の詳細"; +"registrationFinalPageTitlePhaseFour" = "ようこそ"; +"registrationFinalPageSubtitleStandard" = "Mac をセットアップしましょう"; +"registrationFinalPageSubtitlePhaseThree" = ""; +"registrationFinalPageInstructionalMessage" = "次にログインしたときに、新しい macOS ログイン・パスワードを入力し、FileVault ディスク暗号化を有効にするよう求められます。"; +"registrationFinalPageCountdownMessage" = "セットアップ・プロセスを続行するために、%d 秒後に Mac が自動的に再起動されます。「再起動」を選択して、今すぐ続行することもできます。"; + +// MARK: - Installation: bundle selection page + +// Header +"installationBundleSelectionPageTitle" = "始めるためのアプリ・バンドル"; +"installationBundleSelectionPageSubtitle" = "追加のアプリを Mac@IBM App Store からいつでもインストールできます。"; + +// Labels +"installationBundleSelectionPageRecommended" = "(推奨)"; + +// Bundle one +"installationBundleSelectionPageBundleOneTitle" = "接続"; +"installationBundleSelectionPageBundleOneDescription" = "必要なソフトウェアおよび証明書を使用して IBM ネットワークに接続します"; +"installationBundleSelectionPageBundleOnePopoverTitle" = "接続バンドル"; +"installationBundleSelectionPageBundleOnePopoverDescription" = "証明書およびソフトウェアを使用して IBM ネットワークに接続します"; +"installationBundleSelectionPageBundleOneAppOneTitle" = "AnyConnect"; +"installationBundleSelectionPageBundleOneAppOneDescription" = "Ipsum lorem 1"; + +// Bundle two +"installationBundleSelectionPageBundleTwoTitle" = "基本"; +"installationBundleSelectionPageBundleTwoDescription" = "業務を始めるのに必要となる、最も一般的な IBM ツールです。"; +"installationBundleSelectionPageBundleTwoPopoverTitle" = "基本バンドル"; +"installationBundleSelectionPageBundleTwoPopoverDescription" = "多くの社員が使用するアプリ"; +"installationBundleSelectionPageBundleTwoAppOneTitle" = "IBM Notes"; +"installationBundleSelectionPageBundleTwoAppOneDescription" = "IBM メールを送受信し、データベースを操作します"; +"installationBundleSelectionPageBundleTwoAppTwoTitle" = "Webex Meetings"; +"installationBundleSelectionPageBundleTwoAppTwoDescription" = "ビデオ/オーディオ会議と Web ミーティングの機能を提供します"; +"installationBundleSelectionPageBundleTwoAppThreeTitle" = "Code42 CrashPlan"; +"installationBundleSelectionPageBundleTwoAppThreeDescription" = "この Mac のファイルを安全にバックアップおよびリストアします"; +"installationBundleSelectionPageBundleTwoAppFourTitle" = "BluePages"; +"installationBundleSelectionPageBundleTwoAppFourDescription" = "社員情報の検索を高速かつ簡単に行います"; +"installationBundleSelectionPageBundleTwoAppFiveTitle" = "IBM ブックマーク"; +"installationBundleSelectionPageBundleTwoAppFiveDescription" = "よく使われる IBM Web サイトへのリンクです"; + +// Bundle three +"installationBundleSelectionPageBundleThreeTitle" = "生産性"; +"installationBundleSelectionPageBundleThreeDescription" = "ワード・プロセッサー、スプレッドシートなどを使用して生産性を向上しましょう。"; +"installationBundleSelectionPageBundleThreePopoverTitle" = "生産性バンドル"; +"installationBundleSelectionPageBundleThreePopoverDescription" = "資料作成やコラボレーションに役立つツール。"; +"installationBundleSelectionPageBundleThreeAppOneTitle" = "Office 365"; +"installationBundleSelectionPageBundleThreeAppOneDescription" = "Microsoft Word、Excel、PowerPoint、OneNote、および Outlook"; +"installationBundleSelectionPageBundleThreeAppTwoTitle" = "Slack"; +"installationBundleSelectionPageBundleThreeAppTwoDescription" = "IBM 内のチームとのコミュニケーションおよびコラボレーションに使用します"; +"installationBundleSelectionPageBundleThreeAppThreeTitle" = "Box Drive"; +"installationBundleSelectionPageBundleThreeAppThreeDescription" = "ファイルの保管、共有、同期を行います"; + +// MARK: - Installation: bundle installation page +"installationBundleInstallationPageTitle" = "選択したアプリ・バンドルをインストールしています..."; +"installationBundleInstallationPageSubtitle" = "推定残り時間: "; +"installationBundleInstallationPageHideAppLabel" = "アプリを非表示"; +"installationBundleInstallationPageShowAppLabel" = "アプリを表示"; + +// MARK: - Installation: final page + +// Header +"installationFinalPageTitle" = "Mac の使用を開始する"; + +// Elements +"installationFinalPageElementOneTitle" = "Mac@IBM App Store\nからアプリを入手"; +"installationFinalPageElementOneDescription" = "Microsoft Office、Slack、IBM Notes などがあります。"; +"installationFinalPageElementTwoTitle" = "他のコンピューターから\nデータを移行"; +"installationFinalPageElementTwoDescription" = "重要な情報をこの新しい Mac に\n転送します。"; +"installationFinalPageElementThreeTitle" = "Code42 CrashPlan で\nMac をバックアップ"; +"installationFinalPageElementThreeDescription" = "インストールしてアカウントをセットアップ\nすると安心です。"; +"installationFinalPageElementThreeDescriptionAlternate" = "アカウントをセットアップ\nすると安心です。"; +"installationFinalPageElementFourTitle" = "Help@IBM のヒント、チュートリアル、\nおよびサポートを表示"; +"installationFinalPageElementFourDescription" = "IBM の Apple 専用ヘルプ・デスクのアドバイザーにアクセスします。"; +"installationFinalPageElementFiveTitle" = "IBM Notes をご利用の場合、\nNotes ID ファイルをインストール"; +"installationFinalPageElementFiveDescription" = "IBM Notes をインストールし、E メール・クライアントとしてセットアップします。"; +"installationFinalPAgeElementSixTitle" = "w3 ホーム・ページに移動"; +"installationFinalPageElementSixDescription" = "w3 のコンテンツや BluePages を検索します。"; + +// Footer +"installationFinalPageFooterLabel" = " Mac の次回再起動時に通知する"; + +// MARK: - Installation: Notes wizard page + +// Header +"filePickerPageTitle" = "Notes ID ファイルのインストール"; +"filePickerPageSubtitle" = "IBM Notes のセットアップを完了するには、Notes ID が必要です。後で追加することもできます。"; + +// Messages +"filePickerPageMessageSuccess" = "Notes ID が正常にインストールされました。"; +"filePickerPageMessageFailure" = "Notes ID ファイルをインストールできませんでした。"; +"filePickerPageMessageAlreadyExist" = "Notes ID ファイルは既に存在します。新たにインストールすることができます。"; + +// Labels +"filePickerPageButtonBrowse" = "Notes ID ファイルを参照"; +"filePickerPageButtonRemove" = "削除"; +"filePickerPageCenterLabel" = "Notes ID ファイルをドラッグ & ドロップ"; +"filePickerPageAlertMessage" = "ファイルが存在します"; +"filePickerPageAlertInformativeText" = "宛先にはファイルが既に存在します。選択したファイルで既存のファイルを置き換えますか?"; +"filePickerPageFileSelectionPanelTitle" = "IBM Notes の構成に使用する ID ファイルを選択してください"; +"filePickerPageButtonInstall" = "Notes ID ファイルのインストール"; + +// MARK: - Alert labels + +// Un-enrollment +"unenrollmentAlertTitle" = "登録プロセスを終了しますか?"; +"unenrollmentAlertMessage" = "今キャンセルすると、すべてのセキュリティー設定が元に戻され、このコンピューターが管理対象から削除されます。"; +"unenrollmentCancelled" = "フレームワークの削除アクションがキャンセルされました"; + +// Bundle selection +"bundleSelectionAlertTitle" = "続行しますか?"; +"bundleSelectionAlertMessage" = "現在、ネットワークの速度が遅いようです。インストールするバンドルの数を減らすことをお勧めします。"; + +// Bundle installation +"bundleInstallationalertMessage" = "一部のアプリケーションのインストールで問題が発生しました。後で、セルフサービスを使用してインストールしてください。"; + +// Launch failure +"launchFailureAlertTitle" = "このアプリケーションはデバイス管理を必要とします。"; +"launchFailureAlertMessage" = "このデバイスを登録してください。"; + +// External network problem +"externalNetworkAlertMessage" = "インターネットに接続されていません。続行する前に、インターネット・アクセスのあるネットワークに Mac を接続してください。"; +"externalNetworkJspMessage" = "セルフサービスは現在ご利用になれません。後で再試行してください。"; + +// Internal network problem +"internalNetworkProblemAlertMessage" = "\n\n続行するには、イントラネットに接続する必要があります。"; + +// Terms and conditions drop down +"termsAndConditionsTitle" = "個人用デバイスの使用に関する IBM 契約"; +"termsAndConditionsBody" = "このデバイスを「個人所有」として登録することが選択されました。個人所有のデバイスを IBM の業務に使用するには、特定の規約事項に従う必要があります。\n\nIBM の規約事項を確認し、同意するかどうかを指定してください。"; +"termsAndConditionsButtonLink" = "IBM の規約事項を読む"; +"termsAndConditionsButtonAccept" = "同意する"; + +// MARK: - Common button labels +"buttonLabelOk" = "OK"; +"buttonLabelCancel" = "キャンセル"; +"buttonLabelNext" = "次へ"; +"buttonLabelRestart" = "再起動"; +"buttonLabelClose" = "閉じる"; +"buttonLabelBack" = "戻る"; +"buttonLabelOkWithQuestionMark" = "OK?"; +"buttonLabelQuit" = "終了"; +"buttonLabelReplace" = "置き換え"; +"buttonLabelUpdateInfo" = "詳細の編集"; +"buttonLabelUnenroll" = "登録のキャンセル"; + +// MARK: - Common labels +"labelEnabled" = "有効"; +"labelDisabled" = "無効"; +"labelRequired" = "必須"; +"restartFailureMessage" = "コンピューターを再起動できませんでした"; +"restartFailureComment" = "再起動失敗のアラート"; +"estimatedInstallTimeMessage" = "%@ \n \n 推定インストール時間: %@"; +"labelChooseAnswer" = "回答を選択してください。"; +"labelNo" = "いいえ"; +"labelYes" = "はい"; +"buttonLabelInstall" = "選択したバンドルのインストール"; +"buttonLabelSkip" = "スキップ"; diff --git a/enrollment/enrollment/ko.lproj/Localizable.strings b/enrollment/enrollment/ko.lproj/Localizable.strings new file mode 100644 index 0000000..00145b8 --- /dev/null +++ b/enrollment/enrollment/ko.lproj/Localizable.strings @@ -0,0 +1,272 @@ +/* + Localizable.strings + enrollment + + Created by Simone Martorelli on 2/5/20. + Copyright © 2020 IBM. All rights reserved. + SPDX-License-Identifier: GPL-3.0-only + */ + +/// MARK: - Note to the translation +/// +/// Pay attention to not modify, cancel or move the special characters: +/// - %d - This special character is substituted with a number at runtime; +/// - %@ - This special characted is substituted with a string at runtime; +/// - \n - This special characted works like the "return" key; +/// - \" - This special characted insert a "; + +// MARK: - Registration: page one + +// Header +"registrationPageOneTitleSimple" = "여러분을 환영합니다!"; +"registrationPageOneTitleComposed" = "%@님 환영합니다!"; +"registrationPageOneSubtitleSimple" = "이름이 보이지 않으십니까?"; +"registrationPageOneSubtitleComposed" = "%@님이 아니십니까?"; + +// Info popovers +"registrationPageOneSubtitle_info" = "걱정하지 마십시오. 나중에 Mac@IBM App Store를 사용해서 \"사용자 지정\"을 검색하여 업데이트할 수 있습니다. "; +"registrationPageOneDisclaimerPolicies_infoElementOne" = "방화벽"; +"registrationPageOneDisclaimerPolicies_infoElementTwo" = "스텔스 모드"; +"registrationPageOneDisclaimerPolicies_infoElementThree" = "게스트 사용자 계정"; +"registrationPageOneDisclaimerPolicies_infoElementFour" = "FileVault 디스크 암호화"; +"registrationPageOneDisclaimerPolicies_infoElementFive" = "초기 macOS 비밀번호 변경"; +"registrationPageOneDisclaimerPolicies_infoElementSix" = "화면 보호기 비밀번호"; +"registrationPageOneDisclaimerPolicies_infoElementSeven_title" = "화면 보호기 시작 시간"; +"registrationPageOneDisclaimerPolicies_infoElementSeven_description" = "30분 간 비활성"; +"registrationPageOneDisclaimerPolicies_infoElementEight_title" = "엔드포인트 보호 소프트웨어"; + +// Field labels +"registrationPageOneFieldRegion" = "지역"; +"registrationPageOneFieldComputer" = "컴퓨터 유형"; +"registrationPageOneFieldOwner" = "자산 소유자"; +"registrationPageOneFieldUser" = "사용자 유형"; + +// Region field options +"registrationPageOneFieldRegionOptionOne" = "미국"; +"registrationPageOneFieldRegionOptionTwo" = "캐나다"; +"registrationPageOneFieldRegionOptionThree" = "EMEA(유럽, 중동, 아프리카)"; +"registrationPageOneFieldRegionOptionFour" = "LA(라틴 아메리카)"; +"registrationPageOneFieldRegionOptionFive" = "AP(아시아 태평양)"; + +// Computer Type options +"registrationPageOneFieldComputerOptionOne" = "기본"; +"registrationPageOneFieldComputerOptionOne_info" = "단일 사용자를 위해 일반적인 사무실 생산성 플랫폼(예: 이메일, 웹 브라우징/애플리케이션, 인스턴트 메시징, 문서화 등)을 제공합니다. "; +"registrationPageOneFieldComputerOptionTwo" = "보조"; +"registrationPageOneFieldComputerOptionTwo_info" = "고객 데모 활동 및 가상 머신을 포함한 사무실 생산성 활동을 제외한 다양한 태스크에 사용할 수 있습니다."; +"registrationPageOneFieldComputerOptionThree" = "공유"; +"registrationPageOneFieldComputerOptionThree_info" = "여러 사용자가 교육 및 훈련을 위해 사용합니다. "; +"registrationPageOneFieldComputerOptionFour" = "대여"; +"registrationPageOneFieldComputerOptionFour_info" = "테스트 및/또는 개발을 목적으로 합니다. "; +"registrationPageOneFieldComputerOptionFive" = "강의실"; +"registrationPageOneFieldComputerOptionFive_info" = "대체 또는 보완용으로 단기적으로 사용됩니다. "; +"registrationPageOneFieldComputerOptionSix" = "연구실"; +"registrationPageOneFieldComputerOptionSix_info" = "여러 사용자가 사무실 생산성 활동을 포함한 다양한 태스크에 사용할 수 있습니다. "; + +// Asset Owner options +"registrationPageOneFieldOwnerOptionOne" = "IBM 제공"; +"registrationPageOneFieldOwnerOptionTwo" = "개인 소유"; +"registrationPageOneFieldOwnerOptionThree" = "제3자 소유: 공급업체 제공"; +"registrationPageOneFieldOwnerOptionFour" = "제3자 소유: 계약자 대행사 제공"; +"registrationPageOneFieldOwnerOptionFive" = "제3자 소유: 고객 제공"; + +// User Type options +"registrationPageOneFieldUserOptionOne" = "표준"; +"registrationPageOneFieldUserOptionOne_info" = "권한 있는 유스 케이스 또는 콜 센터 유스 케이스에서 수행하는 업무 외의 일반적인 사용입니다. "; +"registrationPageOneFieldUserOptionTwo" = "권한"; +"registrationPageOneFieldUserOptionTwo_info" = "IBM 또는 고객의 보안 관리 권한, 네트워크 디바이스, 컴퓨터 시스템, 미들웨어 구성요소 또는 애플리케이션의 시스템 권한이 지정되어 있습니다. "; +"registrationPageOneFieldUserOptionThree" = "서비스/콜 센터"; +"registrationPageOneFieldUserOptionThree_info" = "서비스 센터, 콜 센터 또는 헬프 데스크에 지정됩니다. "; + +// Policies disclaimer +"registrationPageOneDisclaimerPolicies" = "IBM 보안 정책이 자동으로 적용됩니다."; + +// MARK: - Registration: page two + +// Header +"registrationPageTwoTitle" = "액세스하는 정보"; +"registrationPageTwoSubtitle" = "이 컴퓨터에 저장된 데이터 유형을 선택하십시오. "; + +// Information options +"registrationPageTwoFieldInformationOptionOne_title" = "민감한 개인 정보(SPI)"; +"registrationPageTwoFieldInformationOptionOne_description" = "디바이스에 개인 정보(PI)가 저장됩니다. "; +"registrationPageTwoFieldInformationOptionTwo_title" = "고객 데이터"; +"registrationPageTwoFieldInformationOptionTwo_description" = "디바이스가 고객이 소유하거나 작성한 데이터를 저장하거나 액세스하는 데 사용됩니다. "; +"registrationPageTwoFieldInformationOptionThree_title" = "정부 규제 대상 데이터"; +"registrationPageTwoFieldInformationOptionThree_description" = "관리, 데이터 소유자 또는 관리자로부터 디바이스에 저장되거나 액세스되는 데이터가 정부의 제한이나 규제를 받는다는 정보를 받았습니다. 예를 들어, 일부 의료 데이터는 추가 보호의 대상이 됩니다. "; +"registrationPageTwoFieldInformationOptionFour_title" = "연방 금융기관 심사 위원회(FFIEC) 데이터"; +"registrationPageTwoFieldInformationOptionFour_description" = "고객의 재무 환경을 지원하거나 액세스할 수 있습니다. "; +"registrationPageTwoFieldInformationOptionFive_title" = "의료보험의 양도 및 책임에 관한 법률(HIPAA) 데이터"; +"registrationPageTwoFieldInformationOptionFive_description" = "HIPAA 규제 대상 고객 계정 또는 멀티테넌트 오퍼링을 지원합니다. "; +"registrationPageTwoFieldInformationOptionSix_title" = "PCI 데이터"; +"registrationPageTwoFieldInformationOptionSix_description" = "디바이스가 고객이 소유하거나 생성한 중요한 결제 카드(예: 신용카드) 데이터를 저장하거나 액세스합니다. "; +"registrationPageTwoFieldInformationOptionSeven_title" = "해당 항목 없음"; +"registrationPageTwoFieldInformationOptionSeven_description" = ""; + +// MARK: - Registration: loading page + +// State labels +"registrationLoadingPageStateOne" = "네트워크 속도 테스트"; +"registrationLoadingPageStateTwo" = "등록 완료"; +"registrationLoadingPageStateForPhaseThree" = "등록 업데이트"; + +// MARK: - Registration: final page + +// Header +"registrationFinalPageTitle" = "등록 완료"; +"registrationFinalPageTitlePhaseThree" = "등록 세부사항"; +"registrationFinalPageTitlePhaseFour" = "환영합니다!"; +"registrationFinalPageSubtitleStandard" = "Mac을 설정해 주십시오!"; +"registrationFinalPageSubtitlePhaseThree" = ""; +"registrationFinalPageInstructionalMessage" = "다음에 로그인하면 새로운 macOS 로그인 비밀번호를 입력하고 FileVault 디스크 암호화를 활성화하라는 메시지가 표시됩니다. "; +"registrationFinalPageCountdownMessage" = "설정 과정을 계속하기 위해 Mac이 %d초 안에 자동으로 재시작되거나, \"재시작\"을 선택하여 지금 진행할 수 있습니다. "; + +// MARK: - Installation: bundle selection page + +// Header +"installationBundleSelectionPageTitle" = "시작하기 위한 앱 번들"; +"installationBundleSelectionPageSubtitle" = "Mac@IBM App Store에서 언제든지 추가 앱을 설치할 수 있습니다. "; + +// Labels +"installationBundleSelectionPageRecommended" = "(권장)"; + +// Bundle one +"installationBundleSelectionPageBundleOneTitle" = "연결"; +"installationBundleSelectionPageBundleOneDescription" = "필요한 소프트웨어 및 인증서를 사용하여 IBM 네트워크에 연결"; +"installationBundleSelectionPageBundleOnePopoverTitle" = "연결 번들"; +"installationBundleSelectionPageBundleOnePopoverDescription" = "인증서 및 소프트웨어로 네트워크에 연결"; +"installationBundleSelectionPageBundleOneAppOneTitle" = "AnyConnect"; +"installationBundleSelectionPageBundleOneAppOneDescription" = "Ipsum lorem 1"; + +// Bundle two +"installationBundleSelectionPageBundleTwoTitle" = "필수"; +"installationBundleSelectionPageBundleTwoDescription" = "가장 일반적인 IBM 도구를 사용하여 시작하십시오. "; +"installationBundleSelectionPageBundleTwoPopoverTitle" = "필수 번들"; +"installationBundleSelectionPageBundleTwoPopoverDescription" = "대부분의 직원이 사용하는 앱"; +"installationBundleSelectionPageBundleTwoAppOneTitle" = "IBM Notes"; +"installationBundleSelectionPageBundleTwoAppOneDescription" = "IBM 메일 송수신 및 데이터베이스와 상호 작용"; +"installationBundleSelectionPageBundleTwoAppTwoTitle" = "Webex Meetings"; +"installationBundleSelectionPageBundleTwoAppTwoDescription" = "화상 및 음성 회의 및 웹 회의 기능 결합"; +"installationBundleSelectionPageBundleTwoAppThreeTitle" = "Code42 CrashPlan"; +"installationBundleSelectionPageBundleTwoAppThreeDescription" = "Mac에서 파일을 안전하게 백업 및 복원"; +"installationBundleSelectionPageBundleTwoAppFourTitle" = "BluePages"; +"installationBundleSelectionPageBundleTwoAppFourDescription" = "빠르고 편리한 직원 디렉토리 검색"; +"installationBundleSelectionPageBundleTwoAppFiveTitle" = "IBM Bookmarks"; +"installationBundleSelectionPageBundleTwoAppFiveDescription" = "일반적으로 사용되는 IBM 웹 사이트에 대한 링크"; + +// Bundle three +"installationBundleSelectionPageBundleThreeTitle" = "생산성"; +"installationBundleSelectionPageBundleThreeDescription" = "워드 프로세싱, 스프레드 시트 및 사무 프로그램으로 생산성을 향상시키십시오. "; +"installationBundleSelectionPageBundleThreePopoverTitle" = "생산성 번들"; +"installationBundleSelectionPageBundleThreePopoverDescription" = "작성 및 협업을 돕는 도구입니다. "; +"installationBundleSelectionPageBundleThreeAppOneTitle" = "Office 365"; +"installationBundleSelectionPageBundleThreeAppOneDescription" = "Microsoft Word, Excel, PowerPoint, OneNote 및 Outlook"; +"installationBundleSelectionPageBundleThreeAppTwoTitle" = "Slack"; +"installationBundleSelectionPageBundleThreeAppTwoDescription" = "IBM 전체의 팀과 커뮤니케이션 및 협업"; +"installationBundleSelectionPageBundleThreeAppThreeTitle" = "Box Drive"; +"installationBundleSelectionPageBundleThreeAppThreeDescription" = "파일 저장, 공유 및 동기화"; + +// MARK: - Installation: bundle installation page +"installationBundleInstallationPageTitle" = "선택한 앱 번들 설치 중…"; +"installationBundleInstallationPageSubtitle" = "남은 예상 시간:"; +"installationBundleInstallationPageHideAppLabel" = "앱 숨기기"; +"installationBundleInstallationPageShowAppLabel" = "앱 표시"; + +// MARK: - Installation: final page + +// Header +"installationFinalPageTitle" = "Mac 시작하기"; + +// Elements +"installationFinalPageElementOneTitle" = "Mac@IBM App Store에서\n앱 가져오기"; +"installationFinalPageElementOneDescription" = "Microsoft Office, Slack, IBM Notes 및 기타!"; +"installationFinalPageElementTwoTitle" = "다른 컴퓨터에서 데이터를\n마이그레이션"; +"installationFinalPageElementTwoDescription" = "중요한 정보를 새로운\nMac으로 전송합니다."; +"installationFinalPageElementThreeTitle" = "Code42 CrashPlan으로\nMac 백업"; +"installationFinalPageElementThreeDescription" = "계정 설치 및 설정 후\n안심하고 사용하십시오."; +"installationFinalPageElementThreeDescriptionAlternate" = "계정 설정 후\n안심하고 사용하십시오."; +"installationFinalPageElementFourTitle" = "Help@IBM에 대한 팁, 학습서 및 \n지원 보기"; +"installationFinalPageElementFourDescription" = "IBM의 전담 Apple 헬프 데스크 전문가에게 문의하십시오. "; +"installationFinalPageElementFiveTitle" = "Notes를 사용하십니까? \nNotes ID 파일을 설치하십시오. "; +"installationFinalPageElementFiveDescription" = "Notes를 이메일 클라이언트로 설치하고 설정하십시오. "; +"installationFinalPAgeElementSixTitle" = "w3 홈 페이지로 이동"; +"installationFinalPageElementSixDescription" = "w3 장소 및 BluePages 검색"; + +// Footer +"installationFinalPageFooterLabel" = " 다음에 Mac을 재시작할 때 알리기."; + +// MARK: - Installation: Notes wizard page + +// Header +"filePickerPageTitle" = "Notes ID 파일 설치"; +"filePickerPageSubtitle" = "Notes 설정을 완료하려면 Notes ID가 필요합니다. 나중에 추가할 수도 있습니다. "; + +// Messages +"filePickerPageMessageSuccess" = "Notes ID가 성공적으로 설치되었습니다! "; +"filePickerPageMessageFailure" = "Notes ID 파일을 설치할 수 없습니다. "; +"filePickerPageMessageAlreadyExist" = "Notes ID 파일이 이미 존재합니다. 새로 설치할 수 있습니다. "; + +// Labels +"filePickerPageButtonBrowse" = "Notes ID 파일 찾아보기"; +"filePickerPageButtonRemove" = "제거"; +"filePickerPageCenterLabel" = "Notes ID 파일 끌어다 놓기"; +"filePickerPageAlertMessage" = "파일이 존재합니다. "; +"filePickerPageAlertInformativeText" = "파일이 대상에 이미 존재합니다. 기존 파일을 선택한 파일로 바꾸시겠습니까? "; +"filePickerPageFileSelectionPanelTitle" = "Notes를 구성하는 데 사용할 ID 파일을 선택하십시오. "; +"filePickerPageButtonInstall" = "Notes ID 파일 설치"; + +// MARK: - Alert labels + +// Un-enrollment +"unenrollmentAlertTitle" = "등록 절차를 종료하시겠습니까?"; +"unenrollmentAlertMessage" = "지금 취소하면 모든 보안 설정이 취소되고 이 컴퓨터가 관리에서 제거됩니다. "; +"unenrollmentCancelled" = "프레임워크 제거 조치가 취소되었습니다. "; + +// Bundle selection +"bundleSelectionAlertTitle" = "계속하시겠습니까?"; +"bundleSelectionAlertMessage" = "현재 네트워크 속도가 느린 것 같습니다. 더 적은 수의 번들을 설치하는 것이 좋습니다. "; + +// Bundle installation +"bundleInstallationalertMessage" = "일부 애플리케이션을 설치하는 데 문제가 있었습니다. 나중에 셀프 서비스를 사용하여 설치하십시오. "; + +// Launch failure +"launchFailureAlertTitle" = "이 애플리케이션은 디바이스 관리가 필요합니다. "; +"launchFailureAlertMessage" = "이 디바이스를 등록하십시오. "; + +// External network problem +"externalNetworkAlertMessage" = "인터넷에 연결되어 있지 않습니다. 계속하기 전에 Mac이 인터넷 연결된 네트워크에 연결되어 있는지 확인하십시오. "; +"externalNetworkJspMessage" = "현재 셀프 서비스를 이용할 수 없습니다. 나중에 다시 시도하십시오. "; + +// Internal network problem +"internalNetworkProblemAlertMessage" = "\n\n계속 진행하려면 인트라넷에 연결해야 합니다. "; + +// Terms and conditions drop down +"termsAndConditionsTitle" = "개인 디바이스 사용에 대한 IBM 계약"; +"termsAndConditionsBody" = "이 디바이스를 “개인 소유”로 등록하도록 선택했습니다. 개인 소유 디바이스를 사용하여 IBM Business를 수행하는 경우 특정 이용 약관이 적용됩니다.\n\nIBM 이용 약관을 검토하고 동의 여부를 표시하십시오."; +"termsAndConditionsButtonLink" = "IBM 이용 약관 읽기"; +"termsAndConditionsButtonAccept" = "동의"; + +// MARK: - Common button labels +"buttonLabelOk" = "확인"; +"buttonLabelCancel" = "취소"; +"buttonLabelNext" = "다음"; +"buttonLabelRestart" = "다시 시작"; +"buttonLabelClose" = "닫기"; +"buttonLabelBack" = "이전"; +"buttonLabelOkWithQuestionMark" = "확인?"; +"buttonLabelQuit" = "종료"; +"buttonLabelReplace" = "바꾸기"; +"buttonLabelUpdateInfo" = "세부사항 편집"; +"buttonLabelUnenroll" = "등록 취소"; + +// MARK: - Common labels +"labelEnabled" = "사용"; +"labelDisabled" = "사용 안함"; +"labelRequired" = "필수"; +"restartFailureMessage" = "컴퓨터를 다시 시작할 수 없습니다. "; +"restartFailureComment" = "다시 시작 실패 경보"; +"estimatedInstallTimeMessage" = "%@ \n \n 예상 설치 시간: %@"; +"labelChooseAnswer" = "답변을 선택하십시오. "; +"labelNo" = "아니오"; +"labelYes" = "예"; +"buttonLabelInstall" = "선택된 번들 설치"; +"buttonLabelSkip" = "건너뛰기"; diff --git a/enrollment/enrollment/pt-BR.lproj/Localizable.strings b/enrollment/enrollment/pt-BR.lproj/Localizable.strings new file mode 100644 index 0000000..349e9d0 --- /dev/null +++ b/enrollment/enrollment/pt-BR.lproj/Localizable.strings @@ -0,0 +1,272 @@ +/* + Localizable.strings + enrollment + + Created by Simone Martorelli on 2/5/20. + Copyright © 2020 IBM. All rights reserved. + SPDX-License-Identifier: GPL-3.0-only + */ + +/// MARK: - Note to the translation +/// +/// Pay attention to not modify, cancel or move the special characters: +/// - %d - This special character is substituted with a number at runtime; +/// - %@ - This special characted is substituted with a string at runtime; +/// - \n - This special characted works like the "return" key; +/// - \" - This special characted insert a "; + +// MARK: - Registration: page one + +// Header +"registrationPageOneTitleSimple" = "Bem-vindo, novo funcionário!"; +"registrationPageOneTitleComposed" = "Bem-vindo, %@!"; +"registrationPageOneSubtitleSimple" = "Não está vendo o seu nome?"; +"registrationPageOneSubtitleComposed" = "Não é o %@?"; + +// Info popovers +"registrationPageOneSubtitle_info" = "Não se preocupe, será possível fazer essa atualização mais tarde usando a Mac@IBM App Store e procurando por \"Designar Usuário\"."; +"registrationPageOneDisclaimerPolicies_infoElementOne" = "Firewall"; +"registrationPageOneDisclaimerPolicies_infoElementTwo" = "Modo Stealth"; +"registrationPageOneDisclaimerPolicies_infoElementThree" = "Conta do Usuário Guest"; +"registrationPageOneDisclaimerPolicies_infoElementFour" = "Criptografia de disco FileVault"; +"registrationPageOneDisclaimerPolicies_infoElementFive" = "Mudança inicial de senha do macOS"; +"registrationPageOneDisclaimerPolicies_infoElementSix" = "Senha do ScreenSaver"; +"registrationPageOneDisclaimerPolicies_infoElementSeven_title" = "Horário de início do ScreenSaver"; +"registrationPageOneDisclaimerPolicies_infoElementSeven_description" = "30 minutos de inatividade"; +"registrationPageOneDisclaimerPolicies_infoElementEight_title" = "Software de proteção de terminal"; + +// Field labels +"registrationPageOneFieldRegion" = "Região"; +"registrationPageOneFieldComputer" = "Tipo de sistema computacional"; +"registrationPageOneFieldOwner" = "Proprietário do ativo"; +"registrationPageOneFieldUser" = "Tipo de usuário"; + +// Region field options +"registrationPageOneFieldRegionOptionOne" = "EUA"; +"registrationPageOneFieldRegionOptionTwo" = "Canadá"; +"registrationPageOneFieldRegionOptionThree" = "EOMA (Europa, Oriente Médio, África)"; +"registrationPageOneFieldRegionOptionFour" = "AL (América Latina)"; +"registrationPageOneFieldRegionOptionFive" = "AP (Ásia Pacífico)"; + +// Computer Type options +"registrationPageOneFieldComputerOptionOne" = "Primário"; +"registrationPageOneFieldComputerOptionOne_info" = "para um único usuário como uma plataforma de produtividade de escritório para o trabalho normal de escritório (por exemplo, e-mail, aplicativos/navegação na web, mensagens instantâneas, documentação etc.)"; +"registrationPageOneFieldComputerOptionTwo" = "Secundário"; +"registrationPageOneFieldComputerOptionTwo_info" = "para várias tarefas, excluindo atividades de produtividade de escritório, incluindo atividades de demonstração do cliente e máquinas virtuais"; +"registrationPageOneFieldComputerOptionThree" = "Compartilhado"; +"registrationPageOneFieldComputerOptionThree_info" = "usado por vários usuários para educação e treinamento"; +"registrationPageOneFieldComputerOptionFour" = "Empréstimo"; +"registrationPageOneFieldComputerOptionFour_info" = "para o propósito de teste e/ou desenvolvimento"; +"registrationPageOneFieldComputerOptionFive" = "Sala de aula"; +"registrationPageOneFieldComputerOptionFive_info" = "usado a curto prazo, como substituto ou suplemento"; +"registrationPageOneFieldComputerOptionSix" = "Laboratório"; +"registrationPageOneFieldComputerOptionSix_info" = "para uso de vários usuários em várias tarefas, incluindo atividades de produtividade no escritório"; + +// Asset Owner options +"registrationPageOneFieldOwnerOptionOne" = "Fornecido pela IBM"; +"registrationPageOneFieldOwnerOptionTwo" = "De propriedade pessoal"; +"registrationPageOneFieldOwnerOptionThree" = "De propriedade de terceiro: fornecido pelo fabricante"; +"registrationPageOneFieldOwnerOptionFour" = "De propriedade de terceiro: fornecido pela agência do contratado"; +"registrationPageOneFieldOwnerOptionFive" = "De propriedade de terceiro: fornecido pelo Cliente"; + +// User Type options +"registrationPageOneFieldUserOptionOne" = "Padrão"; +"registrationPageOneFieldUserOptionOne_info" = "uso geral fora das tarefas desempenhadas pelos casos de uso Privilegiado ou Central de atendimento"; +"registrationPageOneFieldUserOptionTwo" = "Privilegiado"; +"registrationPageOneFieldUserOptionTwo_info" = "sob a designação de autoridades administrativas de segurança, de autoridades de sistema em dispositivos de rede, sistemas computacionais, componentes de middleware ou aplicativos para IBM ou clientes "; +"registrationPageOneFieldUserOptionThree" = "Serviço/Central de atendimento"; +"registrationPageOneFieldUserOptionThree_info" = "designado a um Centro de serviços, uma Central de atendimento ou um Help Desk"; + +// Policies disclaimer +"registrationPageOneDisclaimerPolicies" = "As políticas de segurança IBM serão aplicadas automaticamente."; + +// MARK: - Registration: page two + +// Header +"registrationPageTwoTitle" = "Informações que você acessa"; +"registrationPageTwoSubtitle" = "Selecione os tipos de dados armazenados neste sistema computacional."; + +// Information options +"registrationPageTwoFieldInformationOptionOne_title" = "Informações Pessoais Sensíveis (IPS)"; +"registrationPageTwoFieldInformationOptionOne_description" = "seu dispositivo armazena Informações Pessoais (IP)"; +"registrationPageTwoFieldInformationOptionTwo_title" = "Dados do cliente"; +"registrationPageTwoFieldInformationOptionTwo_description" = "o dispositivo armazena ou é usado para acessar dados pertencentes ou criados por um cliente"; +"registrationPageTwoFieldInformationOptionThree_title" = "Dados regulados pelo Governo"; +"registrationPageTwoFieldInformationOptionThree_description" = "você foi informado por sua gerência, pelo proprietário dos dados ou pelo guardião dos dados de que os dados armazenados ou acessados por seu dispositivo estão sujeitos a restrições ou regulamentações governamentais, por exemplo, alguns dados do segmento de saúde estão sujeitos a proteções adicionais"; +"registrationPageTwoFieldInformationOptionFour_title" = "Dados do FFIEC (Federal Financial Institutions Examination Council)"; +"registrationPageTwoFieldInformationOptionFour_description" = "você dá suporte ou tem acesso aos ambientes financeiros do cliente"; +"registrationPageTwoFieldInformationOptionFive_title" = "Dados do HIPAA (Health Insurance Portability and Accountability Act)"; +"registrationPageTwoFieldInformationOptionFive_description" = "você dá suporte a uma conta de cliente regulamentada por HIPAA ou a oferta de hospedagem múltipla"; +"registrationPageTwoFieldInformationOptionSix_title" = "Dados do PCI"; +"registrationPageTwoFieldInformationOptionSix_description" = "o dispositivo armazena ou acessa dados confidenciais de cartão de pagamento (por exemplo, cartão de crédito) pertencentes ou criados por um cliente"; +"registrationPageTwoFieldInformationOptionSeven_title" = "Nenhum dos acima"; +"registrationPageTwoFieldInformationOptionSeven_description" = ""; + +// MARK: - Registration: loading page + +// State labels +"registrationLoadingPageStateOne" = "Testando a velocidade da rede"; +"registrationLoadingPageStateTwo" = "Concluindo a inscrição"; +"registrationLoadingPageStateForPhaseThree" = "Atualizando o registro"; + +// MARK: - Registration: final page + +// Header +"registrationFinalPageTitle" = "Registro concluído"; +"registrationFinalPageTitlePhaseThree" = "Detalhes do registro"; +"registrationFinalPageTitlePhaseFour" = "Bem-vindo!"; +"registrationFinalPageSubtitleStandard" = "Vamos começar a configurar o seu Mac!"; +"registrationFinalPageSubtitlePhaseThree" = ""; +"registrationFinalPageInstructionalMessage" = "Após seu próximo login, você será solicitado a fornecer uma nova senha de login do macOS e a habilitar a criptografia de disco FileVault."; +"registrationFinalPageCountdownMessage" = "O seu Mac será reiniciado automaticamente em %d segundos para continuar o processo de configuração ou selecione \"Reiniciar\" para continuar agora."; + +// MARK: - Installation: bundle selection page + +// Header +"installationBundleSelectionPageTitle" = "Pacotes de aplicativos para você começar"; +"installationBundleSelectionPageSubtitle" = "Aplicativos adicionais podem ser instalados por meio da Mac@IBM App Store a qualquer momento."; + +// Labels +"installationBundleSelectionPageRecommended" = "(recomendado)"; + +// Bundle one +"installationBundleSelectionPageBundleOneTitle" = "Conectividade"; +"installationBundleSelectionPageBundleOneDescription" = "Conecte-se às redes IBM com o software e os certificados necessários"; +"installationBundleSelectionPageBundleOnePopoverTitle" = "Pacote de conectividade"; +"installationBundleSelectionPageBundleOnePopoverDescription" = "Conecte-se à nossa rede com certificados e software"; +"installationBundleSelectionPageBundleOneAppOneTitle" = "AnyConnect"; +"installationBundleSelectionPageBundleOneAppOneDescription" = "Ipsum lorem 1"; + +// Bundle two +"installationBundleSelectionPageBundleTwoTitle" = "Essentials"; +"installationBundleSelectionPageBundleTwoDescription" = "Comece a operar com as ferramentas IBM mais comuns."; +"installationBundleSelectionPageBundleTwoPopoverTitle" = "Pacote do Essentials"; +"installationBundleSelectionPageBundleTwoPopoverDescription" = "Os aplicativos usados pela maioria dos funcionários"; +"installationBundleSelectionPageBundleTwoAppOneTitle" = "IBM Notes"; +"installationBundleSelectionPageBundleTwoAppOneDescription" = "Envie e receba correio IBM e interaja com bancos de dados"; +"installationBundleSelectionPageBundleTwoAppTwoTitle" = "Webex Meetings"; +"installationBundleSelectionPageBundleTwoAppTwoDescription" = "Combine recursos de vídeo e audioconferência e reunião na web"; +"installationBundleSelectionPageBundleTwoAppThreeTitle" = "Code42 CrashPlan"; +"installationBundleSelectionPageBundleTwoAppThreeDescription" = "Faça backup e restaure arquivos com segurança no seu Mac"; +"installationBundleSelectionPageBundleTwoAppFourTitle" = "BluePages"; +"installationBundleSelectionPageBundleTwoAppFourDescription" = "Procuras rápidas e convenientes no diretório de funcionários"; +"installationBundleSelectionPageBundleTwoAppFiveTitle" = "IBM Bookmarks"; +"installationBundleSelectionPageBundleTwoAppFiveDescription" = "Links para sites IBM comumente usados"; + +// Bundle three +"installationBundleSelectionPageBundleThreeTitle" = "Produtividade"; +"installationBundleSelectionPageBundleThreeDescription" = "Aumente sua produtividade com processamento de texto, planilhas e muito mais."; +"installationBundleSelectionPageBundleThreePopoverTitle" = "Pacote de produtividade"; +"installationBundleSelectionPageBundleThreePopoverDescription" = "Ferramentas para ajudar você a criar e colaborar."; +"installationBundleSelectionPageBundleThreeAppOneTitle" = "Office 365"; +"installationBundleSelectionPageBundleThreeAppOneDescription" = "Microsoft Word, Excel, PowerPoint, OneNote e Outlook"; +"installationBundleSelectionPageBundleThreeAppTwoTitle" = "Slack"; +"installationBundleSelectionPageBundleThreeAppTwoDescription" = "Comunique-se e colabore com equipes da IBM"; +"installationBundleSelectionPageBundleThreeAppThreeTitle" = "Box Drive"; +"installationBundleSelectionPageBundleThreeAppThreeDescription" = "Armazene, compartilhe e sincronize arquivos"; + +// MARK: - Installation: bundle installation page +"installationBundleInstallationPageTitle" = "Instalando pacotes de aplicativos selecionados…"; +"installationBundleInstallationPageSubtitle" = "Tempo estimado restante: "; +"installationBundleInstallationPageHideAppLabel" = "Ocultar aplicativo"; +"installationBundleInstallationPageShowAppLabel" = "Mostrar aplicativo"; + +// MARK: - Installation: final page + +// Header +"installationFinalPageTitle" = "Comece a usar o seu Mac"; + +// Elements +"installationFinalPageElementOneTitle" = "Obtenha aplicativos na \nMac@IBM App Store"; +"installationFinalPageElementOneDescription" = "Microsoft Office, Slack, IBM Notes e mais!"; +"installationFinalPageElementTwoTitle" = "Migre seus dados \nde outro sistema computacional"; +"installationFinalPageElementTwoDescription" = "Transfira informações importantes \npara o seu novo Mac."; +"installationFinalPageElementThreeTitle" = "Faça backup do seu Mac com o \nCode42 CrashPlan"; +"installationFinalPageElementThreeDescription" = "Instale, configure uma conta \ne aproveite o Peace of Mind."; +"installationFinalPageElementThreeDescriptionAlternate" = "Configure uma conta \ne aproveite o Peace of Mind."; +"installationFinalPageElementFourTitle" = "Visualize dicas, tutoriais e \nsuporte no Help@IBM"; +"installationFinalPageElementFourDescription" = "Acesse os consultores Apple Help Desk dedicados da IBM."; +"installationFinalPageElementFiveTitle" = "Usar o Notes? Instale o seu\narquivo de ID do Notes"; +"installationFinalPageElementFiveDescription" = "Instale e configure o Notes como seu cliente de e-mail."; +"installationFinalPAgeElementSixTitle" = "Acesse a página inicial do w3"; +"installationFinalPageElementSixDescription" = "Procure lugares do w3 e BluePages"; + +// Footer +"installationFinalPageFooterLabel" = " Lembre-me da próxima vez que reiniciar meu Mac."; + +// MARK: - Installation: Notes wizard page + +// Header +"filePickerPageTitle" = "Instale o seu arquivo de ID do Notes"; +"filePickerPageSubtitle" = "O seu ID do Notes é necessário para concluir a configuração do Notes. Também é possível adicioná-lo mais tarde."; + +// Messages +"filePickerPageMessageSuccess" = "O seu ID do Notes foi instalado com sucesso!"; +"filePickerPageMessageFailure" = "Não foi possível instalar o seu arquivo de ID do Notes."; +"filePickerPageMessageAlreadyExist" = "Um arquivo de ID do Notes já existe. Você pode instalar um novo."; + +// Labels +"filePickerPageButtonBrowse" = "Procure seu arquivo de ID do Notes"; +"filePickerPageButtonRemove" = "Remover"; +"filePickerPageCenterLabel" = "Arraste e solte seu arquivo de ID do Notes"; +"filePickerPageAlertMessage" = "O arquivo já existe"; +"filePickerPageAlertInformativeText" = "O arquivo já existe no destino. Deseja substituir o arquivo existente pelo arquivo selecionado?"; +"filePickerPageFileSelectionPanelTitle" = "Selecione o arquivo de ID que você deseja usar para configurar o Notes"; +"filePickerPageButtonInstall" = "Instalar o arquivo de ID do Notes"; + +// MARK: - Alert labels + +// Un-enrollment +"unenrollmentAlertTitle" = "Tem certeza de que deseja sair do processo de inscrição?"; +"unenrollmentAlertMessage" = "O cancelamento agora desfará todas as configurações de segurança e removerá este sistema computacional do gerenciamento."; +"unenrollmentCancelled" = "Ação Remover estrutura foi cancelada"; + +// Bundle selection +"bundleSelectionAlertTitle" = "Tem certeza de que deseja continuar?"; +"bundleSelectionAlertMessage" = "Parece que a velocidade da sua rede está lenta no momento. Recomendamos instalar menos pacotes configuráveis."; + +// Bundle installation +"bundleInstallationalertMessage" = "Ocorreu um problema ao instalar alguns aplicativos. Use o Autoatendimento para instalá-los posteriormente."; + +// Launch failure +"launchFailureAlertTitle" = "Este aplicativo requer gerenciamento de dispositivos."; +"launchFailureAlertMessage" = "Registre este dispositivo."; + +// External network problem +"externalNetworkAlertMessage" = "Você não está conectado à Internet. Verifique se o seu Mac está conectado a uma rede com acesso à Internet antes de continuar."; +"externalNetworkJspMessage" = "O autoatendimento não está disponível no momento. Tente novamente mais tarde."; + +// Internal network problem +"internalNetworkProblemAlertMessage" = "\n\nDeve-se estar conectado à intranet para continuar."; + +// Terms and conditions drop down +"termsAndConditionsTitle" = "Contrato IBM para Uso de Dispositivo Pessoal"; +"termsAndConditionsBody" = "Você optou por registrar este dispositivo como sendo \"de propriedade pessoal\". O uso de um dispositivo de propriedade pessoal para conduzir negócios IBM é governado por certos termos e condições.\n\nRevise os termos e condições IBM e indique se você os aceita. "; +"termsAndConditionsButtonLink" = "Leia os Termos e Condições IBM"; +"termsAndConditionsButtonAccept" = "Aceitar"; + +// MARK: - Common button labels +"buttonLabelOk" = "OK"; +"buttonLabelCancel" = "Cancelar"; +"buttonLabelNext" = "Avançar"; +"buttonLabelRestart" = "Reiniciar"; +"buttonLabelClose" = "Fechar"; +"buttonLabelBack" = "Voltar"; +"buttonLabelOkWithQuestionMark" = "Ok?"; +"buttonLabelQuit" = "Sair"; +"buttonLabelReplace" = "Substituir"; +"buttonLabelUpdateInfo" = "Editar detalhes"; +"buttonLabelUnenroll" = "Cancelar inscrição"; + +// MARK: - Common labels +"labelEnabled" = "Ativado"; +"labelDisabled" = "Desativado"; +"labelRequired" = "Obrigatório"; +"restartFailureMessage" = "Não foi possível reiniciar o seu sistema computacional"; +"restartFailureComment" = "Alerta de reinicialização com alerta"; +"estimatedInstallTimeMessage" = "%@ \n \n Tempo estimado de instalação: %@"; +"labelChooseAnswer" = "Escolha a sua resposta."; +"labelNo" = "Não"; +"labelYes" = "Sim"; +"buttonLabelInstall" = "Instalar pacotes selecionados"; +"buttonLabelSkip" = "Ignorar"; diff --git a/enrollment/enrollment/zh-Hant-TW.lproj/Localizable.strings b/enrollment/enrollment/zh-Hant-TW.lproj/Localizable.strings new file mode 100644 index 0000000..86eb8ee --- /dev/null +++ b/enrollment/enrollment/zh-Hant-TW.lproj/Localizable.strings @@ -0,0 +1,272 @@ +/* + Localizable.strings + enrollment + + Created by Simone Martorelli on 2/5/20. + Copyright © 2020 IBM. All rights reserved. + SPDX-License-Identifier: GPL-3.0-only + */ + +/// MARK: - Note to the translation +/// +/// Pay attention to not modify, cancel or move the special characters: +/// - %d - This special character is substituted with a number at runtime; +/// - %@ - This special characted is substituted with a string at runtime; +/// - \n - This special characted works like the "return" key; +/// - \" - This special characted insert a "; + +// MARK: - Registration: page one + +// Header +"registrationPageOneTitleSimple" = "歡迎加入,新進員工!"; +"registrationPageOneTitleComposed" = "歡迎加入,%@!"; +"registrationPageOneSubtitleSimple" = "沒看到您的名字嗎?"; +"registrationPageOneSubtitleComposed" = "不是 %@ 嗎?"; + +// Info popovers +"registrationPageOneSubtitle_info" = "別擔心,您之後可以使用 Mac@IBM App Store 並搜尋「指派使用者」,來進行更新。"; +"registrationPageOneDisclaimerPolicies_infoElementOne" = "防火牆"; +"registrationPageOneDisclaimerPolicies_infoElementTwo" = "隱身模式"; +"registrationPageOneDisclaimerPolicies_infoElementThree" = "來賓使用者帳戶"; +"registrationPageOneDisclaimerPolicies_infoElementFour" = "FileVault 磁碟加密"; +"registrationPageOneDisclaimerPolicies_infoElementFive" = "初次 macOS 密碼變更"; +"registrationPageOneDisclaimerPolicies_infoElementSix" = "螢幕保護程式密碼"; +"registrationPageOneDisclaimerPolicies_infoElementSeven_title" = "螢幕保護程式啟動時間"; +"registrationPageOneDisclaimerPolicies_infoElementSeven_description" = "閒置 30 分鐘"; +"registrationPageOneDisclaimerPolicies_infoElementEight_title" = "端點保護軟體"; + +// Field labels +"registrationPageOneFieldRegion" = "區域"; +"registrationPageOneFieldComputer" = "電腦類型"; +"registrationPageOneFieldOwner" = "資產擁有者"; +"registrationPageOneFieldUser" = "使用者類型"; + +// Region field options +"registrationPageOneFieldRegionOptionOne" = "美國"; +"registrationPageOneFieldRegionOptionTwo" = "加拿大"; +"registrationPageOneFieldRegionOptionThree" = "EMEA(歐洲、中東、非洲)"; +"registrationPageOneFieldRegionOptionFour" = "LA(拉丁美洲)"; +"registrationPageOneFieldRegionOptionFive" = "AP(亞太)"; + +// Computer Type options +"registrationPageOneFieldComputerOptionOne" = "主要"; +"registrationPageOneFieldComputerOptionOne_info" = "適合單一使用者,作為辦公室生產力平台進行一般辦公室工作(例如電子郵件、網頁瀏覽/應用程式、即時傳訊、文書處理等等)"; +"registrationPageOneFieldComputerOptionTwo" = "次要"; +"registrationPageOneFieldComputerOptionTwo_info" = "適合辦公室生產力活動以外的各種作業,包括客戶展示活動及虛擬機器"; +"registrationPageOneFieldComputerOptionThree" = "共用"; +"registrationPageOneFieldComputerOptionThree_info" = "適合多位使用者用於教育及訓練"; +"registrationPageOneFieldComputerOptionFour" = "借貸方式"; +"registrationPageOneFieldComputerOptionFour_info" = "適用於測試及/或開發"; +"registrationPageOneFieldComputerOptionFive" = "教室"; +"registrationPageOneFieldComputerOptionFive_info" = "短期使用,作為替換或補充"; +"registrationPageOneFieldComputerOptionSix" = "實驗室"; +"registrationPageOneFieldComputerOptionSix_info" = "由多位使用者用於包括辦公室生產力活動在內的各種作業"; + +// Asset Owner options +"registrationPageOneFieldOwnerOptionOne" = "IBM 提供"; +"registrationPageOneFieldOwnerOptionTwo" = "個人擁有"; +"registrationPageOneFieldOwnerOptionThree" = "第三方擁有:供應商提供"; +"registrationPageOneFieldOwnerOptionFour" = "第三方擁有:承包商機構提供"; +"registrationPageOneFieldOwnerOptionFive" = "第三方擁有:客戶提供"; + +// User Type options +"registrationPageOneFieldUserOptionOne" = "標準"; +"registrationPageOneFieldUserOptionOne_info" = "一般用途(不包括特許或客服中心使用案例執行職責)"; +"registrationPageOneFieldUserOptionTwo" = "特許"; +"registrationPageOneFieldUserOptionTwo_info" = "由 IBM 或客戶之安全行政機關,以及網路裝置、電腦系統、中介軟體元件或應用程式之系統管理機關指派。"; +"registrationPageOneFieldUserOptionThree" = "客服中心"; +"registrationPageOneFieldUserOptionThree_info" = "指派給服務中心、客服中心或服務台"; + +// Policies disclaimer +"registrationPageOneDisclaimerPolicies" = "將會自動套用 IBM 安全原則。"; + +// MARK: - Registration: page two + +// Header +"registrationPageTwoTitle" = "您存取的資訊"; +"registrationPageTwoSubtitle" = "請選取儲存在此電腦上的資料類型。"; + +// Information options +"registrationPageTwoFieldInformationOptionOne_title" = "機密個人資訊 (SPI)"; +"registrationPageTwoFieldInformationOptionOne_description" = "您的裝置會儲存個人資訊 (PI)"; +"registrationPageTwoFieldInformationOptionTwo_title" = "客戶資料"; +"registrationPageTwoFieldInformationOptionTwo_description" = "裝置會儲存或是用來存取由客戶所擁有或建立的資料"; +"registrationPageTwoFieldInformationOptionThree_title" = "政府管制資料"; +"registrationPageTwoFieldInformationOptionThree_description" = "管理機關、管理擁有者或資料管理人已通知您,您的裝置所儲存或存取的資料受到政府限制或法令規範,例如部分健康照護資料會受到額外的保護"; +"registrationPageTwoFieldInformationOptionFour_title" = "FFIEC(聯邦金融機構檢查委員會)資料"; +"registrationPageTwoFieldInformationOptionFour_description" = "您支援或可存取客戶的金融環境"; +"registrationPageTwoFieldInformationOptionFive_title" = "HIPAA(健康保險可攜性與責任法案)資料"; +"registrationPageTwoFieldInformationOptionFive_description" = "您支援 HIPAA 規範之客戶帳戶或多租戶供應項目"; +"registrationPageTwoFieldInformationOptionSix_title" = "PCI 資料"; +"registrationPageTwoFieldInformationOptionSix_description" = "裝置會儲存或存取由客戶所擁有或建立的機密支付卡(例如信用卡)資料"; +"registrationPageTwoFieldInformationOptionSeven_title" = "以上皆非"; +"registrationPageTwoFieldInformationOptionSeven_description" = ""; + +// MARK: - Registration: loading page + +// State labels +"registrationLoadingPageStateOne" = "正在測試網路速度"; +"registrationLoadingPageStateTwo" = "正在完成註冊"; +"registrationLoadingPageStateForPhaseThree" = "正在更新登錄"; + +// MARK: - Registration: final page + +// Header +"registrationFinalPageTitle" = "登錄完成"; +"registrationFinalPageTitlePhaseThree" = "登錄詳細資料"; +"registrationFinalPageTitlePhaseFour" = "歡迎!"; +"registrationFinalPageSubtitleStandard" = "讓我們設定您的 Mac!"; +"registrationFinalPageSubtitlePhaseThree" = ""; +"registrationFinalPageInstructionalMessage" = "下次登入之後,您將會收到更新 macOS 登入密碼以及啟用 FileVault 磁碟加密的提示。"; +"registrationFinalPageCountdownMessage" = "您的 Mac 將在 %d 秒後自動重新啟動,以繼續執行設定程序;您也可以選取「重新啟動」立即繼續。"; + +// MARK: - Installation: bundle selection page + +// Header +"installationBundleSelectionPageTitle" = "讓您開始使用的應用程式組合"; +"installationBundleSelectionPageSubtitle" = "隨時都可從 Mac@IBM App Store 安裝其他應用程式。"; + +// Labels +"installationBundleSelectionPageRecommended" = "(建議)"; + +// Bundle one +"installationBundleSelectionPageBundleOneTitle" = "連線功能"; +"installationBundleSelectionPageBundleOneDescription" = "使用必要的軟體及憑證連接至 IBM 網路"; +"installationBundleSelectionPageBundleOnePopoverTitle" = "連線功能組合"; +"installationBundleSelectionPageBundleOnePopoverDescription" = "使用憑證及軟體連接至我們的網路"; +"installationBundleSelectionPageBundleOneAppOneTitle" = "AnyConnect"; +"installationBundleSelectionPageBundleOneAppOneDescription" = "Ipsum lorem 1"; + +// Bundle two +"installationBundleSelectionPageBundleTwoTitle" = "基本"; +"installationBundleSelectionPageBundleTwoDescription" = "以最常用的 IBM 工具開始進行。"; +"installationBundleSelectionPageBundleTwoPopoverTitle" = "基本組合"; +"installationBundleSelectionPageBundleTwoPopoverDescription" = "大部分員工使用的應用程式"; +"installationBundleSelectionPageBundleTwoAppOneTitle" = "IBM Notes"; +"installationBundleSelectionPageBundleTwoAppOneDescription" = "收送 IBM 郵件並與資料庫互動"; +"installationBundleSelectionPageBundleTwoAppTwoTitle" = "Webex Meetings"; +"installationBundleSelectionPageBundleTwoAppTwoDescription" = "結合視訊及音訊會議,和網頁會議功能"; +"installationBundleSelectionPageBundleTwoAppThreeTitle" = "Code42 CrashPlan"; +"installationBundleSelectionPageBundleTwoAppThreeDescription" = "安全地備份及還原 Mac 上的檔案"; +"installationBundleSelectionPageBundleTwoAppFourTitle" = "BluePages"; +"installationBundleSelectionPageBundleTwoAppFourDescription" = "快速便利地搜尋員工目錄"; +"installationBundleSelectionPageBundleTwoAppFiveTitle" = "IBM Bookmarks"; +"installationBundleSelectionPageBundleTwoAppFiveDescription" = "常用 IBM 網站的鏈結"; + +// Bundle three +"installationBundleSelectionPageBundleThreeTitle" = "生產力"; +"installationBundleSelectionPageBundleThreeDescription" = "用文書處理、試算表等等提高您的生產力。"; +"installationBundleSelectionPageBundleThreePopoverTitle" = "生產力組合"; +"installationBundleSelectionPageBundleThreePopoverDescription" = "用來協助您建立及分工合作的工具。"; +"installationBundleSelectionPageBundleThreeAppOneTitle" = "Office 365"; +"installationBundleSelectionPageBundleThreeAppOneDescription" = "Microsoft Word、Excel、PowerPoint、OneNote 及 Outlook"; +"installationBundleSelectionPageBundleThreeAppTwoTitle" = "Slack"; +"installationBundleSelectionPageBundleThreeAppTwoDescription" = "與 IBM 各地團隊溝通與分工合作"; +"installationBundleSelectionPageBundleThreeAppThreeTitle" = "Box Drive"; +"installationBundleSelectionPageBundleThreeAppThreeDescription" = "儲存、共用及同步化檔案"; + +// MARK: - Installation: bundle installation page +"installationBundleInstallationPageTitle" = "正在安裝選取的應用程式組合…"; +"installationBundleInstallationPageSubtitle" = "預估剩餘時間:"; +"installationBundleInstallationPageHideAppLabel" = "隱藏應用程式"; +"installationBundleInstallationPageShowAppLabel" = "顯示應用程式"; + +// MARK: - Installation: final page + +// Header +"installationFinalPageTitle" = "開始使用您的 Mac"; + +// Elements +"installationFinalPageElementOneTitle" = "從 Mac@IBM App Store \n取得應用程式"; +"installationFinalPageElementOneDescription" = "Microsoft Office、Slack、IBM Notes 以及更多應用程式!"; +"installationFinalPageElementTwoTitle" = "從另一台電腦\n移轉您的資料"; +"installationFinalPageElementTwoDescription" = "將重要資訊傳送到\n您的新 Mac。"; +"installationFinalPageElementThreeTitle" = "使用 Code42 CrashPlan\n備份您的 Mac"; +"installationFinalPageElementThreeDescription" = "安裝、設定帳戶,\n大功告成!"; +"installationFinalPageElementThreeDescriptionAlternate" = "設定帳戶,\n大功告成!"; +"installationFinalPageElementFourTitle" = "在 Help@IBM 上檢視\n提示、指導教學及支援"; +"installationFinalPageElementFourDescription" = "存取 IBM 的專用 Apple Help Desk 諮詢程式。"; +"installationFinalPageElementFiveTitle" = "使用 Notes?請安裝您的\nNotes ID 檔案"; +"installationFinalPageElementFiveDescription" = "安裝 Notes 並將其設定為電子郵件用戶端。"; +"installationFinalPAgeElementSixTitle" = "前往 w3 首頁"; +"installationFinalPageElementSixDescription" = "搜尋 w3 工作區及 BluePages"; + +// Footer +"installationFinalPageFooterLabel" = " 下次重新啟動 Mac 時提醒我。"; + +// MARK: - Installation: Notes wizard page + +// Header +"filePickerPageTitle" = "請安裝您的 Notes ID 檔案"; +"filePickerPageSubtitle" = "需要您的 Notes ID 才能完成 Notes 設定。您也可以之後再新增。"; + +// Messages +"filePickerPageMessageSuccess" = "您的 Notes ID 已順利安裝!"; +"filePickerPageMessageFailure" = "我們無法安裝您的 Notes ID 檔案。"; +"filePickerPageMessageAlreadyExist" = "Notes ID 檔案已存在。您可以安裝新的。"; + +// Labels +"filePickerPageButtonBrowse" = "瀏覽 Notes ID 檔案"; +"filePickerPageButtonRemove" = "移除"; +"filePickerPageCenterLabel" = "拖放 Notes ID 檔案"; +"filePickerPageAlertMessage" = "檔案已存在"; +"filePickerPageAlertInformativeText" = "檔案已存在於目的地。要將現有檔案取代為您選取的檔案嗎?"; +"filePickerPageFileSelectionPanelTitle" = "選取您要用來配置 Notes 的 ID 檔案"; +"filePickerPageButtonInstall" = "安裝 Notes ID 檔案"; + +// MARK: - Alert labels + +// Un-enrollment +"unenrollmentAlertTitle" = "您確定要退出註冊處理程序嗎?"; +"unenrollmentAlertMessage" = "現在取消會復原所有安全設定,並從管理工作移除這台電腦。"; +"unenrollmentCancelled" = "已取消移除架構動作"; + +// Bundle selection +"bundleSelectionAlertTitle" = "您確定要繼續嗎?"; +"bundleSelectionAlertMessage" = "您的網路速度目前似乎很慢。我們建議減少安裝的組合數目。"; + +// Bundle installation +"bundleInstallationalertMessage" = "安裝部分應用程式時出現困難 - 稍後請使用 Self Service 進行安裝。"; + +// Launch failure +"launchFailureAlertTitle" = "此應用程式需要裝置管理。"; +"launchFailureAlertMessage" = "請登記此裝置。"; + +// External network problem +"externalNetworkAlertMessage" = "您未連接網際網路。請確定您的 Mac 已連接至具有網際網路存取的網路,然後才繼續進行。"; +"externalNetworkJspMessage" = "目前無法使用 Self Service。請稍後重試。"; + +// Internal network problem +"internalNetworkProblemAlertMessage" = "\n\n您必須連接內部網路以便繼續。"; + +// Terms and conditions drop down +"termsAndConditionsTitle" = "IBM 個人裝置使用合約"; +"termsAndConditionsBody" = "如果您使用個人擁有的裝置來處理 IBM 業務,則必須接受特定條款之規範。\n\n請檢閱 IBM 條款,並表示是否接受。"; +"termsAndConditionsButtonLink" = "閱讀 IBM 條款"; +"termsAndConditionsButtonAccept" = "接受"; + +// MARK: - Common button labels +"buttonLabelOk" = "確定"; +"buttonLabelCancel" = "取消"; +"buttonLabelNext" = "下一步"; +"buttonLabelRestart" = "重新啟動"; +"buttonLabelClose" = "關閉"; +"buttonLabelBack" = "上一步"; +"buttonLabelOkWithQuestionMark" = "確定嗎?"; +"buttonLabelQuit" = "退出"; +"buttonLabelReplace" = "取代"; +"buttonLabelUpdateInfo" = "編輯詳細資料"; +"buttonLabelUnenroll" = "取消註冊"; + +// MARK: - Common labels +"labelEnabled" = "已啟用"; +"labelDisabled" = "已停用"; +"labelRequired" = "必要"; +"restartFailureMessage" = "無法重新啟動您的電腦"; +"restartFailureComment" = "重新啟動失敗警示"; +"estimatedInstallTimeMessage" = "%@ \n \n 預估的安裝時間:%@"; +"labelChooseAnswer" = "請選擇您的回答。"; +"labelNo" = "否"; +"labelYes" = "是"; +"buttonLabelInstall" = "安裝選取的組合"; +"buttonLabelSkip" = "跳過"; diff --git a/enrollment/enrollment/zh-Hant.lproj/Localizable.strings b/enrollment/enrollment/zh-Hant.lproj/Localizable.strings new file mode 100644 index 0000000..c98ae39 --- /dev/null +++ b/enrollment/enrollment/zh-Hant.lproj/Localizable.strings @@ -0,0 +1,272 @@ +/* + Localizable.strings + enrollment + + Created by Simone Martorelli on 2/5/20. + Copyright © 2020 IBM. All rights reserved. + SPDX-License-Identifier: GPL-3.0-only + */ + +/// MARK: - Note to the translation +/// +/// Pay attention to not modify, cancel or move the special characters: +/// - %d - This special character is substituted with a number at runtime; +/// - %@ - This special characted is substituted with a string at runtime; +/// - \n - This special characted works like the "return" key; +/// - \" - This special characted insert a "; + +// MARK: - Registration: page one + +// Header +"registrationPageOneTitleSimple" = "欢迎您,新员工!"; +"registrationPageOneTitleComposed" = "欢迎您,%@!"; +"registrationPageOneSubtitleSimple" = "看不到您的姓名?"; +"registrationPageOneSubtitleComposed" = "不是 %@?"; + +// Info popovers +"registrationPageOneSubtitle_info" = "不用担心,您稍后可以使用 Mac@IBM App Store 并搜索\"分配用户\"来更新此项。"; +"registrationPageOneDisclaimerPolicies_infoElementOne" = "防火墙"; +"registrationPageOneDisclaimerPolicies_infoElementTwo" = "隐身方式"; +"registrationPageOneDisclaimerPolicies_infoElementThree" = "访客用户帐户"; +"registrationPageOneDisclaimerPolicies_infoElementFour" = "FileVault 磁盘加密"; +"registrationPageOneDisclaimerPolicies_infoElementFive" = "初始 macOS 密码更改"; +"registrationPageOneDisclaimerPolicies_infoElementSix" = "屏幕保护程序密码"; +"registrationPageOneDisclaimerPolicies_infoElementSeven_title" = "屏幕保护程序开始时间"; +"registrationPageOneDisclaimerPolicies_infoElementSeven_description" = "30 分钟没有活动"; +"registrationPageOneDisclaimerPolicies_infoElementEight_title" = "端点保护软件"; + +// Field labels +"registrationPageOneFieldRegion" = "区域"; +"registrationPageOneFieldComputer" = "计算机类型"; +"registrationPageOneFieldOwner" = "资产所有者"; +"registrationPageOneFieldUser" = "用户类型"; + +// Region field options +"registrationPageOneFieldRegionOptionOne" = "美国"; +"registrationPageOneFieldRegionOptionTwo" = "加拿大"; +"registrationPageOneFieldRegionOptionThree" = "EMEA(欧洲、中东和非洲)"; +"registrationPageOneFieldRegionOptionFour" = "LA(拉丁美洲)"; +"registrationPageOneFieldRegionOptionFive" = "AP(亚太地区)"; + +// Computer Type options +"registrationPageOneFieldComputerOptionOne" = "主要"; +"registrationPageOneFieldComputerOptionOne_info" = "适用于单用户,可用作办公生产力平台来处理日常办公事务(例如,电子邮件、Web 浏览/应用程序、即时消息传递、文档等)。"; +"registrationPageOneFieldComputerOptionTwo" = "次要"; +"registrationPageOneFieldComputerOptionTwo_info" = "用于处理各种任务(但办公生产力活动除外),包括客户演示活动和虚拟机"; +"registrationPageOneFieldComputerOptionThree" = "共享"; +"registrationPageOneFieldComputerOptionThree_info" = "供多个用户用于教育和培训"; +"registrationPageOneFieldComputerOptionFour" = "出借"; +"registrationPageOneFieldComputerOptionFour_info" = "用于测试和/或开发"; +"registrationPageOneFieldComputerOptionFive" = "教室"; +"registrationPageOneFieldComputerOptionFive_info" = "短期使用,作为替代或补充"; +"registrationPageOneFieldComputerOptionSix" = "实验室"; +"registrationPageOneFieldComputerOptionSix_info" = "供多个用户用于处理各种任务,包括办公室生产力活动"; + +// Asset Owner options +"registrationPageOneFieldOwnerOptionOne" = "IBM 提供"; +"registrationPageOneFieldOwnerOptionTwo" = "个人拥有"; +"registrationPageOneFieldOwnerOptionThree" = "第三方拥有:供应商提供"; +"registrationPageOneFieldOwnerOptionFour" = "第三方拥有:承包商代理提供"; +"registrationPageOneFieldOwnerOptionFive" = "第三方拥有:客户提供"; + +// User Type options +"registrationPageOneFieldUserOptionOne" = "标准"; +"registrationPageOneFieldUserOptionOne_info" = "常规使用,但“特权”或“呼叫中心”用例履行的职责除外"; +"registrationPageOneFieldUserOptionTwo" = "特权"; +"registrationPageOneFieldUserOptionTwo_info" = "由安全管理机构分配,具有对 IBM 或客户的网络设备、计算机系统、中间件组件或应用程序的系统权限"; +"registrationPageOneFieldUserOptionThree" = "服务/呼叫中心"; +"registrationPageOneFieldUserOptionThree_info" = "分配给服务中心、呼叫中心或帮助台"; + +// Policies disclaimer +"registrationPageOneDisclaimerPolicies" = "IBM 安全策略将自动应用。"; + +// MARK: - Registration: page two + +// Header +"registrationPageTwoTitle" = "您访问的信息"; +"registrationPageTwoSubtitle" = "选择在此计算机上存储的数据类型。"; + +// Information options +"registrationPageTwoFieldInformationOptionOne_title" = "敏感个人信息 (SPI)"; +"registrationPageTwoFieldInformationOptionOne_description" = "您的设备存储个人信息 (PI)"; +"registrationPageTwoFieldInformationOptionTwo_title" = "客户数据"; +"registrationPageTwoFieldInformationOptionTwo_description" = "设备存储或用于访问客户拥有或创建的数据"; +"registrationPageTwoFieldInformationOptionThree_title" = "政府监管数据"; +"registrationPageTwoFieldInformationOptionThree_description" = "管理层、数据所有者或数据管理人通知您,您的设备存储或访问的数据受到政府的限制或监管,例如某些医疗保健数据受到额外保护"; +"registrationPageTwoFieldInformationOptionFour_title" = "FFIEC(联邦金融机构审查委员会)数据"; +"registrationPageTwoFieldInformationOptionFour_description" = "您支持或有权访问客户的财务环境"; +"registrationPageTwoFieldInformationOptionFive_title" = "HIPAA(健康保险可移植性和责任法案)数据"; +"registrationPageTwoFieldInformationOptionFive_description" = "您支持受 HIPAA 监管的客户帐户或多租户产品"; +"registrationPageTwoFieldInformationOptionSix_title" = "PCI 数据"; +"registrationPageTwoFieldInformationOptionSix_description" = "设备存储或访问客户拥有或创建的敏感支付卡(例如,信用卡)数据"; +"registrationPageTwoFieldInformationOptionSeven_title" = "以上都不是"; +"registrationPageTwoFieldInformationOptionSeven_description" = ""; + +// MARK: - Registration: loading page + +// State labels +"registrationLoadingPageStateOne" = "正在测试网络速度"; +"registrationLoadingPageStateTwo" = "正在完成注册"; +"registrationLoadingPageStateForPhaseThree" = "正在更新注册"; + +// MARK: - Registration: final page + +// Header +"registrationFinalPageTitle" = "注册完成"; +"registrationFinalPageTitlePhaseThree" = "注册详细信息"; +"registrationFinalPageTitlePhaseFour" = "欢迎!"; +"registrationFinalPageSubtitleStandard" = "让我们来设置您的 Mac!"; +"registrationFinalPageSubtitlePhaseThree" = ""; +"registrationFinalPageInstructionalMessage" = "下次登录后,系统将提示您输入新的 macOS 登录密码,并启用 FileVault 磁盘加密。"; +"registrationFinalPageCountdownMessage" = "您的 Mac 将在 %d 秒后自动重新启动以继续设置过程,或者您可以选择\"重新启动\"立即继续。"; + +// MARK: - Installation: bundle selection page + +// Header +"installationBundleSelectionPageTitle" = "可帮助您开始使用的应用程序捆绑软件"; +"installationBundleSelectionPageSubtitle" = "其他应用程序可以通过 Mac@IBM App Store 随时安装。"; + +// Labels +"installationBundleSelectionPageRecommended" = "(建议)"; + +// Bundle one +"installationBundleSelectionPageBundleOneTitle" = "连接"; +"installationBundleSelectionPageBundleOneDescription" = "使用必需的软件和证书连接到 IBM 网络"; +"installationBundleSelectionPageBundleOnePopoverTitle" = "连接捆绑软件"; +"installationBundleSelectionPageBundleOnePopoverDescription" = "使用软件和证书连接到我们的网络"; +"installationBundleSelectionPageBundleOneAppOneTitle" = "AnyConnect"; +"installationBundleSelectionPageBundleOneAppOneDescription" = "Ipsum lorem 1"; + +// Bundle two +"installationBundleSelectionPageBundleTwoTitle" = "基本"; +"installationBundleSelectionPageBundleTwoDescription" = "启动并运行最常用的 IBM 工具。"; +"installationBundleSelectionPageBundleTwoPopoverTitle" = "基本捆绑软件"; +"installationBundleSelectionPageBundleTwoPopoverDescription" = "大多数员工使用的应用程序"; +"installationBundleSelectionPageBundleTwoAppOneTitle" = "IBM Notes"; +"installationBundleSelectionPageBundleTwoAppOneDescription" = "发送和接收 IBM 邮件并与数据库进行交互"; +"installationBundleSelectionPageBundleTwoAppTwoTitle" = "Webex Meetings"; +"installationBundleSelectionPageBundleTwoAppTwoDescription" = "组合使用视频和音频会议以及 Web 会议功能"; +"installationBundleSelectionPageBundleTwoAppThreeTitle" = "Code42 CrashPlan"; +"installationBundleSelectionPageBundleTwoAppThreeDescription" = "在 Mac 上安全地备份和复原文件"; +"installationBundleSelectionPageBundleTwoAppFourTitle" = "BluePages"; +"installationBundleSelectionPageBundleTwoAppFourDescription" = "快速便捷的员工目录搜索"; +"installationBundleSelectionPageBundleTwoAppFiveTitle" = "IBM Bookmarks"; +"installationBundleSelectionPageBundleTwoAppFiveDescription" = "常用 IBM 网站的链接"; + +// Bundle three +"installationBundleSelectionPageBundleThreeTitle" = "生产力"; +"installationBundleSelectionPageBundleThreeDescription" = "通过文字处理、电子表格等来提高生产力。"; +"installationBundleSelectionPageBundleThreePopoverTitle" = "生产力捆绑软件"; +"installationBundleSelectionPageBundleThreePopoverDescription" = "用于帮助创建和协作的工具。"; +"installationBundleSelectionPageBundleThreeAppOneTitle" = "Office 365"; +"installationBundleSelectionPageBundleThreeAppOneDescription" = "Microsoft Word、Excel、PowerPoint、OneNote 和 Outlook"; +"installationBundleSelectionPageBundleThreeAppTwoTitle" = "Slack"; +"installationBundleSelectionPageBundleThreeAppTwoDescription" = "与 IBM 的团队进行沟通和协作"; +"installationBundleSelectionPageBundleThreeAppThreeTitle" = "Box Drive"; +"installationBundleSelectionPageBundleThreeAppThreeDescription" = "存储、共享和同步文件"; + +// MARK: - Installation: bundle installation page +"installationBundleInstallationPageTitle" = "正在安装所选应用程序捆绑软件…"; +"installationBundleInstallationPageSubtitle" = "估计剩余时间:"; +"installationBundleInstallationPageHideAppLabel" = "隐藏应用程序"; +"installationBundleInstallationPageShowAppLabel" = "显示应用程序"; + +// MARK: - Installation: final page + +// Header +"installationFinalPageTitle" = "开始使用 Mac"; + +// Elements +"installationFinalPageElementOneTitle" = "从 Mac@IBM App Store \n获取应用程序"; +"installationFinalPageElementOneDescription" = "Microsoft Office、Slack、IBM Notes 等!"; +"installationFinalPageElementTwoTitle" = "从另一台计算机\n迁移数据"; +"installationFinalPageElementTwoDescription" = "将重要信息\n传输到新 Mac。"; +"installationFinalPageElementThreeTitle" = "使用 Code42 CrashPlan \n备份 Mac"; +"installationFinalPageElementThreeDescription" = "安装、设置帐户,\n随即放心使用。"; +"installationFinalPageElementThreeDescriptionAlternate" = "设置帐户,\n随即放心使用。"; +"installationFinalPageElementFourTitle" = "在 Help@IBM 上\n查看提示、教程和支持"; +"installationFinalPageElementFourDescription" = "访问 IBM 专用的 Apple 帮助台顾问。"; +"installationFinalPageElementFiveTitle" = "要使用 Notes?请安装 \nNotes 标识文件"; +"installationFinalPageElementFiveDescription" = "安装 Notes 并将其设置为电子邮件客户端。"; +"installationFinalPAgeElementSixTitle" = "转至 w3 主页"; +"installationFinalPageElementSixDescription" = "搜索 w3 位置和 BluePages"; + +// Footer +"installationFinalPageFooterLabel" = " 下次重新启动 Mac 时提醒我。"; + +// MARK: - Installation: Notes wizard page + +// Header +"filePickerPageTitle" = "安装 Notes 标识文件"; +"filePickerPageSubtitle" = "完成 Notes 设置需要 Notes 标识。您也可以稍后添加。"; + +// Messages +"filePickerPageMessageSuccess" = "Notes 标识已成功安装!"; +"filePickerPageMessageFailure" = "我们无法安装 Notes 标识文件。"; +"filePickerPageMessageAlreadyExist" = "Notes 标识文件已经存在。您可以安装新的标识文件。"; + +// Labels +"filePickerPageButtonBrowse" = "浏览以查找 Notes 标识文件"; +"filePickerPageButtonRemove" = "除去"; +"filePickerPageCenterLabel" = "拖放 Notes 标识文件"; +"filePickerPageAlertMessage" = "文件已存在"; +"filePickerPageAlertInformativeText" = "目标位置已存在该文件。要用所选文件替换现有文件吗?"; +"filePickerPageFileSelectionPanelTitle" = "选择要用于配置 Notes 的标识文件"; +"filePickerPageButtonInstall" = "安装 Notes 标识文件"; + +// MARK: - Alert labels + +// Un-enrollment +"unenrollmentAlertTitle" = "确定要退出注册过程吗?"; +"unenrollmentAlertMessage" = "立即取消将撤销所有安全设置,并从管理中除去此计算机。"; +"unenrollmentCancelled" = "除去框架操作已取消"; + +// Bundle selection +"bundleSelectionAlertTitle" = "确定要继续吗?"; +"bundleSelectionAlertMessage" = "似乎目前的网络速度很慢。我们建议减少安装的捆绑软件。"; + +// Bundle installation +"bundleInstallationalertMessage" = "安装某些应用程序时遇到了问题 - 请稍后使用自助服务来安装这些应用程序。"; + +// Launch failure +"launchFailureAlertTitle" = "此应用程序需要设备管理。"; +"launchFailureAlertMessage" = "请注册此设备。"; + +// External network problem +"externalNetworkAlertMessage" = "您尚未连接到因特网。请确保将 Mac 连接到具有因特网访问权的网络后再继续。"; +"externalNetworkJspMessage" = "目前自助服务不可用。请稍后重试。"; + +// Internal network problem +"internalNetworkProblemAlertMessage" = "\n\n您必须连接到内部网才能继续。"; + +// Terms and conditions drop down +"termsAndConditionsTitle" = "IBM 个人设备使用协议"; +"termsAndConditionsBody" = "您已选择将此设备注册为“个人拥有”。使用个人拥有的设备来处理 IBM 业务,受到某些条款和条件的约束。\n\n请查看 IBM 条款和条件,并表示是否接受这些条款和条件。"; +"termsAndConditionsButtonLink" = "阅读 IBM 条款和条件"; +"termsAndConditionsButtonAccept" = "接受"; + +// MARK: - Common button labels +"buttonLabelOk" = "确定"; +"buttonLabelCancel" = "取消"; +"buttonLabelNext" = "下一步"; +"buttonLabelRestart" = "重新启动"; +"buttonLabelClose" = "关闭"; +"buttonLabelBack" = "返回"; +"buttonLabelOkWithQuestionMark" = "确定?"; +"buttonLabelQuit" = "退出"; +"buttonLabelReplace" = "替换"; +"buttonLabelUpdateInfo" = "编辑详细信息"; +"buttonLabelUnenroll" = "取消注册"; + +// MARK: - Common labels +"labelEnabled" = "已启用"; +"labelDisabled" = "已禁用"; +"labelRequired" = "必需"; +"restartFailureMessage" = "计算机无法重新启动"; +"restartFailureComment" = "重新启动失败警报"; +"estimatedInstallTimeMessage" = "%@ \n \n 估计安装时间:%@"; +"labelChooseAnswer" = "选择您的回答。"; +"labelNo" = "否"; +"labelYes" = "是"; +"buttonLabelInstall" = "安装所选捆绑软件"; +"buttonLabelSkip" = "跳过"; diff --git a/enrollment/enrollmentJAMFIntegrationHelper/main.swift b/enrollment/enrollmentJAMFIntegrationHelper/main.swift deleted file mode 100644 index 8b5894e..0000000 --- a/enrollment/enrollmentJAMFIntegrationHelper/main.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// main.swift -// enrollmentJAMFIntegrationHelper -// -// Created by Jay Latman on 10/11/18. -// Copyright © 2018 IBM. All rights reserved. -// SPDX-License-Identifier: GPL-3.0-only -// - -import Foundation - -let helper = JAMFIntegrationHelper() -NSLog("Starting JAMFIntegrationHelper....") -helper.run() - diff --git a/scripts/bundleInstallSample.py b/scripts/bundleInstallSample.py deleted file mode 100644 index 039c1c8..0000000 --- a/scripts/bundleInstallSample.py +++ /dev/null @@ -1,132 +0,0 @@ -#!/usr/bin/env python2.7 -# -# IBM 11/15/2018 -# App Installs called by the enrollment app after bundle choices -# Sample code for Open Source project. -# -# SPDX-License-Identifier: GPL-3.0-only - -import os -import time -import subprocess -from subprocess import Popen, PIPE -from collections import OrderedDict - -''' -# These are the paramaters that are passed from the bundle install to the install function. -install_event_list is a dictionary with multiple values for the install function. - install_event_list = {AppText1 : [AppInstallOrder1,AppPlistUpdateName1,AppJPSEventTrigger1, AppInstallVerifyPath1]} - AppText1 = Message that is displayed to the UI for the application being installed. - AppInstallOrder1 = Order to install - AppPlistUpdateName1 = Text that is added to the plist key to start the spinner in the UI for that app. anyconnect+InstallStatus = anyconnectInstallStatus - AppJPSEventTrigger1 = Policy event for the jamf binary to execute - AppInstallVerifyPath1 = The application path to verify that the install was successful - - Example: - install_event_list = {Installing AnyConnect : [1,anyconnect,anyconnect_trigger, /Applications/AnyConnect.app]} - -''' - -''' -# The example bundle install block at the bottom will need to be updated for each bundle in the application. -# This bundles are shown on the wiki under Bundle Selection View page. -bundlename = "connectivity" -''' - -############### Start of function ############### -# Function to run the installs. -def install(section, event, loggedInUser, appText, plistText, appPath): - print section, event, loggedInUser, appText, plistText, appPath - appInstall = plistText + "InstallStatus" - # Set the status of the spinner 1=ON, 2=OFF - statusstart = '1' - statusstop = '2' - - # Set the install status for the application that is being installed. - plistbuddy = 'sudo -u %s /usr/libexec/PlistBuddy -c "Set :%sInstallStatus %s" %s' % (loggedInUser, plistText, statusstart, filePath) - sub_command = [ plistbuddy ] - ssUser = subprocess.Popen(sub_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) - - - # Set the message for the end user - print "%sMessaging %s" % (section, appText) - Message = "%sMessaging" % (section) - Text = "%s" % (appText) - sub_command = ['sudo', '-u', loggedInUser, 'defaults', 'write', filePath, Message, Text] - ssUser = subprocess.Popen(sub_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - - if "ibmmangement" in appPath: - os.system("sudo jamf policy -event %s -forceNoRecon" % event) - else: - if os.path.exists(appPath): - print "App %s already installed" % appPath - time.sleep(2) - else: - print "jamf %s" % event - os.system("sudo jamf policy -event %s -forceNoRecon" % event) - - - # Updated the install completion status... 2=Success, 3=Fail - if os.path.exists(appPath): - statusstop = '2' - else: - statusstop = '3' - - print statusstop - plistbuddy = 'sudo -u %s /usr/libexec/PlistBuddy -c "Set :%sInstallStatus %s" %s' % (loggedInUser, plistText, statusstop, filePath) - sub_command = [ plistbuddy ] - ssUser = subprocess.Popen(sub_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) - time.sleep(2) -############### End of function ############### - -################################################################################################################################################### -################################################################################################################################################### -## Get the User home directory path. -sub_command = "/bin/ls -la /dev/console | /usr/bin/cut -d ' ' -f 4" -loggedInUser = subprocess.Popen(sub_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) -loggedInUser = loggedInUser.communicate()[0] -loggedInUser = loggedInUser.strip() -print "logged in user is: %s" % loggedInUser -filePath = "/Users/%s/Library/Preferences/com.ibm.enrollment.plist" % loggedInUser - -# Set the status of the spinner 1=ON, 2=OFF -statusstart = '1' -statusstop = '2' - -# Read the plist for the Selected Bundles to install -sub_command = "sudo -u %s defaults read %s SelectedBundles" % (loggedInUser, filePath) -bundles = subprocess.Popen(sub_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) -bundles = bundles.communicate()[0] -print bundles - -# Example install bundle. -#For each bundle you will need to create a loop or duplicate the block below. -################# Start of Block ######################### - -# Name of bundles in the application plist shown in the Wiki docs under Bundle Selection View page. -bundlename = "connectivity" -if bundlename in bundles: - print "Install %s" % bundlename - section = bundlename - sub_command = ['sudo', '-u', loggedInUser, 'defaults', 'write', filePath, '%sBundleStatus', '-int', statusstart] % bundlename - ssUser = subprocess.Popen(sub_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - # You will need to add each app to the install_event_list - install_event_list = {'AppText1' : ['AppInstallOrder1','AppPlistUpdateName1','AppJPSEventTrigger1', 'AppInstallVerifyPath1'], 'AppText2' : ['AppInstallOrder2','AppPlistUpdateName2','AppJPSEventTrigger2', 'AppInstallVerifyPath2']} - install_event_list = OrderedDict(sorted(install_event_list.items(), key=lambda t: t[1])) - for dict in install_event_list: - plistText = (install_event_list[dict][1]) - event = (install_event_list[dict][2]) - appPath = (install_event_list[dict][3]) - install(section, event, loggedInUser, dict, plistText, appPath) - - Message = "%sMessaging" % (section) - sub_command = ['sudo', '-u', loggedInUser, 'defaults', 'write', filePath, Message, '%s bundle complete '] % bundlename - ssUser = subprocess.Popen(sub_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - - sub_command = ['sudo', '-u', loggedInUser, 'defaults', 'write', filePath, '%sBundleStatus', '-int', statusstop] % bundlename - ssUser = subprocess.Popen(sub_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) -#################### End of Block ###################### - -# Set the App Screen to close it -sub_command = ['sudo', '-u', loggedInUser, 'defaults', 'write', filePath, 'appScreenStatus', '-int', '1'] -ssUser = subprocess.Popen(sub_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) diff --git a/scripts/com.ibm.jamf.IntegrationHelper.plist b/scripts/com.ibm.jamf.IntegrationHelper.plist deleted file mode 100644 index d48adb8..0000000 --- a/scripts/com.ibm.jamf.IntegrationHelper.plist +++ /dev/null @@ -1,19 +0,0 @@ - - - - - Label - com.ibm.jamf.IntegrationHelper - MachServices - - com.ibm.jamf.IntegrationHelper - - - Program - /Library/PrivilegedHelperTools/com.ibm.jamf.IntegrationHelper - ProgramArguments - - /Library/PrivilegedHelperTools/com.ibm.jamf.IntegrationHelper - - - diff --git a/scripts/enrollmentSample.py b/scripts/enrollmentSample.py deleted file mode 100644 index 8cf55c3..0000000 --- a/scripts/enrollmentSample.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python2.7 -# -# IBM 11/15/2018 -# Sample code for Open Source project -# Items used in the UI during enrollment -# -# SPDX-License-Identifier: GPL-3.0-only -import os -import subprocess -import time -from subprocess import Popen, PIPE -from SystemConfiguration import SCDynamicStoreCopyConsoleUser -import urllib2 -import base64 -import sys -import json - -# Get the logged in user -loggedInUser = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0] -loggedInUser = [loggedInUser,""][loggedInUser in [u"loginwindow", None, u""]] - -print "logged in user is: %s" % loggedInUser -fileUserPath="/Users/%s/Library/Preferences/com.ibm.enrollment.plist" % loggedInUser - -# Setup for enrollment -if os.path.exists(fileUserPath): - os.remove(fileUserPath) - -# Sample code for pulling data from the JSS with the api -# sys arguements are pulled from script parameters in the jss -''' -jss_url = sys.argv[4] -jss_url = jss_url.rstrip('/') -jss_api_user = sys.argv[5] -jss_api_passwd = sys.argv[6] - -sub_command = "system_profiler SPHardwareDataType | grep UUID | awk '" " { print $NF }'" -result = subprocess.Popen(sub_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) -UDID = result.communicate()[0] -UDID = UDID.rstrip('\r\n') - -jss_sub_url = str(jss_url + '/JSSResource/computers/udid/%s/subset/general&location&extension_attributes') % UDID -request = urllib2.Request(jss_sub_url) -request.add_header('Accept', 'application/json') -request.add_header('Authorization', 'Basic ' + base64.b64encode(jss_api_user + ':' + jss_api_passwd)) -response = urllib2.urlopen(request) -apidata = json.load(response) - -# Read the xml -username = apidata['computer']['location']['username'] -jssid = apidata['computer']['general']['id'] -email = apidata['computer']['location']['email_address'] -position = apidata['computer']['location']['position'] -''' - -# The username to display in the app. You can use the username pulled from the api call above or use your on method to populate. -hrFirstName="%s" % username -#Example for enrollmentAppItems below add the bundle size and the seconds to install. -#enrollmentAppItems= {"LDAPHRFName": hrFirstName, "connectivitySize": "18.0", "connectivityInstallSeconds": "13.57","jpsCommSeconds": "60.0",} - -# Update the plsit file -# First value is the key in the plist Second is the value. -enrollmentAppItems= {"username": hrFirstName, "NameOfBundleSize1": "BundleSize1", "NameOfBundleSize2": "BundleSize2", "NameOfBundleInstallSeconds1": "BundleInstallTime1", "NameOfBundleInstallSeconds2": "BundleInstallTime2","jpsCommSeconds": "60.0",} -print(enrollmentAppItems) -for key, value in enrollmentAppItems.items(): - print(key, value) - sub_command = ['sudo', '-u', loggedInUser, 'defaults', 'write', fileUserPath, key, value] - ssUser = subprocess.Popen(sub_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - -# Launch the enrollment application -os.system("open /Applications/Enrollment.app") diff --git a/scripts/postinstall b/scripts/postinstall deleted file mode 100755 index cf0be52..0000000 --- a/scripts/postinstall +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -launchctl load -w /Library/LaunchDaemons/com.ibm.JAMFIntegrationHelper.plist -exit 0 diff --git a/scripts/speedtestSample.py b/scripts/speedtestSample.py deleted file mode 100644 index e459915..0000000 --- a/scripts/speedtestSample.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python -# Determines the time it takes to download a 10MB pkg from the distribution point for the enrollment app to calculate download times. -# Sample code for Open Source project. used examples from https://docs.python.org/3/library/urllib.request.html and -# -# SPDX-License-Identifier: GPL-3.0-only - -import sys -import time -import urllib -import ssl -import plistlib -import os -import subprocess -import commands -import datetime - -########### VARIABLES THAT NEED TO BE CHANGED PER ENVIRONMENT ########### -# url is the path of a 10mb pkg to get a sample time from. -''' -url example https://jss_distrobution_point.com/SamplePackage.pkg -If you are using Enable Remote Authentication in the JSS you may need to create a non expiring download. -''' -url="https://my10mb.pkg" -###################################################################### -################## DO NOT CHANGE BELOW THIS LINE ################## - -lastrun = datetime.datetime.today().strftime('%Y-%m-%d') -speedtest = [] -filename="/private/tmp/sample.pkg" - -# reporthook function will calculate how long it takes to download the package from the save function. -def reporthook(number, blocksize, totalSize): - global starttime - if number == 0: - starttime = time.time() - return - speed = int(int(number * blocksize) / (1024 * (time.time() - starttime))) - speedtest.append(speed) - -# Save function downloads the url specified and saves it to the file location specified in filename. -def save(url, filename): - ssl._create_default_https_context = ssl._create_unverified_context - urllib.urlretrieve(url, filename, reporthook) - -#__main__ - -# run the save function passing the url and filename. -result=save(url,filename) -result = str(round(int(sum(speedtest) / float(len(speedtest))) * float(0.000976562),2)) -print result - -# Write the results to the plist file for the enrollment app. -sub_command = "/bin/ls -la /dev/console | /usr/bin/cut -d ' ' -f 4" -loggedInUser = subprocess.Popen(sub_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) -loggedInUser = loggedInUser.communicate()[0] -loggedInUser = loggedInUser.strip() - -print "logged in user is: %s" % loggedInUser -filePath = "/Users/%s/Library/Preferences/com.ibm.enrollment.plist" % loggedInUser -print filePath - -sub_command = ['sudo', '-u', loggedInUser, 'defaults', 'write', filePath, 'speedTestResult', result] -ssUser = subprocess.Popen(sub_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) -