Add touchbar support (#862)

* Add touchbar support for the password input

* Add touchbar support for entry list

* Set NSTouchBarItemIdentifier as static strings

* Simplify touchbar initialization in NSTextView

* Remove colored buttons in touchbar to adhere to the Human Interface Guidelines

* Add search action to touchbar

* Create a TouchBarButtonCreator

* Enable Touchbar customization

* Fix typo

* Add customizationLabel to all buttons

* Use localised strings instead of hardcoded

* Add a popover touchbar for editing

* Update localisation

* Set the bezel color of the show password button to selected if toggled
This commit is contained in:
Veit-Hendrik Schlenker
2019-07-10 12:00:38 +02:00
committed by Michael Starke
parent 30a68fc9e3
commit 2d98c480da
12 changed files with 293 additions and 2 deletions

View File

@@ -45,6 +45,7 @@
#import "MPAutotypeDoctor.h"
#import "NSApplication+MPAdditions.h"
#import "NSTextView+MPTouchBarExtension.h"
#import "KeePassKit/KeePassKit.h"
@@ -222,6 +223,13 @@ typedef NS_OPTIONS(NSInteger, MPAppStartupState) {
[SUUpdater sharedUpdater];
#endif
self.startupState |= MPAppStartupStateFinishedLaunch;
// Here we just opt-in for allowing our bar to be customized throughout the app.
if ([[NSApplication sharedApplication] respondsToSelector:@selector(isAutomaticCustomizeTouchBarMenuItemEnabled)])
{
if (@available(macOS 10.12.2, *)) {
[NSApplication sharedApplication].automaticCustomizeTouchBarMenuItemEnabled = YES;
}
}
}
#pragma mark -

View File

@@ -31,7 +31,7 @@
@class MPOutlineViewController;
@class MPToolbarDelegate;
@interface MPDocumentWindowController : NSWindowController
@interface MPDocumentWindowController : NSWindowController <NSTouchBarDelegate>
@property (readonly, strong) MPPasswordInputController *passwordInputController;
@property (readonly, strong) MPEntryViewController *entryViewController;

View File

@@ -39,12 +39,26 @@
#import "MPSettingsHelper.h"
#import "MPToolbarDelegate.h"
#import "MPTitlebarColorAccessoryViewController.h"
#import "MPTouchBarButtonCreator.h"
#import "MPIconHelper.h"
#import "MPPluginHost.h"
#import "MPPlugin.h"
#import "KeePassKit/KeePassKit.h"
static NSTouchBarCustomizationIdentifier touchBarIdentifier = @"com.hicknhacksoftware.MacPass.TouchBar.documentWindow";
static NSTouchBarItemIdentifier touchBarSearchIdentifier = @"com.hicknhacksoftware.MacPass.TouchBar.documentWindow.search";
static NSTouchBarItemIdentifier touchBarEditPopoverIdentifier = @"com.hicknhacksoftware.MacPass.TouchBar.documentWindow.editPopover";
static NSTouchBarItemIdentifier touchBarCopyUsernameIdentifier = @"com.hicknhacksoftware.MacPass.TouchBar.documentWindow.copyUsername";
static NSTouchBarItemIdentifier touchBarCopyPasswordIdentifier = @"com.hicknhacksoftware.MacPass.TouchBar.documentWindow.copyPassword";
static NSTouchBarItemIdentifier touchBarPerformAutotypeIdentifier = @"com.hicknhacksoftware.MacPass.TouchBar.documentWindow.performAutotype";
static NSTouchBarItemIdentifier touchBarLockIdentifier = @"com.hicknhacksoftware.MacPass.TouchBar.documentWindow.lock";
static NSTouchBarItemIdentifier secondaryTouchBarNewEntryIdentifier = @"com.hicknhacksoftware.MacPass.TouchBar.documentWindow.newEntry";
static NSTouchBarItemIdentifier secondaryTouchBarNewGroupIdentifier = @"com.hicknhacksoftware.MacPass.TouchBar.documentWindow.newGroup";
static NSTouchBarItemIdentifier secondaryTouchBarDeleteIdentifier = @"com.hicknhacksoftware.MacPass.TouchBar.documentWindow.delete";
typedef NS_ENUM(NSUInteger, MPAlertContext) {
MPAlertLossySaveWarning,
};
@@ -652,4 +666,48 @@ typedef void (^MPPasswordChangedBlock)(BOOL didChangePassword);
return (nil != inspectorView.superview);
}
- (NSTouchBar *)makeTouchBar {
NSTouchBar *touchBar = [[NSTouchBar alloc] init];
touchBar.delegate = self;
touchBar.customizationIdentifier = touchBarIdentifier;
NSArray<NSTouchBarItemIdentifier> *defaultItemIdentifiers = @[touchBarSearchIdentifier, touchBarEditPopoverIdentifier, touchBarCopyUsernameIdentifier, touchBarCopyPasswordIdentifier, touchBarPerformAutotypeIdentifier, NSTouchBarItemIdentifierFlexibleSpace, touchBarLockIdentifier];
touchBar.defaultItemIdentifiers = defaultItemIdentifiers;
touchBar.customizationAllowedItemIdentifiers = defaultItemIdentifiers;
return touchBar;
}
- (NSTouchBarItem *)touchBar:(NSTouchBar *)touchBar makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier API_AVAILABLE(macos(10.12.2)) {
#pragma mark primary touchbar elements
if (identifier == touchBarSearchIdentifier) {
return [MPTouchBarButtonCreator touchBarButtonWithImage:[NSImage imageNamed:NSImageNameTouchBarSearchTemplate] identifier:touchBarSearchIdentifier target:self selector:@selector(focusSearchField) customizationLabel:NSLocalizedString(@"TOUCHBAR_SEARCH","Touchbar button label for searching the database")];
} else if (identifier == touchBarEditPopoverIdentifier) {
NSTouchBar *secondaryTouchBar = [[NSTouchBar alloc] init];
secondaryTouchBar.delegate = self;
secondaryTouchBar.defaultItemIdentifiers = @[secondaryTouchBarNewEntryIdentifier, secondaryTouchBarNewGroupIdentifier, secondaryTouchBarDeleteIdentifier];
return [MPTouchBarButtonCreator popoverTouchBarButton:NSLocalizedString(@"TOUCHBAR_EDIT","Touchbar button label for opening the popover to edit") identifier:touchBarEditPopoverIdentifier popoverTouchBar:secondaryTouchBar customizationLabel:NSLocalizedString(@"TOUCHBAR_EDIT","Touchbar button label for opening the popover to edit")];
} else if (identifier == touchBarCopyUsernameIdentifier) {
return [MPTouchBarButtonCreator touchBarButtonWithTitle:NSLocalizedString(@"TOUCHBAR_COPY_USERNAME","Touchbar button label for copying the username") identifier:touchBarCopyUsernameIdentifier target:self selector:@selector(copyUsername:) customizationLabel:NSLocalizedString(@"TOUCHBAR_COPY_USERNAME","Touchbar button label for copying the username")];
} else if (identifier == touchBarCopyPasswordIdentifier) {
return [MPTouchBarButtonCreator touchBarButtonWithTitle:NSLocalizedString(@"TOUCHBAR_COPY_PASSWORD","Touchbar button label for copying the password") identifier:touchBarCopyPasswordIdentifier target:self selector:@selector(copyPassword:) customizationLabel:NSLocalizedString(@"TOUCHBAR_COPY_PASSWORD","Touchbar button label for copying the password")];
} else if (identifier == touchBarPerformAutotypeIdentifier) {
return [MPTouchBarButtonCreator touchBarButtonWithTitle:NSLocalizedString(@"TOUCHBAR_PERFORM_AUTOTYPE","Touchbar button label for performing autotype") identifier:touchBarPerformAutotypeIdentifier target:self selector:@selector(performAutotypeForEntry:) customizationLabel:NSLocalizedString(@"TOUCHBAR_PERFORM_AUTOTYPE","Touchbar button label for performing autotype")];
} else if (identifier == touchBarLockIdentifier) {
return [MPTouchBarButtonCreator touchBarButtonWithImage:[NSImage imageNamed:NSImageNameLockUnlockedTemplate] identifier:touchBarLockIdentifier target:self selector:@selector(lock:) customizationLabel:NSLocalizedString(@"TOUCHBAR_LOCK_DATABASE","Touchbar button label for locking the database")];
}
#pragma mark secondary/popover touchbar elements
else if (identifier == secondaryTouchBarNewEntryIdentifier) {
return [MPTouchBarButtonCreator touchBarButtonWithTitleAndImage:NSLocalizedString(@"TOUCHBAR_NEW_ENTRY","Touchbar button label for creating a new item") identifier:secondaryTouchBarNewEntryIdentifier image:[MPIconHelper icon:MPIconAddEntry] target:self selector:@selector(createEntry:) customizationLabel:NSLocalizedString(@"TOUCHBAR_NEW_ENTRY","Touchbar button label for creating a new item")];
} else if (identifier == secondaryTouchBarNewGroupIdentifier) {
return [MPTouchBarButtonCreator touchBarButtonWithTitleAndImage:NSLocalizedString(@"TOUCHBAR_NEW_GROUP","Touchbar button label for creating a new group") identifier:secondaryTouchBarNewGroupIdentifier image:[MPIconHelper icon:MPIconAddFolder] target:self selector:@selector(createGroup:) customizationLabel:NSLocalizedString(@"TOUCHBAR_NEW_GROUP","Touchbar button label for creating a new group")];
} else if (identifier == secondaryTouchBarDeleteIdentifier) {
return [MPTouchBarButtonCreator touchBarButtonWithTitleAndImageAndColor:NSLocalizedString(@"TOUCHBAR_DELETE","Touchbar button label for deleting elements") identifier:secondaryTouchBarDeleteIdentifier image:[MPIconHelper icon:MPIconTrash] color:[NSColor systemRedColor] target:self selector:@selector(delete:) customizationLabel:NSLocalizedString(@"TOUCHBAR_DELETE","Touchbar button label for deleting elements")];
} else {
return nil;
}
}
- (void)focusSearchField {
[self.window makeFirstResponder:[self searchField]];
}
@end

