Added “everywhere” search option

This commit is contained in:
Michael Starke
2018-03-09 17:43:31 +01:00
parent 8fc55f06dc
commit 6f37b98d92
6 changed files with 55 additions and 25 deletions

View File

@@ -1,14 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="13196" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="13771" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13196"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13771"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="MPContextBarViewController">
<connections>
<outlet property="emptyTrashButton" destination="szx-Hx-OrV" id="i1Y-qB-TW3"/>
<outlet property="everywhereButton" destination="RGg-wK-hz4" id="xIZ-YB-pkm"/>
<outlet property="exitHistoryButton" destination="pqx-su-vAh" id="JmV-vC-F48"/>
<outlet property="filterLabelTextField" destination="6" id="60"/>
<outlet property="historyBar" destination="S8L-rB-h0h" id="6yZ-El-fVs"/>
@@ -108,18 +109,27 @@
</menu>
</popUpButtonCell>
</popUpButton>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="RGg-wK-hz4">
<rect key="frame" x="379" y="6" width="86" height="17"/>
<buttonCell key="cell" type="recessed" title="Everywhere" bezelStyle="recessed" alignment="center" controlSize="small" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="WMK-bb-ESj">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES" changeBackground="YES" changeGray="YES"/>
<font key="font" metaFont="systemBold" size="12"/>
</buttonCell>
</button>
</subviews>
<constraints>
<constraint firstAttribute="centerY" secondItem="O7W-cn-eUP" secondAttribute="centerY" id="2uC-wS-HDi"/>
<constraint firstItem="O7W-cn-eUP" firstAttribute="leading" secondItem="6" secondAttribute="trailing" constant="8" symbolic="YES" id="5hN-x3-XlX"/>
<constraint firstItem="0R1-PX-dgn" firstAttribute="leading" secondItem="O7W-cn-eUP" secondAttribute="trailing" constant="8" symbolic="YES" id="67f-i6-eOb"/>
<constraint firstAttribute="centerY" secondItem="SaV-5p-jIX" secondAttribute="centerY" id="7ch-eZ-Hzh"/>
<constraint firstItem="aPQ-t2-bgz" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="SaV-5p-jIX" secondAttribute="trailing" constant="8" symbolic="YES" id="91Q-Aq-ulG"/>
<constraint firstItem="RGg-wK-hz4" firstAttribute="leading" secondItem="SaV-5p-jIX" secondAttribute="trailing" constant="8" symbolic="YES" id="Bbh-au-wHa"/>
<constraint firstItem="aPQ-t2-bgz" firstAttribute="centerY" secondItem="SaV-5p-jIX" secondAttribute="centerY" id="EUG-hL-jbn"/>
<constraint firstAttribute="centerY" secondItem="0R1-PX-dgn" secondAttribute="centerY" id="Huh-PB-cbs"/>
<constraint firstItem="aPQ-t2-bgz" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="RGg-wK-hz4" secondAttribute="trailing" constant="8" symbolic="YES" id="QoK-F3-goX"/>
<constraint firstItem="6" firstAttribute="leading" secondItem="1" secondAttribute="leading" constant="8" id="Seo-dI-FzX"/>
<constraint firstItem="Bn2-iY-mQ3" firstAttribute="leading" secondItem="Uhl-ck-vVQ" secondAttribute="trailing" constant="8" id="TCJ-vg-IIt"/>
<constraint firstAttribute="trailing" secondItem="aPQ-t2-bgz" secondAttribute="trailing" constant="20" symbolic="YES" id="XFv-Pv-Bzq"/>
<constraint firstItem="RGg-wK-hz4" firstAttribute="centerY" secondItem="1" secondAttribute="centerY" id="hsT-uo-6H8"/>
<constraint firstItem="SaV-5p-jIX" firstAttribute="leading" secondItem="Bn2-iY-mQ3" secondAttribute="trailing" constant="8" symbolic="YES" id="pAA-uU-moF"/>
<constraint firstAttribute="centerY" secondItem="6" secondAttribute="centerY" id="qak-8F-xbj"/>
<constraint firstItem="Uhl-ck-vVQ" firstAttribute="leading" secondItem="0R1-PX-dgn" secondAttribute="trailing" constant="8" id="u8d-C2-O9h"/>
@@ -244,7 +254,7 @@
</connections>
</tabViewItem>
</tabViewItems>
<point key="canvasLocation" x="104" y="293"/>
<point key="canvasLocation" x="-152" y="121"/>
</tabView>
</objects>
</document>

View File

@@ -35,6 +35,7 @@
@property (weak) IBOutlet NSButton *notesButton;
@property (weak) IBOutlet NSButton *duplicatePasswordsButton;
@property (weak) IBOutlet NSPopUpButton *specialFilterPopUpButton;
@property (weak) IBOutlet NSButton *everywhereButton;
- (void)registerNotificationsForDocument:(MPDocument *)document;

