| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/ntp/google_landing_controller.h" | 5 #import "ios/chrome/browser/ui/ntp/google_landing_controller.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/i18n/case_conversion.h" | 9 #include "base/i18n/case_conversion.h" |
| 10 #import "base/ios/weak_nsobject.h" | 10 #import "base/ios/weak_nsobject.h" |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 #include "components/strings/grit/components_strings.h" | 27 #include "components/strings/grit/components_strings.h" |
| 28 #include "ios/chrome/browser/application_context.h" | 28 #include "ios/chrome/browser/application_context.h" |
| 29 #include "ios/chrome/browser/browser_state/chrome_browser_state.h" | 29 #include "ios/chrome/browser/browser_state/chrome_browser_state.h" |
| 30 #import "ios/chrome/browser/favicon/favicon_loader.h" | 30 #import "ios/chrome/browser/favicon/favicon_loader.h" |
| 31 #include "ios/chrome/browser/favicon/favicon_service_factory.h" | 31 #include "ios/chrome/browser/favicon/favicon_service_factory.h" |
| 32 #include "ios/chrome/browser/favicon/ios_chrome_favicon_loader_factory.h" | 32 #include "ios/chrome/browser/favicon/ios_chrome_favicon_loader_factory.h" |
| 33 #include "ios/chrome/browser/favicon/large_icon_cache.h" | 33 #include "ios/chrome/browser/favicon/large_icon_cache.h" |
| 34 #import "ios/chrome/browser/metrics/new_tab_page_uma.h" | 34 #import "ios/chrome/browser/metrics/new_tab_page_uma.h" |
| 35 #include "ios/chrome/browser/notification_promo.h" | 35 #include "ios/chrome/browser/notification_promo.h" |
| 36 #include "ios/chrome/browser/ntp_tiles/ios_most_visited_sites_factory.h" | 36 #include "ios/chrome/browser/ntp_tiles/ios_most_visited_sites_factory.h" |
| 37 #import "ios/chrome/browser/ntp_tiles/most_visited_sites_observer_bridge.h" |
| 37 #include "ios/chrome/browser/reading_list/reading_list_model_factory.h" | 38 #include "ios/chrome/browser/reading_list/reading_list_model_factory.h" |
| 38 #include "ios/chrome/browser/search_engines/template_url_service_factory.h" | 39 #include "ios/chrome/browser/search_engines/template_url_service_factory.h" |
| 39 #include "ios/chrome/browser/suggestions/suggestions_service_factory.h" | 40 #include "ios/chrome/browser/suggestions/suggestions_service_factory.h" |
| 40 #import "ios/chrome/browser/tabs/tab_model.h" | 41 #import "ios/chrome/browser/tabs/tab_model.h" |
| 41 #import "ios/chrome/browser/ui/browser_view_controller.h" | 42 #import "ios/chrome/browser/ui/browser_view_controller.h" |
| 42 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h" | 43 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h" |
| 43 #import "ios/chrome/browser/ui/commands/generic_chrome_command.h" | 44 #import "ios/chrome/browser/ui/commands/generic_chrome_command.h" |
| 44 #include "ios/chrome/browser/ui/commands/ios_command_ids.h" | 45 #include "ios/chrome/browser/ui/commands/ios_command_ids.h" |
| 45 #import "ios/chrome/browser/ui/context_menu/context_menu_coordinator.h" | 46 #import "ios/chrome/browser/ui/context_menu/context_menu_coordinator.h" |
| 46 #import "ios/chrome/browser/ui/ntp/most_visited_cell.h" | 47 #import "ios/chrome/browser/ui/ntp/most_visited_cell.h" |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 101 const NSInteger kMaxNumMostVisitedFavicons = 8; | 102 const NSInteger kMaxNumMostVisitedFavicons = 8; |
| 102 const NSInteger kMaxNumMostVisitedFaviconRows = 2; | 103 const NSInteger kMaxNumMostVisitedFaviconRows = 2; |
| 103 const CGFloat kMaxSearchFieldFrameMargin = 200; | 104 const CGFloat kMaxSearchFieldFrameMargin = 200; |
| 104 const CGFloat kShiftTilesDownAnimationDuration = 0.2; | 105 const CGFloat kShiftTilesDownAnimationDuration = 0.2; |
| 105 | 106 |
| 106 const CGFloat kMostVisitedPaddingIPhone = 16; | 107 const CGFloat kMostVisitedPaddingIPhone = 16; |
| 107 const CGFloat kMostVisitedPaddingIPadFavicon = 24; | 108 const CGFloat kMostVisitedPaddingIPadFavicon = 24; |
| 108 | 109 |
| 109 } // namespace | 110 } // namespace |
| 110 | 111 |
| 111 @interface GoogleLandingController () | |
| 112 - (void)onMostVisitedURLsAvailable:(const ntp_tiles::NTPTilesVector&)data; | |
| 113 - (void)onIconMadeAvailable:(const GURL&)siteUrl; | |
| 114 @end | |
| 115 | |
| 116 namespace google_landing { | 112 namespace google_landing { |
| 117 | 113 |
| 118 // MostVisitedSitesObserverBridge allow registration as a | |
| 119 // MostVisitedSites::Observer. | |
| 120 class MostVisitedSitesObserverBridge | |
| 121 : public ntp_tiles::MostVisitedSites::Observer { | |
| 122 public: | |
| 123 MostVisitedSitesObserverBridge(GoogleLandingController* owner); | |
| 124 ~MostVisitedSitesObserverBridge() override; | |
| 125 | |
| 126 // MostVisitedSites::Observer implementation. | |
| 127 void OnMostVisitedURLsAvailable( | |
| 128 const ntp_tiles::NTPTilesVector& most_visited) override; | |
| 129 void OnIconMadeAvailable(const GURL& site_url) override; | |
| 130 | |
| 131 private: | |
| 132 GoogleLandingController* _owner; | |
| 133 }; | |
| 134 | |
| 135 MostVisitedSitesObserverBridge::MostVisitedSitesObserverBridge( | |
| 136 GoogleLandingController* owner) | |
| 137 : _owner(owner) {} | |
| 138 | |
| 139 MostVisitedSitesObserverBridge::~MostVisitedSitesObserverBridge() {} | |
| 140 | |
| 141 void MostVisitedSitesObserverBridge::OnMostVisitedURLsAvailable( | |
| 142 const ntp_tiles::NTPTilesVector& tiles) { | |
| 143 [_owner onMostVisitedURLsAvailable:tiles]; | |
| 144 } | |
| 145 | |
| 146 void MostVisitedSitesObserverBridge::OnIconMadeAvailable(const GURL& site_url) { | |
| 147 [_owner onIconMadeAvailable:site_url]; | |
| 148 } | |
| 149 | |
| 150 // Observer used to hide the Google logo and doodle if the TemplateURLService | 114 // Observer used to hide the Google logo and doodle if the TemplateURLService |
| 151 // changes. | 115 // changes. |
| 152 class SearchEngineObserver : public TemplateURLServiceObserver { | 116 class SearchEngineObserver : public TemplateURLServiceObserver { |
| 153 public: | 117 public: |
| 154 SearchEngineObserver(GoogleLandingController* owner, | 118 SearchEngineObserver(GoogleLandingController* owner, |
| 155 TemplateURLService* urlService); | 119 TemplateURLService* urlService); |
| 156 ~SearchEngineObserver() override; | 120 ~SearchEngineObserver() override; |
| 157 void OnTemplateURLServiceChanged() override; | 121 void OnTemplateURLServiceChanged() override; |
| 158 | 122 |
| 159 private: | 123 private: |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 // To prevent this from happening, we reset the inset to 0 before changing the | 177 // To prevent this from happening, we reset the inset to 0 before changing the |
| 214 // frame. | 178 // frame. |
| 215 [_googleLanding resetSectionInset]; | 179 [_googleLanding resetSectionInset]; |
| 216 [super setFrame:frame]; | 180 [super setFrame:frame]; |
| 217 [_googleLanding updateSubviewFrames]; | 181 [_googleLanding updateSubviewFrames]; |
| 218 [_googleLanding reloadData]; | 182 [_googleLanding reloadData]; |
| 219 } | 183 } |
| 220 | 184 |
| 221 @end | 185 @end |
| 222 | 186 |
| 223 @interface GoogleLandingController ()<OverscrollActionsControllerDelegate, | 187 @interface GoogleLandingController ()<MostVisitedSitesObserving, |
| 188 OverscrollActionsControllerDelegate, |
| 224 UICollectionViewDataSource, | 189 UICollectionViewDataSource, |
| 225 UICollectionViewDelegate, | 190 UICollectionViewDelegate, |
| 226 UICollectionViewDelegateFlowLayout, | 191 UICollectionViewDelegateFlowLayout, |
| 227 UIGestureRecognizerDelegate, | 192 UIGestureRecognizerDelegate, |
| 228 WhatsNewHeaderViewDelegate> { | 193 WhatsNewHeaderViewDelegate> { |
| 229 // The main view. | 194 // The main view. |
| 230 base::scoped_nsobject<GoogleLandingView> _view; | 195 base::scoped_nsobject<GoogleLandingView> _view; |
| 231 | 196 |
| 232 // Fake omnibox. | 197 // Fake omnibox. |
| 233 base::scoped_nsobject<UIButton> _searchTapTarget; | 198 base::scoped_nsobject<UIButton> _searchTapTarget; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 260 base::scoped_nsobject<UISwipeGestureRecognizer> _swipeGestureRecognizer; | 225 base::scoped_nsobject<UISwipeGestureRecognizer> _swipeGestureRecognizer; |
| 261 | 226 |
| 262 // Handles displaying the context menu for all form factors. | 227 // Handles displaying the context menu for all form factors. |
| 263 base::scoped_nsobject<ContextMenuCoordinator> _contextMenuCoordinator; | 228 base::scoped_nsobject<ContextMenuCoordinator> _contextMenuCoordinator; |
| 264 | 229 |
| 265 // What's new promo. | 230 // What's new promo. |
| 266 std::unique_ptr<NotificationPromoWhatsNew> _notification_promo; | 231 std::unique_ptr<NotificationPromoWhatsNew> _notification_promo; |
| 267 | 232 |
| 268 // A MostVisitedSites::Observer bridge object to get notified of most visited | 233 // A MostVisitedSites::Observer bridge object to get notified of most visited |
| 269 // sites changes. | 234 // sites changes. |
| 270 std::unique_ptr<google_landing::MostVisitedSitesObserverBridge> | 235 std::unique_ptr<ntp_tiles::MostVisitedSitesObserverBridge> |
| 271 _most_visited_observer_bridge; | 236 _most_visited_observer_bridge; |
| 272 | 237 |
| 273 std::unique_ptr<ntp_tiles::MostVisitedSites> _most_visited_sites; | 238 std::unique_ptr<ntp_tiles::MostVisitedSites> _most_visited_sites; |
| 274 | 239 |
| 275 // URL of the last deleted most viewed entry. If present the UI to restore it | 240 // URL of the last deleted most viewed entry. If present the UI to restore it |
| 276 // is shown. | 241 // is shown. |
| 277 base::scoped_nsobject<NSURL> _deletedUrl; | 242 base::scoped_nsobject<NSURL> _deletedUrl; |
| 278 | 243 |
| 279 // Listen for default search engine changes. | 244 // Listen for default search engine changes. |
| 280 std::unique_ptr<google_landing::SearchEngineObserver> _observer; | 245 std::unique_ptr<google_landing::SearchEngineObserver> _observer; |
| (...skipping 642 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 923 withReuseIdentifier:@"whatsNew"]; | 888 withReuseIdentifier:@"whatsNew"]; |
| 924 [_mostVisitedView registerClass:[NewTabPageHeaderView class] | 889 [_mostVisitedView registerClass:[NewTabPageHeaderView class] |
| 925 forSupplementaryViewOfKind:UICollectionElementKindSectionHeader | 890 forSupplementaryViewOfKind:UICollectionElementKindSectionHeader |
| 926 withReuseIdentifier:@"header"]; | 891 withReuseIdentifier:@"header"]; |
| 927 [_mostVisitedView setAccessibilityIdentifier:@"Google Landing"]; | 892 [_mostVisitedView setAccessibilityIdentifier:@"Google Landing"]; |
| 928 | 893 |
| 929 [_view addSubview:_mostVisitedView]; | 894 [_view addSubview:_mostVisitedView]; |
| 930 _most_visited_sites = | 895 _most_visited_sites = |
| 931 IOSMostVisitedSitesFactory::NewForBrowserState(_browserState); | 896 IOSMostVisitedSitesFactory::NewForBrowserState(_browserState); |
| 932 _most_visited_observer_bridge.reset( | 897 _most_visited_observer_bridge.reset( |
| 933 new google_landing::MostVisitedSitesObserverBridge(self)); | 898 new ntp_tiles::MostVisitedSitesObserverBridge(self)); |
| 934 _most_visited_sites->SetMostVisitedURLsObserver( | 899 _most_visited_sites->SetMostVisitedURLsObserver( |
| 935 _most_visited_observer_bridge.get(), kMaxNumMostVisitedFavicons); | 900 _most_visited_observer_bridge.get(), kMaxNumMostVisitedFavicons); |
| 936 } | 901 } |
| 937 | 902 |
| 938 - (void)updateSearchField { | 903 - (void)updateSearchField { |
| 939 NSArray* constraints = | 904 NSArray* constraints = |
| 940 @[ _hintLabelLeadingConstraint, _voiceTapTrailingConstraint ]; | 905 @[ _hintLabelLeadingConstraint, _voiceTapTrailingConstraint ]; |
| 941 [_headerView updateSearchField:_searchTapTarget | 906 [_headerView updateSearchField:_searchTapTarget |
| 942 withInitialFrame:[self searchFieldFrame] | 907 withInitialFrame:[self searchFieldFrame] |
| 943 subviewConstraints:constraints | 908 subviewConstraints:constraints |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1089 | 1054 |
| 1090 - (void)logMostVisitedClick:(const NSUInteger)visitedIndex | 1055 - (void)logMostVisitedClick:(const NSUInteger)visitedIndex |
| 1091 tileType:(ntp_tiles::metrics::MostVisitedTileType)tileType { | 1056 tileType:(ntp_tiles::metrics::MostVisitedTileType)tileType { |
| 1092 new_tab_page_uma::RecordAction( | 1057 new_tab_page_uma::RecordAction( |
| 1093 _browserState, new_tab_page_uma::ACTION_OPENED_MOST_VISITED_ENTRY); | 1058 _browserState, new_tab_page_uma::ACTION_OPENED_MOST_VISITED_ENTRY); |
| 1094 base::RecordAction(UserMetricsAction("MobileNTPMostVisited")); | 1059 base::RecordAction(UserMetricsAction("MobileNTPMostVisited")); |
| 1095 const ntp_tiles::NTPTile& tile = _mostVisitedData[visitedIndex]; | 1060 const ntp_tiles::NTPTile& tile = _mostVisitedData[visitedIndex]; |
| 1096 ntp_tiles::metrics::RecordTileClick(visitedIndex, tile.source, tileType); | 1061 ntp_tiles::metrics::RecordTileClick(visitedIndex, tile.source, tileType); |
| 1097 } | 1062 } |
| 1098 | 1063 |
| 1099 - (void)onMostVisitedURLsAvailable:(const ntp_tiles::NTPTilesVector&)data { | |
| 1100 _mostVisitedData = data; | |
| 1101 [self reloadData]; | |
| 1102 | |
| 1103 if (data.size() && !_recordedPageImpression) { | |
| 1104 _recordedPageImpression = YES; | |
| 1105 std::vector<ntp_tiles::metrics::TileImpression> tiles; | |
| 1106 for (const ntp_tiles::NTPTile& ntpTile : data) { | |
| 1107 tiles.emplace_back(ntpTile.source, ntp_tiles::metrics::UNKNOWN_TILE_TYPE, | |
| 1108 ntpTile.url); | |
| 1109 } | |
| 1110 ntp_tiles::metrics::RecordPageImpression( | |
| 1111 tiles, GetApplicationContext()->GetRapporServiceImpl()); | |
| 1112 } | |
| 1113 } | |
| 1114 | |
| 1115 - (void)onIconMadeAvailable:(const GURL&)siteUrl { | |
| 1116 for (size_t i = 0; i < [self numberOfItems]; ++i) { | |
| 1117 const ntp_tiles::NTPTile& ntpTile = _mostVisitedData[i]; | |
| 1118 if (ntpTile.url == siteUrl) { | |
| 1119 NSIndexPath* indexPath = | |
| 1120 [NSIndexPath indexPathForRow:i inSection:SectionWithMostVisited]; | |
| 1121 [_mostVisitedView reloadItemsAtIndexPaths:@[ indexPath ]]; | |
| 1122 break; | |
| 1123 } | |
| 1124 } | |
| 1125 } | |
| 1126 | |
| 1127 - (void)reloadData { | 1064 - (void)reloadData { |
| 1128 // -reloadData updates from |_mostVisitedData|. | 1065 // -reloadData updates from |_mostVisitedData|. |
| 1129 // -invalidateLayout is necessary because sometimes the flowLayout has the | 1066 // -invalidateLayout is necessary because sometimes the flowLayout has the |
| 1130 // wrong cached size and will throw an internal exception if the | 1067 // wrong cached size and will throw an internal exception if the |
| 1131 // -numberOfItems shrinks. -setNeedsLayout is needed in case | 1068 // -numberOfItems shrinks. -setNeedsLayout is needed in case |
| 1132 // -numberOfItems increases enough to add a new row and change the height | 1069 // -numberOfItems increases enough to add a new row and change the height |
| 1133 // of _mostVisitedView. | 1070 // of _mostVisitedView. |
| 1134 [_mostVisitedView reloadData]; | 1071 [_mostVisitedView reloadData]; |
| 1135 [[_mostVisitedView collectionViewLayout] invalidateLayout]; | 1072 [[_mostVisitedView collectionViewLayout] invalidateLayout]; |
| 1136 [self.view setNeedsLayout]; | 1073 [self.view setNeedsLayout]; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1154 ? kTopSpacingMaterialPortrait | 1091 ? kTopSpacingMaterialPortrait |
| 1155 : kTopSpacingMaterialLandscape; | 1092 : kTopSpacingMaterialLandscape; |
| 1156 } | 1093 } |
| 1157 } else { | 1094 } else { |
| 1158 headerHeight = kNonGoogleSearchHeaderHeightIPad; | 1095 headerHeight = kNonGoogleSearchHeaderHeightIPad; |
| 1159 } | 1096 } |
| 1160 } | 1097 } |
| 1161 return headerHeight; | 1098 return headerHeight; |
| 1162 } | 1099 } |
| 1163 | 1100 |
| 1101 #pragma mark - MostVisitedSitesObserving |
| 1102 |
| 1103 - (void)onMostVisitedURLsAvailable:(const ntp_tiles::NTPTilesVector&)data { |
| 1104 _mostVisitedData = data; |
| 1105 [self reloadData]; |
| 1106 |
| 1107 if (data.size() && !_recordedPageImpression) { |
| 1108 _recordedPageImpression = YES; |
| 1109 std::vector<ntp_tiles::metrics::TileImpression> tiles; |
| 1110 for (const ntp_tiles::NTPTile& ntpTile : data) { |
| 1111 tiles.emplace_back(ntpTile.source, ntp_tiles::metrics::UNKNOWN_TILE_TYPE, |
| 1112 ntpTile.url); |
| 1113 } |
| 1114 ntp_tiles::metrics::RecordPageImpression( |
| 1115 tiles, GetApplicationContext()->GetRapporServiceImpl()); |
| 1116 } |
| 1117 } |
| 1118 |
| 1119 - (void)onIconMadeAvailable:(const GURL&)siteUrl { |
| 1120 for (size_t i = 0; i < [self numberOfItems]; ++i) { |
| 1121 const ntp_tiles::NTPTile& ntpTile = _mostVisitedData[i]; |
| 1122 if (ntpTile.url == siteUrl) { |
| 1123 NSIndexPath* indexPath = |
| 1124 [NSIndexPath indexPathForRow:i inSection:SectionWithMostVisited]; |
| 1125 [_mostVisitedView reloadItemsAtIndexPaths:@[ indexPath ]]; |
| 1126 break; |
| 1127 } |
| 1128 } |
| 1129 } |
| 1130 |
| 1164 #pragma mark - UICollectionView Methods. | 1131 #pragma mark - UICollectionView Methods. |
| 1165 | 1132 |
| 1166 - (CGSize)collectionView:(UICollectionView*)collectionView | 1133 - (CGSize)collectionView:(UICollectionView*)collectionView |
| 1167 layout: | 1134 layout: |
| 1168 (UICollectionViewLayout*)collectionViewLayout | 1135 (UICollectionViewLayout*)collectionViewLayout |
| 1169 referenceSizeForHeaderInSection:(NSInteger)section { | 1136 referenceSizeForHeaderInSection:(NSInteger)section { |
| 1170 CGFloat headerHeight = 0; | 1137 CGFloat headerHeight = 0; |
| 1171 if (section == SectionWithOmnibox) { | 1138 if (section == SectionWithOmnibox) { |
| 1172 headerHeight = [self heightForSectionWithOmnibox]; | 1139 headerHeight = [self heightForSectionWithOmnibox]; |
| 1173 ((UICollectionViewFlowLayout*)collectionViewLayout).headerReferenceSize = | 1140 ((UICollectionViewFlowLayout*)collectionViewLayout).headerReferenceSize = |
| (...skipping 564 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1738 if (!view) { | 1705 if (!view) { |
| 1739 return nil; | 1706 return nil; |
| 1740 } | 1707 } |
| 1741 if ([view isKindOfClass:aClass]) { | 1708 if ([view isKindOfClass:aClass]) { |
| 1742 return view; | 1709 return view; |
| 1743 } | 1710 } |
| 1744 return [self nearestAncestorOfView:[view superview] withClass:aClass]; | 1711 return [self nearestAncestorOfView:[view superview] withClass:aClass]; |
| 1745 } | 1712 } |
| 1746 | 1713 |
| 1747 @end | 1714 @end |
| OLD | NEW |