Commit e12ec8ac authored by Yuwei Huang's avatar Yuwei Huang Committed by Commit Bot

[CRD iOS] Fix the jarring "Hide Keyboard" UX

Previously when the user taps "Hide Keyboard" from the session menu, the
keyboard will immediately show then hide itself. This CL prevents the
keyboard from showing between (alert is shown, action is executed) and
manually shows it again only when necessary.

This CL also includes some refactoring to reduce redundant common code.

Bug: 750956
Change-Id: I545e1880352e279ebf324676f7680600761b78f3
Reviewed-on: https://chromium-review.googlesource.com/595016Reviewed-by: default avatarScott Nichols <nicholss@chromium.org>
Commit-Queue: Yuwei Huang <yuweih@chromium.org>
Cr-Commit-Position: refs/heads/master@{#491154}
parent a41ecf3a
...@@ -44,6 +44,10 @@ static const CGFloat kKeyboardAnimationTime = 0.3; ...@@ -44,6 +44,10 @@ static const CGFloat kKeyboardAnimationTime = 0.3;
CGSize _keyboardSize; CGSize _keyboardSize;
BOOL _surfaceCreated; BOOL _surfaceCreated;
HostSettings* _settings; HostSettings* _settings;
// When set to true, ClientKeyboard will immediately resign first responder
// after it becomes first responder.
BOOL _blocksKeyboard;
} }
@end @end
...@@ -55,6 +59,7 @@ static const CGFloat kKeyboardAnimationTime = 0.3; ...@@ -55,6 +59,7 @@ static const CGFloat kKeyboardAnimationTime = 0.3;
_client = client; _client = client;
_keyboardSize = CGSizeZero; _keyboardSize = CGSizeZero;
_surfaceCreated = NO; _surfaceCreated = NO;
_blocksKeyboard = NO;
_settings = _settings =
[[RemotingPreferences instance] settingsForHost:client.hostInfo.hostId]; [[RemotingPreferences instance] settingsForHost:client.hostInfo.hostId];
} }
...@@ -203,6 +208,15 @@ static const CGFloat kKeyboardAnimationTime = 0.3; ...@@ -203,6 +208,15 @@ static const CGFloat kKeyboardAnimationTime = 0.3;
#pragma mark - Keyboard Notifications #pragma mark - Keyboard Notifications
- (void)keyboardWillShow:(NSNotification*)notification { - (void)keyboardWillShow:(NSNotification*)notification {
if (_blocksKeyboard) {
[self hideKeyboard];
// This is to make sure the keyboard is removed from the responder chain.
[_clientKeyboard removeFromSuperview];
[self.view addSubview:_clientKeyboard];
return;
}
CGSize keyboardSize = CGSize keyboardSize =
[[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey]
CGRectValue] CGRectValue]
...@@ -320,41 +334,44 @@ static const CGFloat kKeyboardAnimationTime = 0.3; ...@@ -320,41 +334,44 @@ static const CGFloat kKeyboardAnimationTime = 0.3;
// more options. This is not ideal but it gets us an easy way to make a // more options. This is not ideal but it gets us an easy way to make a
// modal window option selector. Replace this with a real menu later. // modal window option selector. Replace this with a real menu later.
// ClientKeyboard may gain first responder immediately after the alert is
// dismissed. This will cause weird show-then-hide animation when hiding
// keyboard on iPhone (iPad is unaffected since it shows the alert as popup).
// The fix is to remove ClientKeyboard from the responder chain in
// keyboardWillShow and manually show the keyboard again only when needed.
UIAlertController* alert = [UIAlertController UIAlertController* alert = [UIAlertController
alertControllerWithTitle:nil alertControllerWithTitle:nil
message:nil message:nil
preferredStyle:UIAlertControllerStyleActionSheet]; preferredStyle:UIAlertControllerStyleActionSheet];
__weak HostViewController* weakSelf = self;
if (!_clientKeyboard.hasPhysicalKeyboard) { if (!_clientKeyboard.hasPhysicalKeyboard) {
// These are only needed for soft keyboard. // These are only needed for soft keyboard.
if ([self isKeyboardActive]) { if ([self isKeyboardActive]) {
void (^hideKeyboardHandler)(UIAlertAction*) = ^(UIAlertAction*) { [self addActionToAlert:alert
[self hideKeyboard]; title:IDS_HIDE_KEYBOARD
[_actionImageView setActive:NO animated:YES]; style:UIAlertActionStyleDefault
}; restoresKeyboard:NO
[alert addAction:[UIAlertAction actionWithTitle:l10n_util::GetNSString( handler:^() {
IDS_HIDE_KEYBOARD) [weakSelf hideKeyboard];
style:UIAlertActionStyleDefault }];
handler:hideKeyboardHandler]];
} else { } else {
void (^showKeyboardHandler)(UIAlertAction*) = ^(UIAlertAction*) { [self addActionToAlert:alert
[self showKeyboard]; title:IDS_SHOW_KEYBOARD
[_actionImageView setActive:NO animated:YES]; handler:^() {
}; [weakSelf showKeyboard];
[alert addAction:[UIAlertAction actionWithTitle:l10n_util::GetNSString( }];
IDS_SHOW_KEYBOARD)
style:UIAlertActionStyleDefault
handler:showKeyboardHandler]];
} }
} }
remoting::GestureInterpreter::InputMode currentInputMode = remoting::GestureInterpreter::InputMode currentInputMode =
_client.gestureInterpreter->GetInputMode(); _client.gestureInterpreter->GetInputMode();
NSString* switchInputModeTitle = l10n_util::GetNSString( int switchInputModeTitle =
currentInputMode == remoting::GestureInterpreter::DIRECT_INPUT_MODE currentInputMode == remoting::GestureInterpreter::DIRECT_INPUT_MODE
? IDS_SELECT_TRACKPAD_MODE ? IDS_SELECT_TRACKPAD_MODE
: IDS_SELECT_TOUCH_MODE); : IDS_SELECT_TOUCH_MODE;
void (^switchInputModeHandler)(UIAlertAction*) = ^(UIAlertAction*) { void (^switchInputModeHandler)() = ^() {
switch (currentInputMode) { switch (currentInputMode) {
case remoting::GestureInterpreter::DIRECT_INPUT_MODE: case remoting::GestureInterpreter::DIRECT_INPUT_MODE:
[self useTrackpadInputMode]; [self useTrackpadInputMode];
...@@ -364,25 +381,22 @@ static const CGFloat kKeyboardAnimationTime = 0.3; ...@@ -364,25 +381,22 @@ static const CGFloat kKeyboardAnimationTime = 0.3;
[self useDirectInputMode]; [self useDirectInputMode];
break; break;
} }
[_actionImageView setActive:NO animated:YES];
}; };
[alert addAction:[UIAlertAction actionWithTitle:switchInputModeTitle [self addActionToAlert:alert
style:UIAlertActionStyleDefault title:switchInputModeTitle
handler:switchInputModeHandler]]; handler:switchInputModeHandler];
void (^disconnectHandler)(UIAlertAction*) = ^(UIAlertAction*) { void (^disconnectHandler)() = ^() {
[_client disconnectFromHost]; [_client disconnectFromHost];
[self.navigationController popToRootViewControllerAnimated:YES]; [self.navigationController popToRootViewControllerAnimated:YES];
[_actionImageView setActive:NO animated:YES];
}; };
[alert [self addActionToAlert:alert
addAction:[UIAlertAction actionWithTitle:l10n_util::GetNSString( title:IDS_DISCONNECT_MYSELF_BUTTON
IDS_DISCONNECT_MYSELF_BUTTON) style:UIAlertActionStyleDefault
style:UIAlertActionStyleDefault restoresKeyboard:NO
handler:disconnectHandler]]; handler:disconnectHandler];
__weak HostViewController* weakSelf = self; void (^settingsHandler)() = ^() {
void (^settingsHandler)(UIAlertAction*) = ^(UIAlertAction*) {
RemotingSettingsViewController* settingsViewController = RemotingSettingsViewController* settingsViewController =
[[RemotingSettingsViewController alloc] init]; [[RemotingSettingsViewController alloc] init];
settingsViewController.delegate = weakSelf; settingsViewController.delegate = weakSelf;
...@@ -392,22 +406,23 @@ static const CGFloat kKeyboardAnimationTime = 0.3; ...@@ -392,22 +406,23 @@ static const CGFloat kKeyboardAnimationTime = 0.3;
UINavigationController* navController = [[UINavigationController alloc] UINavigationController* navController = [[UINavigationController alloc]
initWithRootViewController:settingsViewController]; initWithRootViewController:settingsViewController];
[weakSelf presentViewController:navController animated:YES completion:nil]; [weakSelf presentViewController:navController animated:YES completion:nil];
[_actionImageView setActive:NO animated:YES];
}; };
[alert addAction:[UIAlertAction actionWithTitle:l10n_util::GetNSString( // Don't restore keyboard since the settings view will be show immediately.
IDS_SETTINGS_BUTTON) [self addActionToAlert:alert
style:UIAlertActionStyleDefault title:IDS_SETTINGS_BUTTON
handler:settingsHandler]]; style:UIAlertActionStyleDefault
restoresKeyboard:NO
handler:settingsHandler];
__weak UIAlertController* weakAlert = alert; __weak UIAlertController* weakAlert = alert;
void (^cancelHandler)(UIAlertAction*) = ^(UIAlertAction*) { void (^cancelHandler)() = ^() {
[weakAlert dismissViewControllerAnimated:YES completion:nil]; [weakAlert dismissViewControllerAnimated:YES completion:nil];
[_actionImageView setActive:NO animated:YES];
}; };
[alert addAction:[UIAlertAction [self addActionToAlert:alert
actionWithTitle:l10n_util::GetNSString(IDS_CANCEL) title:IDS_CANCEL
style:UIAlertActionStyleCancel style:UIAlertActionStyleCancel
handler:cancelHandler]]; restoresKeyboard:YES
handler:cancelHandler];
alert.popoverPresentationController.sourceView = self.view; alert.popoverPresentationController.sourceView = self.view;
// Target the alert menu at the top middle of the FAB. // Target the alert menu at the top middle of the FAB.
...@@ -417,7 +432,48 @@ static const CGFloat kKeyboardAnimationTime = 0.3; ...@@ -417,7 +432,48 @@ static const CGFloat kKeyboardAnimationTime = 0.3;
alert.popoverPresentationController.permittedArrowDirections = alert.popoverPresentationController.permittedArrowDirections =
UIPopoverArrowDirectionDown; UIPopoverArrowDirectionDown;
[self presentViewController:alert animated:YES completion:nil]; [self presentViewController:alert animated:YES completion:nil];
// Prevent keyboard from showing between (alert is shown, action is executed).
_blocksKeyboard = YES;
[_actionImageView setActive:YES animated:YES]; [_actionImageView setActive:YES animated:YES];
} }
// Adds an action to the alert. And restores the states for you.
// restoresKeyboard:
// Set to YES to show the keyboard if it was previously shown. Do not assume
// the keyboard will always be hidden when the alert view is shown.
- (void)addActionToAlert:(UIAlertController*)alert
title:(int)titleMessageId
style:(UIAlertActionStyle)style
restoresKeyboard:(BOOL)restoresKeyboard
handler:(void (^)())handler {
BOOL isKeyboardActive = [self isKeyboardActive];
[alert addAction:[UIAlertAction
actionWithTitle:l10n_util::GetNSString(titleMessageId)
style:style
handler:^(UIAlertAction*) {
_blocksKeyboard = NO;
if (isKeyboardActive && restoresKeyboard) {
[self showKeyboard];
}
if (handler) {
handler();
}
[_actionImageView setActive:NO animated:YES];
}]];
}
// Shorter version of addActionToAlert with default action style and
// restoresKeyboard == YES.
- (void)addActionToAlert:(UIAlertController*)alert
title:(int)titleMessageId
handler:(void (^)())handler {
[self addActionToAlert:alert
title:titleMessageId
style:UIAlertActionStyleDefault
restoresKeyboard:YES
handler:handler];
}
@end @end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment