introducting delete buttons for custom icons

This commit is contained in:
michael starke
2017-09-16 10:46:54 +02:00
parent 51a99a8bd0
commit 4493e8cb2c
10 changed files with 199 additions and 21 deletions

View File

@@ -1,3 +1,3 @@
github "sparkle-project/Sparkle" ~> 1.18.1
github "mstarke/KeePassKit" "3eac526e6f7e6b102cd38f7361b153ebc25dde2d"
github "mstarke/KeePassKit" "afb5bc189a36c30524d7a966d424f89212a12b3d"
github "mstarke/HNHUi" ~> 1.1

View File

@@ -1,3 +1,3 @@
github "mstarke/HNHUi" "1.1.2"
github "mstarke/KeePassKit" "3eac526e6f7e6b102cd38f7361b153ebc25dde2d"
github "mstarke/KeePassKit" "afb5bc189a36c30524d7a966d424f89212a12b3d"
github "sparkle-project/Sparkle" "1.18.1"

View File

@@ -114,6 +114,7 @@
4C4DC0A61C3AD17500DE9DCF /* KeePassKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C7B63791C0CB55600D7038C /* KeePassKit.framework */; };
4C4F72D118DF704400E8D378 /* DDHotKeyTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C4F72CF18DF704400E8D378 /* DDHotKeyTextField.m */; };
4C4FCE15177CFE6B00BBF7AE /* MPCustomFieldTableCellView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C4FCE14177CFE6B00BBF7AE /* MPCustomFieldTableCellView.m */; };
4C50CC041F6C18830095629D /* MPCollectionViewItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C50CC031F6C18830095629D /* MPCollectionViewItem.m */; };
4C52A88E1788628B00868229 /* 06_BlockDeviceTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4C52A88B1788628B00868229 /* 06_BlockDeviceTemplate.pdf */; };
4C52A88F1788628B00868229 /* 13_KeysTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4C52A88C1788628B00868229 /* 13_KeysTemplate.pdf */; };
4C52A8901788628B00868229 /* 18_DisplayTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4C52A88D1788628B00868229 /* 18_DisplayTemplate.pdf */; };
@@ -465,6 +466,8 @@
4C4F72D018DF704400E8D378 /* DDHotKeyTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDHotKeyTextField.h; path = DDHotKey/DDHotKeyTextField.h; sourceTree = "<group>"; };
4C4FCE13177CFE6B00BBF7AE /* MPCustomFieldTableCellView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPCustomFieldTableCellView.h; sourceTree = "<group>"; };
4C4FCE14177CFE6B00BBF7AE /* MPCustomFieldTableCellView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCustomFieldTableCellView.m; sourceTree = "<group>"; };
4C50CC021F6C18830095629D /* MPCollectionViewItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPCollectionViewItem.h; sourceTree = "<group>"; };
4C50CC031F6C18830095629D /* MPCollectionViewItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCollectionViewItem.m; sourceTree = "<group>"; };
4C52A88B1788628B00868229 /* 06_BlockDeviceTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = 06_BlockDeviceTemplate.pdf; sourceTree = "<group>"; };
4C52A88C1788628B00868229 /* 13_KeysTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = 13_KeysTemplate.pdf; sourceTree = "<group>"; };
4C52A88D1788628B00868229 /* 18_DisplayTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = 18_DisplayTemplate.pdf; sourceTree = "<group>"; };
@@ -1367,6 +1370,8 @@
4C1BDF281E4392640012A3F0 /* MPPluginDataViewController.h */,
4C1BDF291E4392640012A3F0 /* MPPluginDataViewController.m */,
4C1BDF2A1E4392640012A3F0 /* PluginDataView.xib */,
4C50CC021F6C18830095629D /* MPCollectionViewItem.h */,
4C50CC031F6C18830095629D /* MPCollectionViewItem.m */,
);
name = "View Controller";
sourceTree = "<group>";
@@ -1806,6 +1811,7 @@
4C10412C178CDD44001B5239 /* NSDate+Humanized.m in Sources */,
4C0C59F118B17F10009C7B76 /* DDHotKeyUtilities.m in Sources */,
4CEE46DD181C301D006BF1E5 /* MPAutotypeDaemon.m in Sources */,
4C50CC041F6C18830095629D /* MPCollectionViewItem.m in Sources */,
4C8990F71EE978EB0043B48D /* MPDuplicateEntryOptionsWindowController.m in Sources */,
4CA3530B18A53CB800839B0F /* MPKeyMapper.m in Sources */,
4CE298EB1795FC2A00DF7BDB /* MPEntryContextMenuDelegate.m in Sources */,

