OLD | NEW |
---|---|
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #if !defined(__has_feature) || !__has_feature(objc_arc) | 5 #if !defined(__has_feature) || !__has_feature(objc_arc) |
6 #error "This file requires ARC support." | 6 #error "This file requires ARC support." |
7 #endif | 7 #endif |
8 | 8 |
9 #import "remoting/ios/app/client_connection_view_controller.h" | 9 #import "remoting/ios/app/client_connection_view_controller.h" |
10 | 10 |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
102 [[_navBar trailingAnchor] | 102 [[_navBar trailingAnchor] |
103 constraintEqualToAnchor:[self.view trailingAnchor]], | 103 constraintEqualToAnchor:[self.view trailingAnchor]], |
104 [[_navBar heightAnchor] constraintEqualToConstant:kBarHeight], | 104 [[_navBar heightAnchor] constraintEqualToConstant:kBarHeight], |
105 ]]; | 105 ]]; |
106 | 106 |
107 [self attemptConnectionToHost]; | 107 [self attemptConnectionToHost]; |
108 } | 108 } |
109 return self; | 109 return self; |
110 } | 110 } |
111 | 111 |
112 - (void)dealloc { | |
113 [[NSNotificationCenter defaultCenter] removeObserver:self]; | |
114 } | |
115 | |
112 #pragma mark - UIViewController | 116 #pragma mark - UIViewController |
113 | 117 |
114 - (void)viewDidLoad { | 118 - (void)viewDidLoad { |
115 [super viewDidLoad]; | 119 [super viewDidLoad]; |
116 self.view.backgroundColor = RemotingTheme.connectionViewBackgroundColor; | 120 self.view.backgroundColor = RemotingTheme.connectionViewBackgroundColor; |
117 | 121 |
118 _activityIndicator = [[MDCActivityIndicator alloc] initWithFrame:CGRectZero]; | 122 _activityIndicator = [[MDCActivityIndicator alloc] initWithFrame:CGRectZero]; |
119 _activityIndicator.radius = kActivityIndicatorRadius; | 123 _activityIndicator.radius = kActivityIndicatorRadius; |
120 _activityIndicator.trackEnabled = YES; | 124 _activityIndicator.trackEnabled = YES; |
121 _activityIndicator.strokeWidth = kActivityIndicatorStrokeWidth; | 125 _activityIndicator.strokeWidth = kActivityIndicatorStrokeWidth; |
(...skipping 24 matching lines...) Expand all Loading... | |
146 _reconnectView.translatesAutoresizingMaskIntoConstraints = NO; | 150 _reconnectView.translatesAutoresizingMaskIntoConstraints = NO; |
147 [self.view addSubview:_reconnectView]; | 151 [self.view addSubview:_reconnectView]; |
148 _reconnectView.delegate = self; | 152 _reconnectView.delegate = self; |
149 | 153 |
150 _pinEntryView = [[PinEntryView alloc] init]; | 154 _pinEntryView = [[PinEntryView alloc] init]; |
151 _pinEntryView.hidden = YES; | 155 _pinEntryView.hidden = YES; |
152 _pinEntryView.translatesAutoresizingMaskIntoConstraints = NO; | 156 _pinEntryView.translatesAutoresizingMaskIntoConstraints = NO; |
153 [self.view addSubview:_pinEntryView]; | 157 [self.view addSubview:_pinEntryView]; |
154 _pinEntryView.delegate = self; | 158 _pinEntryView.delegate = self; |
155 | 159 |
160 _reconnectView.hidden = YES; | |
161 | |
156 [self | 162 [self |
157 initializeLayoutConstraintsWithViews:NSDictionaryOfVariableBindings( | 163 initializeLayoutConstraintsWithViews:NSDictionaryOfVariableBindings( |
158 _activityIndicator, _statusLabel, | 164 _activityIndicator, _statusLabel, |
159 _iconView, _reconnectView, | 165 _iconView, _reconnectView, |
160 _pinEntryView)]; | 166 _pinEntryView)]; |
167 | |
168 [[NSNotificationCenter defaultCenter] | |
169 addObserver:self | |
170 selector:@selector(hostSessionStatusChanged:) | |
171 name:kHostSessionStatusChanged | |
172 object:nil]; | |
161 } | 173 } |
162 | 174 |
163 - (void)initializeLayoutConstraintsWithViews:(NSDictionary*)views { | 175 - (void)initializeLayoutConstraintsWithViews:(NSDictionary*)views { |
164 // Metrics to use in visual format strings. | 176 // Metrics to use in visual format strings. |
165 NSDictionary* layoutMetrics = @{ | 177 NSDictionary* layoutMetrics = @{ |
166 @"padding" : @(kPadding), | 178 @"padding" : @(kPadding), |
167 @"margin" : @(kMargin), | 179 @"margin" : @(kMargin), |
168 @"topPadding" : @(kTopPadding), | 180 @"topPadding" : @(kTopPadding), |
169 @"iconDiameter" : @(kIconRadius * 2), | 181 @"iconDiameter" : @(kIconRadius * 2), |
170 @"pinEntryViewWidth" : @(kPinEntryViewWidth), | 182 @"pinEntryViewWidth" : @(kPinEntryViewWidth), |
171 @"pinEntryViewHeight" : @(kPinEntryViewHeight), | 183 @"pinEntryViewHeight" : @(kPinEntryViewHeight), |
172 @"reconnectViewWidth" : @(kReconnectViewWidth), | 184 @"reconnectViewWidth" : @(kReconnectViewWidth), |
173 @"reconnectViewHeight" : @(kReconnectViewHeight), | 185 @"reconnectViewHeight" : @(kReconnectViewHeight), |
174 }; | 186 }; |
175 [_activityIndicator sizeToFit]; | 187 [_activityIndicator sizeToFit]; |
176 NSString* f; | 188 NSString* f; |
177 | 189 |
178 // Horizontal constraints: | 190 // Horizontal constraints: |
179 | |
180 [self.view addConstraints: | 191 [self.view addConstraints: |
181 [NSLayoutConstraint | 192 [NSLayoutConstraint |
182 constraintsWithVisualFormat:@"H:[_iconView(iconDiameter)]" | 193 constraintsWithVisualFormat:@"H:[_iconView(iconDiameter)]" |
183 options:0 | 194 options:0 |
184 metrics:layoutMetrics | 195 metrics:layoutMetrics |
185 views:views]]; | 196 views:views]]; |
186 | 197 |
187 [self.view addConstraints:[NSLayoutConstraint | 198 [self.view addConstraints:[NSLayoutConstraint |
188 constraintsWithVisualFormat: | 199 constraintsWithVisualFormat: |
189 @"H:|-margin-[_statusLabel]-margin-|" | 200 @"H:|-margin-[_statusLabel]-margin-|" |
190 options:0 | 201 options:0 |
191 metrics:layoutMetrics | 202 metrics:layoutMetrics |
192 views:views]]; | 203 views:views]]; |
193 | 204 |
194 [self.view addConstraints:[NSLayoutConstraint | 205 [self.view addConstraints:[NSLayoutConstraint |
195 constraintsWithVisualFormat: | 206 constraintsWithVisualFormat: |
196 @"H:[_pinEntryView(pinEntryViewWidth)]" | 207 @"H:[_pinEntryView(pinEntryViewWidth)]" |
197 options:0 | 208 options:0 |
198 metrics:layoutMetrics | 209 metrics:layoutMetrics |
199 views:views]]; | 210 views:views]]; |
200 | 211 |
201 [self.view addConstraints:[NSLayoutConstraint | 212 [self.view addConstraints:[NSLayoutConstraint |
202 constraintsWithVisualFormat: | 213 constraintsWithVisualFormat: |
203 @"H:[_reconnectView(reconnectViewWidth)]" | 214 @"H:[_reconnectView(reconnectViewWidth)]" |
204 options:0 | 215 options:0 |
205 metrics:layoutMetrics | 216 metrics:layoutMetrics |
206 views:views]]; | 217 views:views]]; |
207 | 218 |
208 // Anchors: | 219 // Anchors: |
209 | |
210 _activityIndicatorTopConstraintFull = | 220 _activityIndicatorTopConstraintFull = |
211 [_activityIndicator.topAnchor constraintEqualToAnchor:self.view.topAnchor | 221 [_activityIndicator.topAnchor constraintEqualToAnchor:self.view.topAnchor |
212 constant:kTopPadding]; | 222 constant:kTopPadding]; |
213 _activityIndicatorTopConstraintFull.active = YES; | 223 _activityIndicatorTopConstraintFull.active = YES; |
214 | 224 |
215 [_iconView.centerYAnchor | 225 [_iconView.centerYAnchor |
216 constraintEqualToAnchor:_activityIndicator.centerYAnchor] | 226 constraintEqualToAnchor:_activityIndicator.centerYAnchor] |
217 .active = YES; | 227 .active = YES; |
218 | 228 |
219 // Vertical constraints: | 229 // Vertical constraints: |
220 | |
221 [self.view addConstraints: | 230 [self.view addConstraints: |
222 [NSLayoutConstraint | 231 [NSLayoutConstraint |
223 constraintsWithVisualFormat:@"V:[_iconView(iconDiameter)]" | 232 constraintsWithVisualFormat:@"V:[_iconView(iconDiameter)]" |
224 options:0 | 233 options:0 |
225 metrics:layoutMetrics | 234 metrics:layoutMetrics |
226 views:views]]; | 235 views:views]]; |
227 | 236 |
228 [self.view addConstraints: | 237 [self.view addConstraints: |
229 [NSLayoutConstraint | 238 [NSLayoutConstraint |
230 constraintsWithVisualFormat: | 239 constraintsWithVisualFormat: |
(...skipping 25 matching lines...) Expand all Loading... | |
256 options:NSLayoutFormatAlignAllCenterX | 265 options:NSLayoutFormatAlignAllCenterX |
257 metrics:layoutMetrics | 266 metrics:layoutMetrics |
258 views:views]]; | 267 views:views]]; |
259 | 268 |
260 [self.view setNeedsUpdateConstraints]; | 269 [self.view setNeedsUpdateConstraints]; |
261 } | 270 } |
262 | 271 |
263 - (void)viewWillAppear:(BOOL)animated { | 272 - (void)viewWillAppear:(BOOL)animated { |
264 [super viewWillAppear:animated]; | 273 [super viewWillAppear:animated]; |
265 [self.navigationController setNavigationBarHidden:YES animated:animated]; | 274 [self.navigationController setNavigationBarHidden:YES animated:animated]; |
266 | |
267 [[NSNotificationCenter defaultCenter] | |
268 addObserver:self | |
269 selector:@selector(hostSessionStatusChanged:) | |
270 name:kHostSessionStatusChanged | |
271 object:nil]; | |
272 } | 275 } |
273 | 276 |
274 - (void)viewDidAppear:(BOOL)animated { | 277 - (void)viewDidAppear:(BOOL)animated { |
275 [super viewDidAppear:animated]; | 278 [super viewDidAppear:animated]; |
276 [[NSNotificationCenter defaultCenter] | 279 [[NSNotificationCenter defaultCenter] |
277 addObserver:self | 280 addObserver:self |
278 selector:@selector(keyboardWillShow:) | 281 selector:@selector(keyboardWillShow:) |
279 name:UIKeyboardWillShowNotification | 282 name:UIKeyboardWillShowNotification |
280 object:nil]; | 283 object:nil]; |
281 | 284 |
282 [[NSNotificationCenter defaultCenter] | 285 [[NSNotificationCenter defaultCenter] |
283 addObserver:self | 286 addObserver:self |
284 selector:@selector(keyboardWillHide:) | 287 selector:@selector(keyboardWillHide:) |
285 name:UIKeyboardWillHideNotification | 288 name:UIKeyboardWillHideNotification |
286 object:nil]; | 289 object:nil]; |
287 | 290 |
288 [_activityIndicator startAnimating]; | 291 [_activityIndicator startAnimating]; |
289 } | 292 } |
290 | 293 |
291 - (void)viewWillDisappear:(BOOL)animated { | 294 - (void)viewWillDisappear:(BOOL)animated { |
292 [super viewWillDisappear:animated]; | 295 [super viewWillDisappear:animated]; |
293 [_activityIndicator stopAnimating]; | 296 [_activityIndicator stopAnimating]; |
294 [[NSNotificationCenter defaultCenter] removeObserver:self]; | |
295 } | 297 } |
296 | 298 |
297 - (BOOL)prefersStatusBarHidden { | 299 - (BOOL)prefersStatusBarHidden { |
298 return YES; | 300 return YES; |
299 } | 301 } |
300 | 302 |
301 #pragma mark - Keyboard | 303 #pragma mark - Keyboard |
302 | 304 |
305 // TODO(nicholss): We need to listen to screen rotation and re-adjust the | |
306 // topAnchor. | |
307 | |
303 - (void)keyboardWillShow:(NSNotification*)notification { | 308 - (void)keyboardWillShow:(NSNotification*)notification { |
304 CGSize keyboardSize = | 309 CGSize keyboardSize = |
305 [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] | 310 [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] |
306 CGRectValue] | 311 CGRectValue] |
307 .size; | 312 .size; |
308 | 313 |
309 CGFloat newHeight = self.view.frame.size.height - keyboardSize.height; | 314 CGFloat newHeight = self.view.frame.size.height - keyboardSize.height; |
310 CGFloat overlap = newHeight - (_pinEntryView.frame.origin.y + | 315 CGFloat overlap = newHeight - (_pinEntryView.frame.origin.y + |
311 _pinEntryView.frame.size.height + kPadding); | 316 _pinEntryView.frame.size.height + kPadding); |
312 if (overlap > 0) { | 317 if (overlap > 0) { |
(...skipping 27 matching lines...) Expand all Loading... | |
340 switch (_state) { | 345 switch (_state) { |
341 case ClientViewConnecting: | 346 case ClientViewConnecting: |
342 [self showConnectingState]; | 347 [self showConnectingState]; |
343 break; | 348 break; |
344 case ClientViewPinPrompt: | 349 case ClientViewPinPrompt: |
345 [self showPinPromptState]; | 350 [self showPinPromptState]; |
346 break; | 351 break; |
347 case ClientViewConnected: | 352 case ClientViewConnected: |
348 [self showConnectedState]; | 353 [self showConnectedState]; |
349 break; | 354 break; |
355 case ClientViewReconnect: | |
356 [self showReconnect]; | |
357 break; | |
350 case ClientViewClosed: | 358 case ClientViewClosed: |
351 [self.navigationController popToRootViewControllerAnimated:YES]; | 359 [self.navigationController popToRootViewControllerAnimated:YES]; |
352 break; | 360 break; |
353 case ClientViewError: | 361 case ClientViewError: |
354 [self showError]; | 362 [self showError]; |
355 break; | 363 break; |
356 } | 364 } |
357 } | 365 } |
358 | 366 |
359 #pragma mark - SessionReconnectViewDelegate | 367 #pragma mark - SessionReconnectViewDelegate |
(...skipping 15 matching lines...) Expand all Loading... | |
375 username:userEmail | 383 username:userEmail |
376 accessToken:accessToken]; | 384 accessToken:accessToken]; |
377 }]; | 385 }]; |
378 [self setState:ClientViewConnecting]; | 386 [self setState:ClientViewConnecting]; |
379 } | 387 } |
380 | 388 |
381 - (void)showConnectingState { | 389 - (void)showConnectingState { |
382 [_pinEntryView endEditing:YES]; | 390 [_pinEntryView endEditing:YES]; |
383 _statusLabel.text = | 391 _statusLabel.text = |
384 [NSString stringWithFormat:@"Connecting to %@", _remoteHostName]; | 392 [NSString stringWithFormat:@"Connecting to %@", _remoteHostName]; |
393 | |
394 _pinEntryView.hidden = YES; | |
395 | |
396 _reconnectView.hidden = YES; | |
397 | |
385 [_activityIndicator stopAnimating]; | 398 [_activityIndicator stopAnimating]; |
386 _activityIndicator.cycleColors = @[ [UIColor whiteColor] ]; | 399 _activityIndicator.cycleColors = @[ [UIColor whiteColor] ]; |
387 _activityIndicator.indicatorMode = MDCActivityIndicatorModeIndeterminate; | 400 _activityIndicator.indicatorMode = MDCActivityIndicatorModeIndeterminate; |
388 _activityIndicator.hidden = NO; | 401 _activityIndicator.hidden = NO; |
389 _pinEntryView.hidden = YES; | |
390 _reconnectView.hidden = YES; | |
391 [_activityIndicator startAnimating]; | 402 [_activityIndicator startAnimating]; |
392 } | 403 } |
393 | 404 |
394 - (void)showPinPromptState { | 405 - (void)showPinPromptState { |
395 _statusLabel.text = [NSString stringWithFormat:@"%@", _remoteHostName]; | 406 _statusLabel.text = [NSString stringWithFormat:@"%@", _remoteHostName]; |
396 [_activityIndicator stopAnimating]; | 407 [_activityIndicator stopAnimating]; |
397 _activityIndicator.hidden = YES; | 408 _activityIndicator.hidden = YES; |
409 | |
398 _pinEntryView.hidden = NO; | 410 _pinEntryView.hidden = NO; |
411 | |
399 _reconnectView.hidden = YES; | 412 _reconnectView.hidden = YES; |
400 | 413 |
401 // TODO(yuweih): This may be called before viewDidAppear and miss the keyboard | 414 // TODO(yuweih): This may be called before viewDidAppear and miss the keyboard |
402 // callback. | 415 // callback. |
403 [_pinEntryView becomeFirstResponder]; | 416 [_pinEntryView becomeFirstResponder]; |
404 } | 417 } |
405 | 418 |
406 - (void)showConnectedState { | 419 - (void)showConnectedState { |
407 [_pinEntryView endEditing:YES]; | 420 [_pinEntryView endEditing:YES]; |
408 _statusLabel.text = | 421 _statusLabel.text = |
409 [NSString stringWithFormat:@"Connected to %@", _remoteHostName]; | 422 [NSString stringWithFormat:@"Connected to %@", _remoteHostName]; |
423 | |
424 _pinEntryView.hidden = YES; | |
425 [_pinEntryView clearPinEntry]; | |
426 | |
410 _activityIndicator.progress = 0.0; | 427 _activityIndicator.progress = 0.0; |
411 _pinEntryView.hidden = YES; | |
412 _activityIndicator.hidden = NO; | 428 _activityIndicator.hidden = NO; |
413 _activityIndicator.indicatorMode = MDCActivityIndicatorModeDeterminate; | 429 _activityIndicator.indicatorMode = MDCActivityIndicatorModeDeterminate; |
414 _activityIndicator.cycleColors = @[ [UIColor greenColor] ]; | 430 _activityIndicator.cycleColors = @[ [UIColor greenColor] ]; |
415 [_activityIndicator startAnimating]; | 431 [_activityIndicator startAnimating]; |
416 _activityIndicator.progress = 1.0; | 432 _activityIndicator.progress = 1.0; |
433 | |
417 _reconnectView.hidden = YES; | 434 _reconnectView.hidden = YES; |
418 | 435 |
419 HostViewController* hostViewController = | 436 HostViewController* hostViewController = |
420 [[HostViewController alloc] initWithClient:_client]; | 437 [[HostViewController alloc] initWithClient:_client]; |
421 _client = nil; | 438 _client = nil; |
422 | 439 |
423 // Replaces current (topmost) view controller with |hostViewController|. | 440 [self.navigationController pushViewController:hostViewController animated:NO]; |
424 NSMutableArray* controllers = | 441 } |
425 [self.navigationController.viewControllers mutableCopy]; | 442 |
426 [controllers removeLastObject]; | 443 - (void)showReconnect { |
427 [controllers addObject:hostViewController]; | 444 _statusLabel.text = |
428 [self.navigationController setViewControllers:controllers animated:NO]; | 445 [NSString stringWithFormat:@"Connection closed for %@", _remoteHostName]; |
446 [_activityIndicator stopAnimating]; | |
447 _activityIndicator.hidden = YES; | |
448 | |
449 _pinEntryView.hidden = YES; | |
450 | |
451 _reconnectView.hidden = NO; | |
452 | |
453 [self.navigationController popToViewController:self animated:YES]; | |
454 [MDCSnackbarManager | |
455 showMessage:[MDCSnackbarMessage messageWithText:@"Connection Closed."]]; | |
Yuwei
2017/07/06 22:29:45
Do we really need to show the message twice?
nicholss
2017/07/06 22:40:01
yessss.
| |
429 } | 456 } |
430 | 457 |
431 - (void)showError { | 458 - (void)showError { |
432 _statusLabel.text = | 459 _statusLabel.text = |
433 [NSString stringWithFormat:@"Error connecting to %@", _remoteHostName]; | 460 [NSString stringWithFormat:@"Error connecting to %@", _remoteHostName]; |
434 _activityIndicator.progress = 0.0; | 461 |
435 _pinEntryView.hidden = YES; | 462 _pinEntryView.hidden = YES; |
436 _activityIndicator.hidden = NO; | 463 |
437 _activityIndicator.indicatorMode = MDCActivityIndicatorModeDeterminate; | 464 _activityIndicator.indicatorMode = MDCActivityIndicatorModeDeterminate; |
438 _activityIndicator.cycleColors = @[ [UIColor redColor] ]; | 465 _activityIndicator.cycleColors = @[ [UIColor redColor] ]; |
466 _activityIndicator.progress = 1.0; | |
467 _activityIndicator.hidden = NO; | |
439 [_activityIndicator startAnimating]; | 468 [_activityIndicator startAnimating]; |
440 _activityIndicator.progress = 1.0; | 469 |
441 _reconnectView.hidden = NO; | 470 _reconnectView.hidden = NO; |
442 | 471 |
443 MDCSnackbarMessage* message = nil; | 472 MDCSnackbarMessage* message = nil; |
444 switch (_lastError) { | 473 switch (_lastError) { |
445 case SessionErrorOk: | 474 case SessionErrorOk: |
446 // Do nothing. | 475 // Do nothing. |
447 break; | 476 break; |
448 case SessionErrorPeerIsOffline: | 477 case SessionErrorPeerIsOffline: |
449 message = [MDCSnackbarMessage | 478 message = [MDCSnackbarMessage |
450 messageWithText:@"Error: SessionErrorPeerIsOffline."]; | 479 messageWithText:@"Error: SessionErrorPeerIsOffline."]; |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
530 case SessionPinPrompt: | 559 case SessionPinPrompt: |
531 state = ClientViewPinPrompt; | 560 state = ClientViewPinPrompt; |
532 break; | 561 break; |
533 case SessionConnected: | 562 case SessionConnected: |
534 state = ClientViewConnected; | 563 state = ClientViewConnected; |
535 break; | 564 break; |
536 case SessionFailed: | 565 case SessionFailed: |
537 state = ClientViewError; | 566 state = ClientViewError; |
538 break; | 567 break; |
539 case SessionClosed: | 568 case SessionClosed: |
540 state = ClientViewClosed; | 569 // If the session closes, offer the user to reconnect. |
570 state = ClientViewReconnect; | |
541 break; | 571 break; |
542 default: | 572 default: |
543 LOG(ERROR) << "Unknown State for Session, " << sessionDetails.state; | 573 LOG(ERROR) << "Unknown State for Session, " << sessionDetails.state; |
544 return; | 574 return; |
545 } | 575 } |
546 _lastError = sessionDetails.error; | 576 _lastError = sessionDetails.error; |
547 [[NSOperationQueue mainQueue] addOperationWithBlock:^{ | 577 [[NSOperationQueue mainQueue] addOperationWithBlock:^{ |
548 [self setState:state]; | 578 [self setState:state]; |
549 }]; | 579 }]; |
550 } | 580 } |
551 | 581 |
552 @end | 582 @end |
OLD | NEW |