// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/spotlight_debugger/ui_bundled/spotlight_debugger_view_controller.h"
#import "base/apple/foundation_util.h"
#import "base/notreached.h"
#import "base/time/time.h"
#import "components/prefs/pref_service.h"
#import "ios/chrome/app/spotlight/bookmarks_spotlight_manager.h"
#import "ios/chrome/app/spotlight/open_tabs_spotlight_manager.h"
#import "ios/chrome/app/spotlight/reading_list_spotlight_manager.h"
#import "ios/chrome/app/spotlight/spotlight_interface.h"
#import "ios/chrome/app/spotlight/spotlight_logger.h"
#import "ios/chrome/app/spotlight/spotlight_util.h"
#import "ios/chrome/app/spotlight/topsites_spotlight_manager.h"
#import "ios/chrome/browser/shared/ui/symbols/symbols.h"
#import "ios/chrome/browser/shared/ui/table_view/table_view_navigation_controller.h"
#import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h"
#import "ios/chrome/common/ui/colors/semantic_color_names.h"
#import "ios/chrome/common/ui/elements/highlight_button.h"
#import "ios/chrome/common/ui/util/button_util.h"
#import "url/gurl.h"
typedef NS_ENUM(NSUInteger, Sections) {
StatusSection = 0,
DebugCommandsSection,
SectionCount,
};
typedef NS_ENUM(NSUInteger, StatusSectionRows) {
AvailabilityRow = 0,
LastIndexDateRow,
DonatedItemsRow,
StatusSectionRowsCount,
};
typedef NS_ENUM(NSUInteger, DebugCommandsRows) {
ClearAllRow = 0,
ReindexBookmarks,
ReindexReadingList,
ReindexOpenTabs,
ReindexTopSites,
DebugCommandsRowsCount,
};
@interface SpotlightDebuggerViewController ()
@property(nonatomic, strong) UIActivityIndicatorView* spinner;
@property(nonatomic, readonly) SpotlightInterface* spotlightInterface;
@end
@implementation SpotlightDebuggerViewController {
// PrefService per a browser state.
PrefService* _prefService;
}
- (instancetype)initWithPrefService:(PrefService*)prefService {
self = [super initWithStyle:UITableViewStyleInsetGrouped];
if (self) {
_spinner = [[UIActivityIndicatorView alloc]
initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleLarge];
_spinner.translatesAutoresizingMaskIntoConstraints = NO;
_spotlightInterface = [SpotlightInterface defaultInterface];
_prefService = prefService;
}
return self;
}
- (void)dealloc {
[self.bookmarksManager shutdown];
[self.readingListSpotlightManager shutdown];
[self.openTabsSpotlightManager shutdown];
[self.topSitesSpotlightManager shutdown];
}
#pragma mark - Public
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"Spotlight Debugger";
[self.tableView registerClass:[UITableViewCell class]
forCellReuseIdentifier:@"Cell"];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView {
return SectionCount;
}
- (NSInteger)tableView:(UITableView*)tableView
numberOfRowsInSection:(NSInteger)section {
switch (section) {
case StatusSection:
return StatusSectionRowsCount;
case DebugCommandsSection:
return DebugCommandsRowsCount;
default:
NOTREACHED_IN_MIGRATION();
}
return 0;
}
- (UITableViewCell*)tableView:(UITableView*)tableView
cellForRowAtIndexPath:(NSIndexPath*)indexPath {
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
UIListContentConfiguration* content = cell.defaultContentConfiguration;
switch (indexPath.section) {
case StatusSection:
switch (indexPath.row) {
case AvailabilityRow:
content.text = @"Spotlight Status";
content.secondaryText = spotlight::IsSpotlightAvailable()
? @"Available"
: @"Not Available";
content.image =
spotlight::IsSpotlightAvailable()
? DefaultSymbolWithPointSize(@"checkmark.circle.fill",
kSymbolAccessoryPointSize)
: DefaultSymbolWithPointSize(@"exclamationmark.triangle",
kSymbolAccessoryPointSize);
break;
case LastIndexDateRow:
content.text = @"Time since last reindexing";
content.secondaryText = [self timeSinceLastReindexAsString];
content.image = DefaultSymbolWithPointSize(
@"arrow.counterclockwise.icloud", kSymbolAccessoryPointSize);
break;
case DonatedItemsRow:
content.text = @"Donated items";
content.image = DefaultSymbolWithPointSize(
@"square.stack.3d.down.right", kSymbolAccessoryPointSize);
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
break;
default:
NOTREACHED_IN_MIGRATION();
break;
}
break;
case DebugCommandsSection:
switch (indexPath.row) {
case ClearAllRow: {
content.text = @"Clear all Spotlight entries";
content.image = DefaultSymbolWithPointSize(@"bin.xmark",
kSymbolAccessoryPointSize);
break;
}
case ReindexBookmarks: {
content.text = @"Clear and Reindex Bookmarks";
content.image = DefaultSymbolWithPointSize(@"bin.xmark",
kSymbolAccessoryPointSize);
break;
}
case ReindexReadingList: {
content.text = @"Clear and Reindex reading list";
content.image = DefaultSymbolWithPointSize(@"bin.xmark",
kSymbolAccessoryPointSize);
break;
}
case ReindexOpenTabs: {
content.text = @"Clear and Reindex open tabs";
content.image = DefaultSymbolWithPointSize(@"bin.xmark",
kSymbolAccessoryPointSize);
break;
}
case ReindexTopSites: {
content.text = @"Clear and Reindex Top sites";
content.image = DefaultSymbolWithPointSize(@"bin.xmark",
kSymbolAccessoryPointSize);
break;
}
default:
NOTREACHED_IN_MIGRATION();
break;
}
break;
default:
NOTREACHED_IN_MIGRATION();
break;
}
cell.contentConfiguration = content;
return cell;
}
- (void)tableView:(UITableView*)tableView
didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
switch (indexPath.section) {
case StatusSection:
switch (indexPath.row) {
case AvailabilityRow:
break;
case LastIndexDateRow:
break;
case DonatedItemsRow:
[self.delegate showAllItems];
break;
default:
NOTREACHED_IN_MIGRATION();
break;
}
break;
case DebugCommandsSection:
switch (indexPath.row) {
case ClearAllRow:
[self clearAllSpotlightEntries];
break;
case ReindexBookmarks:
[self clearAndReindexBookmarks];
break;
case ReindexReadingList:
[self clearAndReindexReadingList];
break;
case ReindexOpenTabs:
[self clearAndReindexOpenTabs];
break;
case ReindexTopSites:
[self clearAndReindexTopSites];
break;
default:
NOTREACHED_IN_MIGRATION();
break;
}
break;
default:
NOTREACHED_IN_MIGRATION();
break;
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#pragma mark - actions
- (void)clearAllSpotlightEntries {
[self showSpinner];
[self.spotlightInterface deleteAllSearchableItemsWithCompletionHandler:^(
NSError* error) {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertController* controller = [UIAlertController
alertControllerWithTitle:@"Clear Entries"
message:error ? error.localizedDescription
: @"Success"
preferredStyle:UIAlertControllerStyleAlert];
[controller
addAction:[UIAlertAction actionWithTitle:@"OK"
style:UIAlertActionStyleDefault
handler:nil]];
[self presentViewController:controller animated:YES completion:nil];
[self removeSpinner];
[self.tableView reloadData];
});
}];
_prefService->ClearPref(spotlight::kSpotlightLastIndexingDateKey);
}
- (void)clearAndReindexBookmarks {
[self.bookmarksManager clearAndReindexModel];
[self.tableView reloadData];
}
- (void)clearAndReindexReadingList {
[self.readingListSpotlightManager clearAndReindexReadingList];
[self.tableView reloadData];
}
- (void)clearAndReindexOpenTabs {
[self.openTabsSpotlightManager clearAndReindexOpenTabs];
[self.tableView reloadData];
}
- (void)clearAndReindexTopSites {
[self.topSitesSpotlightManager reindexTopSites];
[self.tableView reloadData];
}
#pragma mark - private
- (void)showSpinner {
[self.view addSubview:self.spinner];
[self.spinner startAnimating];
[self.spinner.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor]
.active = YES;
[self.spinner.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor]
.active = YES;
}
- (void)removeSpinner {
[self.spinner stopAnimating];
[self.spinner removeFromSuperview];
}
- (NSString*)timeSinceLastReindexAsString {
const base::Time date =
_prefService->GetTime(spotlight::kSpotlightLastIndexingDateKey);
if (date == base::Time()) {
return @"Never";
}
NSTimeInterval timeSinceReindexing =
[[NSDate date] timeIntervalSinceDate:date.ToNSDate()];
NSDateComponentsFormatter* formatter =
[[NSDateComponentsFormatter alloc] init];
formatter.unitsStyle = NSDateComponentsFormatterUnitsStyleBrief;
formatter.allowedUnits = NSCalendarUnitNanosecond | NSCalendarUnitSecond |
NSCalendarUnitMinute | NSCalendarUnitHour;
return [formatter stringFromTimeInterval:timeSinceReindexing];
}
@end