View File

@@ -23,12 +23,13 @@
<rect key="frame" x="0.0" y="0.0" width="380" height="270"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<collectionView focusRingType="none" id="58">
<collectionView focusRingType="none" selectable="YES" id="58">
<rect key="frame" x="0.0" y="0.0" width="380" height="270"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="primaryBackgroundColor" name="windowBackgroundColor" catalog="System" colorSpace="catalog"/>
<connections>
<outlet property="itemPrototype" destination="61" id="63"/>
<outlet property="menu" destination="vS0-bP-ZyJ" id="nAW-cJ-Vzp"/>
</connections>
</collectionView>
</subviews>
@@ -54,10 +55,13 @@
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="8kv-BJ-IEk">
<rect key="frame" x="153" y="18" width="104" height="25"/>
<buttonCell key="cell" type="roundTextured" title="Download Icon" bezelStyle="texturedRounded" alignment="center" lineBreakMode="truncatingTail" enabled="NO" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="iaf-XW-XUo">
<buttonCell key="cell" type="roundTextured" title="Download Icon" bezelStyle="texturedRounded" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="iaf-XW-XUo">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="downloadIcon:" target="-2" id="VIQ-4U-K4z"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="His-4A-hcY">
<rect key="frame" x="89" y="18" width="56" height="25"/>
@@ -85,8 +89,9 @@
</constraints>
<point key="canvasLocation" x="-143" y="15"/>
</customView>
<collectionViewItem id="61">
<collectionViewItem id="61" customClass="MPCollectionViewItem">
<connections>
<outlet property="deleteImageButton" destination="MEC-x9-zrX" id="PSx-mD-G8C"/>
<outlet property="view" destination="113" id="128"/>
</connections>
</collectionViewItem>
@@ -94,6 +99,31 @@
<rect key="frame" x="0.0" y="0.0" width="48" height="48"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<button translatesAutoresizingMaskIntoConstraints="NO" id="MEC-x9-zrX">
<rect key="frame" x="32" y="32" width="16" height="16"/>
<constraints>
<constraint firstAttribute="width" constant="16" id="cau-QV-8TQ"/>
<constraint firstAttribute="height" constant="16" id="yHZ-qj-Rcy"/>
</constraints>
<buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="NSRefreshFreestandingTemplate" imagePosition="overlaps" alignment="center" imageScaling="proportionallyUpOrDown" inset="2" id="zWZ-Wt-ThY">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="61" name="argument" keyPath="representedObject" id="rJw-Yy-JjZ">
<dictionary key="options">
<bool key="NSConditionallySetsEnabled" value="NO"/>
<string key="NSSelectorName">_deleteIcon:</string>
</dictionary>
</binding>
<binding destination="-2" name="target" keyPath="self" previousBinding="rJw-Yy-JjZ" id="j04-R4-qhO">
<dictionary key="options">
<bool key="NSConditionallySetsEnabled" value="NO"/>
<string key="NSSelectorName">_deleteIcon:</string>
</dictionary>
</binding>
</connections>
</button>
<button translatesAutoresizingMaskIntoConstraints="NO" id="114">
<rect key="frame" x="8" y="8" width="32" height="32"/>
<constraints>
@@ -124,10 +154,27 @@
<constraints>
<constraint firstItem="114" firstAttribute="centerY" secondItem="113" secondAttribute="centerY" id="168"/>
<constraint firstItem="114" firstAttribute="centerX" secondItem="113" secondAttribute="centerX" id="169"/>
<constraint firstAttribute="trailing" secondItem="MEC-x9-zrX" secondAttribute="trailing" id="l85-hK-J0S"/>
<constraint firstItem="MEC-x9-zrX" firstAttribute="top" secondItem="113" secondAttribute="top" id="uEr-Jk-Jfa"/>
</constraints>
</customView>
<menu id="vS0-bP-ZyJ">
<items>
<menuItem title="Item 1" id="M2B-II-30N">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Item 2" id="Vc1-gW-L1b">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Item 3" id="cUN-GX-EWu">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
</items>
<point key="canvasLocation" x="298" y="163"/>
</menu>
</objects>
<resources>
<image name="NSAddTemplate" width="11" height="11"/>
<image name="NSRefreshFreestandingTemplate" width="14" height="14"/>
</resources>
</document>

View File

