Skip to content

Commit

Permalink
Don't use data provider if using custom chooser view (#226)
Browse files Browse the repository at this point in the history
Don't use data provider if using custom chooser view

lixed with directlyUpdateQueryWithCustomDelegate
  • Loading branch information
bkoatz authored Dec 10, 2020
1 parent 068f24f commit fa2d17d
Show file tree
Hide file tree
Showing 10 changed files with 129 additions and 44 deletions.
6 changes: 6 additions & 0 deletions Hakawai/Core/Default/HKWDefaultChooserView.m
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ @implementation HKWDefaultChooserView

@synthesize borderMode = _borderMode;

+ (id)chooserViewWithFrame:(CGRect)frame {
HKWDefaultChooserView *chooserView = [[[self class] alloc] initWithFrame:frame];
[chooserView initialSetupForFrame:frame];
return chooserView;
}

+ (instancetype)chooserViewWithFrame:(CGRect)frame
delegate:(id<UITableViewDelegate>)delegate
dataSource:(id<UITableViewDataSource>)dataSource {
Expand Down
10 changes: 8 additions & 2 deletions Hakawai/Core/HKWChooserViewProtocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,19 @@ typedef NS_ENUM(NSInteger, HKWChooserBorderMode) {

@optional

/*!
Return an instance of the chooser view with a given frame with no delegate. This method is intended for
use with completely custom chooser views.
*/
+ (id)chooserViewWithFrame:(CGRect)frame;

/*!
Return an instance of the chooser view with a given frame, properly setting the delegate. This method is intended for
use with chooser views that are not backed by a \c UITableView instance, or wish to completely control the process of
displaying chooser options, although it can be used for table view-backed views.
\warning At least one of the two methods: this method, or \c chooserViewWithFrame:delegate:dataSource must be
implemented.
implemented, unless you are using a custom chooser view.
*/
+ (id)chooserViewWithFrame:(CGRect)frame
delegate:(id<UITableViewDelegate>)delegate;
Expand All @@ -58,7 +64,7 @@ typedef NS_ENUM(NSInteger, HKWChooserBorderMode) {
Return an instance of the chooser view with a given frame, properly setting the delegate and data source. This method
is intended for use with chooser views that are backed by a \c UITableView instance.
\warning At least one of the two methods: this method, or \c chooserViewWithFrame:delegate: must be implemented.
\warning At least one of the two methods: this method, or \c chooserViewWithFrame:delegate: must be implemented, unless you are using a custom chooser view.
*/
+ (id)chooserViewWithFrame:(CGRect)frame
delegate:(id<UITableViewDelegate>)delegate
Expand Down
2 changes: 2 additions & 0 deletions Hakawai/Core/HKWTextView.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,10 @@ NS_ASSUME_NONNULL_BEGIN

+ (BOOL) enableMentionsPluginV2;
+ (BOOL) enableMentionsCreationStateMachineV2;
+ (BOOL) directlyUpdateQueryWithCustomDelegate;
+ (void) setEnableMentionsPluginV2:(BOOL)enabled;
+ (void) setEnableMentionsCreationStateMachineV2:(BOOL)enabled;
+ (void) setDirectlyUpdateQueryWithCustomDelegate:(BOOL)enabled;

#pragma mark - Initialization

Expand Down
9 changes: 9 additions & 0 deletions Hakawai/Core/HKWTextView.m
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ @interface HKWTextView () <UITextViewDelegate, HKWAbstractionLayerDelegate>

static BOOL enableMentionsPluginV2 = NO;
static BOOL enableMentionsCreationStateMachineV2 = NO;
static BOOL directlyUpdateQueryWithCustomDelegate = NO;

@implementation HKWTextView

Expand All @@ -61,6 +62,14 @@ + (void)setEnableMentionsCreationStateMachineV2:(BOOL)enabled {
enableMentionsCreationStateMachineV2 = enabled;
}

+ (BOOL)directlyUpdateQueryWithCustomDelegate {
return directlyUpdateQueryWithCustomDelegate;
}

+ (void)setDirectlyUpdateQueryWithCustomDelegate:(BOOL)enabled {
directlyUpdateQueryWithCustomDelegate = enabled;
}

#pragma mark - Lifecycle

- (instancetype _Nonnull)initWithFrame:(CGRect)frame textContainer:(nullable __unused NSTextContainer *)textContainer {
Expand Down
102 changes: 68 additions & 34 deletions Hakawai/Mentions/HKWMentionsCreationStateMachineV2.m
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ @interface HKWMentionsCreationStateMachineV2 ()

@property (nonatomic, weak) id<HKWMentionsCreationStateMachineProtocol> delegate;

@property (nonatomic) HKWMentionDataProvider *dataProvider;
@property (nonatomic, nullable) HKWMentionDataProvider *dataProvider;
@property (nonatomic) HKWMentionsCreationState state;
@property (nonatomic) HKWMentionsCreationResultsState resultsState;
@property (nonatomic) HKWMentionsCreationChooserState chooserState;
Expand Down Expand Up @@ -101,14 +101,17 @@ @implementation HKWMentionsCreationStateMachineV2

#pragma mark - API

+ (instancetype)stateMachineWithDelegate:(id<HKWMentionsCreationStateMachineProtocol>)delegate {
+ (instancetype)stateMachineWithDelegate:(id<HKWMentionsCreationStateMachineProtocol>)delegate isUsingCustomChooserView:(BOOL)isUsingCustomChooserView {
NSAssert(delegate != nil, @"Cannot create state machine with nil delegate.");
HKWMentionsCreationStateMachineV2 *sm = [[self class] new];
sm.chooserViewClass = [HKWDefaultChooserView class];
sm.delegate = delegate;
sm.state = HKWMentionsCreationStateQuiescent;
sm.chooserViewEdgeInsets = UIEdgeInsetsZero;
sm.dataProvider = [[HKWMentionDataProvider alloc] initWithStateMachine:sm delegate:delegate];
// We only need a data provider if we are not using a custom chooser view
if (!isUsingCustomChooserView) {
sm.dataProvider = [[HKWMentionDataProvider alloc] initWithStateMachine:sm delegate:delegate];
}
return sm;
}

Expand Down Expand Up @@ -165,11 +168,17 @@ - (void)stringInserted:(NSString *)string isWhitespace:(BOOL)isWhitespace isNewl
? HKWMentionsCreationActionWhitespaceCharacterInserted
: HKWMentionsCreationActionNormalCharacterInserted);
[self.stringBuffer appendString:string];
// Fire off the request and start the timer
[self.dataProvider queryUpdatedWithKeyString:[self.stringBuffer copy]
searchType:self.searchType
isWhitespace:isWhitespace
controlCharacter:self.explicitSearchControlCharacter];
if (self.dataProvider) {
// Fire off the request and start the timer
[self.dataProvider queryUpdatedWithKeyString:[self.stringBuffer copy]
searchType:self.searchType
isWhitespace:isWhitespace
controlCharacter:self.explicitSearchControlCharacter];
} else {
// If we do not have a data provider, just pass the updated query directly to the mention plugin
[delegate didUpdateKeyString:[self.stringBuffer copy]
controlCharacter:self.explicitSearchControlCharacter];
}
}
break;
}
Expand Down Expand Up @@ -265,11 +274,17 @@ the string buffer will not be empty (it will have "John" in it), but mentions ha
// The user hasn't completely backed out of mentions creation, so we can continue firing requests.
// Remove a character from the buffer and immediately fire a request
[self.stringBuffer deleteCharactersInRange:toDeleteRange];
// Fire off the request and start the timer
[self.dataProvider queryUpdatedWithKeyString:[self.stringBuffer copy]
searchType:self.searchType
isWhitespace:NO
controlCharacter:self.explicitSearchControlCharacter];
if (self.dataProvider) {
// Fire off the request and start the timer
[self.dataProvider queryUpdatedWithKeyString:[self.stringBuffer copy]
searchType:self.searchType
isWhitespace:NO
controlCharacter:self.explicitSearchControlCharacter];
} else {
// If we do not have a data provider, just pass the updated query directly to the mention plugin
[delegate didUpdateKeyString:[self.stringBuffer copy]
controlCharacter:self.explicitSearchControlCharacter];
}
break;
}

Expand Down Expand Up @@ -310,11 +325,17 @@ - (void)mentionCreationStartedWithPrefix:(NSString *)prefix
// Prepare state
self.resultsState = HKWMentionsCreationResultsStateAwaitingFirstResult;

// Start the timer and fire off a request
[self.dataProvider queryUpdatedWithKeyString:prefix
searchType:self.searchType
isWhitespace:NO
controlCharacter:self.explicitSearchControlCharacter];
if (self.dataProvider) {
// Start the timer and fire off a request
[self.dataProvider queryUpdatedWithKeyString:prefix
searchType:self.searchType
isWhitespace:NO
controlCharacter:self.explicitSearchControlCharacter];
} else {
// If we do not have a data provider, just pass the updated query directly to the mention plugin
[self.delegate didUpdateKeyString:prefix
controlCharacter:self.explicitSearchControlCharacter];
}
}

