WKTextInputListViewController.mm [plain text]
/*
* Copyright (C) 2020 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "config.h"
#import "WKTextInputListViewController.h"
#if PLATFORM(WATCHOS)
#import "WKNumberPadViewController.h"
#import <wtf/RetainPtr.h>
static const CGFloat textSuggestionButtonHeight = 44;
static const CGFloat textSuggestionLabelHorizontalMargin = 9;
static NSString *textSuggestionCellReuseIdentifier = @"WebKitQuickboardTextSuggestionCell";
@implementation WKTextInputListViewController {
RetainPtr<WKNumberPadViewController> _numberPadViewController;
}
@dynamic delegate;
- (instancetype)initWithDelegate:(id <WKTextInputListViewControllerDelegate>)delegate
{
if (!(self = [super initWithDelegate:delegate]))
return nil;
self.textContentType = [self.delegate textContentTypeForListViewController:self];
return self;
}
- (void)willPresentArouetViewController:(PUICQuickboardArouetViewController *)quickboard
{
NSString *initialText = [self.delegate initialValueForViewController:self];
if (initialText.length)
[quickboard setInputText:initialText selectionRange:NSMakeRange(initialText.length, 0)];
quickboard.minTextLengthForEnablingAccept = 0;
}
- (NSArray *)additionalTrayButtons
{
if ([self.delegate numericInputModeForListViewController:self] == WKNumberPadInputModeNone)
return @[ ];
UIImage *numberPadButtonIcon = [PUICResources imageNamed:@"QuickboardAddPhoneNumber" inBundle:[NSBundle bundleWithIdentifier:@"com.apple.PepperUICore"] shouldCache:YES];
auto numberPadButton = adoptNS([[PUICQuickboardListTrayButton alloc] initWithFrame:CGRectZero tintColor:nil defaultHeight:self.specs.defaultButtonHeight]);
[numberPadButton setImage:numberPadButtonIcon forState:UIControlStateNormal];
[numberPadButton addTarget:self action:@selector(presentNumberPadViewController) forControlEvents:UIControlEventTouchUpInside];
return @[ numberPadButton.get() ];
}
- (void)presentNumberPadViewController
{
if (_numberPadViewController)
return;
WKNumberPadInputMode mode = [self.delegate numericInputModeForListViewController:self];
if (mode == WKNumberPadInputModeNone) {
ASSERT_NOT_REACHED();
return;
}
NSString *initialText = [self.delegate initialValueForViewController:self];
_numberPadViewController = adoptNS([[WKNumberPadViewController alloc] initWithDelegate:self.delegate initialText:initialText inputMode:mode]);
[self presentViewController:_numberPadViewController.get() animated:YES completion:nil];
}
- (void)reloadTextSuggestions
{
[self reloadListItems];
}
- (void)enterText:(NSString *)text
{
[self.delegate quickboard:self textEntered:[[[NSAttributedString alloc] initWithString:text] autorelease]];
}
#pragma mark - Quickboard subclassing
- (BOOL)supportsDictationInput
{
return [self.delegate allowsDictationInputForListViewController:self];
}
- (void)didSelectListItemAtIndexPath:(NSIndexPath *)indexPath
{
[self _didSelectListItem:indexPath.row];
}
// FIXME: This method can be removed when <rdar://problem/57807445> lands in a build.
- (void)didSelectListItem:(NSInteger)itemNumber
{
[self _didSelectListItem:itemNumber];
}
- (void)_didSelectListItem:(NSInteger)itemNumber
{
NSArray<UITextSuggestion *> *textSuggestions = [self.delegate textSuggestionsForListViewController:self];
if (textSuggestions.count <= static_cast<NSUInteger>(itemNumber)) {
ASSERT_NOT_REACHED();
return;
}
[self.delegate listViewController:self didSelectTextSuggestion:[textSuggestions objectAtIndex:itemNumber]];
}
- (NSInteger)numberOfListItems
{
return [self.delegate textSuggestionsForListViewController:self].count;
}
- (CGFloat)heightForListItem:(NSInteger)itemNumber width:(CGFloat)width
{
return textSuggestionButtonHeight;
}
// FIXME: This method can be removed when <rdar://problem/57807445> lands in a build.
- (PUICQuickboardListItemCell *)cellForListItem:(NSInteger)itemNumber
{
NSArray<UITextSuggestion *> *textSuggestions = [self.delegate textSuggestionsForListViewController:self];
if (textSuggestions.count <= static_cast<NSUInteger>(itemNumber)) {
ASSERT_NOT_REACHED();
return nil;
}
UITextSuggestion *textSuggestion = [textSuggestions objectAtIndex:itemNumber];
auto reusableCell = retainPtr([self.listView dequeueReusableCellWithIdentifier:textSuggestionCellReuseIdentifier]);
if (!reusableCell) {
reusableCell = adoptNS([[WKQuickboardListItemCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:textSuggestionCellReuseIdentifier]);
[reusableCell itemLabel].numberOfLines = 1;
[reusableCell itemLabel].lineBreakMode = NSLineBreakByTruncatingTail;
[reusableCell itemLabel].allowsDefaultTighteningForTruncation = YES;
}
CGFloat viewWidth = CGRectGetWidth(self.listView.bounds);
[reusableCell configureForText:textSuggestion.displayText width:viewWidth];
// The default behavior of -configureForText:width: causes the text label to run off the end of the cell.
// Adjust for this by shrinking the label width to actually fit the bounds of the cell.
[reusableCell itemLabel].frame = UIRectInset([reusableCell contentView].bounds, 0, textSuggestionLabelHorizontalMargin, 0, textSuggestionLabelHorizontalMargin);
return reusableCell.autorelease();
}
- (NSString *)listItemCellReuseIdentifier
{
return textSuggestionCellReuseIdentifier;
}
#if HAVE(QUICKBOARD_COLLECTION_VIEWS)
- (Class)listItemCellClass
{
return [WKQuickboardListCollectionViewItemCell class];
}
- (PUICQuickboardListCollectionViewItemCell *)itemCellForListItem:(NSInteger)itemNumber forIndexPath:(NSIndexPath *)indexPath
{
NSArray<UITextSuggestion *> *textSuggestions = [self.delegate textSuggestionsForListViewController:self];
if (textSuggestions.count <= static_cast<NSUInteger>(itemNumber)) {
ASSERT_NOT_REACHED();
return nil;
}
UITextSuggestion *textSuggestion = [textSuggestions objectAtIndex:itemNumber];
auto reusableCell = retainPtr([self.collectionView dequeueReusableCellWithReuseIdentifier:textSuggestionCellReuseIdentifier forIndexPath:indexPath]);
[reusableCell bodyLabel].numberOfLines = 1;
[reusableCell bodyLabel].lineBreakMode = NSLineBreakByTruncatingTail;
[reusableCell bodyLabel].allowsDefaultTighteningForTruncation = YES;
[reusableCell setText:textSuggestion.displayText];
// The default behavior of -configureForText:width: causes the text label to run off the end of the cell.
// Adjust for this by shrinking the label width to actually fit the bounds of the cell.
[reusableCell bodyLabel].frame = UIRectInset([reusableCell contentView].bounds, 0, textSuggestionLabelHorizontalMargin, 0, textSuggestionLabelHorizontalMargin);
return reusableCell.autorelease();
}
#endif // HAVE(QUICKBOARD_COLLECTION_VIEWS)
- (BOOL)supportsArouetInput
{
return [self.delegate numericInputModeForListViewController:self] == WKNumberPadInputModeNone;
}
@end
#endif // PLATFORM(WATCHOS)