@@ -0,0 +1,15 @@
//
// MPCollectionViewItem.h
// MacPass
//
// Created by Michael Starke on 15.09.17.
// Copyright © 2017 HicknHack Software GmbH. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface MPCollectionViewItem : NSCollectionViewItem
@property BOOL showDeleteIndicator;
@end

View File

@@ -0,0 +1,32 @@
//
// MPCollectionViewItem.m
// MacPass
//
// Created by Michael Starke on 15.09.17.
// Copyright © 2017 HicknHack Software GmbH. All rights reserved.
//
#import "MPCollectionViewItem.h"
#import "MPIconSelectViewController.h"
@interface MPCollectionViewItem ()
@property (strong) IBOutlet NSButton *deleteImageButton;
@end
@implementation MPCollectionViewItem
@dynamic showDeleteIndicator;
- (void)viewDidLoad {
self.showDeleteIndicator = NO;
}
- (void)setShowDeleteIndicator:(BOOL)showDeleteIndicator {
self.deleteImageButton.hidden = !showDeleteIndicator;
}
- (BOOL)showDeleteIndicator {
return !self.deleteImageButton.hidden;
}
@end

View File

@@ -80,9 +80,9 @@ static void MPContextmenuHelperBeginSection(NSMutableArray *items) {
NSMenuItem *emptyTrash = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"EMPTY_TRASH", @"")
action:[MPActionHelper actionOfType:MPActionEmptyTrash]
keyEquivalent:@""];
[emptyTrash setKeyEquivalentModifierMask:(NSShiftKeyMask | NSCommandKeyMask)];
emptyTrash.keyEquivalentModifierMask = (NSShiftKeyMask | NSCommandKeyMask);
unichar backSpace = NSBackspaceCharacter;
[emptyTrash setKeyEquivalent:[NSString stringWithCharacters:&backSpace length:1]];
emptyTrash.keyEquivalent = [NSString stringWithCharacters:&backSpace length:1];
[items addObject:emptyTrash];
}
@@ -95,12 +95,12 @@ static void MPContextmenuHelperBeginSection(NSMutableArray *items) {
NSMenuItem *copyPassword = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"COPY_PASSWORD", @"")
action:[MPActionHelper actionOfType:MPActionCopyPassword]
keyEquivalent:@"c"];
[copyPassword setKeyEquivalentModifierMask:[copyPassword keyEquivalentModifierMask] | NSAlternateKeyMask];
copyPassword.keyEquivalentModifierMask = (copyPassword.keyEquivalentModifierMask | NSAlternateKeyMask);
NSMenu *urlMenu = [[NSMenu alloc] init];
NSMenuItem *urlItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"URL", @"")
action:0
keyEquivalent:@""];
[urlItem setSubmenu:urlMenu];
urlItem.submenu = urlMenu;
NSMenuItem *copyURL = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"COPY_URL", @"")
action:[MPActionHelper actionOfType:MPActionCopyURL]

View File

@@ -54,8 +54,7 @@
continue; // Skip all non-db Keys
}
MPIconType iconType = (MPIconType)iconNumber.integerValue;
KPKIcon *icon = [[KPKIcon alloc] init];
icon.image = [MPIconHelper icon:iconType];
KPKIcon *icon = [[KPKIcon alloc] initWithImage:[MPIconHelper icon:iconType]];
[mutableIcons addObject:icon];
}
icons = [mutableIcons copy];

View File

@@ -23,9 +23,12 @@
#import "MPViewController.h"
@class MPDocument;
@class MPCollectionViewItem;
@interface MPIconSelectViewController : MPViewController <NSCollectionViewDelegate>
@property (weak, nullable) NSPopover *popover;
- (IBAction)didSelectCollectionViewItem:(id _Nullable)sender;
@end

View File