View File

@@ -24,7 +24,7 @@
@class KPKCompositeKey;
@interface MPPasswordInputController : MPViewController
@interface MPPasswordInputController : MPViewController <NSTouchBarDelegate>
typedef BOOL (^passwordInputCompletionBlock)(NSString *password, NSURL *keyURL, BOOL didCancel, NSError *__autoreleasing*error);

View File

@@ -26,13 +26,20 @@
#import "MPDocument.h"
#import "MPSettingsHelper.h"
#import "MPPathControl.h"
#import "MPTouchBarButtonCreator.h"
#import "HNHUi/HNHUi.h"
#import "NSError+Messages.h"
static NSTouchBarCustomizationIdentifier touchBarIdentifier = @"com.hicknhacksoftware.MacPass.TouchBar.passwordInput";
static NSTouchBarItemIdentifier touchBarChooseKeyfileIdentifier = @"com.hicknhacksoftware.MacPass.TouchBar.passwordInput.chooseKeyfile";
static NSTouchBarItemIdentifier touchBarShowPasswordIdentifier = @"com.hicknhacksoftware.MacPass.TouchBar.passwordInput.showPassword";
static NSTouchBarItemIdentifier touchBarUnlockIdentifier = @"com.hicknhacksoftware.MacPass.TouchBar.passwordInput.unlock";
@interface MPPasswordInputController ()
@property (strong) NSButton *showPasswordButton;
@property (weak) IBOutlet HNHUISecureTextField *passwordTextField;
@property (weak) IBOutlet MPPathControl *keyPathControl;
@property (weak) IBOutlet NSImageView *messageImageView;
@@ -177,4 +184,36 @@
self.messageInfoTextField.hidden = NO;
}
- (NSTouchBar *)makeTouchBar {
NSTouchBar *touchBar = [[NSTouchBar alloc] init];
touchBar.delegate = self;
touchBar.customizationIdentifier = touchBarIdentifier;
NSArray<NSTouchBarItemIdentifier> *defaultItemIdentifiers = @[touchBarShowPasswordIdentifier, touchBarChooseKeyfileIdentifier, NSTouchBarItemIdentifierFlexibleSpace,touchBarUnlockIdentifier];
touchBar.defaultItemIdentifiers = defaultItemIdentifiers;
touchBar.customizationAllowedItemIdentifiers = defaultItemIdentifiers;
return touchBar;
}
- (NSTouchBarItem *)touchBar:(NSTouchBar *)touchBar makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier API_AVAILABLE(macos(10.12.2)) {
if (identifier == touchBarChooseKeyfileIdentifier) {
return [MPTouchBarButtonCreator touchBarButtonWithTitleAndImage:NSLocalizedString(@"TOUCHBAR_CHOOSE_KEYFILE","Touchbar button label for choosing the keyfile") identifier:touchBarChooseKeyfileIdentifier image:[NSImage imageNamed:NSImageNameTouchBarFolderTemplate] target:self.keyPathControl selector:@selector(showOpenPanel:) customizationLabel:NSLocalizedString(@"TOUCHBAR_CHOOSE_KEYFILE","Touchbar button label for choosing the keyfile")];
} else if (identifier == touchBarShowPasswordIdentifier) {
NSTouchBarItem *item = [MPTouchBarButtonCreator touchBarButtonWithTitleAndImage:NSLocalizedString(@"TOUCHBAR_SHOW_PASSWORD","Touchbar button label for showing the password") identifier:touchBarShowPasswordIdentifier image:[NSImage imageNamed:NSImageNameTouchBarQuickLookTemplate] target:self selector:@selector(toggleShowPassword) customizationLabel:NSLocalizedString(@"TOUCHBAR_SHOW_PASSWORD","Touchbar button label for showing the password")];
_showPasswordButton = (NSButton *) item.view;
return item;
} else if (identifier == touchBarUnlockIdentifier) {
return [MPTouchBarButtonCreator touchBarButtonWithImage:[NSImage imageNamed:NSImageNameLockUnlockedTemplate] identifier:touchBarUnlockIdentifier target:self selector:@selector(_submit:) customizationLabel:NSLocalizedString(@"TOUCHBAR_UNLOCK_DATABASE","Touchbar button label for unlocking the database")];
} else {
return nil;
}
}
- (void)toggleShowPassword {
self.showPassword = !self.showPassword;
if (@available(macOS 10.12.2, *)) {
_showPasswordButton.bezelColor = self.showPassword ? [NSColor selectedControlColor] : [NSColor controlColor];
}
}
@end

