| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 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 #import "ios/chrome/browser/ui/stack_view/card_set.h" | 5 #import "ios/chrome/browser/ui/stack_view/card_set.h" |
| 6 | 6 |
| 7 #import <QuartzCore/QuartzCore.h> | 7 #import <QuartzCore/QuartzCore.h> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #import "base/mac/scoped_nsobject.h" | |
| 11 #import "ios/chrome/browser/tabs/tab.h" | 10 #import "ios/chrome/browser/tabs/tab.h" |
| 12 #import "ios/chrome/browser/tabs/tab_model.h" | 11 #import "ios/chrome/browser/tabs/tab_model.h" |
| 13 #include "ios/chrome/browser/ui/rtl_geometry.h" | 12 #include "ios/chrome/browser/ui/rtl_geometry.h" |
| 14 #import "ios/chrome/browser/ui/stack_view/card_stack_layout_manager.h" | 13 #import "ios/chrome/browser/ui/stack_view/card_stack_layout_manager.h" |
| 15 #import "ios/chrome/browser/ui/stack_view/page_animation_util.h" | 14 #import "ios/chrome/browser/ui/stack_view/page_animation_util.h" |
| 16 #import "ios/chrome/browser/ui/stack_view/stack_card.h" | 15 #import "ios/chrome/browser/ui/stack_view/stack_card.h" |
| 17 #include "ios/chrome/browser/ui/ui_util.h" | 16 #include "ios/chrome/browser/ui/ui_util.h" |
| 18 #import "ios/web/web_state/ui/crw_web_controller.h" | 17 #import "ios/web/web_state/ui/crw_web_controller.h" |
| 19 | 18 |
| 19 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 20 #error "This file requires ARC support." |
| 21 #endif |
| 22 |
| 20 namespace { | 23 namespace { |
| 21 const CGFloat kMaxCardStaggerPercentage = 0.35; | 24 const CGFloat kMaxCardStaggerPercentage = 0.35; |
| 22 } | 25 } |
| 23 | 26 |
| 24 @interface CardSet ()<StackCardViewProvider, TabModelObserver> { | 27 @interface CardSet ()<StackCardViewProvider, TabModelObserver> { |
| 25 base::scoped_nsobject<TabModel> tabModel_; | 28 TabModel* tabModel_; |
| 26 base::scoped_nsobject<UIView> view_; | 29 UIView* view_; |
| 27 base::scoped_nsobject<CardStackLayoutManager> stackModel_; | 30 CardStackLayoutManager* stackModel_; |
| 28 base::scoped_nsobject<UIImageView> stackShadow_; | 31 UIImageView* stackShadow_; |
| 29 } | 32 } |
| 30 | 33 |
| 31 // Set to |YES| when the card set should draw a shadow around the entire stack. | 34 // Set to |YES| when the card set should draw a shadow around the entire stack. |
| 32 @property(nonatomic, assign) BOOL shouldShowShadow; | 35 @property(nonatomic, assign) BOOL shouldShowShadow; |
| 33 | 36 |
| 34 // Creates and returns an autoreleased StackCard from the given |tab| (which | 37 // Creates and returns an autoreleased StackCard from the given |tab| (which |
| 35 // must not be nil). | 38 // must not be nil). |
| 36 - (StackCard*)buildCardFromTab:(Tab*)tab; | 39 - (StackCard*)buildCardFromTab:(Tab*)tab; |
| 37 | 40 |
| 38 // Rebuilds the set of cards from the current state of the tab model. | 41 // Rebuilds the set of cards from the current state of the tab model. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 54 @implementation CardSet | 57 @implementation CardSet |
| 55 | 58 |
| 56 @synthesize observer = observer_; | 59 @synthesize observer = observer_; |
| 57 @synthesize ignoresTabModelChanges = ignoresTabModelChanges_; | 60 @synthesize ignoresTabModelChanges = ignoresTabModelChanges_; |
| 58 @synthesize defersCardHiding = defersCardHiding_; | 61 @synthesize defersCardHiding = defersCardHiding_; |
| 59 @synthesize keepOnlyVisibleCardViewsAlive = keepOnlyVisibleCardViewsAlive_; | 62 @synthesize keepOnlyVisibleCardViewsAlive = keepOnlyVisibleCardViewsAlive_; |
| 60 @synthesize shouldShowShadow = shouldShowShadow_; | 63 @synthesize shouldShowShadow = shouldShowShadow_; |
| 61 @synthesize closingCard = closingCard_; | 64 @synthesize closingCard = closingCard_; |
| 62 | 65 |
| 63 - (CardStackLayoutManager*)stackModel { | 66 - (CardStackLayoutManager*)stackModel { |
| 64 return stackModel_.get(); | 67 return stackModel_; |
| 65 } | 68 } |
| 66 | 69 |
| 67 - (id)initWithModel:(TabModel*)model { | 70 - (id)initWithModel:(TabModel*)model { |
| 68 if ((self = [super init])) { | 71 if ((self = [super init])) { |
| 69 tabModel_.reset([model retain]); | 72 tabModel_ = model; |
| 70 [tabModel_ addObserver:self]; | 73 [tabModel_ addObserver:self]; |
| 71 stackModel_.reset([[CardStackLayoutManager alloc] init]); | 74 stackModel_ = [[CardStackLayoutManager alloc] init]; |
| 72 [self rebuildCards]; | 75 [self rebuildCards]; |
| 73 self.shouldShowShadow = YES; | 76 self.shouldShowShadow = YES; |
| 74 } | 77 } |
| 75 return self; | 78 return self; |
| 76 } | 79 } |
| 77 | 80 |
| 78 - (void)dealloc { | 81 - (void)dealloc { |
| 79 [tabModel_ removeObserver:self]; | 82 [tabModel_ removeObserver:self]; |
| 80 [super dealloc]; | |
| 81 } | 83 } |
| 82 | 84 |
| 83 #pragma mark Properties | 85 #pragma mark Properties |
| 84 | 86 |
| 85 - (TabModel*)tabModel { | 87 - (TabModel*)tabModel { |
| 86 return tabModel_; | 88 return tabModel_; |
| 87 } | 89 } |
| 88 | 90 |
| 89 - (void)setTabModel:(TabModel*)tabModel { | 91 - (void)setTabModel:(TabModel*)tabModel { |
| 90 DCHECK([tabModel count] == 0); | 92 DCHECK([tabModel count] == 0); |
| 91 DCHECK([tabModel_ count] == 0); | 93 DCHECK([tabModel_ count] == 0); |
| 92 [tabModel_ removeObserver:self]; | 94 [tabModel_ removeObserver:self]; |
| 93 tabModel_.reset([tabModel retain]); | 95 tabModel_ = tabModel; |
| 94 if (!ignoresTabModelChanges_) | 96 if (!ignoresTabModelChanges_) |
| 95 [tabModel_ addObserver:self]; | 97 [tabModel_ addObserver:self]; |
| 96 } | 98 } |
| 97 | 99 |
| 98 - (NSArray*)cards { | 100 - (NSArray*)cards { |
| 99 return [stackModel_ cards]; | 101 return [stackModel_ cards]; |
| 100 } | 102 } |
| 101 | 103 |
| 102 - (StackCard*)currentCard { | 104 - (StackCard*)currentCard { |
| 103 DCHECK(!ignoresTabModelChanges_); | 105 DCHECK(!ignoresTabModelChanges_); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 115 } | 117 } |
| 116 | 118 |
| 117 - (void)setCurrentCard:(StackCard*)card { | 119 - (void)setCurrentCard:(StackCard*)card { |
| 118 DCHECK(!ignoresTabModelChanges_); | 120 DCHECK(!ignoresTabModelChanges_); |
| 119 NSInteger cardIndex = [self.cards indexOfObject:card]; | 121 NSInteger cardIndex = [self.cards indexOfObject:card]; |
| 120 DCHECK(cardIndex != NSNotFound); | 122 DCHECK(cardIndex != NSNotFound); |
| 121 [tabModel_ setCurrentTab:[tabModel_ tabAtIndex:cardIndex]]; | 123 [tabModel_ setCurrentTab:[tabModel_ tabAtIndex:cardIndex]]; |
| 122 } | 124 } |
| 123 | 125 |
| 124 - (UIView*)displayView { | 126 - (UIView*)displayView { |
| 125 return view_.get(); | 127 return view_; |
| 126 } | 128 } |
| 127 | 129 |
| 128 - (void)setDisplayView:(UIView*)view { | 130 - (void)setDisplayView:(UIView*)view { |
| 129 if (view == view_.get()) | 131 if (view == view_) |
| 130 return; | 132 return; |
| 131 for (StackCard* card in self.cards) { | 133 for (StackCard* card in self.cards) { |
| 132 if (card.viewIsLive) { | 134 if (card.viewIsLive) { |
| 133 [card.view removeFromSuperview]; | 135 [card.view removeFromSuperview]; |
| 134 [card releaseView]; | 136 [card releaseView]; |
| 135 } | 137 } |
| 136 } | 138 } |
| 137 [stackShadow_ removeFromSuperview]; | 139 [stackShadow_ removeFromSuperview]; |
| 138 view_.reset([view retain]); | 140 view_ = view; |
| 139 // Add the stack shadow view to the new display view. | 141 // Add the stack shadow view to the new display view. |
| 140 if (!stackShadow_) { | 142 if (!stackShadow_) { |
| 141 UIImage* shadowImage = [UIImage imageNamed:kCardShadowImageName]; | 143 UIImage* shadowImage = [UIImage imageNamed:kCardShadowImageName]; |
| 142 shadowImage = [shadowImage | 144 shadowImage = [shadowImage |
| 143 resizableImageWithCapInsets:UIEdgeInsetsMake( | 145 resizableImageWithCapInsets:UIEdgeInsetsMake( |
| 144 shadowImage.size.height / 2.0, | 146 shadowImage.size.height / 2.0, |
| 145 shadowImage.size.width / 2.0, | 147 shadowImage.size.width / 2.0, |
| 146 shadowImage.size.height / 2.0, | 148 shadowImage.size.height / 2.0, |
| 147 shadowImage.size.width / 2.0)]; | 149 shadowImage.size.width / 2.0)]; |
| 148 stackShadow_.reset([[UIImageView alloc] initWithImage:shadowImage]); | 150 stackShadow_ = [[UIImageView alloc] initWithImage:shadowImage]; |
| 149 [stackShadow_ setHidden:!self.cards.count]; | 151 [stackShadow_ setHidden:!self.cards.count]; |
| 150 } | 152 } |
| 151 [view_ addSubview:stackShadow_]; | 153 [view_ addSubview:stackShadow_]; |
| 152 // Don't set the stack's end limit when the view is set to nil in order to | 154 // Don't set the stack's end limit when the view is set to nil in order to |
| 153 // avoid losing existing card positions; these positions will be needed | 155 // avoid losing existing card positions; these positions will be needed |
| 154 // if/when the view is restored (e.g., if the view was purged due to a memory | 156 // if/when the view is restored (e.g., if the view was purged due to a memory |
| 155 // warning while in a modal view and then restored when exiting the modal | 157 // warning while in a modal view and then restored when exiting the modal |
| 156 // view). | 158 // view). |
| 157 if (view_.get()) | 159 if (view_) |
| 158 [self displayViewSizeWasChanged]; | 160 [self displayViewSizeWasChanged]; |
| 159 } | 161 } |
| 160 | 162 |
| 161 - (CardCloseButtonSide)closeButtonSide { | 163 - (CardCloseButtonSide)closeButtonSide { |
| 162 return [stackModel_ layoutIsVertical] ? CardCloseButtonSide::TRAILING | 164 return [stackModel_ layoutIsVertical] ? CardCloseButtonSide::TRAILING |
| 163 : CardCloseButtonSide::LEADING; | 165 : CardCloseButtonSide::LEADING; |
| 164 } | 166 } |
| 165 | 167 |
| 166 - (void)setIgnoresTabModelChanges:(BOOL)ignoresTabModelChanges { | 168 - (void)setIgnoresTabModelChanges:(BOOL)ignoresTabModelChanges { |
| 167 if (ignoresTabModelChanges_ == ignoresTabModelChanges) | 169 if (ignoresTabModelChanges_ == ignoresTabModelChanges) |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 397 // associated with this target to be removed. Note that if |object| is | 399 // associated with this target to be removed. Note that if |object| is |
| 398 // not a target of |recognizer| this method is a no-op. | 400 // not a target of |recognizer| this method is a no-op. |
| 399 [recognizer removeTarget:object action:NULL]; | 401 [recognizer removeTarget:object action:NULL]; |
| 400 } | 402 } |
| 401 } | 403 } |
| 402 } | 404 } |
| 403 | 405 |
| 404 - (void)removeCardAtIndex:(NSUInteger)index { | 406 - (void)removeCardAtIndex:(NSUInteger)index { |
| 405 DCHECK(index < [self.cards count]); | 407 DCHECK(index < [self.cards count]); |
| 406 StackCard* card = [self.cards objectAtIndex:index]; | 408 StackCard* card = [self.cards objectAtIndex:index]; |
| 407 [[card retain] autorelease]; | |
| 408 [self.observer cardSet:self willRemoveCard:card atIndex:index]; | 409 [self.observer cardSet:self willRemoveCard:card atIndex:index]; |
| 409 [stackModel_ removeCard:card]; | 410 [stackModel_ removeCard:card]; |
| 410 | 411 |
| 411 [self.observer cardSet:self didRemoveCard:card atIndex:index]; | 412 [self.observer cardSet:self didRemoveCard:card atIndex:index]; |
| 412 } | 413 } |
| 413 | 414 |
| 414 #pragma mark Card Construction/Display | 415 #pragma mark Card Construction/Display |
| 415 | 416 |
| 416 - (StackCard*)buildCardFromTab:(Tab*)tab { | 417 - (StackCard*)buildCardFromTab:(Tab*)tab { |
| 417 DCHECK(tab); | 418 DCHECK(tab); |
| 418 StackCard* card = [[[StackCard alloc] initWithViewProvider:self] autorelease]; | 419 StackCard* card = [[StackCard alloc] initWithViewProvider:self]; |
| 419 card.size = [stackModel_ cardSize]; | 420 card.size = [stackModel_ cardSize]; |
| 420 card.tabID = reinterpret_cast<NSUInteger>(tab); | 421 card.tabID = reinterpret_cast<NSUInteger>(tab); |
| 421 | 422 |
| 422 return card; | 423 return card; |
| 423 } | 424 } |
| 424 | 425 |
| 425 - (void)rebuildCards { | 426 - (void)rebuildCards { |
| 426 [stackModel_ removeAllCards]; | 427 [stackModel_ removeAllCards]; |
| 427 | 428 |
| 428 for (Tab* tab in tabModel_.get()) { | 429 for (Tab* tab in tabModel_) { |
| 429 StackCard* card = [self buildCardFromTab:tab]; | 430 StackCard* card = [self buildCardFromTab:tab]; |
| 430 [stackModel_ addCard:card]; | 431 [stackModel_ addCard:card]; |
| 431 } | 432 } |
| 432 | 433 |
| 433 [self.observer cardSetRecreatedCards:self]; | 434 [self.observer cardSetRecreatedCards:self]; |
| 434 } | 435 } |
| 435 | 436 |
| 436 - (void)displayCard:(StackCard*)card { | 437 - (void)displayCard:(StackCard*)card { |
| 437 DCHECK(view_); | 438 DCHECK(view_); |
| 438 card.view.hidden = [stackModel_ cardIsCovered:card]; | 439 card.view.hidden = [stackModel_ cardIsCovered:card]; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 478 | 479 |
| 479 - (CardView*)cardViewWithFrame:(CGRect)frame forStackCard:(StackCard*)card { | 480 - (CardView*)cardViewWithFrame:(CGRect)frame forStackCard:(StackCard*)card { |
| 480 DCHECK(!ignoresTabModelChanges_); | 481 DCHECK(!ignoresTabModelChanges_); |
| 481 NSUInteger cardIndex = [self.cards indexOfObject:card]; | 482 NSUInteger cardIndex = [self.cards indexOfObject:card]; |
| 482 DCHECK(cardIndex != NSNotFound); | 483 DCHECK(cardIndex != NSNotFound); |
| 483 Tab* tab = [tabModel_ tabAtIndex:cardIndex]; | 484 Tab* tab = [tabModel_ tabAtIndex:cardIndex]; |
| 484 DCHECK(tab); | 485 DCHECK(tab); |
| 485 NSString* title = tab.title; | 486 NSString* title = tab.title; |
| 486 if (![title length]) | 487 if (![title length]) |
| 487 title = tab.urlDisplayString; | 488 title = tab.urlDisplayString; |
| 488 CardView* view = | 489 CardView* view = [[CardView alloc] initWithFrame:frame |
| 489 [[[CardView alloc] initWithFrame:frame | 490 isIncognito:[tabModel_ isOffTheRecord]]; |
| 490 isIncognito:[tabModel_ isOffTheRecord]] autorelease]; | |
| 491 [view setTitle:title]; | 491 [view setTitle:title]; |
| 492 [view setFavicon:[tab favicon]]; | 492 [view setFavicon:[tab favicon]]; |
| 493 [tab retrieveSnapshot:^(UIImage* image) { | 493 [tab retrieveSnapshot:^(UIImage* image) { |
| 494 [view setImage:image]; | 494 [view setImage:image]; |
| 495 }]; | 495 }]; |
| 496 if (!view.image) | 496 if (!view.image) |
| 497 [view setImage:[CRWWebController defaultSnapshotImage]]; | 497 [view setImage:[CRWWebController defaultSnapshotImage]]; |
| 498 view.closeButtonSide = self.closeButtonSide; | 498 view.closeButtonSide = self.closeButtonSide; |
| 499 | 499 |
| 500 return view; | 500 return view; |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 585 @implementation CardSet (Testing) | 585 @implementation CardSet (Testing) |
| 586 | 586 |
| 587 - (StackCard*)cardForTab:(Tab*)tab { | 587 - (StackCard*)cardForTab:(Tab*)tab { |
| 588 NSUInteger tabIndex = [tabModel_ indexOfTab:tab]; | 588 NSUInteger tabIndex = [tabModel_ indexOfTab:tab]; |
| 589 if (tabIndex == NSNotFound) | 589 if (tabIndex == NSNotFound) |
| 590 return nil; | 590 return nil; |
| 591 return [self.cards objectAtIndex:tabIndex]; | 591 return [self.cards objectAtIndex:tabIndex]; |
| 592 } | 592 } |
| 593 | 593 |
| 594 - (void)setStackModelForTesting:(CardStackLayoutManager*)stackModel { | 594 - (void)setStackModelForTesting:(CardStackLayoutManager*)stackModel { |
| 595 stackModel_.reset([stackModel retain]); | 595 stackModel_ = stackModel; |
| 596 } | 596 } |
| 597 | 597 |
| 598 @end | 598 @end |
| OLD | NEW |