@@ -23,6 +23,7 @@
#import "MPIconSelectViewController.h"
#import "MPIconHelper.h"
#import "MPDocument.h"
#import "MPCollectionViewItem.h"
@interface MPIconSelectViewController () <NSCollectionViewDelegate>
@@ -45,10 +46,7 @@
self.iconCollectionView.delegate = self;
[self.iconCollectionView registerForDraggedTypes:@[(NSString *)kUTTypeURL, (NSString *)kUTTypeFileURL]];
MPDocument *document = [NSDocumentController sharedDocumentController].currentDocument;
self.iconCollectionView.content = document.tree.metaData.customIcons;
self.iconCollectionView.content = [[MPIconHelper databaseIcons] arrayByAddingObjectsFromArray:document.tree.metaData.customIcons];
[self _updateCollectionViewContent];
}
- (IBAction)useDefault:(id)sender {
@@ -62,15 +60,64 @@
- (IBAction)downloadIcon:(id)sender {
KPKNode *node = self.representedObject;
[self.observer willChangeModelProperty];
[self.observer didChangeModelProperty];
[self.view.window performClose:sender];
if(!node.asEntry) {
return;
}
NSString *rawURL = node.asEntry.url;
if([rawURL hasPrefix:@"http://"] || ![rawURL hasPrefix:@"https://"]) {
rawURL = [@"https://" stringByAppendingString:rawURL];
}
NSURL *url = [NSURL URLWithString:rawURL];
if(!url) {
return;
}
NSString *urlString = [NSString stringWithFormat:@"%@://%@/favicon.ico", url.scheme, url.host ? url.host : @""];
NSURL *favIconURL = [NSURL URLWithString:urlString];
if(!favIconURL) {
return;
}
KPKMetaData *metaData = ((MPDocument *)[NSDocumentController sharedDocumentController].currentDocument).tree.metaData;
NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:favIconURL completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if(data) {
dispatch_async(dispatch_get_main_queue(), ^{
KPKIcon *newIcon = [[KPKIcon alloc] initWithImageData:data];
if(newIcon) {
[metaData addCustomIcon:newIcon];
[self _updateCollectionViewContent];
}
});
}
}];
[task resume];
}
- (void)_deleteIcon:(KPKIcon *)icon {
NSUInteger iconIndex = [self.iconCollectionView.content indexOfObject:icon];
if(iconIndex < [MPIconHelper databaseIcons].count) {
return; // defautl icons cannot be delted
}
MPDocument *document = [NSDocumentController sharedDocumentController].currentDocument;
[document.tree.metaData removeCustomIcon:icon];
[self _updateCollectionViewContent];
}
- (IBAction)cancel:(id)sender {
[self.view.window performClose:sender];
}
- (void)didSelectCollectionViewItem:(id)sender {
if(![sender isKindOfClass:[NSCollectionViewItem class]]) {
return;
}
NSCollectionViewItem *item = sender;
NSLog(@"selected item.frame: %@", NSStringFromRect(item.view.frame));
//[self _selectIcon:item.representedObject];
}
- (void)_selectIcon:(KPKIcon *)icon {
KPKNode *node = self.representedObject;
NSUInteger iconIndex = [self.iconCollectionView.content indexOfObject:icon];
@@ -105,16 +152,45 @@
for(NSURL *url in urls) {
KPKIcon *icon = [[KPKIcon alloc] initWithImageAtURL:url];
if(icon.image) {
NSLog(@"Added Icon at:%@", url);
[document.tree.metaData addCustomIcon:icon];
success = YES;
}
}
if(success) {
self.iconCollectionView.content = document.tree.metaData.customIcons;
self.iconCollectionView.content = [[MPIconHelper databaseIcons] arrayByAddingObjectsFromArray:document.tree.metaData.customIcons];
[self _updateCollectionViewContent];
}
return success;
}
- (BOOL)collectionView:(NSCollectionView *)collectionView writeItemsAtIndexes:(NSIndexSet *)indexes toPasteboard:(NSPasteboard *)pasteboard {
NSLog(@"dragStart for indexes:%@", indexes);
[pasteboard declareTypes:@[(NSString *)kUTTypeText] owner:nil];
return YES;
}
- (void)collectionView:(NSCollectionView *)collectionView draggingSession:(NSDraggingSession *)session endedAtPoint:(NSPoint)screenPoint dragOperation:(NSDragOperation)operation {
if(nil == [self.view hitTest:screenPoint]) {
NSLog(@"Delete Item!");
}
else {
NSLog(@"Keep Item!");
}
}
- (void)_updateCollectionViewContent {
MPDocument *document = [NSDocumentController sharedDocumentController].currentDocument;
self.iconCollectionView.content = [[MPIconHelper databaseIcons] arrayByAddingObjectsFromArray:document.tree.metaData.customIcons];
}
- (void)flagsChanged:(NSEvent *)theEvent {
BOOL altDown = (0 != (theEvent.modifierFlags & NSEventModifierFlagOption));
for(NSUInteger index = 0; index < self.iconCollectionView.content.count; index++) {
MPCollectionViewItem *item = (MPCollectionViewItem *)[self.iconCollectionView itemAtIndex:index];
item.showDeleteIndicator = altDown;
}
}
@end