View File

@@ -0,0 +1,22 @@
//
// MPTouchBarButtonCreator.h
// MacPass
//
// Created by Veit-Hendrik Schlenker on 25.12.18.
// Copyright © 2018 HicknHack Software GmbH. All rights reserved.
//
#import "MPPasswordInputController.h"
@interface MPTouchBarButtonCreator: NSObject
+ (NSTouchBarItem *) touchBarButtonWithTitle:(NSString *)title identifier:(NSTouchBarItemIdentifier)identifier target:(id)target selector:(SEL)selector customizationLabel:(NSString *)customizationLabel API_AVAILABLE(macos(10.12.2));
+ (NSTouchBarItem *) touchBarButtonWithTitleAndImage:(NSString *)title identifier:(NSTouchBarItemIdentifier)identifier image:(NSImage *)image target:(id)target selector:(SEL)selector customizationLabel:(NSString *)customizationLabel API_AVAILABLE(macos(10.12.2));
+ (NSTouchBarItem *) touchBarButtonWithTitleAndImageAndColor:(NSString *)title identifier:(NSTouchBarItemIdentifier)identifier image:(NSImage *)image color:(NSColor *)color target:(id)target selector:(SEL)selector customizationLabel:(NSString *)customizationLabel API_AVAILABLE(macos(10.12.2));
+ (NSTouchBarItem *) touchBarButtonWithImage:(NSImage *)image identifier:(NSTouchBarItemIdentifier)identifier target:(id)target selector:(SEL)selector customizationLabel:(NSString *)customizationLabel API_AVAILABLE(macos(10.12.2));
+ (NSPopoverTouchBarItem *) popoverTouchBarButton:(NSString *)title identifier:(NSTouchBarItemIdentifier)identifier popoverTouchBar:(NSTouchBar *)popoverTouchBar customizationLabel:(NSString *)customizationLabel API_AVAILABLE(macos(10.12.2));
@end

