@@ -38,9 +38,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
3838 @IBOutlet private var installMailPluginMenuItem : NSMenuItem !
3939 @IBOutlet private var installAltStoreMenuItem : NSMenuItem !
4040 @IBOutlet private var sideloadAppMenuItem : NSMenuItem !
41-
42- private weak var authenticationAppleIDTextField : NSTextField ?
43- private weak var authenticationPasswordTextField : NSSecureTextField ?
41+ @IBOutlet private var logInMenuItem : NSMenuItem !
4442
4543 private var connectedDevicesMenuController : MenuController < ALTDevice > !
4644 private var sideloadIPAConnectedDevicesMenuController : MenuController < ALTDevice > !
@@ -119,6 +117,8 @@ class AppDelegate: NSObject, NSApplicationDelegate {
119117 self . installMailPlugin ( )
120118 }
121119 }
120+
121+ setupLoginMenuItem ( )
122122 }
123123
124124 func applicationWillTerminate( _ aNotification: Notification )
@@ -191,48 +191,32 @@ private extension AppDelegate
191191
192192 func installApplication( at url: URL , to device: ALTDevice )
193193 {
194- let alert = NSAlert ( )
195- alert. messageText = NSLocalizedString ( " Please enter your Apple ID and password. " , comment: " " )
196- alert. informativeText = NSLocalizedString ( " Your Apple ID and password are not saved and are only sent to Apple for authentication. " , comment: " " )
197-
198- let textFieldSize = NSSize ( width: 300 , height: 22 )
199-
200- let appleIDTextField = NSTextField ( frame: NSRect ( x: 0 , y: 0 , width: textFieldSize. width, height: textFieldSize. height) )
201- appleIDTextField. delegate = self
202- appleIDTextField. translatesAutoresizingMaskIntoConstraints = false
203- appleIDTextField. placeholderString = NSLocalizedString ( " Apple ID " , comment: " " )
204- alert. window. initialFirstResponder = appleIDTextField
205- self . authenticationAppleIDTextField = appleIDTextField
206-
207- let passwordTextField = NSSecureTextField ( frame: NSRect ( x: 0 , y: 0 , width: textFieldSize. width, height: textFieldSize. height) )
208- passwordTextField. delegate = self
209- passwordTextField. translatesAutoresizingMaskIntoConstraints = false
210- passwordTextField. placeholderString = NSLocalizedString ( " Password " , comment: " " )
211- self . authenticationPasswordTextField = passwordTextField
212-
213- appleIDTextField. nextKeyView = passwordTextField
214-
215- let stackView = NSStackView ( frame: NSRect ( x: 0 , y: 0 , width: textFieldSize. width, height: textFieldSize. height * 2 ) )
216- stackView. orientation = . vertical
217- stackView. distribution = . equalSpacing
218- stackView. spacing = 0
219- stackView. addArrangedSubview ( appleIDTextField)
220- stackView. addArrangedSubview ( passwordTextField)
221- alert. accessoryView = stackView
222-
223- alert. addButton ( withTitle: NSLocalizedString ( " Install " , comment: " " ) )
224- alert. addButton ( withTitle: NSLocalizedString ( " Cancel " , comment: " " ) )
225-
226- self . authenticationAlert = alert
227- self . validate ( )
228-
229- NSRunningApplication . current. activate ( options: . activateIgnoringOtherApps)
230-
231- let response = alert. runModal ( )
232- guard response == . alertFirstButtonReturn else { return }
233-
234- let username = appleIDTextField. stringValue
235- let password = passwordTextField. stringValue
194+ let username : String
195+ let password : String
196+
197+ if let _username = try ? Keychain . shared. getValue ( for: . appleIDEmail) ,
198+ let _password = try ? Keychain . shared. getValue ( for: . appleIDPassword) {
199+ username = _username
200+ password = _password
201+ } else {
202+ let alert = AppleIDAuthenticationAlert ( )
203+ self . authenticationAlert = alert
204+
205+ NSRunningApplication . current. activate ( options: . activateIgnoringOtherApps)
206+
207+ let didTapContinue = alert. display ( )
208+ guard didTapContinue else { return }
209+
210+ username = alert. appleIDValue. trimmingCharacters ( in: . whitespacesAndNewlines)
211+ password = alert. passwordValue. trimmingCharacters ( in: . whitespacesAndNewlines)
212+
213+ do {
214+ try Keychain . shared. setValue ( username. isEmpty ? nil : username, for: . appleIDEmail)
215+ try Keychain . shared. setValue ( password. isEmpty ? nil : password, for: . appleIDPassword)
216+ } catch {
217+ print ( " AppleID Auth: Error saving credentials: \( error) " )
218+ }
219+ }
236220
237221 func finish( _ result: Result < ALTApplication , Error > )
238222 {
@@ -447,6 +431,58 @@ private extension AppDelegate
447431 }
448432}
449433
434+ // MARK: - AppDelegate+loginMenuItem
435+
436+ private extension AppDelegate {
437+ private func setupLoginMenuItem( ) {
438+ do {
439+ let email = try Keychain . shared. getValue ( for: . appleIDEmail)
440+ logInMenuItem. title = " Log out ( \( email) ) "
441+ logInMenuItem. action = #selector( logoutFromAppleID)
442+ } catch {
443+ print ( " Error getting stored AppleID credentials: \( error) " )
444+ logInMenuItem. title = " Log in... "
445+ logInMenuItem. action = #selector( loginToAppleID)
446+ }
447+ }
448+
449+ @objc private func loginToAppleID( ) {
450+ let alert = AppleIDAuthenticationAlert ( )
451+
452+ NSRunningApplication . current. activate ( options: . activateIgnoringOtherApps)
453+ let didTapContinue = alert. display ( )
454+ guard didTapContinue else { return }
455+
456+ let username = alert. appleIDValue. trimmingCharacters ( in: . whitespacesAndNewlines)
457+ let password = alert. passwordValue. trimmingCharacters ( in: . whitespacesAndNewlines)
458+
459+ guard !username. isEmpty && !password. isEmpty else {
460+ print ( " AppleID Auth: Username and/or password was empty. " )
461+ return
462+ }
463+
464+ do {
465+ try Keychain . shared. setValue ( username, for: . appleIDEmail)
466+ try Keychain . shared. setValue ( password, for: . appleIDPassword)
467+ } catch {
468+ let errorAlert = NSAlert ( error: error)
469+ NSRunningApplication . current. activate ( options: . activateIgnoringOtherApps)
470+ errorAlert. runModal ( )
471+
472+ print ( " AppleID Auth: Error saving credentials: \( error) " )
473+ }
474+
475+ setupLoginMenuItem ( )
476+ }
477+
478+ @objc private func logoutFromAppleID( ) {
479+ print ( " Removing AppleID credentials! " )
480+ try ? Keychain . shared. setValue ( nil , for: . appleIDEmail)
481+ try ? Keychain . shared. setValue ( nil , for: . appleIDPassword)
482+ setupLoginMenuItem ( )
483+ }
484+ }
485+
450486extension AppDelegate : NSMenuDelegate
451487{
452488 func menuWillOpen( _ menu: NSMenu )
@@ -565,38 +601,6 @@ extension AppDelegate: NSMenuDelegate
565601 }
566602}
567603
568- extension AppDelegate : NSTextFieldDelegate
569- {
570- func controlTextDidChange( _ obj: Notification )
571- {
572- self . validate ( )
573- }
574-
575- func controlTextDidEndEditing( _ obj: Notification )
576- {
577- self . validate ( )
578- }
579-
580- private func validate( )
581- {
582- guard
583- let appleID = self . authenticationAppleIDTextField? . stringValue. trimmingCharacters ( in: . whitespacesAndNewlines) ,
584- let password = self . authenticationPasswordTextField? . stringValue. trimmingCharacters ( in: . whitespacesAndNewlines)
585- else { return }
586-
587- if appleID. isEmpty || password. isEmpty
588- {
589- self . authenticationAlert? . buttons. first? . isEnabled = false
590- }
591- else
592- {
593- self . authenticationAlert? . buttons. first? . isEnabled = true
594- }
595-
596- self . authenticationAlert? . layout ( )
597- }
598- }
599-
600604extension AppDelegate : UNUserNotificationCenterDelegate
601605{
602606 func userNotificationCenter( _ center: UNUserNotificationCenter , willPresent notification: UNNotification , withCompletionHandler completionHandler: @escaping ( UNNotificationPresentationOptions ) -> Void )
0 commit comments