View File

@@ -85,8 +85,8 @@ typedef NS_ENUM(NSUInteger, MPContextTab) {
[self.view bind:NSSelectedIndexBinding toObject:self withKeyPath:NSStringFromSelector(@selector(activeTab)) options:nil];
/* Setup Filter Bar buttons and menu */
NSInteger tags[] = { MPEntrySearchTitles, MPEntrySearchUsernames, MPEntrySearchPasswords, MPEntrySearchNotes, MPEntrySearchUrls };
NSArray<NSControl *> *buttons = @[self.titleButton, self.usernameButton, self.passwordButton, self.notesButton, self.urlButton ];
NSInteger tags[] = { MPEntrySearchTitles, MPEntrySearchUsernames, MPEntrySearchPasswords, MPEntrySearchNotes, MPEntrySearchUrls, MPEntrySearchAllAttributes };
NSArray<NSControl *> *buttons = @[self.titleButton, self.usernameButton, self.passwordButton, self.notesButton, self.urlButton, self.everywhereButton ];
for(NSUInteger iIndex = 0; iIndex < buttons.count; iIndex++) {
buttons[iIndex].action = @selector(toggleSearchFlags:);
buttons[iIndex].tag = tags[iIndex];
@@ -103,7 +103,7 @@ typedef NS_ENUM(NSUInteger, MPContextTab) {
item.tag = specialTags[iIndex];
[specialMenu addItem:item];
}
[self.specialFilterPopUpButton setMenu:specialMenu];
self.specialFilterPopUpButton.menu = specialMenu;
[self _updateFilterButtons];
}
@@ -154,8 +154,9 @@ typedef NS_ENUM(NSUInteger, MPContextTab) {
self.titleButton.state = HNHUIStateForBool(MPIsFlagSetInOptions(MPEntrySearchTitles, currentFlags));
self.urlButton.state = HNHUIStateForBool(MPIsFlagSetInOptions(MPEntrySearchUrls, currentFlags));
self.usernameButton.state = HNHUIStateForBool(MPIsFlagSetInOptions(MPEntrySearchUsernames, currentFlags));
self.everywhereButton.state = HNHUIStateForBool(MPIsFlagSetInOptions(MPEntrySearchAllAttributes, currentFlags));
NSInteger selectedTag = MPEntrySearchNone;
for(NSMenuItem *item in [[self.specialFilterPopUpButton menu] itemArray]) {
for(NSMenuItem *item in self.specialFilterPopUpButton.menu.itemArray) {
MPEntrySearchFlags flag = item.tag;
if(flag == MPEntrySearchNone) {
item.state = NSOffState;

View File

@@ -65,16 +65,16 @@ NSString *const kMPDocumentSearchResultsKey = @"kMPDocumentSearchResul
dispatch_async(backgroundQueue, ^{
NSArray *results = [weakSelf _findEntriesMatchingCurrentSearch];
dispatch_sync(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidChangeSearchResults object:weakSelf userInfo:@{ kMPDocumentSearchResultsKey: results }];
[NSNotificationCenter.defaultCenter postNotificationName:MPDocumentDidChangeSearchResults object:weakSelf userInfo:@{ kMPDocumentSearchResultsKey: results }];
});
});
}
- (void)exitSearch:(id)sender {
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSUndoManagerDidUndoChangeNotification object:self.undoManager];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSUndoManagerDidRedoChangeNotification object:self.undoManager];
[NSNotificationCenter.defaultCenter removeObserver:self name:NSUndoManagerDidUndoChangeNotification object:self.undoManager];
[NSNotificationCenter.defaultCenter removeObserver:self name:NSUndoManagerDidRedoChangeNotification object:self.undoManager];
self.searchContext = nil;
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidExitSearchNotification object:self];
[NSNotificationCenter.defaultCenter postNotificationName:MPDocumentDidExitSearchNotification object:self];
}
- (void)toggleSearchFlags:(id)sender {
@@ -88,7 +88,7 @@ NSString *const kMPDocumentSearchResultsKey = @"kMPDocumentSearchResul
MPEntrySearchFlags newFlags = MPEntrySearchNone;
BOOL isSingleFlag = toggleFlag & MPEntrySearchSingleFlags;
NSButton *button = sender;
switch([button state]) {
switch(button.state) {
case NSOffState:
toggleFlag ^= MPEntrySearchAllCombineableFlags;
newFlags = isSingleFlag ? MPEntrySearchNone : (self.searchContext.searchFlags & toggleFlag);
@@ -109,7 +109,7 @@ NSString *const kMPDocumentSearchResultsKey = @"kMPDocumentSearchResul
}
if(newFlags != self.searchContext.searchFlags) {
self.searchContext.searchFlags = (newFlags == MPEntrySearchNone) ? MPEntrySearchTitles : newFlags;
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidChangeSearchFlags object:self];
[NSNotificationCenter.defaultCenter postNotificationName:MPDocumentDidChangeSearchFlags object:self];
[self updateSearch:self];
}
}
@@ -166,6 +166,9 @@ NSString *const kMPDocumentSearchResultsKey = @"kMPDocumentSearchResul
- (NSArray *)_filterPredicatesWithString:(NSString *)string{
NSMutableArray *prediactes = [[NSMutableArray alloc] initWithCapacity:4];
BOOL searchInAllAttributes = MPIsFlagSetInOptions(MPEntrySearchAllAttributes, self.searchContext.searchFlags);
if(MPIsFlagSetInOptions(MPEntrySearchTitles, self.searchContext.searchFlags)) {
[prediactes addObject:[NSPredicate predicateWithFormat:@"SELF.title CONTAINS[cd] %@", string]];
}
@@ -181,6 +184,23 @@ NSString *const kMPDocumentSearchResultsKey = @"kMPDocumentSearchResul
if(MPIsFlagSetInOptions(MPEntrySearchNotes, self.searchContext.searchFlags)) {
[prediactes addObject:[NSPredicate predicateWithFormat:@"SELF.notes CONTAINS[cd] %@", string]];
}
if(searchInAllAttributes) {
[prediactes addObject:[NSPredicate predicateWithFormat:@"SELF.tags CONTAINS[cd] %@", string]];
[prediactes addObject:[NSPredicate predicateWithFormat:@"SELF.uuid.UUIDString CONTAINS[cd] %@", string]];
NSPredicate *allAttributesPredicate = [NSPredicate predicateWithBlock:^BOOL(id _Nullable evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
KPKEntry *entry = evaluatedObject;
for(KPKAttribute *attribute in entry.attributes) {
if([attribute.value rangeOfString:string options:NSCaseInsensitiveSearch].location != NSNotFound) {
return YES;
}
}
return NO;
}];
[prediactes addObject:allAttributesPredicate];
}
return prediactes;
}