View File

@@ -0,0 +1,50 @@
//
// MPTouchBarButtonCreator.m
// MacPass
//
// Created by Veit-Hendrik Schlenker on 25.12.18.
// Copyright © 2018 HicknHack Software GmbH. All rights reserved.
//
#import "MPTouchBarButtonCreator.h"
@implementation MPTouchBarButtonCreator
+ (NSTouchBarItem *) touchBarButtonWithTitle:(NSString *)title identifier:(NSTouchBarItemIdentifier)identifier target:(id)target selector:(SEL)selector customizationLabel:(NSString *)customizationLabel API_AVAILABLE(macos(10.12.2)){
NSCustomTouchBarItem *item = [[NSCustomTouchBarItem alloc] initWithIdentifier:identifier];
NSButton *button = [NSButton buttonWithTitle:title target:target action:selector];
item.view = button;
item.customizationLabel = customizationLabel;
return item;
}
+ (NSTouchBarItem *) touchBarButtonWithTitleAndImage:(NSString *)title identifier:(NSTouchBarItemIdentifier)identifier image:(NSImage *)image target:(id)target selector:(SEL)selector customizationLabel:(NSString *)customizationLabel API_AVAILABLE(macos(10.12.2)){
return [self touchBarButtonWithTitleAndImageAndColor:title identifier:identifier image:image color:nil target:target selector:selector customizationLabel:customizationLabel];
}
+ (NSTouchBarItem *) touchBarButtonWithTitleAndImageAndColor:(NSString *)title identifier:(NSTouchBarItemIdentifier)identifier image:(NSImage *)image color:(NSColor *)color target:(id)target selector:(SEL)selector customizationLabel:(NSString *)customizationLabel API_AVAILABLE(macos(10.12.2)){
NSCustomTouchBarItem *item = [[NSCustomTouchBarItem alloc] initWithIdentifier:identifier];
NSButton *button = [NSButton buttonWithTitle:title image:image target:target action:selector];
button.bezelColor = color;
item.view = button;
item.customizationLabel = customizationLabel;
return item;
}
+ (NSTouchBarItem *) touchBarButtonWithImage:(NSImage *)image identifier:(NSTouchBarItemIdentifier)identifier target:(id)target selector:(SEL)selector customizationLabel:(NSString *)customizationLabel API_AVAILABLE(macos(10.12.2)){
NSCustomTouchBarItem *item = [[NSCustomTouchBarItem alloc] initWithIdentifier:identifier];
NSButton *button = [NSButton buttonWithImage:image target:target action:selector];
item.view = button;
item.customizationLabel = customizationLabel;
return item;
}
+ (NSPopoverTouchBarItem *) popoverTouchBarButton:(NSString *)title identifier:(NSTouchBarItemIdentifier)identifier popoverTouchBar:(NSTouchBar *)popoverTouchBar customizationLabel:(NSString *)customizationLabel API_AVAILABLE(macos(10.12.2)){
NSPopoverTouchBarItem *item = [[NSPopoverTouchBarItem alloc] initWithIdentifier:identifier];
item.collapsedRepresentationLabel = title;
item.popoverTouchBar = popoverTouchBar;
item.customizationLabel = customizationLabel;
return item;
}
@end

