mirror of
https://github.com/samuelclay/NewsBlur.git
synced 2025-08-05 16:58:59 +00:00

- Replaced the feeds list notificaitons icon. - The feed detail folder title icon now matches the color. - Changed all of the settings icons to the new style. - Changed the feed detail mark read icon. - Changed the focus and hidden unread indicators. - Unread indicators sized to match the web. - Tweaked feed detail spacing. - Increased feed detail titles to up to three lines. - Titlecased Interactions / Your Activities. - Removed borders and tweaked section titles in trainer.
862 lines
33 KiB
Objective-C
862 lines
33 KiB
Objective-C
//
|
|
// FeedChooserViewController.m
|
|
// NewsBlur
|
|
//
|
|
// Created by David Sinclair on 2016-01-22.
|
|
// Copyright © 2016 NewsBlur. All rights reserved.
|
|
//
|
|
|
|
#import "FeedChooserViewController.h"
|
|
#import "NewsBlurAppDelegate.h"
|
|
#import "NSObject+SBJSON.h"
|
|
#import "MenuViewController.h"
|
|
#import "FeedChooserTitleView.h"
|
|
#import "FeedChooserViewCell.h"
|
|
#import "FeedChooserItem.h"
|
|
|
|
static const CGFloat kTableViewRowHeight = 31.0;
|
|
static const CGFloat kFolderTitleHeight = 36.0;
|
|
|
|
@interface FeedChooserViewController () <FeedChooserTitleDelegate>
|
|
|
|
@property (nonatomic, strong) UIBarButtonItem *optionsItem;
|
|
@property (nonatomic, strong) UIBarButtonItem *moveItem;
|
|
@property (nonatomic, strong) UIBarButtonItem *deleteItem;
|
|
@property (nonatomic, strong) NSArray *sections;
|
|
@property (nonatomic, strong) NSArray *indexTitles;
|
|
@property (nonatomic, strong) NSArray *folders;
|
|
@property (nonatomic, strong) NSDictionary *dictFolders;
|
|
@property (nonatomic, strong) NSDictionary *inactiveFeeds;
|
|
@property (nonatomic) FeedChooserSort sort;
|
|
@property (nonatomic) BOOL ascending;
|
|
@property (nonatomic) BOOL flat;
|
|
@property (nonatomic, readonly) NewsBlurAppDelegate *appDelegate;
|
|
@property (nonatomic, strong) NSUserDefaults *groupDefaults;
|
|
@property (nonatomic, readonly) NSArray *widgetFeeds;
|
|
|
|
@end
|
|
|
|
@implementation FeedChooserViewController
|
|
|
|
- (void)dealloc {
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
}
|
|
|
|
- (void)viewDidLoad {
|
|
[super viewDidLoad];
|
|
|
|
appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
|
|
|
|
if (self.operation == FeedChooserOperationWidgetSites) {
|
|
self.groupDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.newsblur.NewsBlur-Group"];
|
|
}
|
|
|
|
UIBarButtonItem *doneItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(done)];
|
|
self.optionsItem = [[UIBarButtonItem alloc] initWithImage:[Utilities imageNamed:@"settings" sized:30] style:UIBarButtonItemStylePlain target:self action:@selector(showOptionsMenu)];
|
|
|
|
if (self.operation == FeedChooserOperationMuteSites) {
|
|
UIBarButtonItem *cancelItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel)];
|
|
|
|
self.navigationItem.leftBarButtonItem = cancelItem;
|
|
self.navigationItem.rightBarButtonItems = @[doneItem, self.optionsItem];
|
|
|
|
self.tableView.editing = NO;
|
|
} else if (self.operation == FeedChooserOperationOrganizeSites) {
|
|
self.moveItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"menu_icn_move.png"] style:UIBarButtonItemStylePlain target:self action:@selector(showMoveMenu)];
|
|
self.deleteItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"menu_icn_delete.png"] style:UIBarButtonItemStylePlain target:self action:@selector(deleteFeeds)];
|
|
|
|
self.navigationItem.leftBarButtonItems = @[self.moveItem, self.deleteItem];
|
|
self.navigationItem.rightBarButtonItems = @[doneItem, self.optionsItem];
|
|
|
|
self.tableView.editing = YES;
|
|
} else {
|
|
self.navigationItem.leftBarButtonItems = nil;
|
|
self.navigationItem.rightBarButtonItems = @[doneItem, self.optionsItem];
|
|
|
|
self.tableView.editing = YES;
|
|
}
|
|
|
|
self.tableView.backgroundColor = UIColorFromRGB(0xECEEEA);
|
|
self.tableView.separatorColor = UIColorFromRGB(0xF0F0F0);
|
|
self.tableView.sectionIndexColor = UIColorFromRGB(0x303030);
|
|
self.tableView.sectionIndexBackgroundColor = UIColorFromRGB(0xDCDFD6);
|
|
|
|
if (@available(iOS 15.0, *)) {
|
|
self.tableView.sectionHeaderTopPadding = 0;
|
|
}
|
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(finishedLoadingFeedsNotification:) name:@"FinishedLoadingFeedsNotification" object:nil];
|
|
|
|
[self updateTitle];
|
|
|
|
if (self.operation == FeedChooserOperationMuteSites) {
|
|
[self performGetInactiveFeeds];
|
|
} else if (self.operation == FeedChooserOperationOrganizeSites) {
|
|
[self updateDictFolders];
|
|
[self rebuildItemsAnimated:NO];
|
|
} else {
|
|
[self updateDictFolders];
|
|
[self rebuildItemsAnimated:NO];
|
|
[self updateSelectedWidgets];
|
|
}
|
|
}
|
|
|
|
- (void)performGetInactiveFeeds {
|
|
[MBProgressHUD hideHUDForView:self.view animated:YES];
|
|
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
|
|
HUD.labelText = @"Loading...";
|
|
|
|
NSArray *selection = self.tableView.indexPathsForSelectedRows;
|
|
NSMutableArray *feedsByFolder = [NSMutableArray arrayWithCapacity:selection.count];
|
|
|
|
for (NSIndexPath *indexPath in selection) {
|
|
FeedChooserItem *fromFolder = self.sections[indexPath.section];
|
|
FeedChooserItem *item = fromFolder.contents[indexPath.row];
|
|
|
|
[feedsByFolder addObject:@[item.identifier, fromFolder.identifier]];
|
|
}
|
|
|
|
NSString *urlString = [NSString stringWithFormat:@"%@/reader/feeds?flat=true&update_counts=false&include_inactive=true", self.appDelegate.url];
|
|
[appDelegate GET:urlString parameters:nil target:self success:@selector(finishLoadingInactiveFeeds:) failure:@selector(finishedWithError:)];
|
|
}
|
|
|
|
- (void)finishLoadingInactiveFeeds:(NSDictionary *)results {
|
|
self.dictFolders = results[@"flat_folders_with_inactive"];
|
|
self.inactiveFeeds = results[@"inactive_feeds"];
|
|
|
|
[self rebuildItemsAnimated:NO];
|
|
|
|
[self enumerateAllRowsUsingBlock:^(NSIndexPath *indexPath, FeedChooserItem *item) {
|
|
if (![item.info[@"active"] boolValue]) {
|
|
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
|
|
}
|
|
}];
|
|
|
|
[self updateControls];
|
|
[MBProgressHUD hideHUDForView:self.view animated:YES];
|
|
}
|
|
|
|
- (void)finishedWithError:(NSError *)error {
|
|
NSLog(@"informError: %@", error);
|
|
NSString *errorMessage = [error localizedDescription];
|
|
|
|
[MBProgressHUD hideHUDForView:self.view animated:YES];
|
|
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
|
|
[HUD setCustomView:[[UIImageView alloc]
|
|
initWithImage:[UIImage imageNamed:@"warning.gif"]]];
|
|
[HUD setMode:MBProgressHUDModeCustomView];
|
|
HUD.labelText = errorMessage;
|
|
[HUD hide:YES afterDelay:1];
|
|
|
|
[self rebuildItemsAnimated:YES];
|
|
}
|
|
|
|
- (void)rebuildItemsAnimated:(BOOL)animated {
|
|
FeedChooserItem *section = nil;
|
|
|
|
NSMutableArray *sections = [NSMutableArray array];
|
|
NSMutableArray *indexTitles = [NSMutableArray array];
|
|
NSMutableArray *folders = [NSMutableArray array];
|
|
|
|
if (self.flat) {
|
|
section = [FeedChooserItem makeFolderWithTitle:@""];
|
|
[sections addObject:section];
|
|
}
|
|
|
|
NSArray *folderArray = [self.dictFolders.allKeys sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
|
|
|
|
for (NSString *folderName in folderArray) {
|
|
if (![folderName hasPrefix:@"river_"] && ![folderName isEqualToString:@"read_stories"] && ![folderName isEqualToString:@"saved_searches"] && ![folderName isEqualToString:@"saved_stories"]) {
|
|
FeedChooserItem *folder = [FeedChooserItem makeFolderWithTitle:folderName];
|
|
[folders addObject:folder];
|
|
|
|
if (!self.flat) {
|
|
section = folder;
|
|
}
|
|
|
|
for (id feedId in self.dictFolders[folderName]) {
|
|
NSString *feedIdStr = [NSString stringWithFormat:@"%@", feedId];
|
|
feedIdStr = [appDelegate feedIdWithoutSearchQuery:feedIdStr];
|
|
NSDictionary *info = appDelegate.dictFeeds[feedIdStr];
|
|
|
|
if (!info) {
|
|
info = self.inactiveFeeds[feedIdStr];
|
|
}
|
|
|
|
BOOL wantFeed = ![appDelegate isSocialFeed:feedIdStr] && ![appDelegate isSavedFeed:feedIdStr];
|
|
|
|
if (wantFeed && self.operation == FeedChooserOperationWidgetSites && ![info[@"active"] boolValue]) {
|
|
wantFeed = NO;
|
|
}
|
|
|
|
if (wantFeed) {
|
|
[section addItemWithInfo:info];
|
|
}
|
|
}
|
|
|
|
if (!self.flat && section.contents.count) {
|
|
[sections addObject:section];
|
|
[indexTitles addObject:section.title.length ? [section.title substringToIndex:1] : @"-"];
|
|
}
|
|
}
|
|
}
|
|
|
|
self.sections = sections;
|
|
self.indexTitles = indexTitles;
|
|
self.folders = folders;
|
|
|
|
[self.tableView reloadData];
|
|
[self sortItemsAnimated:animated];
|
|
[self updateControls];
|
|
}
|
|
|
|
- (void)sortItemsAnimated:(BOOL)animated {
|
|
[self.tableView beginUpdates];
|
|
|
|
NSString *key = [FeedChooserItem keyForSort:self.sort];
|
|
|
|
[self enumerateSectionsUsingBlock:^(NSUInteger section, FeedChooserItem *folder) {
|
|
NSArray *oldItems = [NSArray arrayWithArray:folder.contents];
|
|
|
|
if (self.sort == FeedChooserSortName) {
|
|
[folder.contents sortUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:key ascending:self.ascending selector:@selector(caseInsensitiveCompare:)], [NSSortDescriptor sortDescriptorWithKey:@"info.feed_title" ascending:self.ascending selector:@selector(caseInsensitiveCompare:)]]];
|
|
} else {
|
|
[folder.contents sortUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:key ascending:self.ascending], [NSSortDescriptor sortDescriptorWithKey:@"info.feed_title" ascending:self.ascending selector:@selector(caseInsensitiveCompare:)]]];
|
|
}
|
|
|
|
if (animated) {
|
|
[self enumerateRowsInSection:section usingBlock:^(NSUInteger row, FeedChooserItem *item) {
|
|
NSUInteger newRow = [folder.contents indexOfObject:oldItems[row]];
|
|
|
|
[self.tableView moveRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:section] toIndexPath:[NSIndexPath indexPathForRow:newRow inSection:section]];
|
|
}];
|
|
}
|
|
}];
|
|
|
|
[self.tableView endUpdates];
|
|
|
|
if (!animated) {
|
|
[self.tableView reloadData];
|
|
}
|
|
}
|
|
|
|
- (FeedChooserItem *)itemForIndexPath:(NSIndexPath *)indexPath {
|
|
FeedChooserItem *folder = self.sections[indexPath.section];
|
|
|
|
return folder.contents[indexPath.row];
|
|
}
|
|
|
|
- (NSIndexPath *)indexPathForItem:(FeedChooserItem *)item {
|
|
__block NSIndexPath *indexPath = nil;
|
|
|
|
[self enumerateAllRowsUsingBlock:^(NSIndexPath *localIndexPath, FeedChooserItem *localItem) {
|
|
if ([item.identifierString isEqualToString:localItem.identifierString]) {
|
|
indexPath = localIndexPath;
|
|
}
|
|
}];
|
|
|
|
return indexPath;
|
|
}
|
|
|
|
- (NewsBlurAppDelegate *)appDelegate {
|
|
return [NewsBlurAppDelegate sharedAppDelegate];
|
|
}
|
|
|
|
- (void)enumerateSectionsUsingBlock:(void (^)(NSUInteger section, FeedChooserItem *folder))block {
|
|
if (!block) {
|
|
return;
|
|
}
|
|
|
|
for (NSUInteger section = 0; section < self.sections.count; section++) {
|
|
FeedChooserItem *folder = self.sections[section];
|
|
|
|
block(section, folder);
|
|
}
|
|
}
|
|
|
|
- (void)enumerateRowsInSection:(NSUInteger)section usingBlock:(void (^)(NSUInteger row, FeedChooserItem *item))block {
|
|
if (!block) {
|
|
return;
|
|
}
|
|
|
|
FeedChooserItem *folder = self.sections[section];
|
|
|
|
for (NSUInteger row = 0; row < folder.contents.count; row++) {
|
|
FeedChooserItem *item = folder.contents[row];
|
|
|
|
block(row, item);
|
|
}
|
|
}
|
|
|
|
- (void)enumerateAllRowsUsingBlock:(void (^)(NSIndexPath *indexPath, FeedChooserItem *item))block {
|
|
if (!block) {
|
|
return;
|
|
}
|
|
|
|
[self enumerateSectionsUsingBlock:^(NSUInteger section, FeedChooserItem *folder) {
|
|
[self enumerateRowsInSection:section usingBlock:^(NSUInteger row, FeedChooserItem *item) {
|
|
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
|
|
|
|
block(indexPath, item);
|
|
}];
|
|
}];
|
|
}
|
|
|
|
- (BOOL)isSelectionInSection:(NSUInteger)section {
|
|
NSArray *selection = self.tableView.indexPathsForSelectedRows;
|
|
|
|
for (NSIndexPath *indexPath in selection) {
|
|
if (indexPath.section == section) {
|
|
return YES;
|
|
}
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
- (NSArray *)selectedItemIdentifiers {
|
|
NSMutableArray *identifiers = [NSMutableArray array];
|
|
NSArray *selection = self.tableView.indexPathsForSelectedRows;
|
|
|
|
for (NSIndexPath *indexPath in selection) {
|
|
[identifiers addObject:[self itemForIndexPath:indexPath].identifier];
|
|
}
|
|
|
|
return identifiers;
|
|
}
|
|
|
|
- (void)selectItemsWithIdentifiers:(NSArray *)itemIdentifiers animated:(BOOL)animated {
|
|
[self enumerateAllRowsUsingBlock:^(NSIndexPath *indexPath, FeedChooserItem *item) {
|
|
if ([itemIdentifiers containsObject:item.identifier]) {
|
|
[self.tableView selectRowAtIndexPath:indexPath animated:animated scrollPosition:UITableViewScrollPositionNone];
|
|
} else {
|
|
[self.tableView deselectRowAtIndexPath:indexPath animated:animated];
|
|
}
|
|
}];
|
|
|
|
[self updateControls];
|
|
}
|
|
|
|
- (void)deselectRowsOutsideSection:(NSUInteger)section {
|
|
[self enumerateSectionsUsingBlock:^(NSUInteger thisSection, FeedChooserItem *folder) {
|
|
if (thisSection != section) {
|
|
[self select:NO section:thisSection isSelectAll:NO];
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)select:(BOOL)select section:(NSUInteger)section isSelectAll:(BOOL)isSelectAll {
|
|
if (select && !isSelectAll && self.operation == FeedChooserOperationWidgetSites) {
|
|
[self deselectRowsOutsideSection:section];
|
|
}
|
|
|
|
[self enumerateRowsInSection:section usingBlock:^(NSUInteger row, FeedChooserItem *item) {
|
|
if (select) {
|
|
[self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:section] animated:YES scrollPosition:UITableViewScrollPositionNone];
|
|
} else {
|
|
[self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:section] animated:YES];
|
|
}
|
|
|
|
if (self.operation == FeedChooserOperationWidgetSites) {
|
|
[self setWidgetIncludes:select item:item];
|
|
}
|
|
}];
|
|
|
|
[self updateControls];
|
|
}
|
|
|
|
- (void)updateTitle {
|
|
if (self.operation == FeedChooserOperationMuteSites) {
|
|
NSUInteger count = self.tableView.indexPathsForSelectedRows.count;
|
|
|
|
if (count == 0) {
|
|
self.navigationItem.title = @"Mute Sites";
|
|
} else if (count == 1) {
|
|
self.navigationItem.title = @"Mute 1 Site";
|
|
} else {
|
|
self.navigationItem.title = [NSString stringWithFormat:@"Mute %@ Sites", @(count)];
|
|
}
|
|
} else if (self.operation == FeedChooserOperationOrganizeSites) {
|
|
self.navigationItem.title = @"Organize Sites";
|
|
} else {
|
|
NSUInteger count = self.tableView.indexPathsForSelectedRows.count;
|
|
|
|
if (count == 0) {
|
|
self.navigationItem.title = @"No Widget Sites";
|
|
} else if (count == 1) {
|
|
self.navigationItem.title = @"1 Widget Site";
|
|
} else {
|
|
self.navigationItem.title = [NSString stringWithFormat:@"%@ Widget Sites", @(count)];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)updateControls {
|
|
BOOL hasSelection = self.tableView.indexPathsForSelectedRows.count > 0;
|
|
|
|
self.moveItem.enabled = hasSelection;
|
|
self.deleteItem.enabled = hasSelection;
|
|
|
|
[self updateTitle];
|
|
}
|
|
|
|
- (NSArray *)widgetFeeds {
|
|
NSMutableArray *feeds = [self.groupDefaults objectForKey:@"widget:feeds_array"];
|
|
|
|
if (feeds == nil) {
|
|
feeds = [NSMutableArray array];
|
|
|
|
[self enumerateAllRowsUsingBlock:^(NSIndexPath *indexPath, FeedChooserItem *item) {
|
|
[feeds addObject:[self widgetFeedForItem:item]];
|
|
}];
|
|
|
|
[self.groupDefaults setObject:feeds forKey:@"widget:feeds_array"];
|
|
}
|
|
|
|
return feeds;
|
|
}
|
|
|
|
- (NSDictionary *)widgetFeedForItem:(FeedChooserItem *)item {
|
|
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
|
|
|
dict[@"id"] = item.identifierString;
|
|
dict[@"feed_title"] = item.title;
|
|
|
|
if (item.info[@"favicon_fade"] != [NSNull null]) {
|
|
dict[@"favicon_fade"] = item.info[@"favicon_fade"];
|
|
}
|
|
|
|
if (item.info[@"favicon_color"] != [NSNull null]) {
|
|
dict[@"favicon_color"] = item.info[@"favicon_color"];
|
|
}
|
|
|
|
return dict;
|
|
}
|
|
|
|
- (NSInteger)widgetIndexOfFeed:(NSString *)feedId {
|
|
return [self.widgetFeeds indexOfObjectPassingTest:^BOOL(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
|
return [obj[@"id"] isEqualToString:feedId];
|
|
}];
|
|
}
|
|
|
|
- (void)setWidgetIncludes:(BOOL)include item:(FeedChooserItem *)item {
|
|
NSMutableArray *feeds = [self.widgetFeeds mutableCopy];
|
|
NSInteger feedIndex = [self widgetIndexOfFeed:item.identifierString];
|
|
|
|
if (include) {
|
|
if (feedIndex == NSNotFound) {
|
|
[feeds addObject:[self widgetFeedForItem:item]];
|
|
}
|
|
} else {
|
|
if (feedIndex != NSNotFound) {
|
|
[feeds removeObjectAtIndex:feedIndex];
|
|
}
|
|
}
|
|
|
|
[self.groupDefaults setObject:feeds forKey:@"widget:feeds_array"];
|
|
}
|
|
|
|
- (void)setWidgetIncludes:(BOOL)include itemForIndexPath:(NSIndexPath *)indexPath {
|
|
[self setWidgetIncludes:include item:[self itemForIndexPath:indexPath]];
|
|
}
|
|
|
|
#pragma mark - Title delegate methods
|
|
|
|
- (void)didSelectTitleView:(UIButton *)sender {
|
|
NSUInteger section = sender.tag;
|
|
BOOL select = ![self isSelectionInSection:section];
|
|
|
|
[self enumerateRowsInSection:section usingBlock:^(NSUInteger row, FeedChooserItem *item) {
|
|
[self select:select section:section isSelectAll:NO];
|
|
}];
|
|
|
|
if (self.operation == FeedChooserOperationWidgetSites) {
|
|
FeedChooserItem *folderItem = self.sections[section];
|
|
|
|
[self.groupDefaults setObject:folderItem.identifierString forKey:@"widget:show_folder"];
|
|
}
|
|
}
|
|
|
|
#pragma mark - Target/action methods
|
|
|
|
- (NSString *)sortIconName {
|
|
if (self.ascending) {
|
|
return @"barbutton_sort_asc.png";
|
|
} else {
|
|
return @"barbutton_sort_desc.png";
|
|
}
|
|
}
|
|
|
|
- (void)sort:(FeedChooserSort)sort {
|
|
NSArray *identifiers = [self selectedItemIdentifiers];
|
|
|
|
// Rebuild to get the new info values (which also quietly sorts in the old order), then sort with animation:
|
|
[self rebuildItemsAnimated:NO];
|
|
self.sort = sort;
|
|
[self sortItemsAnimated:YES];
|
|
|
|
[self selectItemsWithIdentifiers:identifiers animated:NO];
|
|
}
|
|
|
|
- (void)showOptionsMenu {
|
|
MenuViewController *viewController = [MenuViewController new];
|
|
BOOL isMute = self.operation == FeedChooserOperationMuteSites;
|
|
|
|
[viewController addTitle:@"Name" iconTemplateName:[self sortIconName] selectionShouldDismiss:YES handler:^{
|
|
[self sort:FeedChooserSortName];
|
|
}];
|
|
|
|
[viewController addTitle:@"Subscribers" iconTemplateName:[self sortIconName] selectionShouldDismiss:YES handler:^{
|
|
[self sort:FeedChooserSortSubscribers];
|
|
}];
|
|
|
|
[viewController addTitle:@"Stories per Month" iconTemplateName:[self sortIconName] selectionShouldDismiss:YES handler:^{
|
|
[self sort:FeedChooserSortFrequency];
|
|
}];
|
|
|
|
[viewController addTitle:@"Most Recent Story" iconTemplateName:[self sortIconName] selectionShouldDismiss:YES handler:^{
|
|
[self sort:FeedChooserSortRecency];
|
|
}];
|
|
|
|
[viewController addTitle:@"Number of Opens" iconTemplateName:[self sortIconName] selectionShouldDismiss:YES handler:^{
|
|
[self sort:FeedChooserSortOpens];
|
|
}];
|
|
|
|
viewController.checkedRow = self.sort;
|
|
|
|
[viewController addSegmentedControlWithTitles:@[@"Ascending", @"Descending"] selectIndex:self.ascending ? 0 : 1 selectionShouldDismiss:YES handler:^(NSUInteger selectedIndex) {
|
|
NSArray *identifiers = [self selectedItemIdentifiers];
|
|
self.ascending = selectedIndex == 0;
|
|
[self sortItemsAnimated:YES];
|
|
[self selectItemsWithIdentifiers:identifiers animated:NO];
|
|
}];
|
|
|
|
[viewController addSegmentedControlWithTitles:@[@"Nested", @"Flat"] selectIndex:self.flat ? 1 : 0 selectionShouldDismiss:YES handler:^(NSUInteger selectedIndex) {
|
|
NSArray *identifiers = [self selectedItemIdentifiers];
|
|
self.flat = selectedIndex == 1;
|
|
[self rebuildItemsAnimated:YES];
|
|
[self selectItemsWithIdentifiers:identifiers animated:NO];
|
|
}];
|
|
|
|
MenuItemHandler selectAllHandler = ^{
|
|
[self enumerateSectionsUsingBlock:^(NSUInteger section, FeedChooserItem *folder) {
|
|
[self select:YES section:section isSelectAll:YES];
|
|
}];
|
|
|
|
if (self.operation == FeedChooserOperationWidgetSites) {
|
|
[self.groupDefaults setObject:@"everything" forKey:@"widget:show_folder"];
|
|
}
|
|
}, selectNoneHandler = ^{
|
|
[self enumerateSectionsUsingBlock:^(NSUInteger section, FeedChooserItem *folder) {
|
|
[self select:NO section:section isSelectAll:NO];
|
|
}];
|
|
|
|
if (self.operation == FeedChooserOperationWidgetSites) {
|
|
[self.groupDefaults setObject:@"everything" forKey:@"widget:show_folder"];
|
|
}
|
|
};
|
|
|
|
if (isMute) {
|
|
[viewController addTitle:@"Mute All" iconName:@"mute_feed_off.png" selectionShouldDismiss:YES handler:selectAllHandler];
|
|
[viewController addTitle:@"Unmute All" iconName:@"mute_feed_on.png" selectionShouldDismiss:YES handler:selectNoneHandler];
|
|
} else {
|
|
[viewController addTitle:@"Select All" iconTemplateName:@"barbutton_selection.png" selectionShouldDismiss:YES handler:selectAllHandler];
|
|
[viewController addTitle:@"Select None" iconTemplateName:@"barbutton_selection_off.png" selectionShouldDismiss:YES handler:selectNoneHandler];
|
|
}
|
|
|
|
[viewController showFromNavigationController:self.navigationController barButtonItem:self.optionsItem];
|
|
}
|
|
|
|
- (void)performMoveToFolder:(FeedChooserItem *)toFolder {
|
|
[MBProgressHUD hideHUDForView:self.view animated:YES];
|
|
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
|
|
HUD.labelText = @"Moving...";
|
|
|
|
NSArray *selection = self.tableView.indexPathsForSelectedRows;
|
|
NSMutableArray *feedsByFolder = [NSMutableArray arrayWithCapacity:selection.count];
|
|
|
|
for (NSIndexPath *indexPath in selection) {
|
|
FeedChooserItem *fromFolder = self.sections[indexPath.section];
|
|
FeedChooserItem *item = fromFolder.contents[indexPath.row];
|
|
|
|
[feedsByFolder addObject:@[item.identifier, fromFolder.identifier]];
|
|
}
|
|
|
|
NSString *urlString = [NSString stringWithFormat:@"%@/reader/move_feeds_by_folder_to_folder", self.appDelegate.url];
|
|
NSMutableDictionary *params = [NSMutableDictionary dictionary];
|
|
[params setObject:feedsByFolder.JSONRepresentation forKey:@"feeds_by_folder"];
|
|
[params setObject:toFolder.identifier forKey:@"to_folder"];
|
|
[appDelegate POST:urlString parameters:params success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
|
|
HUD.labelText = @"Reloading...";
|
|
[self.appDelegate reloadFeedsView:YES];
|
|
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
|
|
[self finishedWithError:error];
|
|
}];
|
|
|
|
}
|
|
|
|
- (void)showMoveMenu {
|
|
MenuViewController *viewController = [MenuViewController new];
|
|
|
|
for (FeedChooserItem *folder in self.folders) {
|
|
NSString *title = folder.title;
|
|
NSString *iconName = @"menu_icn_move.png";
|
|
|
|
if (!title.length) {
|
|
title = @"Top Level";
|
|
iconName = @"menu_icn_all.png";
|
|
} else {
|
|
NSArray *components = [title componentsSeparatedByString:@" ▸ "];
|
|
title = components.lastObject;
|
|
for (NSUInteger idx = 0; idx < components.count; idx++) {
|
|
title = [@"\t" stringByAppendingString:title];
|
|
}
|
|
}
|
|
|
|
[viewController addTitle:title iconName:iconName selectionShouldDismiss:YES handler:^{
|
|
[self performMoveToFolder:folder];
|
|
}];
|
|
}
|
|
|
|
[viewController showFromNavigationController:self.navigationController barButtonItem:self.moveItem];
|
|
}
|
|
|
|
- (void)performDeleteFeeds {
|
|
[MBProgressHUD hideHUDForView:self.view animated:YES];
|
|
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
|
|
HUD.labelText = @"Deleting...";
|
|
|
|
NSArray *selection = self.tableView.indexPathsForSelectedRows;
|
|
NSMutableArray *feedsByFolder = [NSMutableArray arrayWithCapacity:selection.count];
|
|
|
|
for (NSIndexPath *indexPath in selection) {
|
|
FeedChooserItem *fromFolder = self.sections[indexPath.section];
|
|
FeedChooserItem *item = fromFolder.contents[indexPath.row];
|
|
|
|
[feedsByFolder addObject:@[item.identifier, fromFolder.identifier]];
|
|
}
|
|
|
|
NSString *urlString = [NSString stringWithFormat:@"%@/reader/delete_feeds_by_folder", self.appDelegate.url];
|
|
NSMutableDictionary *params = [NSMutableDictionary dictionary];
|
|
[params setObject:feedsByFolder.JSONRepresentation forKey:@"feeds_by_folder"];
|
|
[appDelegate POST:urlString parameters:params success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
|
|
HUD.labelText = @"Reloading...";
|
|
[self.appDelegate reloadFeedsView:YES];
|
|
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
|
|
[self finishedWithError:error];
|
|
}];
|
|
}
|
|
|
|
- (void)deleteFeeds {
|
|
MenuViewController *viewController = [MenuViewController new];
|
|
NSUInteger count = self.tableView.indexPathsForSelectedRows.count;
|
|
NSString *title = count == 1 ? @"Delete selected site?" : [NSString stringWithFormat:@"Delete %@ sites?", @(count)];
|
|
|
|
[viewController addTitle:title iconName:@"menu_icn_delete.png" destructive:YES selectionShouldDismiss:YES handler:^{
|
|
[self performDeleteFeeds];
|
|
}];
|
|
|
|
[viewController showFromNavigationController:self.navigationController barButtonItem:self.deleteItem];
|
|
}
|
|
|
|
- (void)finishedLoadingFeedsNotification:(NSNotification *)note {
|
|
if (self.operation != FeedChooserOperationMuteSites) {
|
|
[self updateDictFolders];
|
|
}
|
|
|
|
[self rebuildItemsAnimated:YES];
|
|
[MBProgressHUD hideHUDForView:self.view animated:YES];
|
|
}
|
|
|
|
- (void)updateDictFolders {
|
|
NSMutableDictionary *folders = [self.appDelegate.dictFolders mutableCopy];
|
|
if ([folders objectForKey:@"everything"]) {
|
|
NSDictionary *everything = folders[@"everything"];
|
|
|
|
[folders removeObjectForKey:@"everything"];
|
|
[folders setObject:everything forKey:@" "];
|
|
}
|
|
|
|
self.dictFolders = folders;
|
|
}
|
|
|
|
- (void)updateSelectedWidgets {
|
|
NSMutableArray *identifiers = [NSMutableArray array];
|
|
|
|
[self enumerateAllRowsUsingBlock:^(NSIndexPath *indexPath, FeedChooserItem *item) {
|
|
if ([self widgetIndexOfFeed:item.identifierString] != NSNotFound) {
|
|
[identifiers addObject:item.identifier];
|
|
}
|
|
}];
|
|
|
|
[self selectItemsWithIdentifiers:identifiers animated:NO];
|
|
}
|
|
|
|
- (void)performSaveActiveFeeds {
|
|
[MBProgressHUD hideHUDForView:self.view animated:YES];
|
|
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
|
|
HUD.labelText = @"Updating...";
|
|
|
|
NSString *urlString = [NSString stringWithFormat:@"%@/reader/save_feed_chooser", self.appDelegate.url];
|
|
NSArray *mutedIndexPaths = self.tableView.indexPathsForSelectedRows;
|
|
NSMutableArray *feeds = [NSMutableArray array];
|
|
NSMutableDictionary *params = [NSMutableDictionary dictionary];
|
|
|
|
[self enumerateAllRowsUsingBlock:^(NSIndexPath *indexPath, FeedChooserItem *item) {
|
|
if (![mutedIndexPaths containsObject:indexPath]) {
|
|
[feeds addObject:item.identifier];
|
|
}
|
|
}];
|
|
|
|
[params setObject:feeds forKey:@"approved_feeds"];
|
|
[appDelegate POST:urlString parameters:params success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
|
|
[self.appDelegate reloadFeedsView:YES];
|
|
[self dismissViewControllerAnimated:YES completion:nil];
|
|
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
|
|
[self finishedWithError:error];
|
|
}];
|
|
}
|
|
|
|
- (BOOL)didChangeActiveFeeds {
|
|
__block BOOL didChange = NO;
|
|
NSArray *inactiveFeedsIdentifiers = self.inactiveFeeds.allKeys;
|
|
NSArray *selectedIndexPaths = self.tableView.indexPathsForSelectedRows;
|
|
|
|
[self enumerateAllRowsUsingBlock:^(NSIndexPath *indexPath, FeedChooserItem *item) {
|
|
BOOL wasInactive = [inactiveFeedsIdentifiers containsObject:item.identifierString];
|
|
BOOL isInactive = [selectedIndexPaths containsObject:indexPath];
|
|
|
|
if (wasInactive != isInactive) {
|
|
didChange = YES;
|
|
}
|
|
}];
|
|
|
|
return didChange;
|
|
}
|
|
|
|
- (void)done {
|
|
if (self.operation == FeedChooserOperationMuteSites && [self didChangeActiveFeeds]) {
|
|
[self performSaveActiveFeeds];
|
|
} else {
|
|
if (self.operation == FeedChooserOperationWidgetSites) {
|
|
[self.appDelegate.storyPagesViewController reloadWidget];
|
|
}
|
|
|
|
[self dismissViewControllerAnimated:YES completion:nil];
|
|
}
|
|
}
|
|
|
|
- (void)cancel {
|
|
[self dismissViewControllerAnimated:YES completion:nil];
|
|
}
|
|
|
|
#pragma mark - Table view data source
|
|
|
|
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
|
if (self.appDelegate.hasNoSites) {
|
|
return 0;
|
|
} else {
|
|
return self.sections.count;
|
|
}
|
|
}
|
|
|
|
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
|
|
FeedChooserItem *item = self.sections[section];
|
|
return item.title;
|
|
}
|
|
|
|
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
|
FeedChooserItem *item = self.sections[section];
|
|
NSArray *contents = item.contents;
|
|
return contents.count;
|
|
}
|
|
|
|
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
|
static NSString *CellIndentifier = @"FeedChooserCell";
|
|
FeedChooserViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIndentifier];
|
|
|
|
if (!cell) {
|
|
cell = [[FeedChooserViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIndentifier];
|
|
}
|
|
|
|
FeedChooserItem *item = [self itemForIndexPath:indexPath];
|
|
|
|
cell.isMuteOperation = self.operation == FeedChooserOperationMuteSites;
|
|
cell.textLabel.text = item.title;
|
|
cell.detailTextLabel.text = [item detailForSort:self.sort];
|
|
cell.isFaded = [[cell.detailTextLabel.text substringToIndex:2] isEqualToString:@"0 "];
|
|
cell.imageView.image = item.icon;
|
|
|
|
if (self.operation == FeedChooserOperationMuteSites) {
|
|
UIImage *image = [UIImage imageNamed:@"mute_feed_on.png"];
|
|
UIImage *highlightedImage = [UIImage imageNamed:@"mute_feed_off.png"];
|
|
UIImageView *imageView = [[UIImageView alloc] initWithImage:image highlightedImage:highlightedImage];
|
|
imageView.highlighted = [tableView.indexPathsForSelectedRows containsObject:indexPath];
|
|
cell.accessoryView = imageView;
|
|
} else {
|
|
cell.accessoryView = nil;
|
|
}
|
|
|
|
return cell;
|
|
}
|
|
|
|
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
|
|
CGRect rect = CGRectMake(0.0, 0.0, tableView.frame.size.width, kFolderTitleHeight);
|
|
FeedChooserTitleView *titleView = [[FeedChooserTitleView alloc] initWithFrame:rect];
|
|
FeedChooserItem *item = self.sections[section];
|
|
|
|
titleView.delegate = self;
|
|
titleView.section = section;
|
|
titleView.title = item.title;
|
|
|
|
return titleView;
|
|
}
|
|
|
|
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
|
|
FeedChooserItem *item = self.sections[section];
|
|
|
|
return !item.title.length ? 0.0 : kFolderTitleHeight;
|
|
}
|
|
|
|
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
|
return kTableViewRowHeight;
|
|
}
|
|
|
|
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)theTableView {
|
|
return self.indexTitles;
|
|
}
|
|
|
|
- (NSInteger)tableView:(UITableView *)theTableView sectionForSectionIndexTitle:(NSString *)indexTitle atIndex:(NSInteger)indexIndex {
|
|
return indexIndex;
|
|
}
|
|
|
|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
|
if (self.operation == FeedChooserOperationWidgetSites) {
|
|
[self deselectRowsOutsideSection:indexPath.section];
|
|
[self setWidgetIncludes:YES itemForIndexPath:indexPath];
|
|
|
|
FeedChooserItem *folderItem = self.sections[indexPath.section];
|
|
|
|
[self.groupDefaults setObject:folderItem.identifierString forKey:@"widget:show_folder"];
|
|
}
|
|
|
|
UIImageView *imageView = (UIImageView *)[tableView cellForRowAtIndexPath:indexPath].accessoryView;
|
|
|
|
imageView.highlighted = YES;
|
|
|
|
[self updateControls];
|
|
}
|
|
|
|
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
|
|
if (self.operation == FeedChooserOperationWidgetSites) {
|
|
[self setWidgetIncludes:NO itemForIndexPath:indexPath];
|
|
}
|
|
|
|
UIImageView *imageView = (UIImageView *)[tableView cellForRowAtIndexPath:indexPath].accessoryView;
|
|
|
|
imageView.highlighted = NO;
|
|
|
|
[self updateControls];
|
|
}
|
|
|
|
@end
|