View File

@@ -30,10 +30,9 @@ typedef NS_OPTIONS(NSUInteger, MPEntrySearchFlags) {
MPEntrySearchPasswords = (1<<3),
MPEntrySearchNotes = (1<<4),
MPEntrySearchAllAttributes = (1<<5),
/* The following two flags should be used like enums.
They are not intended to be used in conjunction with any other flag */
MPEntrySearchDoublePasswords = (1<<6),
MPEntrySearchExpiredEntries = (1<<7),
MPEntrySearchDoublePasswords = (1<<6), // do not combine with others. Exclusive flag
MPEntrySearchExpiredEntries = (1<<7), // do not combine with others. Exclusive flag
/* All combine-able search flags combined */
MPEntrySearchAllCombineableFlags = (MPEntrySearchDoublePasswords |
MPEntrySearchExpiredEntries |
@@ -41,9 +40,8 @@ typedef NS_OPTIONS(NSUInteger, MPEntrySearchFlags) {
MPEntrySearchPasswords |
MPEntrySearchTitles |
MPEntrySearchUrls |
MPEntrySearchUsernames |
MPEntrySearchAllAttributes),
MPEntrySearchSingleFlags = (MPEntrySearchDoublePasswords | MPEntrySearchExpiredEntries),
MPEntrySearchUsernames),
MPEntrySearchSingleFlags = (MPEntrySearchDoublePasswords | MPEntrySearchExpiredEntries | MPEntrySearchAllAttributes ),
MPEntrySearchAllFlags = (MPEntrySearchAllCombineableFlags | MPEntrySearchSingleFlags )
};

View File

@@ -34,7 +34,7 @@
}
+ (instancetype)userContext {
NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:kMPSettingsKeyEntrySearchFilterContext];
NSData *data = [NSUserDefaults.standardUserDefaults dataForKey:kMPSettingsKeyEntrySearchFilterContext];
if(data) {
return [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
@@ -64,7 +64,7 @@
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [self init];
self.searchString = [aDecoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(searchString))];
self.searchString = [aDecoder decodeObjectOfClass:NSString.class forKey:NSStringFromSelector(@selector(searchString))];
self.searchFlags = [aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(searchFlags))];
return self;
}
@@ -90,7 +90,7 @@
- (void )_updatePreferences {
NSData *myData = [NSKeyedArchiver archivedDataWithRootObject:self];
[[NSUserDefaults standardUserDefaults] setObject:myData forKey:kMPSettingsKeyEntrySearchFilterContext];
[[NSUserDefaults standardUserDefaults] synchronize];
[NSUserDefaults.standardUserDefaults setObject:myData forKey:kMPSettingsKeyEntrySearchFilterContext];
[NSUserDefaults.standardUserDefaults synchronize];
}
@end