View File

@@ -0,0 +1,13 @@
//
// NSTextView+MPNSTextView_TouchBarExtension_h.h
// MacPass
//
// Created by Veit-Hendrik Schlenker on 23.12.18.
// Copyright © 2018 HicknHack Software GmbH. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface NSTextView (TouchBarExtension)
@end

View File

@@ -0,0 +1,17 @@
//
// MP.m
// MacPass
//
// Created by Veit-Hendrik Schlenker on 23.12.18.
// Copyright © 2018 HicknHack Software GmbH. All rights reserved.
//
#import "NSTextView+MPTouchBarExtension.h"
@implementation NSTextView (TouchBarExtension)
- (NSTouchBar *) makeTouchBar {
return [self.window makeTouchBar];
}
@end

View File

@@ -676,6 +676,42 @@
/* Toolbar item to perform autotype */
"TOOLBAR_PERFORM_AUTOTYPE_FOR_ENTRY" = "Autotype";
/* Touchbar button label for choosing the keyfile */
"TOUCHBAR_CHOOSE_KEYFILE" = "Schlüsseldatei wählen";
/* Touchbar button label for copying the password */
"TOUCHBAR_COPY_PASSWORD" = "Passwort kopieren";
/* Touchbar button label for copying the username */
"TOUCHBAR_COPY_USERNAME" = "Benutzername kopieren";
/* Touchbar button label for deleting elements */
"TOUCHBAR_DELETE" = "Löschen";
/* Touchbar button label for opening the popover to edit */
"TOUCHBAR_EDIT" = "Bearbeiten";
/* Touchbar button label for locking the database */
"TOUCHBAR_LOCK_DATABASE" = "Datenbank sperren";
/* Touchbar button label for creating a new item */
"TOUCHBAR_NEW_ENTRY" = "Neuer Eintrag";
/* Touchbar button label for creating a new group */
"TOUCHBAR_NEW_GROUP" = "Neue Gruppe";
/* Touchbar button label for performing autotype */
"TOUCHBAR_PERFORM_AUTOTYPE" = "Autotype ausführen";
/* Touchbar button label for searching the database */
"TOUCHBAR_SEARCH" = "Datenbank durchsuchen";
/* Touchbar button label for showing the password */
"TOUCHBAR_SHOW_PASSWORD" = "Password anzeigen";
/* Touchbar button label for unlocking the database */
"TOUCHBAR_UNLOCK_DATABASE" = "Datenbank entsperren";
/* Move Entry to Trash */
"TRASH_ENTRY" = "Eintrag löschen";