- (void)cancelMentionCreation {
Expand Down Expand Up @@ -346,10 +367,16 @@ - (void)hideChooserArrow {

- (void)fetchInitialMentions {
self.searchType = HKWMentionsSearchTypeInitial;
[self.dataProvider queryUpdatedWithKeyString:@""
searchType:self.searchType
isWhitespace:NO
controlCharacter:self.explicitSearchControlCharacter];
if (self.dataProvider) {
[self.dataProvider queryUpdatedWithKeyString:@""
searchType:self.searchType
isWhitespace:NO
controlCharacter:self.explicitSearchControlCharacter];
} else {
// If we do not have a data provider, just pass the updated query directly to the mention plugin
[self.delegate didUpdateKeyString:@""
controlCharacter:self.explicitSearchControlCharacter];
}
}

#pragma mark - Chooser View Frame
Expand Down Expand Up @@ -469,18 +496,25 @@ - (void)hideChooserView {

// Instantiate the chooser view
UIView<HKWChooserViewProtocol> *chooserView = nil;
if ([(id)self.chooserViewClass respondsToSelector:@selector(chooserViewWithFrame:delegate:)]) {
chooserView = [self.chooserViewClass chooserViewWithFrame:chooserFrame
delegate:self.dataProvider];
}
else if ([(id)self.chooserViewClass respondsToSelector:@selector(chooserViewWithFrame:delegate:dataSource:)]) {
chooserView = [self.chooserViewClass chooserViewWithFrame:chooserFrame
delegate:self.dataProvider
dataSource:self.dataProvider];
}
else {
NSAssert(NO, @"Chooser view class must support one or both of the following methods: \
chooserViewWithFrame:delegate: or chooserViewWithFrame:delegate:dataSource:");
if (self.dataProvider) {
if ([(id)self.chooserViewClass respondsToSelector:@selector(chooserViewWithFrame:delegate:)]) {
chooserView = [self.chooserViewClass chooserViewWithFrame:chooserFrame
delegate:self.dataProvider];
}
else if ([(id)self.chooserViewClass respondsToSelector:@selector(chooserViewWithFrame:delegate:dataSource:)]) {
chooserView = [self.chooserViewClass chooserViewWithFrame:chooserFrame
delegate:self.dataProvider
dataSource:self.dataProvider];
}
else {
NSAssert(NO, @"If there is a dataprovider, chooser view class must support one or both of the following methods: \
chooserViewWithFrame:delegate: or chooserViewWithFrame:delegate:dataSource:");
}
} else {
// If we are not using a data provider, just create the chooser view without one
if ([(id)self.chooserViewClass respondsToSelector:@selector(chooserViewWithFrame:)]) {
chooserView = [self.chooserViewClass chooserViewWithFrame:chooserFrame];
}
}

if ([chooserView respondsToSelector:@selector(setBorderMode:)]) {
Expand Down
12 changes: 11 additions & 1 deletion Hakawai/Mentions/HKWMentionsPluginV1.m
Original file line number Diff line number Diff line change
Expand Up @@ -2123,7 +2123,7 @@ - (HKWMentionsStartDetectionStateMachine *)startDetectionStateMachine {
- (id<HKWMentionsCreationStateMachine>)creationStateMachine {
if (HKWTextView.enableMentionsCreationStateMachineV2) {
if (!_creationStateMachine) {
_creationStateMachine = [HKWMentionsCreationStateMachineV2 stateMachineWithDelegate:self];
_creationStateMachine = [HKWMentionsCreationStateMachineV2 stateMachineWithDelegate:self isUsingCustomChooserView:(self.customChooserViewDelegate != nil && HKWTextView.directlyUpdateQueryWithCustomDelegate)];
}
return _creationStateMachine;
} else {
Expand Down Expand Up @@ -2210,6 +2210,16 @@ - (void)textView:(__unused UITextView *)textView willCustomPasteTextInRange:(__u
return;
}

- (void)didUpdateKeyString:(nonnull NSString *)keyString
controlCharacter:(unichar)character {
// set up the chooser view prior to data request in order to support fully customized view
[self.creationStateMachine setupChooserViewIfNeeded];
__strong __auto_type strongCustomChooserViewDelegate = self.customChooserViewDelegate;
NSAssert(strongCustomChooserViewDelegate != nil, @"Must have a custom chooser view if the query is being updated directly via this method");
[strongCustomChooserViewDelegate didUpdateKeyString:keyString
controlCharacter:character];
}

#pragma mark - Developer

NSString * _Nonnull nameForMentionsState(HKWMentionsState s) {
Expand Down
13 changes: 12 additions & 1 deletion Hakawai/Mentions/HKWMentionsPluginV2.m
Original file line number Diff line number Diff line change
Expand Up @@ -1115,6 +1115,7 @@ - (void)asyncRetrieveEntitiesForKeyString:(NSString *)keyString
completion:(void (^)(NSArray *, BOOL, BOOL))completionBlock {
// set up the chooser view prior to data request in order to support fully customized view
[self.creationStateMachine setupChooserViewIfNeeded];
// Remove this after directlyUpdateQueryWithCustomDelegate is ramped, because async vs. didUpdate should be totally separate
__strong __auto_type strongCustomChooserViewDelegate = self.customChooserViewDelegate;
if (strongCustomChooserViewDelegate) {
[strongCustomChooserViewDelegate didUpdateKeyString:keyString
Expand All @@ -1127,6 +1128,16 @@ - (void)asyncRetrieveEntitiesForKeyString:(NSString *)keyString
}
}

- (void)didUpdateKeyString:(nonnull NSString *)keyString
controlCharacter:(unichar)character {
// set up the chooser view prior to data request in order to support fully customized view
[self.creationStateMachine setupChooserViewIfNeeded];
__strong __auto_type strongCustomChooserViewDelegate = self.customChooserViewDelegate;
NSAssert(strongCustomChooserViewDelegate != nil, @"Must have a custom chooser view if the query is being updated directly via this method");
[strongCustomChooserViewDelegate didUpdateKeyString:keyString
controlCharacter:character];
}

- (UITableViewCell *)cellForMentionsEntity:(id<HKWMentionsEntityProtocol>)entity
withMatchString:(NSString *)matchString
tableView:(UITableView *)tableView
Expand Down Expand Up @@ -1421,7 +1432,7 @@ - (BOOL)loadingCellSupported {
- (id<HKWMentionsCreationStateMachine>)creationStateMachine {
if (HKWTextView.enableMentionsCreationStateMachineV2) {
if (!_creationStateMachine) {
_creationStateMachine = [HKWMentionsCreationStateMachineV2 stateMachineWithDelegate:self];
_creationStateMachine = [HKWMentionsCreationStateMachineV2 stateMachineWithDelegate:self isUsingCustomChooserView:(self.customChooserViewDelegate != nil && HKWTextView.directlyUpdateQueryWithCustomDelegate)];
}
return _creationStateMachine;
} else {
Expand Down
7 changes: 1 addition & 6 deletions Hakawai/Mentions/_HKWMentionsCreationStateMachine.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#import "HKWMentionsDefaultChooserViewDelegate.h"
#import "HKWMentionsPlugin.h"

@protocol HKWMentionsCreationStateMachineProtocol <HKWMentionsDefaultChooserViewDelegate>
@protocol HKWMentionsCreationStateMachineProtocol <HKWMentionsDefaultChooserViewDelegate, HKWMentionsCustomChooserViewDelegate>

/*!
Get whether or not the host app supports displaying a loading cell.
Expand Down Expand Up @@ -96,11 +96,6 @@
*/
@property (nonatomic) unichar explicitSearchControlCharacter;

/*!
Return a new, initialized state machine instance.
*/
+ (instancetype)stateMachineWithDelegate:(id<HKWMentionsCreationStateMachineProtocol>)delegate;

/**
Informs the state machine typeahead results are returned, so it can update its internal state accordingly.
*/
Expand Down
6 changes: 6 additions & 0 deletions Hakawai/Mentions/_HKWMentionsCreationStateMachineV1.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ NS_ASSUME_NONNULL_BEGIN
*/

@interface HKWMentionsCreationStateMachineV1 : NSObject <HKWMentionsCreationStateMachine>

/*!
Return a new, initialized state machine instance.
*/
+ (instancetype)stateMachineWithDelegate:(id<HKWMentionsCreationStateMachineProtocol>)delegate;

@end

NS_ASSUME_NONNULL_END
Expand Down
6 changes: 6 additions & 0 deletions Hakawai/Mentions/_HKWMentionsCreationStateMachineV2.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ NS_ASSUME_NONNULL_BEGIN
*/

@interface HKWMentionsCreationStateMachineV2 : NSObject <HKWMentionsCreationStateMachine>

/*!
Return a new, initialized state machine instance, and let it know whether we are using a custom chooser view or not
*/
+ (instancetype)stateMachineWithDelegate:(id<HKWMentionsCreationStateMachineProtocol>)delegate isUsingCustomChooserView:(BOOL)isUsingCustomChooserView;

@end

NS_ASSUME_NONNULL_END

0 comments on commit fa2d17d

Please sign in to comment.