sc_follow_view_controller.mm 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. // Copyright 2022 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #import "ios/showcase/follow/sc_follow_view_controller.h"
  5. #import "ios/chrome/browser/net/crurl.h"
  6. #import "ios/chrome/browser/ui/follow/first_follow_view_controller.h"
  7. #import "ios/chrome/browser/ui/follow/followed_web_channel.h"
  8. #import "ios/chrome/browser/ui/icons/chrome_symbol.h"
  9. #import "ios/chrome/browser/ui/ntp/feed_management/feed_management_follow_delegate.h"
  10. #import "ios/chrome/browser/ui/ntp/feed_management/feed_management_navigation_delegate.h"
  11. #import "ios/chrome/browser/ui/ntp/feed_management/feed_management_view_controller.h"
  12. #import "ios/chrome/browser/ui/ntp/feed_management/follow_management_ui_updater.h"
  13. #import "ios/chrome/browser/ui/ntp/feed_management/follow_management_view_controller.h"
  14. #import "ios/chrome/browser/ui/ntp/feed_management/followed_web_channels_data_source.h"
  15. #import "ios/chrome/browser/ui/table_view/table_view_favicon_data_source.h"
  16. #import "ios/chrome/browser/ui/table_view/table_view_navigation_controller.h"
  17. #import "ios/chrome/common/ui/favicon/favicon_attributes.h"
  18. #import "ios/showcase/common/protocol_alerter.h"
  19. #if !defined(__has_feature) || !__has_feature(objc_arc)
  20. #error "This file requires ARC support."
  21. #endif
  22. namespace {
  23. // Sets a custom radius for the half sheet presentation.
  24. constexpr CGFloat kHalfSheetCornerRadius = 20;
  25. // An example favicon URL given from the Discover backend.
  26. static NSString* const kExampleFaviconURL = @"https://www.the-sun.com/";
  27. // Specific symbols used to create favicons.
  28. NSString* kGlobeSymbol = @"globe";
  29. NSString* kGlobeAmericaSymbol = @"globe.americas.fill";
  30. // The size of favicon symbol images.
  31. NSInteger kFaviconSymbolPointSize = 17;
  32. } // namespace
  33. @interface SCFollowViewController () <FollowedWebChannelsDataSource,
  34. TableViewFaviconDataSource>
  35. // Shows alerts of protocol method calls.
  36. @property(nonatomic, strong) ProtocolAlerter* alerter;
  37. // Called to unfollow/refollow channels in the follow mgmt UI.
  38. @property(nonatomic, weak) id<FollowManagementUIUpdater>
  39. followManagementUIUpdater;
  40. // An owner of the web channels list is required to test unfollow/refollow.
  41. @property(nonatomic, strong)
  42. NSArray<FollowedWebChannel*>* strongFollowedWebChannels;
  43. @end
  44. @implementation SCFollowViewController
  45. - (void)viewDidLoad {
  46. [super viewDidLoad];
  47. self.alerter = [[ProtocolAlerter alloc] initWithProtocols:@[
  48. @protocol(FeedManagementFollowDelegate),
  49. @protocol(FeedManagementNavigationDelegate)
  50. ]];
  51. UIButton* button1 = [[UIButton alloc] init];
  52. [button1 setTitle:@"Show Feed Mgmt UI" forState:UIControlStateNormal];
  53. [button1 addTarget:self
  54. action:@selector(handleFeedMgmtButtonTapped)
  55. forControlEvents:UIControlEventTouchUpInside];
  56. UIButton* button2 = [[UIButton alloc] init];
  57. [button2 setTitle:@"Show Follow Mgmt UI" forState:UIControlStateNormal];
  58. [button2 addTarget:self
  59. action:@selector(handleFollowMgmtButtonTapped)
  60. forControlEvents:UIControlEventTouchUpInside];
  61. UIButton* button3 = [[UIButton alloc] init];
  62. [button3 setTitle:@"Show First Follow modal" forState:UIControlStateNormal];
  63. [button3 addTarget:self
  64. action:@selector(handleFirstFollowButtonTapped)
  65. forControlEvents:UIControlEventTouchUpInside];
  66. UIStackView* verticalStack = [[UIStackView alloc]
  67. initWithArrangedSubviews:@[ button1, button2, button3 ]];
  68. verticalStack.axis = UILayoutConstraintAxisVertical;
  69. verticalStack.distribution = UIStackViewDistributionFill;
  70. verticalStack.alignment = UIStackViewAlignmentCenter;
  71. verticalStack.spacing = 10;
  72. verticalStack.translatesAutoresizingMaskIntoConstraints = NO;
  73. [self.view addSubview:verticalStack];
  74. [NSLayoutConstraint activateConstraints:@[
  75. [verticalStack.centerXAnchor
  76. constraintEqualToAnchor:self.view.centerXAnchor],
  77. [verticalStack.centerYAnchor
  78. constraintEqualToAnchor:self.view.centerYAnchor],
  79. ]];
  80. }
  81. - (void)handleFeedMgmtButtonTapped {
  82. FeedManagementViewController* feedManagementViewController =
  83. [[FeedManagementViewController alloc]
  84. initWithStyle:UITableViewStyleInsetGrouped];
  85. self.alerter.baseViewController = feedManagementViewController;
  86. feedManagementViewController.followDelegate =
  87. static_cast<id<FeedManagementFollowDelegate>>(self.alerter);
  88. feedManagementViewController.navigationDelegate =
  89. static_cast<id<FeedManagementNavigationDelegate>>(self.alerter);
  90. TableViewNavigationController* navigationController =
  91. [[TableViewNavigationController alloc]
  92. initWithTable:feedManagementViewController];
  93. [self presentViewController:navigationController animated:YES completion:nil];
  94. }
  95. - (void)handleFollowMgmtButtonTapped {
  96. FollowManagementViewController* followManagementViewController =
  97. [[FollowManagementViewController alloc]
  98. initWithStyle:UITableViewStyleInsetGrouped];
  99. self.followManagementUIUpdater =
  100. (id<FollowManagementUIUpdater>)followManagementViewController;
  101. followManagementViewController.followedWebChannelsDataSource = self;
  102. followManagementViewController.faviconDataSource = self;
  103. TableViewNavigationController* navigationController =
  104. [[TableViewNavigationController alloc]
  105. initWithTable:followManagementViewController];
  106. [self presentViewController:navigationController animated:YES completion:nil];
  107. }
  108. - (void)handleFirstFollowButtonTapped {
  109. __weak __typeof(self) weakSelf = self;
  110. FirstFollowViewController* firstFollowViewController =
  111. [[FirstFollowViewController alloc]
  112. initWithTitle:@"First Web Channel"
  113. available:YES
  114. faviconSource:^(void (^completion)(UIImage* favicon)) {
  115. [weakSelf faviconForURL:nil
  116. completion:^(FaviconAttributes* attributes) {
  117. completion(attributes.faviconImage);
  118. }];
  119. }];
  120. self.alerter.baseViewController = firstFollowViewController;
  121. firstFollowViewController.imageEnclosedWithShadowAndBadge = YES;
  122. if (@available(iOS 15, *)) {
  123. firstFollowViewController.modalPresentationStyle =
  124. UIModalPresentationPageSheet;
  125. UISheetPresentationController* presentationController =
  126. firstFollowViewController.sheetPresentationController;
  127. presentationController.prefersEdgeAttachedInCompactHeight = YES;
  128. presentationController.widthFollowsPreferredContentSizeWhenEdgeAttached =
  129. YES;
  130. presentationController.detents = @[
  131. UISheetPresentationControllerDetent.mediumDetent,
  132. UISheetPresentationControllerDetent.largeDetent
  133. ];
  134. presentationController.preferredCornerRadius = kHalfSheetCornerRadius;
  135. } else {
  136. firstFollowViewController.modalPresentationStyle =
  137. UIModalPresentationFormSheet;
  138. }
  139. [self presentViewController:firstFollowViewController
  140. animated:YES
  141. completion:nil];
  142. }
  143. #pragma mark - FollowedWebChannelsDataSource
  144. - (NSArray<FollowedWebChannel*>*)followedWebChannels {
  145. NSMutableArray<FollowedWebChannel*>* followedWebChannels =
  146. [[NSMutableArray alloc] init];
  147. for (int i = 0; i < 10; i++) {
  148. NSString* title = [NSString stringWithFormat:@"Channel %d", i];
  149. [followedWebChannels addObject:[self createWebChannelWithTitle:title]];
  150. }
  151. self.strongFollowedWebChannels = followedWebChannels;
  152. return followedWebChannels;
  153. }
  154. - (FollowedWebChannel*)createWebChannelWithTitle:(NSString*)title {
  155. FollowedWebChannel* channel = [[FollowedWebChannel alloc] init];
  156. channel.title = title;
  157. channel.available = YES;
  158. channel.faviconURL =
  159. [[CrURL alloc] initWithNSURL:[NSURL URLWithString:kExampleFaviconURL]];
  160. return channel;
  161. }
  162. #pragma mark - TableViewFaviconDataSource
  163. - (void)faviconForURL:(CrURL*)URL
  164. completion:(void (^)(FaviconAttributes*))completion {
  165. // This mimics the behavior of favicon loader by immediately returning a
  166. // default image, then fetching and returning another image.
  167. UIImage* image1 =
  168. DefaultSymbolTemplateWithPointSize(kGlobeSymbol, kFaviconSymbolPointSize);
  169. UIImage* image2 = DefaultSymbolTemplateWithPointSize(kGlobeAmericaSymbol,
  170. kFaviconSymbolPointSize);
  171. completion([FaviconAttributes attributesWithImage:image1]);
  172. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC),
  173. dispatch_get_main_queue(), ^{
  174. completion([FaviconAttributes attributesWithImage:image2]);
  175. });
  176. }
  177. @end