View File

@@ -685,6 +685,42 @@
/* Toolbar item to perform autotype */
"TOOLBAR_PERFORM_AUTOTYPE_FOR_ENTRY" = "Autotype";
/* Touchbar button label for choosing the keyfile */
"TOUCHBAR_CHOOSE_KEYFILE" = "Choose Keyfile";
/* Touchbar button label for copying the password */
"TOUCHBAR_COPY_PASSWORD" = "Copy Password";
/* Touchbar button label for copying the username */
"TOUCHBAR_COPY_USERNAME" = "Copy Username";
/* Touchbar button label for deleting elements */
"TOUCHBAR_DELETE" = "Delete";
/* Touchbar button label for opening the popover to edit */
"TOUCHBAR_EDIT" = "Edit";
/* Touchbar button label for locking the database */
"TOUCHBAR_LOCK_DATABASE" = "Lock Database";
/* Touchbar button label for creating a new item */
"TOUCHBAR_NEW_ENTRY" = "New Entry";
/* Touchbar button label for creating a new group */
"TOUCHBAR_NEW_GROUP" = "New Group";
/* Touchbar button label for performing autotype */
"TOUCHBAR_PERFORM_AUTOTYPE" = "Perform Autotype";
/* Touchbar button label for searching the database */
"TOUCHBAR_SEARCH" = "Search Database";
/* Touchbar button label for showing the password */
"TOUCHBAR_SHOW_PASSWORD" = "Show Password";
/* Touchbar button label for unlocking the database */
"TOUCHBAR_UNLOCK_DATABASE" = "Unlock Database";
/* Move Entry to Trash */
"TRASH_ENTRY" = "Trash Entry";