mirror of
https://github.com/samuelclay/NewsBlur.git
synced 2025-09-18 21:50:56 +00:00
Merge branch 'dejal'
* dejal: (43 commits) Load offline story images even when online to speed up image display. #1875 (borders between panes not using theme colors) #1247 (Mac Catalyst edition) #1874 (Crash on opening widget story) #1247 (Mac Catalyst edition) #1247 (Mac Catalyst edition) #1247 (Mac Catalyst edition) #1247 (Mac Catalyst edition) #1247 (Mac Catalyst edition) #1247 (Mac Catalyst edition) Bumped version number #1247 (Mac Catalyst edition) #1851 (mark as read button at bottom of story list) #1247 (Mac Catalyst edition) #1247 (Mac Catalyst edition) Added privacy manifest #1247 (Mac Catalyst edition) #1247 (Mac Catalyst edition) #1247 (Mac Catalyst edition) #1247 (Mac Catalyst edition) ...
This commit is contained in:
commit
de448e5415
117 changed files with 4845 additions and 948 deletions
|
@ -154,7 +154,7 @@
|
|||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSInteger activitiesCount = [appDelegate.userActivitiesArray count];
|
||||
int minimumHeight;
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!appDelegate.isPhone) {
|
||||
minimumHeight = MINIMUM_ACTIVITY_HEIGHT_IPAD;
|
||||
} else {
|
||||
minimumHeight = MINIMUM_ACTIVITY_HEIGHT_IPHONE;
|
||||
|
@ -165,7 +165,7 @@
|
|||
}
|
||||
|
||||
id activityCell;
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!appDelegate.isPhone) {
|
||||
activityCell = [[ActivityCell alloc] init];
|
||||
} else {
|
||||
activityCell = [[SmallActivityCell alloc] init];
|
||||
|
@ -185,7 +185,7 @@
|
|||
ActivityCell *cell = [tableView
|
||||
dequeueReusableCellWithIdentifier:@"ActivityCell"];
|
||||
if (cell == nil) {
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!appDelegate.isPhone) {
|
||||
cell = [[ActivityCell alloc]
|
||||
initWithStyle:UITableViewCellStyleDefault
|
||||
reuseIdentifier:@"ActivityCell"];
|
||||
|
@ -304,7 +304,7 @@
|
|||
UIImage *img = [UIImage imageNamed:@"fleuron.png"];
|
||||
UIImageView *fleuron = [[UIImageView alloc] initWithImage:img];
|
||||
int height;
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!appDelegate.isPhone) {
|
||||
height = MINIMUM_ACTIVITY_HEIGHT_IPAD;
|
||||
} else {
|
||||
height = MINIMUM_ACTIVITY_HEIGHT_IPHONE;
|
||||
|
|
|
@ -7,15 +7,10 @@
|
|||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "NewsBlurAppDelegate.h"
|
||||
#import "NewsBlur-Swift.h"
|
||||
|
||||
@class NewsBlurAppDelegate;
|
||||
|
||||
@interface AddSiteViewController : BaseViewController
|
||||
<UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource> {
|
||||
NewsBlurAppDelegate *appDelegate;
|
||||
}
|
||||
<UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource>
|
||||
|
||||
- (void)reload;
|
||||
- (IBAction)addSite;
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#import "AddSiteViewController.h"
|
||||
#import "AddSiteAutocompleteCell.h"
|
||||
#import "NewsBlurAppDelegate.h"
|
||||
#import "MenuViewController.h"
|
||||
#import "SBJson4.h"
|
||||
#import "NewsBlur-Swift.h"
|
||||
|
@ -93,7 +92,7 @@
|
|||
|
||||
//- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||
// // Return YES for supported orientations
|
||||
// if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
// if (!self.isPhone) {
|
||||
// return YES;
|
||||
// } else if (UIInterfaceOrientationIsPortrait(interfaceOrientation)) {
|
||||
// return YES;
|
||||
|
@ -130,7 +129,7 @@
|
|||
}
|
||||
|
||||
- (IBAction)doCancelButton {
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!self.isPhone) {
|
||||
[appDelegate hidePopover];
|
||||
} else {
|
||||
[appDelegate hidePopoverAnimated:YES];
|
||||
|
@ -272,7 +271,7 @@
|
|||
[self.errorLabel setText:[responseObject valueForKey:@"message"]];
|
||||
[self.errorLabel setHidden:NO];
|
||||
} else {
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!self.isPhone) {
|
||||
[self->appDelegate hidePopover];
|
||||
} else {
|
||||
[self->appDelegate hidePopoverAnimated:YES];
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
[self.webView loadRequest:requestObj];
|
||||
}];
|
||||
|
||||
if (self.fromStory && [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (self.fromStory && !appDelegate.isPhone) {
|
||||
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc]
|
||||
initWithTitle: @"Cancel"
|
||||
style: UIBarButtonItemStylePlain
|
||||
|
@ -75,6 +75,7 @@
|
|||
}
|
||||
|
||||
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
|
||||
BOOL isPhone = appDelegate.isPhone;
|
||||
NSURLRequest *request = navigationAction.request;
|
||||
NSString *URLString = [[request URL] absoluteString];
|
||||
NSLog(@"URL STRING IS %@", URLString);
|
||||
|
@ -86,7 +87,7 @@
|
|||
|
||||
if (self.fromStory) {
|
||||
[self.appDelegate refreshUserProfile:^{
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!isPhone) {
|
||||
[self.appDelegate.shareNavigationController viewWillAppear:YES];
|
||||
[self.appDelegate.modalNavigationController dismissViewControllerAnimated:YES completion:nil];
|
||||
} else {
|
||||
|
|
70
clients/ios/Classes/AuxSceneDelegate.swift
Normal file
70
clients/ios/Classes/AuxSceneDelegate.swift
Normal file
|
@ -0,0 +1,70 @@
|
|||
//
|
||||
// AuxSceneDelegate.swift
|
||||
// NewsBlur
|
||||
//
|
||||
// Created by David Sinclair on 2024-05-30.
|
||||
// Copyright © 2024 NewsBlur. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
/// Scene delegate for auxiliary windows. Currently only used on macOS.
|
||||
class AuxSceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
let appDelegate: NewsBlurAppDelegate = .shared
|
||||
|
||||
var window: UIWindow?
|
||||
#if targetEnvironment(macCatalyst)
|
||||
var toolbar = NSToolbar(identifier: "aux")
|
||||
var toolbarDelegate = ToolbarDelegate()
|
||||
#endif
|
||||
|
||||
/// Open a new window with an `OriginalStoryViewController` for the given URL.
|
||||
@objc(openWindowForURL:customTitle:) class func openWindow(for url: URL, customTitle: String) {
|
||||
let activity = NSUserActivity(activityType: "aux")
|
||||
|
||||
activity.userInfo = ["url" : url, "title" : customTitle]
|
||||
|
||||
if #available(iOS 17.0, *) {
|
||||
let request = UISceneSessionActivationRequest(userActivity: activity)
|
||||
|
||||
UIApplication.shared.activateSceneSession(for: request) { error in
|
||||
print("Error activating scene: \(error)")
|
||||
}
|
||||
} else {
|
||||
UIApplication.shared.requestSceneSessionActivation(nil, userActivity: activity, options: nil) { error in
|
||||
print("Error activating scene: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
|
||||
#if targetEnvironment(macCatalyst)
|
||||
guard let windowScene = scene as? UIWindowScene, //let titlebar = windowScene.titlebar,
|
||||
let userInfo = connectionOptions.userActivities.first?.userInfo else {
|
||||
return
|
||||
}
|
||||
|
||||
let url = userInfo["url"] as? URL
|
||||
let title = userInfo["title"] as? String
|
||||
|
||||
let controller = OriginalStoryViewController()
|
||||
|
||||
windowScene.title = "Loading…"
|
||||
window?.rootViewController = controller
|
||||
|
||||
appDelegate.activeOriginalStoryURL = url
|
||||
|
||||
controller.customPageTitle = title
|
||||
_ = controller.view
|
||||
controller.loadInitialStory()
|
||||
|
||||
//TODO: 🚧 perhaps make a toolbar for this window
|
||||
// toolbar.delegate = toolbarDelegate
|
||||
// toolbar.displayMode = .iconOnly
|
||||
//
|
||||
// titlebar.toolbar = toolbar
|
||||
// titlebar.toolbarStyle = .automatic
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -1,9 +1,23 @@
|
|||
#import <UIKit/UIKit.h>
|
||||
#import "MBProgressHUD.h"
|
||||
|
||||
@class NewsBlurAppDelegate;
|
||||
|
||||
@interface BaseViewController : UIViewController {
|
||||
NewsBlurAppDelegate *appDelegate;
|
||||
}
|
||||
|
||||
@property (nonatomic) IBOutlet NewsBlurAppDelegate *appDelegate;
|
||||
|
||||
@property (nonatomic, readonly) BOOL isPhone;
|
||||
@property (nonatomic, readonly) BOOL isMac;
|
||||
@property (nonatomic, readonly) BOOL isVision;
|
||||
@property (nonatomic, readonly) BOOL isPortrait;
|
||||
@property (nonatomic, readonly) BOOL isCompactWidth;
|
||||
@property (nonatomic, readonly) BOOL isGrid;
|
||||
@property (nonatomic, readonly) BOOL isFeedShown;
|
||||
@property (nonatomic, readonly) BOOL isStoryShown;
|
||||
|
||||
- (void)informError:(id)error;
|
||||
- (void)informError:(id)error statusCode:(NSInteger)statusCode;
|
||||
- (void)informMessage:(NSString *)message;
|
||||
|
@ -13,6 +27,7 @@
|
|||
- (void)addKeyCommandWithInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)modifierFlags action:(SEL)action discoverabilityTitle:(NSString *)discoverabilityTitle wantPriority:(BOOL)wantPriority;
|
||||
- (void)addCancelKeyCommandWithAction:(SEL)action discoverabilityTitle:(NSString *)discoverabilityTitle;
|
||||
|
||||
- (void)systemAppearanceDidChange:(BOOL)isDark;
|
||||
- (void)updateTheme;
|
||||
|
||||
- (void)tableView:(UITableView *)tableView redisplayCellAtIndexPath:(NSIndexPath *)indexPath;
|
||||
|
@ -25,5 +40,55 @@
|
|||
- (void)collectionView:(UICollectionView *)collectionView selectItemAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(UICollectionViewScrollPosition)scrollPosition;
|
||||
- (void)collectionView:(UICollectionView *)collectionView deselectItemAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated;
|
||||
|
||||
- (IBAction)newSite:(id)sender;
|
||||
- (IBAction)reloadFeeds:(id)sender;
|
||||
- (IBAction)showMuteSites:(id)sender;
|
||||
- (IBAction)showOrganizeSites:(id)sender;
|
||||
- (IBAction)showWidgetSites:(id)sender;
|
||||
- (IBAction)showNotifications:(id)sender;
|
||||
- (IBAction)showFindFriends:(id)sender;
|
||||
- (IBAction)showPremium:(id)sender;
|
||||
- (IBAction)showSupportForum:(id)sender;
|
||||
- (IBAction)showLogout:(id)sender;
|
||||
|
||||
- (IBAction)findInFeeds:(id)sender;
|
||||
- (IBAction)findInFeedDetail:(id)sender;
|
||||
|
||||
- (IBAction)chooseColumns:(id)sender;
|
||||
- (IBAction)chooseLayout:(id)sender;
|
||||
- (IBAction)chooseTitle:(id)sender;
|
||||
- (IBAction)choosePreview:(id)sender;
|
||||
- (IBAction)chooseGridColumns:(id)sender;
|
||||
- (IBAction)chooseGridHeight:(id)sender;
|
||||
- (IBAction)chooseFontSize:(id)sender;
|
||||
- (IBAction)chooseSpacing:(id)sender;
|
||||
- (IBAction)chooseTheme:(id)sender;
|
||||
|
||||
- (IBAction)moveSite:(id)sender;
|
||||
- (IBAction)openRenameSite:(id)sender;
|
||||
- (IBAction)muteSite:(id)sender;
|
||||
- (IBAction)deleteSite:(id)sender;
|
||||
- (IBAction)openTrainSite:(id)sender;
|
||||
- (IBAction)openNotifications:(id)sender;
|
||||
- (IBAction)openStatistics:(id)sender;
|
||||
- (IBAction)instaFetchFeed:(id)sender;
|
||||
- (IBAction)doMarkAllRead:(id)sender;
|
||||
- (IBAction)openMarkReadMenu:(id)sender;
|
||||
- (IBAction)openSettingsMenu:(id)sender;
|
||||
- (IBAction)nextSite:(id)sender;
|
||||
- (IBAction)previousSite:(id)sender;
|
||||
- (IBAction)nextFolder:(id)sender;
|
||||
- (IBAction)previousFolder:(id)sender;
|
||||
- (IBAction)openAllStories:(id)sender;
|
||||
|
||||
- (IBAction)showSendTo:(id)sender;
|
||||
- (IBAction)showTrain:(id)sender;
|
||||
- (IBAction)showShare:(id)sender;
|
||||
- (IBAction)nextUnreadStory:(id)sender;
|
||||
- (IBAction)nextStory:(id)sender;
|
||||
- (IBAction)previousStory:(id)sender;
|
||||
- (IBAction)toggleTextStory:(id)sender;
|
||||
- (IBAction)openInBrowser:(id)sender;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -4,17 +4,33 @@
|
|||
|
||||
@implementation BaseViewController
|
||||
|
||||
@synthesize appDelegate;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark HTTP requests
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
|
||||
self.appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
|
||||
self.appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
|
||||
}
|
||||
|
||||
- (BOOL)becomeFirstResponder {
|
||||
BOOL success = [super becomeFirstResponder];
|
||||
|
||||
NSLog(@"%@ becomeFirstResponder: %@", self, success ? @"yes" : @"no"); // log
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark View methods
|
||||
|
||||
|
@ -37,7 +53,7 @@
|
|||
return [self informError:@"The server barfed!"];
|
||||
} else {
|
||||
errorMessage = [error localizedDescription];
|
||||
if ([error code] == 4 &&
|
||||
if ([error code] == 4 &&
|
||||
[errorMessage rangeOfString:@"cancelled"].location != NSNotFound) {
|
||||
return;
|
||||
}
|
||||
|
@ -45,8 +61,8 @@
|
|||
|
||||
[MBProgressHUD hideHUDForView:self.view animated:YES];
|
||||
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
|
||||
[HUD setCustomView:[[UIImageView alloc]
|
||||
initWithImage:[UIImage imageNamed:@"warning.gif"]]];
|
||||
[HUD setCustomView:[[UIImageView alloc]
|
||||
initWithImage:[UIImage imageNamed:@"warning.gif"]]];
|
||||
[HUD setMode:MBProgressHUDModeCustomView];
|
||||
if (details) {
|
||||
[HUD setDetailsLabelText:details];
|
||||
|
@ -54,19 +70,19 @@
|
|||
HUD.labelText = errorMessage;
|
||||
[HUD hide:YES afterDelay:(details ? 3 : 1)];
|
||||
|
||||
// UIAlertView* alertView = [[UIAlertView alloc]
|
||||
// initWithTitle:@"Error"
|
||||
// message:localizedDescription delegate:nil
|
||||
// cancelButtonTitle:@"OK"
|
||||
// otherButtonTitles:nil];
|
||||
// [alertView show];
|
||||
// [alertView release];
|
||||
// UIAlertView* alertView = [[UIAlertView alloc]
|
||||
// initWithTitle:@"Error"
|
||||
// message:localizedDescription delegate:nil
|
||||
// cancelButtonTitle:@"OK"
|
||||
// otherButtonTitles:nil];
|
||||
// [alertView show];
|
||||
// [alertView release];
|
||||
}
|
||||
|
||||
- (void)informMessage:(NSString *)message {
|
||||
[MBProgressHUD hideHUDForView:self.view animated:YES];
|
||||
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
|
||||
HUD.mode = MBProgressHUDModeText;
|
||||
HUD.mode = MBProgressHUDModeText;
|
||||
HUD.labelText = message;
|
||||
[HUD hide:YES afterDelay:.75];
|
||||
}
|
||||
|
@ -78,8 +94,14 @@
|
|||
[HUD hide:YES afterDelay:2];
|
||||
}
|
||||
|
||||
- (void)systemAppearanceDidChange:(BOOL)isDark {
|
||||
[[ThemeManager themeManager] systemAppearanceDidChange:isDark];
|
||||
}
|
||||
|
||||
- (void)updateTheme {
|
||||
// Subclasses should override this, calling super, to update their nav bar, table, etc
|
||||
|
||||
appDelegate.splitViewController.view.backgroundColor = UIColorFromLightDarkRGB(0x555555, 0x777777);
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView redisplayCellAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
@ -144,7 +166,7 @@
|
|||
#pragma mark UIViewController
|
||||
|
||||
- (void) viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
[super viewDidLoad];
|
||||
|
||||
BOOL isDark = [NewsBlurAppDelegate sharedAppDelegate].window.windowScene.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark;
|
||||
|
||||
|
@ -166,7 +188,7 @@
|
|||
|
||||
BOOL isDark = [NewsBlurAppDelegate sharedAppDelegate].window.windowScene.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark;
|
||||
|
||||
[[ThemeManager themeManager] systemAppearanceDidChange:isDark];
|
||||
[self systemAppearanceDidChange:isDark];
|
||||
}
|
||||
|
||||
- (UIStatusBarStyle)preferredStatusBarStyle {
|
||||
|
@ -177,4 +199,463 @@
|
|||
return UIStatusBarStyleLightContent;
|
||||
}
|
||||
|
||||
- (BOOL)isPhone {
|
||||
return [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone;
|
||||
}
|
||||
|
||||
- (BOOL)isMac {
|
||||
return [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomMac;
|
||||
}
|
||||
|
||||
- (BOOL)isVision {
|
||||
if (@available(iOS 17.0, *)) {
|
||||
return [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomVision;
|
||||
} else {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isPortrait {
|
||||
UIWindow *window = [NewsBlurAppDelegate sharedAppDelegate].window;
|
||||
UIInterfaceOrientation orientation = window.windowScene.interfaceOrientation;
|
||||
if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) {
|
||||
return YES;
|
||||
} else {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isCompactWidth {
|
||||
UIWindow *window = [NewsBlurAppDelegate sharedAppDelegate].window;
|
||||
UITraitCollection *traits = window.windowScene.traitCollection;
|
||||
|
||||
return traits.horizontalSizeClass == UIUserInterfaceSizeClassCompact;
|
||||
//return self.compactWidth > 0.0;
|
||||
}
|
||||
|
||||
- (BOOL)isGrid {
|
||||
return self.appDelegate.detailViewController.storyTitlesInGrid;
|
||||
}
|
||||
|
||||
- (BOOL)isFeedShown {
|
||||
return appDelegate.storiesCollection.activeFeed != nil || appDelegate.storiesCollection.activeFolder != nil;
|
||||
}
|
||||
|
||||
- (BOOL)isStoryShown {
|
||||
return !appDelegate.storyPagesViewController.currentPage.view.isHidden && appDelegate.storyPagesViewController.currentPage.noStoryMessage.isHidden;
|
||||
}
|
||||
|
||||
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
|
||||
if (action == @selector(chooseLayout:) || action == @selector(findInFeedDetail:)) {
|
||||
return self.isFeedShown;
|
||||
} else if (action == @selector(chooseTitle:) || action == @selector(choosePreview:)) {
|
||||
return self.isFeedShown && !self.isGrid;
|
||||
} else if (action == @selector(chooseGridColumns:) || action == @selector(chooseGridHeight:)) {
|
||||
return self.isFeedShown && self.isGrid;
|
||||
} else if (action == @selector(openTrainSite) ||
|
||||
action == @selector(openTrainSite:) ||
|
||||
action == @selector(openNotifications:) ||
|
||||
action == @selector(openStatistics:) ||
|
||||
action == @selector(moveSite:) ||
|
||||
action == @selector(openRenameSite:) ||
|
||||
action == @selector(deleteSite:)) {
|
||||
return self.isFeedShown && appDelegate.storiesCollection.isCustomFolderOrFeed;
|
||||
} else if (action == @selector(muteSite) ||
|
||||
action == @selector(muteSite:)) {
|
||||
return self.isFeedShown && !appDelegate.storiesCollection.isRiverView;
|
||||
} else if (action == @selector(instaFetchFeed:) ||
|
||||
action == @selector(doMarkAllRead:)) {
|
||||
return self.isFeedShown;
|
||||
} else if (action == @selector(showSendTo:) ||
|
||||
action == @selector(showTrain:) ||
|
||||
action == @selector(showShare:) ||
|
||||
action == @selector(nextUnreadStory:) ||
|
||||
action == @selector(nextStory:) ||
|
||||
action == @selector(previousStory:) ||
|
||||
action == @selector(toggleTextStory:) ||
|
||||
action == @selector(openInBrowser:)) {
|
||||
return self.isStoryShown;
|
||||
} else {
|
||||
return [super canPerformAction:action withSender:sender];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)validateCommand:(UICommand *)command {
|
||||
[super validateCommand:command];
|
||||
|
||||
if (command.action == @selector(chooseColumns:)) {
|
||||
command.state = [command.propertyList isEqualToString:appDelegate.detailViewController.behaviorString];
|
||||
} else if (command.action == @selector(chooseLayout:)) {
|
||||
NSString *value = self.appDelegate.storiesCollection.activeStoryTitlesPosition;
|
||||
command.state = [command.propertyList isEqualToString:value];
|
||||
} else if (command.action == @selector(chooseIntelligence:)) {
|
||||
NSInteger intelligence = [[NSUserDefaults standardUserDefaults] integerForKey:@"selectedIntelligence"];
|
||||
NSString *value = [NSString stringWithFormat:@"%@", @(intelligence + 1)];
|
||||
command.state = [command.propertyList isEqualToString:value];
|
||||
} else if (command.action == @selector(toggleSidebar:)) {
|
||||
UISplitViewController *splitViewController = self.appDelegate.splitViewController;
|
||||
if (splitViewController.preferredDisplayMode != UISplitViewControllerDisplayModeTwoBesideSecondary) {
|
||||
command.title = @"Show Sidebar";
|
||||
} else {
|
||||
command.title = @"Hide Sidebar";
|
||||
}
|
||||
} else if (command.action == @selector(chooseTitle:)) {
|
||||
NSString *value = [[NSUserDefaults standardUserDefaults] objectForKey:@"story_list_preview_text_size"];
|
||||
command.state = [command.propertyList isEqualToString:value];
|
||||
} else if (command.action == @selector(choosePreview:)) {
|
||||
NSString *value = [[NSUserDefaults standardUserDefaults] objectForKey:@"story_list_preview_images_size"];
|
||||
command.state = [command.propertyList isEqualToString:value];
|
||||
} else if (command.action == @selector(chooseGridColumns:)) {
|
||||
NSString *value = [[NSUserDefaults standardUserDefaults] objectForKey:@"grid_columns"];
|
||||
if (value == nil) {
|
||||
value = @"auto";
|
||||
}
|
||||
command.state = [command.propertyList isEqualToString:value];
|
||||
} else if (command.action == @selector(chooseGridHeight:)) {
|
||||
NSString *value = [[NSUserDefaults standardUserDefaults] objectForKey:@"grid_height"];
|
||||
if (value == nil) {
|
||||
value = @"medium";
|
||||
}
|
||||
command.state = [command.propertyList isEqualToString:value];
|
||||
} else if (command.action == @selector(chooseFontSize:)) {
|
||||
NSString *value = [[NSUserDefaults standardUserDefaults] objectForKey:@"feed_list_font_size"];
|
||||
command.state = [command.propertyList isEqualToString:value];
|
||||
} else if (command.action == @selector(chooseSpacing:)) {
|
||||
NSString *value = [[NSUserDefaults standardUserDefaults] objectForKey:@"feed_list_spacing"];
|
||||
command.state = [command.propertyList isEqualToString:value];
|
||||
} else if (command.action == @selector(chooseTheme:)) {
|
||||
command.state = [command.propertyList isEqualToString:ThemeManager.themeManager.theme];
|
||||
} else if (command.action == @selector(openRenameSite:)) {
|
||||
if (appDelegate.storiesCollection.isRiverOrSocial) {
|
||||
command.title = @"Rename Folder…";
|
||||
} else {
|
||||
command.title = @"Rename Site…";
|
||||
}
|
||||
} else if (command.action == @selector(deleteSite:)) {
|
||||
if (appDelegate.storiesCollection.isRiverOrSocial) {
|
||||
command.title = @"Delete Folder…";
|
||||
} else {
|
||||
command.title = @"Delete Site…";
|
||||
}
|
||||
} else if (command.action == @selector(toggleStorySaved:)) {
|
||||
BOOL isRead = [[self.appDelegate.activeStory objectForKey:@"starred"] boolValue];
|
||||
if (isRead) {
|
||||
command.title = @"Unsave This Story";
|
||||
} else {
|
||||
command.title = @"Save This Story";
|
||||
}
|
||||
} else if (command.action == @selector(toggleStoryUnread:)) {
|
||||
BOOL isRead = [[self.appDelegate.activeStory objectForKey:@"read_status"] boolValue];
|
||||
if (isRead) {
|
||||
command.title = @"Mark as Unread";
|
||||
} else {
|
||||
command.title = @"Mark as Read";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark File menu
|
||||
|
||||
- (IBAction)newSite:(id)sender {
|
||||
[appDelegate.feedsViewController tapAddSite:nil];
|
||||
}
|
||||
|
||||
- (IBAction)reloadFeeds:(id)sender {
|
||||
[appDelegate reloadFeedsView:NO];
|
||||
}
|
||||
|
||||
- (IBAction)showMuteSites:(id)sender {
|
||||
[self.appDelegate showMuteSites];
|
||||
}
|
||||
|
||||
- (IBAction)showOrganizeSites:(id)sender {
|
||||
[self.appDelegate showOrganizeSites];
|
||||
}
|
||||
|
||||
- (IBAction)showWidgetSites:(id)sender {
|
||||
[self.appDelegate showWidgetSites];
|
||||
}
|
||||
|
||||
- (IBAction)showNotifications:(id)sender {
|
||||
[self.appDelegate openNotificationsWithFeed:nil];
|
||||
}
|
||||
|
||||
- (IBAction)showFindFriends:(id)sender {
|
||||
[self.appDelegate showFindFriends];
|
||||
}
|
||||
|
||||
- (IBAction)showPremium:(id)sender {
|
||||
[self.appDelegate showPremiumDialog];
|
||||
}
|
||||
|
||||
- (IBAction)showSupportForum:(id)sender {
|
||||
NSURL *url = [NSURL URLWithString:@"https://forum.newsblur.com"];
|
||||
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
|
||||
}
|
||||
|
||||
- (IBAction)showLogout:(id)sender {
|
||||
[self.appDelegate confirmLogout];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Edit menu
|
||||
|
||||
- (IBAction)findInFeeds:(id)sender {
|
||||
[self.appDelegate showColumn:UISplitViewControllerColumnPrimary debugInfo:@"findInFeeds"];
|
||||
[self.appDelegate.feedsViewController.searchBar becomeFirstResponder];
|
||||
}
|
||||
|
||||
- (IBAction)findInFeedDetail:(id)sender {
|
||||
[self.appDelegate showColumn:UISplitViewControllerColumnSupplementary debugInfo:@"findInFeedDetail"];
|
||||
[self.appDelegate.feedDetailViewController.searchBar becomeFirstResponder];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark View menu
|
||||
|
||||
- (IBAction)chooseColumns:(id)sender {
|
||||
UICommand *command = sender;
|
||||
NSString *string = command.propertyList;
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setObject:string forKey:@"split_behavior"];
|
||||
|
||||
[UIView animateWithDuration:0.5 animations:^{
|
||||
[self.appDelegate updateSplitBehavior:YES];
|
||||
}];
|
||||
|
||||
[self.appDelegate.detailViewController updateLayoutWithReload:NO fetchFeeds:YES];
|
||||
}
|
||||
|
||||
- (IBAction)chooseLayout:(id)sender {
|
||||
UICommand *command = sender;
|
||||
NSString *string = command.propertyList;
|
||||
NSString *key = self.appDelegate.storiesCollection.storyTitlesPositionKey;
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setObject:string forKey:key];
|
||||
|
||||
[self.appDelegate.detailViewController updateLayoutWithReload:YES fetchFeeds:YES];
|
||||
}
|
||||
|
||||
- (IBAction)chooseIntelligence:(id)sender {
|
||||
UICommand *command = sender;
|
||||
NSInteger index = [command.propertyList integerValue];
|
||||
|
||||
[self.appDelegate.feedsViewController.intelligenceControl setSelectedSegmentIndex:index];
|
||||
[self.appDelegate.feedsViewController selectIntelligence];
|
||||
}
|
||||
|
||||
- (IBAction)chooseTitle:(id)sender {
|
||||
UICommand *command = sender;
|
||||
NSString *string = command.propertyList;
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setObject:string forKey:@"story_list_preview_text_size"];
|
||||
|
||||
[self.appDelegate resizePreviewSize];
|
||||
}
|
||||
|
||||
- (IBAction)choosePreview:(id)sender {
|
||||
UICommand *command = sender;
|
||||
NSString *string = command.propertyList;
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setObject:string forKey:@"story_list_preview_images_size"];
|
||||
|
||||
[self.appDelegate resizePreviewSize];
|
||||
}
|
||||
|
||||
- (IBAction)chooseGridColumns:(id)sender {
|
||||
UICommand *command = sender;
|
||||
NSString *string = command.propertyList;
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setObject:string forKey:@"grid_columns"];
|
||||
|
||||
[self.appDelegate.detailViewController updateLayoutWithReload:YES fetchFeeds:YES];
|
||||
}
|
||||
|
||||
- (IBAction)chooseGridHeight:(id)sender {
|
||||
UICommand *command = sender;
|
||||
NSString *string = command.propertyList;
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setObject:string forKey:@"grid_height"];
|
||||
|
||||
[self.appDelegate.detailViewController updateLayoutWithReload:YES fetchFeeds:YES];
|
||||
}
|
||||
|
||||
- (IBAction)chooseFontSize:(id)sender {
|
||||
UICommand *command = sender;
|
||||
NSString *string = command.propertyList;
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setObject:string forKey:@"feed_list_font_size"];
|
||||
|
||||
[self.appDelegate resizeFontSize];
|
||||
}
|
||||
|
||||
- (IBAction)chooseSpacing:(id)sender {
|
||||
UICommand *command = sender;
|
||||
NSString *string = command.propertyList;
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setObject:string forKey:@"feed_list_spacing"];
|
||||
|
||||
[self.appDelegate.feedsViewController reloadFeedTitlesTable];
|
||||
[self.appDelegate.feedDetailViewController reloadWithSizing];
|
||||
}
|
||||
|
||||
- (IBAction)chooseTheme:(id)sender {
|
||||
UICommand *command = sender;
|
||||
NSString *string = command.propertyList;
|
||||
|
||||
[ThemeManager themeManager].theme = string;
|
||||
}
|
||||
|
||||
- (IBAction)toggleSidebar:(id)sender{
|
||||
UISplitViewController *splitViewController = self.appDelegate.splitViewController;
|
||||
|
||||
[UIView animateWithDuration:0.2 animations:^{
|
||||
NSLog(@"toggleSidebar: displayMode: %@; preferredDisplayMode: %@; UISplitViewControllerDisplayModeSecondaryOnly: %@; UISplitViewControllerDisplayModeTwoBesideSecondary: %@, UISplitViewControllerDisplayModeOneBesideSecondary: %@; ", @(splitViewController.displayMode), @(splitViewController.preferredDisplayMode), @(UISplitViewControllerDisplayModeSecondaryOnly), @(UISplitViewControllerDisplayModeTwoBesideSecondary), @(UISplitViewControllerDisplayModeOneBesideSecondary)); // log
|
||||
|
||||
if (splitViewController.splitBehavior == UISplitViewControllerSplitBehaviorOverlay) {
|
||||
splitViewController.preferredDisplayMode = (splitViewController.displayMode != UISplitViewControllerDisplayModeTwoOverSecondary ? UISplitViewControllerDisplayModeTwoOverSecondary : UISplitViewControllerDisplayModeOneOverSecondary);
|
||||
} else if (splitViewController.splitBehavior == UISplitViewControllerSplitBehaviorDisplace) {
|
||||
if (splitViewController.preferredDisplayMode == UISplitViewControllerDisplayModeTwoDisplaceSecondary &&
|
||||
splitViewController.displayMode == UISplitViewControllerDisplayModeSecondaryOnly) {
|
||||
splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeOneBesideSecondary;
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^(void) {
|
||||
splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeTwoDisplaceSecondary;
|
||||
});
|
||||
} else {
|
||||
splitViewController.preferredDisplayMode = (splitViewController.displayMode != UISplitViewControllerDisplayModeTwoDisplaceSecondary ? UISplitViewControllerDisplayModeTwoDisplaceSecondary : UISplitViewControllerDisplayModeOneBesideSecondary);
|
||||
}
|
||||
} else {
|
||||
if (splitViewController.preferredDisplayMode == UISplitViewControllerDisplayModeTwoBesideSecondary &&
|
||||
splitViewController.displayMode == UISplitViewControllerDisplayModeSecondaryOnly) {
|
||||
splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeOneBesideSecondary;
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^(void) {
|
||||
splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeTwoBesideSecondary;
|
||||
});
|
||||
} else {
|
||||
splitViewController.preferredDisplayMode = (splitViewController.displayMode != UISplitViewControllerDisplayModeTwoBesideSecondary ? UISplitViewControllerDisplayModeTwoBesideSecondary : UISplitViewControllerDisplayModeOneBesideSecondary);
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Site menu
|
||||
|
||||
- (IBAction)moveSite:(id)sender {
|
||||
[self.appDelegate.feedDetailViewController openMoveView:self.appDelegate.navigationController];
|
||||
}
|
||||
|
||||
- (IBAction)openRenameSite:(id)sender {
|
||||
[self.appDelegate.feedDetailViewController openRenameSite];
|
||||
}
|
||||
|
||||
- (IBAction)muteSite:(id)sender {
|
||||
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"Are you sure you wish to mute %@?", self.appDelegate.storiesCollection.activeTitle] message:nil preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alertController addAction:[UIAlertAction actionWithTitle: @"Mute Site" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) {
|
||||
[alertController dismissViewControllerAnimated:YES completion:nil];
|
||||
[self.appDelegate.feedDetailViewController muteSite];
|
||||
}]];
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel"
|
||||
style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self presentViewController:alertController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (IBAction)deleteSite:(id)sender {
|
||||
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"Are you sure you wish to delete %@?", self.appDelegate.storiesCollection.activeTitle] message:nil preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alertController addAction:[UIAlertAction actionWithTitle: @"Delete Site" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) {
|
||||
[alertController dismissViewControllerAnimated:YES completion:nil];
|
||||
[self.appDelegate.feedDetailViewController deleteSite];
|
||||
}]];
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel"
|
||||
style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self presentViewController:alertController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (IBAction)openTrainSite:(id)sender {
|
||||
[self.appDelegate.feedDetailViewController openTrainSite];
|
||||
}
|
||||
|
||||
- (IBAction)openNotifications:(id)sender {
|
||||
[self.appDelegate.feedDetailViewController openNotifications:sender];
|
||||
}
|
||||
|
||||
- (IBAction)openStatistics:(id)sender {
|
||||
[self.appDelegate.feedDetailViewController openStatistics:sender];
|
||||
}
|
||||
|
||||
- (IBAction)instaFetchFeed:(id)sender {
|
||||
[self.appDelegate.feedDetailViewController instafetchFeed];
|
||||
}
|
||||
|
||||
- (IBAction)doMarkAllRead:(id)sender {
|
||||
[self.appDelegate.feedDetailViewController doMarkAllRead:sender];
|
||||
}
|
||||
|
||||
// These two are needed for the toolbar in Grid view.
|
||||
- (IBAction)openMarkReadMenu:(id)sender {
|
||||
[self.appDelegate.feedDetailViewController doOpenMarkReadMenu:sender];
|
||||
}
|
||||
|
||||
- (IBAction)openSettingsMenu:(id)sender {
|
||||
[self.appDelegate.feedDetailViewController doOpenSettingsMenu:sender];
|
||||
}
|
||||
|
||||
- (IBAction)nextSite:(id)sender {
|
||||
[self.appDelegate.feedsViewController selectNextFeed:sender];
|
||||
}
|
||||
|
||||
- (IBAction)previousSite:(id)sender {
|
||||
[self.appDelegate.feedsViewController selectPreviousFeed:sender];
|
||||
}
|
||||
|
||||
- (IBAction)nextFolder:(id)sender {
|
||||
[self.appDelegate.feedsViewController selectNextFolder:sender];
|
||||
}
|
||||
|
||||
- (IBAction)previousFolder:(id)sender {
|
||||
[self.appDelegate.feedsViewController selectPreviousFolder:sender];
|
||||
}
|
||||
|
||||
- (IBAction)openAllStories:(id)sender {
|
||||
[self.appDelegate.feedsViewController selectEverything:sender];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Story menu
|
||||
|
||||
- (IBAction)showSendTo:(id)sender {
|
||||
[appDelegate showSendTo:self sender:sender];
|
||||
}
|
||||
|
||||
- (IBAction)showTrain:(id)sender {
|
||||
[self.appDelegate openTrainStory:self.appDelegate.storyPagesViewController.fontSettingsButton];
|
||||
}
|
||||
|
||||
- (IBAction)showShare:(id)sender {
|
||||
[self.appDelegate.storyPagesViewController.currentPage openShareDialog];
|
||||
}
|
||||
|
||||
- (IBAction)nextUnreadStory:(id)sender {
|
||||
[self.appDelegate.storyPagesViewController doNextUnreadStory:sender];
|
||||
}
|
||||
|
||||
- (IBAction)nextStory:(id)sender {
|
||||
[self.appDelegate.storyPagesViewController changeToNextPage:sender];
|
||||
}
|
||||
|
||||
- (IBAction)previousStory:(id)sender {
|
||||
[self.appDelegate.storyPagesViewController changeToPreviousPage:sender];
|
||||
}
|
||||
|
||||
- (IBAction)toggleTextStory:(id)sender {
|
||||
[self.appDelegate.storyPagesViewController toggleTextView:sender];
|
||||
}
|
||||
|
||||
- (IBAction)openInBrowser:(id)sender {
|
||||
[self.appDelegate.storyPagesViewController showOriginalSubview:sender];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -10,11 +10,6 @@ import UIKit
|
|||
|
||||
/// Manages the detail column of the split view, with the feed detail and/or the story pages.
|
||||
class DetailViewController: BaseViewController {
|
||||
/// Returns the shared app delegate.
|
||||
var appDelegate: NewsBlurAppDelegate {
|
||||
return NewsBlurAppDelegate.shared()
|
||||
}
|
||||
|
||||
/// Preference keys.
|
||||
enum Key {
|
||||
/// Style of the feed detail list layout.
|
||||
|
@ -28,6 +23,9 @@ class DetailViewController: BaseViewController {
|
|||
|
||||
/// Position of the divider between the views when in vertical orientation. Only used for `.top` and `.bottom` layouts.
|
||||
static let verticalPosition = "story_titles_divider_vertical"
|
||||
|
||||
/// Width of the feeds view, i.e. the primary split column.
|
||||
static let feedsWidth = "split_primary_width"
|
||||
}
|
||||
|
||||
/// Preference values.
|
||||
|
@ -173,7 +171,7 @@ class DetailViewController: BaseViewController {
|
|||
|
||||
/// How the split controller behaves.
|
||||
var behavior: Behavior {
|
||||
switch UserDefaults.standard.string(forKey: Key.behavior) {
|
||||
switch behaviorString {
|
||||
case BehaviorValue.tile:
|
||||
return .tile
|
||||
case BehaviorValue.displace:
|
||||
|
@ -185,20 +183,15 @@ class DetailViewController: BaseViewController {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the device is an iPhone, otherwise `false`.
|
||||
@objc var isPhone: Bool {
|
||||
return UIDevice.current.userInterfaceIdiom == .phone
|
||||
}
|
||||
|
||||
/// Returns `true` if the window is in portrait orientation, otherwise `false`.
|
||||
@objc var isPortraitOrientation: Bool {
|
||||
return view.window?.windowScene?.interfaceOrientation.isPortrait ?? false
|
||||
/// The split controller behavior as a raw string.
|
||||
@objc var behaviorString: String {
|
||||
return UserDefaults.standard.string(forKey: Key.behavior) ?? BehaviorValue.auto
|
||||
}
|
||||
|
||||
/// Position of the divider between the views.
|
||||
var dividerPosition: CGFloat {
|
||||
get {
|
||||
let key = isPortraitOrientation ? Key.verticalPosition : Key.horizontalPosition
|
||||
let key = isPortrait ? Key.verticalPosition : Key.horizontalPosition
|
||||
let value = CGFloat(UserDefaults.standard.float(forKey: key))
|
||||
|
||||
if value == 0 {
|
||||
|
@ -212,12 +205,32 @@ class DetailViewController: BaseViewController {
|
|||
return
|
||||
}
|
||||
|
||||
let key = isPortraitOrientation ? Key.verticalPosition : Key.horizontalPosition
|
||||
let key = isPortrait ? Key.verticalPosition : Key.horizontalPosition
|
||||
|
||||
UserDefaults.standard.set(Float(newValue), forKey: key)
|
||||
}
|
||||
}
|
||||
|
||||
/// Width of the feeds view, i.e. the primary split column.
|
||||
var feedsWidth: CGFloat {
|
||||
get {
|
||||
let value = CGFloat(UserDefaults.standard.float(forKey: Key.feedsWidth))
|
||||
|
||||
if value == 0 {
|
||||
return 320
|
||||
} else {
|
||||
return value
|
||||
}
|
||||
}
|
||||
set {
|
||||
guard newValue != feedsWidth else {
|
||||
return
|
||||
}
|
||||
|
||||
UserDefaults.standard.set(Float(newValue), forKey: Key.feedsWidth)
|
||||
}
|
||||
}
|
||||
|
||||
/// Top container view.
|
||||
@IBOutlet weak var topContainerView: UIView!
|
||||
|
||||
|
@ -395,6 +408,16 @@ class DetailViewController: BaseViewController {
|
|||
}
|
||||
}
|
||||
|
||||
override func viewDidLayoutSubviews() {
|
||||
super.viewDidLayoutSubviews()
|
||||
|
||||
let width = splitViewController?.primaryColumnWidth ?? 320
|
||||
|
||||
if width != feedsWidth {
|
||||
feedsWidth = width
|
||||
}
|
||||
}
|
||||
|
||||
private func adjustTopConstraint() {
|
||||
guard let scene = view.window?.windowScene else {
|
||||
return
|
||||
|
@ -453,6 +476,13 @@ private extension DetailViewController {
|
|||
func checkViewControllers() {
|
||||
let isTop = layout == .top
|
||||
|
||||
#if targetEnvironment(macCatalyst)
|
||||
splitViewController?.primaryBackgroundStyle = .sidebar
|
||||
splitViewController?.minimumPrimaryColumnWidth = 250
|
||||
splitViewController?.maximumPrimaryColumnWidth = 700
|
||||
splitViewController?.preferredPrimaryColumnWidth = feedsWidth
|
||||
#endif
|
||||
|
||||
if layout != .grid || isPhone {
|
||||
storyPagesViewController = listStoryPagesViewController
|
||||
_ = storyPagesViewController?.view
|
||||
|
|
212
clients/ios/Classes/Feed.swift
Normal file
212
clients/ios/Classes/Feed.swift
Normal file
|
@ -0,0 +1,212 @@
|
|||
//
|
||||
// Feed.swift
|
||||
// NewsBlur
|
||||
//
|
||||
// Created by David Sinclair on 2024-04-04.
|
||||
// Copyright © 2024 NewsBlur. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// The Feed, Story, and StoryCache classes could be quite useful going forward; Rather than calling getStory() to get the dictionary, could have a variation that returns a Story instance. Could fetch from the cache if available, or make and cache one from the dictionary. Would need to remove it from the cache when changing anything about a story. Could perhaps make the cache part of StoriesCollection.
|
||||
|
||||
/// A dictionary with the most broad key and value types, common in ObjC code.
|
||||
typealias AnyDictionary = [AnyHashable : Any]
|
||||
|
||||
/// A feed, wrapping the dictionary representation.
|
||||
class Feed: Identifiable {
|
||||
let id: String
|
||||
var name = "<deleted>"
|
||||
var subscribers = 0
|
||||
|
||||
var dictionary = AnyDictionary()
|
||||
|
||||
var isRiverOrSocial = false
|
||||
|
||||
var colorBarLeft: UIColor?
|
||||
var colorBarRight: UIColor?
|
||||
|
||||
lazy var image: UIImage? = {
|
||||
guard let appDelegate = NewsBlurAppDelegate.shared else {
|
||||
return nil
|
||||
}
|
||||
|
||||
if let image = appDelegate.getFavicon(id) {
|
||||
return Utilities.roundCorneredImage(image, radius: 4, convertTo: CGSizeMake(16, 16))
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}()
|
||||
|
||||
var classifiers: AnyDictionary? {
|
||||
guard let appDelegate = NewsBlurAppDelegate.shared else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return appDelegate.storiesCollection.activeClassifiers[id] as? AnyDictionary
|
||||
}
|
||||
|
||||
func classifiers(for kind: String) -> AnyDictionary? {
|
||||
return classifiers?[kind] as? AnyDictionary
|
||||
}
|
||||
|
||||
enum Score: Int {
|
||||
case none = 0
|
||||
case like = 1
|
||||
case dislike = -1
|
||||
|
||||
var imageName: String {
|
||||
switch self {
|
||||
case .none:
|
||||
return "hand.thumbsup"
|
||||
case .like:
|
||||
return "hand.thumbsup.fill"
|
||||
case .dislike:
|
||||
return "hand.thumbsdown.fill"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Training: Identifiable {
|
||||
let name: String
|
||||
let count: Int
|
||||
let score: Score
|
||||
|
||||
var id: String {
|
||||
return name
|
||||
}
|
||||
}
|
||||
|
||||
lazy var titles: [Training] = {
|
||||
guard let appDelegate = NewsBlurAppDelegate.shared,
|
||||
let classifierTitles = self.classifiers(for: "titles") else {
|
||||
return []
|
||||
}
|
||||
|
||||
let userTitles = classifierTitles.map { Training(name: $0.key as! String, count: 0, score: Score(rawValue: $0.value as? Int ?? 0) ?? .none) }
|
||||
|
||||
return userTitles.sorted()
|
||||
}()
|
||||
|
||||
lazy var authors: [Training] = {
|
||||
guard let appDelegate = NewsBlurAppDelegate.shared,
|
||||
let classifierAuthors = self.classifiers(for: "authors"),
|
||||
let activeAuthors = appDelegate.storiesCollection.activePopularAuthors as? [[AnyHashable]] else {
|
||||
return []
|
||||
}
|
||||
|
||||
var userAuthors = [Training]()
|
||||
|
||||
for (someName, someScore) in classifierAuthors {
|
||||
if let name = someName as? String, let score = someScore as? Int, !activeAuthors.contains(where: { $0[0] == someName }) {
|
||||
userAuthors.append(Training(name: name, count: 0, score: Score(rawValue: score) ?? .none))
|
||||
}
|
||||
}
|
||||
|
||||
let otherAuthors: [Training] = activeAuthors.map { Training(name: $0[0] as! String, count: $0[1] as! Int, score: Score(rawValue: classifierAuthors[$0[0] as! String] as? Int ?? 0) ?? .none) }
|
||||
|
||||
return userAuthors.sorted() + otherAuthors
|
||||
}()
|
||||
|
||||
lazy var tags: [Training] = {
|
||||
guard let appDelegate = NewsBlurAppDelegate.shared,
|
||||
let classifierTags = self.classifiers(for: "tags"),
|
||||
let activeTags = appDelegate.storiesCollection.activePopularTags as? [[AnyHashable]] else {
|
||||
return []
|
||||
}
|
||||
|
||||
var userTags = [Training]()
|
||||
|
||||
for (someName, someScore) in classifierTags {
|
||||
if let name = someName as? String, let score = someScore as? Int, !activeTags.contains(where: { $0[0] == someName }) {
|
||||
userTags.append(Training(name: name, count: 0, score: Score(rawValue: score) ?? .none))
|
||||
}
|
||||
}
|
||||
|
||||
let otherTags: [Training] = activeTags.map { Training(name: $0[0] as! String, count: $0[1] as! Int, score: Score(rawValue: classifierTags[$0[0] as! String] as? Int ?? 0) ?? .none) }
|
||||
|
||||
return userTags.sorted() + otherTags
|
||||
}()
|
||||
|
||||
init(id: String) {
|
||||
self.id = id
|
||||
|
||||
guard let appDelegate = NewsBlurAppDelegate.shared else {
|
||||
return
|
||||
}
|
||||
|
||||
var feed: [String : Any]? = appDelegate.dictActiveFeeds[id] as? [String : Any]
|
||||
|
||||
if feed == nil {
|
||||
feed = appDelegate.dictFeeds[id] as? [String : Any]
|
||||
}
|
||||
|
||||
guard let feed else {
|
||||
return
|
||||
}
|
||||
|
||||
dictionary = feed
|
||||
|
||||
load()
|
||||
}
|
||||
|
||||
init(dictionary: AnyDictionary) {
|
||||
id = "\(dictionary["id"] ?? "<invalid>")"
|
||||
|
||||
self.dictionary = dictionary
|
||||
|
||||
load()
|
||||
}
|
||||
|
||||
private func load() {
|
||||
guard let appDelegate = NewsBlurAppDelegate.shared, let storiesCollection = appDelegate.storiesCollection else {
|
||||
return
|
||||
}
|
||||
|
||||
name = dictionary["feed_title"] as? String ?? "<invalid>"
|
||||
subscribers = dictionary["num_subscribers"] as? Int ?? 0
|
||||
|
||||
colorBarLeft = color(for: "favicon_fade", from: dictionary, default: "707070")
|
||||
colorBarRight = color(for: "favicon_color", from: dictionary, default: "505050")
|
||||
|
||||
isRiverOrSocial = storiesCollection.isRiverOrSocial
|
||||
}
|
||||
|
||||
func color(for key: String, from feed: AnyDictionary, default defaultHex: String) -> UIColor {
|
||||
let hex = feed[key] as? String ?? defaultHex
|
||||
let scanner = Scanner(string: hex)
|
||||
var color: Int64 = 0
|
||||
scanner.scanHexInt64(&color)
|
||||
let value = Int(color)
|
||||
|
||||
return ThemeManager.shared.fixedColor(fromRGB: value) ?? UIColor.gray
|
||||
}
|
||||
}
|
||||
|
||||
extension Feed: Equatable {
|
||||
static func == (lhs: Feed, rhs: Feed) -> Bool {
|
||||
return lhs.id == rhs.id
|
||||
}
|
||||
}
|
||||
|
||||
extension Feed: CustomDebugStringConvertible {
|
||||
var debugDescription: String {
|
||||
return "Feed \"\(name)\" (\(id))"
|
||||
}
|
||||
}
|
||||
|
||||
extension Feed.Training: Hashable {
|
||||
static func == (lhs: Feed.Training, rhs: Feed.Training) -> Bool {
|
||||
return lhs.name == rhs.name
|
||||
}
|
||||
|
||||
func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(name)
|
||||
}
|
||||
}
|
||||
|
||||
extension Feed.Training: Comparable {
|
||||
static func < (lhs: Feed.Training, rhs: Feed.Training) -> Bool {
|
||||
return lhs.name < rhs.name
|
||||
}
|
||||
}
|
|
@ -79,7 +79,7 @@
|
|||
UIImage *folderImage = [UIImage imageNamed:@"folder-open"];
|
||||
CGFloat folderImageViewX = 10.0;
|
||||
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] != UIUserInterfaceIdiomPad) {
|
||||
if (((NewsBlurAppDelegate *)[[UIApplication sharedApplication] delegate]).isPhone) {
|
||||
folderImageViewX = 7.0;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,9 +18,7 @@ typedef NS_ENUM(NSUInteger, FeedChooserOperation)
|
|||
};
|
||||
|
||||
|
||||
@interface FeedChooserViewController : BaseViewController {
|
||||
NewsBlurAppDelegate *appDelegate;
|
||||
}
|
||||
@interface FeedChooserViewController : BaseViewController
|
||||
|
||||
@property (weak) IBOutlet UITableView *tableView;
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@ static const CGFloat kFolderTitleHeight = 36.0;
|
|||
@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;
|
||||
|
||||
|
@ -45,8 +44,6 @@ static const CGFloat kFolderTitleHeight = 36.0;
|
|||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
|
||||
|
||||
if (self.operation == FeedChooserOperationWidgetSites) {
|
||||
self.groupDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.newsblur.NewsBlur-Group"];
|
||||
}
|
||||
|
@ -830,6 +827,36 @@ static const CGFloat kFolderTitleHeight = 36.0;
|
|||
return indexIndex;
|
||||
}
|
||||
|
||||
#if TARGET_OS_MACCATALYST
|
||||
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSArray<NSIndexPath *> *selectedRows = [tableView indexPathsForSelectedRows];
|
||||
if ([selectedRows containsObject:indexPath]) {
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:false];
|
||||
return nil;
|
||||
}
|
||||
|
||||
return indexPath;
|
||||
}
|
||||
|
||||
- (NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSArray<NSIndexPath *> *selectedRows = [tableView indexPathsForSelectedRows];
|
||||
if ([selectedRows containsObject:indexPath]) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return indexPath;
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSArray<NSIndexPath *> *selectedRows = [tableView indexPathsForSelectedRows];
|
||||
for (NSIndexPath *index in selectedRows) {
|
||||
[[tableView cellForRowAtIndexPath:index] setHighlighted:YES];
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (self.operation == FeedChooserOperationWidgetSites) {
|
||||
[self deselectRowsOutsideSection:indexPath.section];
|
||||
|
|
|
@ -75,6 +75,7 @@ struct CardView: View {
|
|||
}
|
||||
|
||||
Button {
|
||||
cache.appDelegate.activeStory = story.dictionary
|
||||
cache.appDelegate.feedDetailViewController.markFeedsRead(fromTimestamp: story.timestamp, andOlder: false)
|
||||
cache.appDelegate.feedDetailViewController.reload()
|
||||
} label: {
|
||||
|
@ -82,12 +83,15 @@ struct CardView: View {
|
|||
}
|
||||
|
||||
Button {
|
||||
cache.appDelegate.activeStory = story.dictionary
|
||||
cache.appDelegate.feedDetailViewController.markFeedsRead(fromTimestamp: story.timestamp, andOlder: true)
|
||||
cache.appDelegate.feedDetailViewController.reload()
|
||||
} label: {
|
||||
Label("Mark older stories read", image: "mark-read")
|
||||
}
|
||||
|
||||
Divider()
|
||||
|
||||
Button {
|
||||
cache.appDelegate.storiesCollection.toggleStorySaved(story.dictionary)
|
||||
cache.appDelegate.feedDetailViewController.reload()
|
||||
|
@ -96,13 +100,15 @@ struct CardView: View {
|
|||
}
|
||||
|
||||
Button {
|
||||
cache.appDelegate.activeStory = story.dictionary
|
||||
cache.appDelegate.showSend(to: cache.appDelegate.feedDetailViewController, sender: cache.appDelegate.feedDetailViewController.view)
|
||||
} label: {
|
||||
Label("Send this story to…", image: "email")
|
||||
}
|
||||
|
||||
Button {
|
||||
cache.appDelegate.openTrainStory(nil)
|
||||
cache.appDelegate.activeStory = story.dictionary
|
||||
cache.appDelegate.openTrainStory(cache.appDelegate.feedDetailViewController.view)
|
||||
} label: {
|
||||
Label("Train this story", image: "train")
|
||||
}
|
||||
|
@ -168,14 +174,14 @@ struct CardContentView: View {
|
|||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
if story.isRiverOrSocial, let feedImage {
|
||||
if let feed = story.feed, feed.isRiverOrSocial, let feedImage = feed.image {
|
||||
HStack {
|
||||
Image(uiImage: feedImage)
|
||||
.resizable()
|
||||
.frame(width: 16, height: 16)
|
||||
.padding(.leading, cache.settings.spacing == .compact ? 20 : 24)
|
||||
|
||||
Text(story.feedName)
|
||||
Text(feed.name)
|
||||
.font(font(named: "WhitneySSm-Medium", size: 12))
|
||||
.lineLimit(1)
|
||||
.foregroundColor(feedColor)
|
||||
|
@ -239,14 +245,6 @@ struct CardContentView: View {
|
|||
}
|
||||
}
|
||||
|
||||
var feedImage: UIImage? {
|
||||
if let image = cache.appDelegate.getFavicon(story.feedID) {
|
||||
return Utilities.roundCorneredImage(image, radius: 4, convertTo: CGSizeMake(16, 16))
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var unreadImage: UIImage? {
|
||||
guard story.isReadAvailable else {
|
||||
return nil
|
||||
|
@ -304,7 +302,7 @@ struct CardFeedBarView: View {
|
|||
|
||||
var body: some View {
|
||||
GeometryReader { geometry in
|
||||
if let color = story.feedColorBarLeft {
|
||||
if let feed = story.feed, let color = feed.colorBarLeft {
|
||||
Path { path in
|
||||
path.move(to: CGPoint(x: 0, y: 0))
|
||||
path.addLine(to: CGPoint(x: 0, y: geometry.size.height))
|
||||
|
@ -312,7 +310,7 @@ struct CardFeedBarView: View {
|
|||
.stroke(Color(color), lineWidth: 4)
|
||||
}
|
||||
|
||||
if let color = story.feedColorBarRight {
|
||||
if let feed = story.feed, let color = feed.colorBarRight {
|
||||
Path { path in
|
||||
path.move(to: CGPoint(x: 4, y: 0))
|
||||
path.addLine(to: CGPoint(x: 4, y: geometry.size.height))
|
||||
|
|
|
@ -136,6 +136,7 @@ struct FeedDetailGridView: View {
|
|||
}
|
||||
}
|
||||
.modify({ view in
|
||||
#if !targetEnvironment(macCatalyst)
|
||||
if #available(iOS 15.0, *) {
|
||||
view.refreshable {
|
||||
if cache.canPullToRefresh {
|
||||
|
@ -143,6 +144,7 @@ struct FeedDetailGridView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
})
|
||||
}
|
||||
.background(Color.themed([0xE0E0E0, 0xFFF8CA, 0x363636, 0x101010]))
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#import "MCSwipeTableViewCell.h"
|
||||
#import "FeedDetailTableCell.h"
|
||||
|
||||
@class NewsBlurAppDelegate;
|
||||
@class MCSwipeTableViewCell;
|
||||
|
||||
@interface FeedDetailObjCViewController : BaseViewController
|
||||
|
@ -23,8 +22,6 @@
|
|||
MCSwipeTableViewCellDelegate,
|
||||
UIGestureRecognizerDelegate, UISearchBarDelegate,
|
||||
UITableViewDragDelegate> {
|
||||
NewsBlurAppDelegate *appDelegate;
|
||||
|
||||
BOOL pageFetching;
|
||||
BOOL pageFinished;
|
||||
BOOL finishedAnimatingIn;
|
||||
|
@ -39,7 +36,6 @@
|
|||
NBNotifier *notifier;
|
||||
}
|
||||
|
||||
@property (nonatomic) IBOutlet NewsBlurAppDelegate *appDelegate;
|
||||
@property (nonatomic, strong) IBOutlet UITableView *storyTitlesTable;
|
||||
@property (nonatomic) IBOutlet UIBarButtonItem * feedMarkReadButton;
|
||||
@property (nonatomic) IBOutlet UIBarButtonItem * feedsBarButton;
|
||||
|
@ -50,7 +46,9 @@
|
|||
@property (nonatomic) IBOutlet UIBarButtonItem * titleImageBarButton;
|
||||
@property (nonatomic, retain) NBNotifier *notifier;
|
||||
@property (nonatomic, retain) StoriesCollection *storiesCollection;
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
@property (nonatomic) UIRefreshControl *refreshControl;
|
||||
#endif
|
||||
@property (nonatomic) UISearchBar *searchBar;
|
||||
@property (nonatomic) IBOutlet UIView *messageView;
|
||||
@property (nonatomic) IBOutlet UILabel *messageLabel;
|
||||
|
@ -112,16 +110,19 @@
|
|||
- (void)loadStoryAtRow:(NSInteger)row;
|
||||
- (void)redrawUnreadStory;
|
||||
- (IBAction)doOpenMarkReadMenu:(id)sender;
|
||||
- (IBAction)doMarkAllRead:(id)sender;
|
||||
- (IBAction)doOpenSettingsMenu:(id)sender;
|
||||
- (void)deleteSite;
|
||||
- (void)deleteFolder;
|
||||
- (void)muteSite;
|
||||
- (void)openTrainSite;
|
||||
- (IBAction)muteSite;
|
||||
- (IBAction)openTrainSite;
|
||||
- (IBAction)openNotifications:(id)sender;
|
||||
- (void)openNotificationsWithFeed:(NSString *)feedId;
|
||||
- (void)openRenameSite;
|
||||
- (IBAction)openStatistics:(id)sender;
|
||||
- (IBAction)openRenameSite;
|
||||
- (void)showUserProfile;
|
||||
- (void)changeActiveFeedDetailRow;
|
||||
- (void)instafetchFeed;
|
||||
- (IBAction)instafetchFeed;
|
||||
- (void)changeActiveStoryTitleCellLayout;
|
||||
- (void)didSelectItemAtIndexPath:(NSIndexPath *)indexPath;
|
||||
- (void)loadFaviconsFromActiveFeed;
|
||||
|
@ -132,4 +133,7 @@
|
|||
- (void)failedMarkAsUnsaved:(NSDictionary *)params;
|
||||
- (void)failedMarkAsUnread:(NSDictionary *)params;
|
||||
|
||||
- (void)confirmDeleteSite:(UINavigationController *)menuNavigationController;
|
||||
- (void)openMoveView:(UINavigationController *)menuNavigationController;
|
||||
|
||||
@end
|
||||
|
|
|
@ -69,7 +69,6 @@ typedef NS_ENUM(NSUInteger, FeedSection)
|
|||
@synthesize separatorBarButton;
|
||||
@synthesize titleImageBarButton;
|
||||
@synthesize spacerBarButton, spacer2BarButton;
|
||||
@synthesize appDelegate;
|
||||
@synthesize pageFetching;
|
||||
@synthesize pageFinished;
|
||||
@synthesize finishedAnimatingIn;
|
||||
|
@ -92,8 +91,6 @@ typedef NS_ENUM(NSUInteger, FeedSection)
|
|||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
self.appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(preferredContentSizeChanged:)
|
||||
name:UIContentSizeCategoryDidChangeNotification
|
||||
|
@ -106,7 +103,7 @@ typedef NS_ENUM(NSUInteger, FeedSection)
|
|||
if (@available(iOS 15.0, *)) {
|
||||
self.storyTitlesTable.allowsFocus = NO;
|
||||
}
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!self.isPhone) {
|
||||
self.storyTitlesTable.dragDelegate = self;
|
||||
self.storyTitlesTable.dragInteractionEnabled = YES;
|
||||
}
|
||||
|
@ -119,10 +116,12 @@ typedef NS_ENUM(NSUInteger, FeedSection)
|
|||
initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
|
||||
spacer2BarButton.width = 0;
|
||||
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
self.refreshControl = [UIRefreshControl new];
|
||||
self.refreshControl.tintColor = UIColorFromLightDarkRGB(0x0, 0xffffff);
|
||||
self.refreshControl.backgroundColor = UIColorFromRGB(0xE3E6E0);
|
||||
[self.refreshControl addTarget:self action:@selector(refresh:) forControlEvents:UIControlEventValueChanged];
|
||||
#endif
|
||||
|
||||
self.searchBar = [[UISearchBar alloc]
|
||||
initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.storyTitlesTable.frame), 44.)];
|
||||
|
@ -150,11 +149,11 @@ typedef NS_ENUM(NSUInteger, FeedSection)
|
|||
self.feedsBarButton = [[UIBarButtonItem alloc] initWithTitle:@"Sites" style:UIBarButtonItemStylePlain target:self action:@selector(doShowFeeds:)];
|
||||
self.feedsBarButton.accessibilityLabel = @"Show Sites";
|
||||
|
||||
UIImage *settingsImage = [Utilities imageNamed:@"settings" sized:30];
|
||||
UIImage *settingsImage = [Utilities imageNamed:@"settings" sized:self.isMac ? 24 : 30];
|
||||
settingsBarButton = [UIBarButtonItem barItemWithImage:settingsImage target:self action:@selector(doOpenSettingsMenu:)];
|
||||
settingsBarButton.accessibilityLabel = @"Settings";
|
||||
|
||||
UIImage *markreadImage = [Utilities imageNamed:@"mark-read" sized:30];
|
||||
UIImage *markreadImage = [Utilities imageNamed:@"mark-read" sized:self.isMac ? 24 : 30];
|
||||
feedMarkReadButton = [UIBarButtonItem barItemWithImage:markreadImage target:self action:@selector(doOpenMarkReadMenu:)];
|
||||
feedMarkReadButton.accessibilityLabel = @"Mark all as read";
|
||||
|
||||
|
@ -166,16 +165,19 @@ typedef NS_ENUM(NSUInteger, FeedSection)
|
|||
[view addGestureRecognizer:markReadLongPress];
|
||||
|
||||
titleImageBarButton = [UIBarButtonItem alloc];
|
||||
|
||||
|
||||
#if TARGET_OS_MACCATALYST
|
||||
if (@available(macCatalyst 16.0, *)) {
|
||||
settingsBarButton.hidden = YES;
|
||||
feedMarkReadButton.hidden = YES;
|
||||
}
|
||||
#else
|
||||
UILongPressGestureRecognizer *tableLongPress = [[UILongPressGestureRecognizer alloc]
|
||||
initWithTarget:self action:@selector(handleTableLongPress:)];
|
||||
tableLongPress.minimumPressDuration = 1.0;
|
||||
tableLongPress.delegate = self;
|
||||
[self.storyTitlesTable addGestureRecognizer:tableLongPress];
|
||||
|
||||
#if TARGET_OS_MACCATALYST
|
||||
// CATALYST: support double-click; doing the following breaks clicking on rows in Catalyst.
|
||||
#else
|
||||
UITapGestureRecognizer *doubleTapGesture = [[UITapGestureRecognizer alloc]
|
||||
initWithTarget:self action:nil];
|
||||
doubleTapGesture.numberOfTapsRequired = 2;
|
||||
|
@ -406,6 +408,11 @@ typedef NS_ENUM(NSUInteger, FeedSection)
|
|||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
#if TARGET_OS_MACCATALYST
|
||||
[self.navigationController setNavigationBarHidden:YES animated:animated];
|
||||
[self.navigationController setToolbarHidden:YES animated:animated];
|
||||
#endif
|
||||
|
||||
self.appDelegate = (NewsBlurAppDelegate *)[[UIApplication sharedApplication] delegate];
|
||||
|
||||
if (self.standardInteractivePopGestureDelegate == nil) {
|
||||
|
@ -434,7 +441,7 @@ typedef NS_ENUM(NSUInteger, FeedSection)
|
|||
if (storiesCollection == nil) {
|
||||
NSString *appOpening = [userPreferences stringForKey:@"app_opening"];
|
||||
|
||||
if ([appOpening isEqualToString:@"feeds"] && [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if ([appOpening isEqualToString:@"feeds"] && !self.isPhone) {
|
||||
self.messageLabel.text = @"Select a feed to read";
|
||||
self.messageView.hidden = NO;
|
||||
}
|
||||
|
@ -510,11 +517,13 @@ typedef NS_ENUM(NSUInteger, FeedSection)
|
|||
[self.searchBar setShowsCancelButton:NO animated:YES];
|
||||
}
|
||||
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
if (self.canPullToRefresh) {
|
||||
self.storyTitlesTable.refreshControl = self.refreshControl;
|
||||
} else {
|
||||
self.storyTitlesTable.refreshControl = nil;
|
||||
}
|
||||
#endif
|
||||
|
||||
[self updateTheme];
|
||||
|
||||
|
@ -751,7 +760,7 @@ typedef NS_ENUM(NSUInteger, FeedSection)
|
|||
}
|
||||
|
||||
- (void)beginOfflineTimer {
|
||||
if ([self.storiesCollection.activeFolder isEqualToString:@"infrequent"]) {
|
||||
if (self.storiesCollection.isInfrequent) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -844,6 +853,11 @@ typedef NS_ENUM(NSUInteger, FeedSection)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (indexPath.row > storiesCollection.storyLocationsCount) {
|
||||
NSLog(@"⚠️ row %@ is greater than the story locations count: %@", @(indexPath.row), @(storiesCollection.storyLocationsCount)); // log
|
||||
continue;
|
||||
}
|
||||
|
||||
[self reloadIndexPath:indexPath withRowAnimation:UITableViewRowAnimationNone];
|
||||
break;
|
||||
}
|
||||
|
@ -1300,6 +1314,13 @@ typedef NS_ENUM(NSUInteger, FeedSection)
|
|||
|
||||
NSLog(@"finishedLoadingFeed: %@", receivedFeedId); // log
|
||||
|
||||
#if TARGET_OS_MACCATALYST
|
||||
if (@available(macCatalyst 16.0, *)) {
|
||||
settingsBarButton.hidden = NO;
|
||||
feedMarkReadButton.hidden = NO;
|
||||
}
|
||||
#endif
|
||||
|
||||
self.pageFinished = NO;
|
||||
[self renderStories:confirmedNewStories];
|
||||
|
||||
|
@ -1440,7 +1461,7 @@ typedef NS_ENUM(NSUInteger, FeedSection)
|
|||
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
|
||||
NSString *feedOpening = [preferences stringForKey:@"feed_opening"];
|
||||
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad && feedOpening == nil) {
|
||||
if (!self.isPhone && feedOpening == nil) {
|
||||
feedOpening = @"story";
|
||||
}
|
||||
|
||||
|
@ -1493,7 +1514,7 @@ typedef NS_ENUM(NSUInteger, FeedSection)
|
|||
// NSIndexPath *indexPath = [NSIndexPath indexPathForRow:locationOfStoryId inSection:0];
|
||||
NSIndexPath *indexPath = [self indexPathForStoryLocation:locationOfStoryId];
|
||||
|
||||
if (self.isLegacyTable && self.storyTitlesTable.window != nil) {
|
||||
if (self.isLegacyTable && self.storyTitlesTable.window != nil && indexPath.row < [self.storyTitlesTable numberOfRowsInSection:0]) {
|
||||
[self tableView:self.storyTitlesTable selectRowAtIndexPath:indexPath
|
||||
animated:NO
|
||||
scrollPosition:UITableViewScrollPositionMiddle];
|
||||
|
@ -1621,6 +1642,35 @@ typedef NS_ENUM(NSUInteger, FeedSection)
|
|||
toItem:fleuron
|
||||
attribute:NSLayoutAttributeBottom
|
||||
multiplier:1.0 constant:height/2]];
|
||||
} else if (!self.isMarkReadOnScroll) {
|
||||
UIButton *markReadButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
|
||||
markReadButton.titleLabel.font = [UIFont systemFontOfSize:14];
|
||||
[markReadButton setTitle:@" Mark All Stories as Read " forState:UIControlStateNormal];
|
||||
|
||||
[markReadButton addTarget:self action:@selector(doMarkAllRead:) forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
markReadButton.tintColor = UIColor.whiteColor;
|
||||
markReadButton.backgroundColor = UIColorFromFixedRGB(0x939EAF);
|
||||
markReadButton.layer.cornerRadius = 10;
|
||||
|
||||
[markReadButton sizeToFit];
|
||||
|
||||
markReadButton.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
|
||||
[cell.contentView addSubview:markReadButton];
|
||||
[cell.contentView addConstraint:[NSLayoutConstraint constraintWithItem:markReadButton
|
||||
attribute:NSLayoutAttributeCenterX
|
||||
relatedBy:NSLayoutRelationEqual
|
||||
toItem:cell.contentView
|
||||
attribute:NSLayoutAttributeCenterX
|
||||
multiplier:1.0 constant:0]];
|
||||
[cell.contentView addConstraint:[NSLayoutConstraint constraintWithItem:markReadButton
|
||||
attribute:NSLayoutAttributeTop
|
||||
relatedBy:NSLayoutRelationEqual
|
||||
toItem:fleuron
|
||||
attribute:NSLayoutAttributeBottom
|
||||
multiplier:1.0 constant:height/2]];
|
||||
}
|
||||
|
||||
return cell;
|
||||
|
@ -2380,6 +2430,21 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
visibleUnreadCount = 0;
|
||||
}
|
||||
|
||||
#if TARGET_OS_MACCATALYST
|
||||
UINavigationController *feedDetailNavController = appDelegate.feedDetailViewController.navigationController;
|
||||
UIView *sourceView = feedDetailNavController.view;
|
||||
CGRect sourceRect = CGRectMake(120, 0, 20, 20);
|
||||
|
||||
if (appDelegate.splitViewController.isFeedListHidden) {
|
||||
sourceRect = CGRectMake(192, 0, 20, 20);
|
||||
}
|
||||
|
||||
[self.appDelegate showMarkReadMenuWithFeedIds:feedIds collectionTitle:collectionTitle visibleUnreadCount:visibleUnreadCount sourceView:sourceView sourceRect:sourceRect completionHandler:^(BOOL marked){
|
||||
if (marked) {
|
||||
pop();
|
||||
}
|
||||
}];
|
||||
#else
|
||||
UIBarButtonItem *barButton = self.feedMarkReadButton;
|
||||
if (sender && [sender isKindOfClass:[UIBarButtonItem class]]) barButton = sender;
|
||||
|
||||
|
@ -2388,6 +2453,7 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
pop();
|
||||
}
|
||||
}];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (IBAction)doOpenMarkReadMenu:(id)sender {
|
||||
|
@ -2406,11 +2472,6 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
appDelegate.storiesCollection.isReadView;
|
||||
}
|
||||
|
||||
- (BOOL)isInfrequent {
|
||||
return appDelegate.storiesCollection.isRiverView &&
|
||||
[appDelegate.storiesCollection.activeFolder isEqualToString:@"infrequent"];
|
||||
}
|
||||
|
||||
- (IBAction)doShowFeeds:(id)sender {
|
||||
[self.appDelegate showColumn:UISplitViewControllerColumnPrimary debugInfo:@"showFeeds"];
|
||||
}
|
||||
|
@ -2425,8 +2486,8 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
MenuViewController *viewController = [MenuViewController new];
|
||||
__weak MenuViewController *weakViewController = viewController;
|
||||
|
||||
BOOL everything = [appDelegate.storiesCollection.activeFolder isEqualToString:@"everything"];
|
||||
BOOL infrequent = [self isInfrequent];
|
||||
BOOL everything = appDelegate.storiesCollection.isEverything;
|
||||
BOOL infrequent = appDelegate.storiesCollection.isInfrequent;
|
||||
BOOL river = [self isRiver];
|
||||
BOOL read = appDelegate.storiesCollection.isReadView;
|
||||
BOOL widget = appDelegate.storiesCollection.isWidgetView;
|
||||
|
@ -2608,7 +2669,19 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
|
||||
UINavigationController *navController = self.navigationController ?: appDelegate.storyPagesViewController.navigationController;
|
||||
|
||||
#if TARGET_OS_MACCATALYST
|
||||
UINavigationController *feedDetailNavController = appDelegate.feedDetailViewController.navigationController;
|
||||
UIView *sourceView = feedDetailNavController.view;
|
||||
CGRect sourceRect = CGRectMake(152, 0, 20, 20);
|
||||
|
||||
if (appDelegate.splitViewController.isFeedListHidden) {
|
||||
sourceRect = CGRectMake(224, 0, 20, 20);
|
||||
}
|
||||
|
||||
[viewController showFromNavigationController:navController barButtonItem:nil sourceView:sourceView sourceRect:sourceRect permittedArrowDirections:UIPopoverArrowDirectionDown];
|
||||
#else
|
||||
[viewController showFromNavigationController:navController barButtonItem:self.settingsBarButton];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (NSString *)feedIdForSearch {
|
||||
|
@ -2806,7 +2879,7 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
}];
|
||||
}
|
||||
|
||||
- (void)muteSite {
|
||||
- (IBAction)muteSite {
|
||||
[MBProgressHUD hideHUDForView:self.view animated:YES];
|
||||
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
|
||||
HUD.labelText = @"Muting...";
|
||||
|
@ -2959,7 +3032,7 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
[menuNavigationController showViewController:viewController sender:self];
|
||||
}
|
||||
|
||||
- (void)openTrainSite {
|
||||
- (IBAction)openTrainSite {
|
||||
[appDelegate openTrainSite];
|
||||
}
|
||||
|
||||
|
@ -2969,15 +3042,27 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
[self reload];
|
||||
}
|
||||
|
||||
- (IBAction)openNotifications:(id)sender {
|
||||
NSString *feedIdStr = storiesCollection.activeFeedIdStr;
|
||||
|
||||
[appDelegate openNotificationsWithFeed:feedIdStr];
|
||||
}
|
||||
|
||||
- (void)openNotificationsWithFeed:(NSString *)feedId {
|
||||
[appDelegate openNotificationsWithFeed:feedId];
|
||||
}
|
||||
|
||||
- (IBAction)openStatistics:(id)sender {
|
||||
NSString *feedIdStr = storiesCollection.activeFeedIdStr;
|
||||
|
||||
[appDelegate openStatisticsWithFeed:feedIdStr sender:settingsBarButton];
|
||||
}
|
||||
|
||||
- (void)openStatisticsWithFeed:(NSString *)feedId {
|
||||
[appDelegate openStatisticsWithFeed:feedId sender:settingsBarButton];
|
||||
}
|
||||
|
||||
- (void)openRenameSite {
|
||||
- (IBAction)openRenameSite {
|
||||
NSString *title = [NSString stringWithFormat:@"Rename \"%@\"", appDelegate.storiesCollection.isRiverView ?
|
||||
[appDelegate extractFolderName:appDelegate.storiesCollection.activeFolder] : [appDelegate.storiesCollection.activeFeed objectForKey:@"feed_title"]];
|
||||
NSString *subtitle = (appDelegate.storiesCollection.isRiverView ?
|
||||
|
@ -3068,8 +3153,10 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
self.navigationItem.titleView = [appDelegate makeFeedTitle:storiesCollection.activeFeed];
|
||||
}
|
||||
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
self.refreshControl.tintColor = UIColorFromLightDarkRGB(0x0, 0xffffff);
|
||||
self.refreshControl.backgroundColor = UIColorFromRGB(0xE3E6E0);
|
||||
#endif
|
||||
|
||||
self.searchBar.backgroundColor = UIColorFromRGB(0xE3E6E0);
|
||||
self.searchBar.tintColor = UIColorFromRGB(0xffffff);
|
||||
|
@ -3093,6 +3180,16 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
[self reload];
|
||||
}
|
||||
|
||||
//- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
|
||||
// NSLog(@"canPerformAction: %@ withSender: %@", NSStringFromSelector(action), sender); // log
|
||||
//
|
||||
// if (action == @selector(deleteSite:)) {
|
||||
// return NO;
|
||||
// }
|
||||
//
|
||||
// return YES;
|
||||
//}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Story Actions - save
|
||||
|
||||
|
@ -3127,7 +3224,7 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
|
||||
// called when the user taps refresh button
|
||||
|
||||
- (void)instafetchFeed {
|
||||
- (IBAction)instafetchFeed {
|
||||
NSString *urlString = [NSString
|
||||
stringWithFormat:@"%@/reader/refresh_feed/%@",
|
||||
self.appDelegate.url,
|
||||
|
@ -3152,12 +3249,16 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
}
|
||||
}
|
||||
|
||||
- (IBAction)deleteSite:(id)sender {
|
||||
//TODO
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark PullToRefresh
|
||||
|
||||
- (BOOL)canPullToRefresh {
|
||||
BOOL river = appDelegate.storiesCollection.isRiverView;
|
||||
BOOL infrequent = [self isInfrequent];
|
||||
BOOL infrequent = appDelegate.storiesCollection.isInfrequent;
|
||||
BOOL read = appDelegate.storiesCollection.isReadView;
|
||||
BOOL widget = appDelegate.storiesCollection.isWidgetView;
|
||||
BOOL saved = appDelegate.storiesCollection.isSavedView;
|
||||
|
@ -3165,6 +3266,7 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
return appDelegate.storiesCollection.activeFeed != nil && !river && !infrequent && !saved && !read && !widget;
|
||||
}
|
||||
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
- (void)refresh:(UIRefreshControl *)refreshControl {
|
||||
if (self.canPullToRefresh) {
|
||||
self.inPullToRefresh_ = YES;
|
||||
|
@ -3173,10 +3275,13 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
[self finishRefresh];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)finishRefresh {
|
||||
self.inPullToRefresh_ = NO;
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
[self.refreshControl endRefreshing];
|
||||
#endif
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
|
|
@ -29,10 +29,6 @@ class FeedDetailViewController: FeedDetailObjCViewController {
|
|||
case loading
|
||||
}
|
||||
|
||||
var isGrid: Bool {
|
||||
return appDelegate.detailViewController.layout == .grid
|
||||
}
|
||||
|
||||
var wasGrid: Bool {
|
||||
return appDelegate.detailViewController.wasGrid
|
||||
}
|
||||
|
@ -138,7 +134,15 @@ class FeedDetailViewController: FeedDetailObjCViewController {
|
|||
|
||||
@objc var suppressMarkAsRead = false
|
||||
|
||||
var scrollingDate = Date.distantPast
|
||||
|
||||
func deferredReload(story: Story? = nil) {
|
||||
if let story {
|
||||
print("🪿 queuing deferred reload for \(story)")
|
||||
} else {
|
||||
print("🪿 queuing deferred reload")
|
||||
}
|
||||
|
||||
reloadWorkItem?.cancel()
|
||||
|
||||
if let story {
|
||||
|
@ -153,6 +157,16 @@ class FeedDetailViewController: FeedDetailObjCViewController {
|
|||
}
|
||||
|
||||
if pendingStories.isEmpty {
|
||||
print("🪿 starting deferred reload")
|
||||
|
||||
let secondsSinceScroll = -scrollingDate.timeIntervalSinceNow
|
||||
|
||||
if secondsSinceScroll < 0.5 {
|
||||
print("🪿 too soon to reload; \(secondsSinceScroll) seconds since scroll")
|
||||
deferredReload(story: story)
|
||||
return
|
||||
}
|
||||
|
||||
configureDataSource()
|
||||
} else {
|
||||
for story in pendingStories.values {
|
||||
|
@ -202,6 +216,55 @@ extension FeedDetailViewController {
|
|||
reloadTable()
|
||||
}
|
||||
}
|
||||
|
||||
#if targetEnvironment(macCatalyst)
|
||||
override func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
|
||||
let location = storyLocation(for: indexPath)
|
||||
|
||||
guard location < storiesCollection.storyLocationsCount else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let storyIndex = storiesCollection.index(fromLocation: location)
|
||||
let story = Story(index: storyIndex)
|
||||
|
||||
appDelegate.activeStory = story.dictionary
|
||||
|
||||
return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { suggestedActions in
|
||||
let read = UIAction(title: story.isRead ? "Mark as unread" : "Mark as read", image: UIImage(named: "mark-read")) { action in
|
||||
self.appDelegate.storiesCollection.toggleStoryUnread(story.dictionary)
|
||||
self.reload()
|
||||
}
|
||||
|
||||
let newer = UIAction(title: "Mark newer stories read", image: UIImage(named: "mark-read")) { action in
|
||||
self.markFeedsRead(fromTimestamp: story.timestamp, andOlder: false)
|
||||
self.reload()
|
||||
}
|
||||
|
||||
let older = UIAction(title: "Mark older stories read", image: UIImage(named: "mark-read")) { action in
|
||||
self.markFeedsRead(fromTimestamp: story.timestamp, andOlder: true)
|
||||
self.reload()
|
||||
}
|
||||
|
||||
let saved = UIAction(title: story.isSaved ? "Unsave this story" : "Save this story", image: UIImage(named: "saved-stories")) { action in
|
||||
self.appDelegate.storiesCollection.toggleStorySaved(story.dictionary)
|
||||
self.reload()
|
||||
}
|
||||
|
||||
let send = UIAction(title: "Send this story to…", image: UIImage(named: "email")) { action in
|
||||
self.appDelegate.showSend(to: self, sender: self.view)
|
||||
}
|
||||
|
||||
let train = UIAction(title: "Train this story", image: UIImage(named: "train")) { action in
|
||||
self.appDelegate.openTrainStory(self.view)
|
||||
}
|
||||
|
||||
let submenu = UIMenu(title: "", options: .displayInline, children: [saved, send, train])
|
||||
|
||||
return UIMenu(title: "", children: [read, newer, older, submenu])
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
extension FeedDetailViewController: FeedDetailInteraction {
|
||||
|
@ -232,12 +295,18 @@ extension FeedDetailViewController: FeedDetailInteraction {
|
|||
let cacheCount = storyCache.before.count + storyCache.after.count
|
||||
|
||||
if cacheCount > 0, story.index >= cacheCount - 5 {
|
||||
let debug = Date()
|
||||
|
||||
if storiesCollection.isRiverView, storiesCollection.activeFolder != nil {
|
||||
fetchRiverPage(storiesCollection.feedPage + 1, withCallback: nil)
|
||||
} else {
|
||||
fetchFeedDetail(storiesCollection.feedPage + 1, withCallback: nil)
|
||||
}
|
||||
|
||||
print("🐓 Fetching next page took \(-debug.timeIntervalSinceNow) seconds")
|
||||
}
|
||||
|
||||
scrollingDate = Date()
|
||||
}
|
||||
|
||||
func tapped(story: Story) {
|
||||
|
|
|
@ -174,11 +174,18 @@ static UIFont *textFont = nil;
|
|||
BOOL isHighlighted = cell.highlighted || cell.selected;
|
||||
UIColor *backgroundColor;
|
||||
|
||||
#if TARGET_OS_MACCATALYST
|
||||
backgroundColor = cell.isSocial ? UIColorFromRGB(0xD8E3DB) :
|
||||
cell.isSearch ? UIColorFromRGB(0xDBDFE6) :
|
||||
cell.isSaved ? UIColorFromRGB(0xDFDCD6) :
|
||||
UIColor.clearColor;
|
||||
#else
|
||||
backgroundColor = cell.isSocial ? UIColorFromRGB(0xD8E3DB) :
|
||||
cell.isSearch ? UIColorFromRGB(0xDBDFE6) :
|
||||
cell.isSaved ? UIColorFromRGB(0xDFDCD6) :
|
||||
UIColorFromRGB(0xF7F8F5);
|
||||
|
||||
#endif
|
||||
|
||||
// [backgroundColor set];
|
||||
self.backgroundColor = backgroundColor;
|
||||
cell.backgroundColor = backgroundColor;
|
||||
|
@ -219,7 +226,7 @@ static UIFont *textFont = nil;
|
|||
paragraphStyle.alignment = NSTextAlignmentLeft;
|
||||
CGSize faviconSize;
|
||||
if (cell.isSocial) {
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!cell.appDelegate.isPhone) {
|
||||
faviconSize = CGSizeMake(28, 28);
|
||||
UIImage *feedIcon = [Utilities roundCorneredImage:cell.feedFavicon radius:4 convertToSize:faviconSize];
|
||||
[feedIcon drawInRect:CGRectMake(9.0, CGRectGetMidY(r)-faviconSize.height/2, faviconSize.width, faviconSize.height)];
|
||||
|
@ -239,7 +246,7 @@ static UIFont *textFont = nil;
|
|||
} else {
|
||||
faviconSize = CGSizeMake(16, 16);
|
||||
UIImage *feedIcon = [Utilities roundCorneredImage:cell.feedFavicon radius:4 convertToSize:faviconSize];
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!cell.appDelegate.isPhone) {
|
||||
[feedIcon drawInRect:CGRectMake(12.0, CGRectGetMidY(r)-faviconSize.height/2, faviconSize.width, faviconSize.height)];
|
||||
[cell.feedTitle drawInRect:CGRectMake(36.0, titleOffsetY, r.size.width - ([cell.unreadCount offsetWidth] + 36) - 10, font.pointSize*1.4)
|
||||
withAttributes:@{NSFontAttributeName: font,
|
||||
|
|
|
@ -21,8 +21,6 @@ static enum {
|
|||
NewsBlurTopSectionAllStories = 1
|
||||
} NewsBlurTopSection;
|
||||
|
||||
@class NewsBlurAppDelegate;
|
||||
|
||||
@interface FeedsObjCViewController : BaseViewController
|
||||
<UITableViewDelegate, UITableViewDataSource,
|
||||
NSCacheDelegate,
|
||||
|
@ -30,8 +28,6 @@ UIPopoverControllerDelegate,
|
|||
IASKSettingsDelegate,
|
||||
MCSwipeTableViewCellDelegate,
|
||||
UIGestureRecognizerDelegate, UISearchBarDelegate> {
|
||||
NewsBlurAppDelegate *appDelegate;
|
||||
|
||||
NSMutableDictionary * activeFeedLocations;
|
||||
NSMutableDictionary *stillVisibleFeeds;
|
||||
NSMutableDictionary *visibleFolders;
|
||||
|
@ -53,15 +49,23 @@ UIGestureRecognizerDelegate, UISearchBarDelegate> {
|
|||
NBNotifier *notifier;
|
||||
}
|
||||
|
||||
@property (nonatomic) IBOutlet NewsBlurAppDelegate *appDelegate;
|
||||
@property (nonatomic) IBOutlet UIView *innerView;
|
||||
@property (nonatomic) IBOutlet UITableView *feedTitlesTable;
|
||||
@property (nonatomic) IBOutlet NSLayoutConstraint *feedTitlesTopConstraint;
|
||||
@property (nonatomic) IBOutlet NSLayoutConstraint *feedTitlesLeadingConstraint;
|
||||
@property (nonatomic) IBOutlet NSLayoutConstraint *feedTitlesTrailingConstraint;
|
||||
@property (nonatomic) IBOutlet UIToolbar *feedViewToolbar;
|
||||
@property (nonatomic) IBOutlet UISlider * feedScoreSlider;
|
||||
@property (nonatomic) IBOutlet UIBarButtonItem * homeButton;
|
||||
@property (nonatomic) IBOutlet UIBarButtonItem * addBarButton;
|
||||
@property (nonatomic) IBOutlet UIBarButtonItem * settingsBarButton;
|
||||
@property (nonatomic) UIButton *activityButton;
|
||||
@property (nonatomic) IBOutlet UIBarButtonItem * activitiesButton;
|
||||
#if TARGET_OS_MACCATALYST
|
||||
@property (nonatomic) IBOutlet UIBarButtonItem * spacerBarButton;
|
||||
@property (nonatomic) IBOutlet UIBarButtonItem * userBarButton;
|
||||
#endif
|
||||
@property (nonatomic) IBOutlet UIView *userInfoView;
|
||||
@property (nonatomic) IBOutlet UIButton *userAvatarButton;
|
||||
@property (nonatomic) IBOutlet UILabel *neutralCount;
|
||||
@property (nonatomic) IBOutlet UILabel *positiveCount;
|
||||
|
@ -74,7 +78,9 @@ UIGestureRecognizerDelegate, UISearchBarDelegate> {
|
|||
@property (nonatomic, readwrite) BOOL viewShowingAllFeeds;
|
||||
@property (nonatomic, readwrite) BOOL interactiveFeedDetailTransition;
|
||||
@property (nonatomic, readwrite) BOOL isOffline;
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
@property (nonatomic) UIRefreshControl *refreshControl;
|
||||
#endif
|
||||
@property (nonatomic) UISearchBar *searchBar;
|
||||
@property (nonatomic, strong) NSArray<NSString *> *searchFeedIds;
|
||||
@property (nonatomic) NSCache *imageCache;
|
||||
|
@ -94,7 +100,14 @@ UIGestureRecognizerDelegate, UISearchBarDelegate> {
|
|||
- (void)didSelectSectionHeader:(UIButton *)button;
|
||||
- (void)didSelectSectionHeaderWithTag:(NSInteger)tag;
|
||||
- (void)selectNextFolderOrFeed;
|
||||
|
||||
- (IBAction)selectIntelligence;
|
||||
- (void)selectEverything:(id)sender;
|
||||
- (void)selectNextFeed:(id)sender;
|
||||
- (void)selectPreviousFeed:(id)sender;
|
||||
- (void)selectNextFolder:(id)sender;
|
||||
- (void)selectPreviousFolder:(id)sender;
|
||||
|
||||
- (void)markFeedRead:(NSString *)feedId cutoffDays:(NSInteger)days;
|
||||
- (void)markFeedsRead:(NSArray *)feedIds cutoffDays:(NSInteger)days;
|
||||
- (void)markEverythingReadWithDays:(NSInteger)days;
|
||||
|
|
|
@ -57,7 +57,6 @@ static NSArray<NSString *> *NewsBlurTopSectionNames;
|
|||
|
||||
@implementation FeedsObjCViewController
|
||||
|
||||
@synthesize appDelegate;
|
||||
@synthesize feedTitlesTable;
|
||||
@synthesize feedViewToolbar;
|
||||
@synthesize feedScoreSlider;
|
||||
|
@ -113,12 +112,14 @@ static NSArray<NSString *> *NewsBlurTopSectionNames;
|
|||
self.rowHeights = [NSMutableDictionary dictionary];
|
||||
self.folderTitleViews = [NSMutableDictionary dictionary];
|
||||
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
self.refreshControl = [UIRefreshControl new];
|
||||
self.refreshControl.tintColor = UIColorFromLightDarkRGB(0x0, 0xffffff);
|
||||
self.refreshControl.backgroundColor = UIColorFromRGB(0xE3E6E0);
|
||||
[self.refreshControl addTarget:self action:@selector(refresh:) forControlEvents:UIControlEventValueChanged];
|
||||
self.feedTitlesTable.refreshControl = self.refreshControl;
|
||||
self.feedViewToolbar.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
#endif
|
||||
|
||||
self.searchBar = [[UISearchBar alloc]
|
||||
initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.feedTitlesTable.frame), 44.)];
|
||||
|
@ -129,7 +130,16 @@ static NSArray<NSString *> *NewsBlurTopSectionNames;
|
|||
self.searchBar.nb_searchField.textColor = UIColorFromRGB(0x0);
|
||||
[self.searchBar setSearchBarStyle:UISearchBarStyleMinimal];
|
||||
[self.searchBar setAutocapitalizationType:UITextAutocapitalizationTypeNone];
|
||||
#if TARGET_OS_MACCATALYST
|
||||
// Workaround for Catalyst bug.
|
||||
self.searchBar.frame = CGRectMake(10, 0, CGRectGetWidth(self.feedTitlesTable.frame) - 20, 44.);
|
||||
self.searchBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||
UIView *searchContainerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.feedTitlesTable.frame), 44.)];
|
||||
[searchContainerView addSubview:self.searchBar];
|
||||
self.feedTitlesTable.tableHeaderView = searchContainerView;
|
||||
#else
|
||||
self.feedTitlesTable.tableHeaderView = self.searchBar;
|
||||
#endif
|
||||
|
||||
userLabelFont = [UIFont fontWithName:@"WhitneySSm-Medium" size:15.0];
|
||||
|
||||
|
@ -169,7 +179,17 @@ static NSArray<NSString *> *NewsBlurTopSectionNames;
|
|||
[[UIBarButtonItem appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName:
|
||||
UIColorFromFixedRGB(0x4C4D4A)}
|
||||
forState:UIControlStateHighlighted];
|
||||
#if TARGET_OS_MACCATALYST
|
||||
self.innerView.backgroundColor = UIColor.clearColor;
|
||||
|
||||
if (ThemeManager.themeManager.isLikeSystem) {
|
||||
self.view.backgroundColor = UIColor.clearColor;
|
||||
} else {
|
||||
self.view.backgroundColor = UIColorFromRGB(0xf4f4f4);
|
||||
}
|
||||
#else
|
||||
self.view.backgroundColor = UIColorFromRGB(0xf4f4f4);
|
||||
#endif
|
||||
self.navigationController.navigationBar.tintColor = UIColorFromRGB(0x8F918B);
|
||||
self.navigationController.navigationBar.translucent = NO;
|
||||
UIInterfaceOrientation orientation = self.view.window.windowScene.interfaceOrientation;
|
||||
|
@ -199,6 +219,12 @@ static NSArray<NSString *> *NewsBlurTopSectionNames;
|
|||
self.feedTitlesTable.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
self.feedTitlesTable.estimatedRowHeight = 0;
|
||||
|
||||
#if TARGET_OS_MACCATALYST
|
||||
// Workaround for Catalyst bug.
|
||||
self.feedTitlesLeadingConstraint.constant = -10;
|
||||
self.feedTitlesTrailingConstraint.constant = -10;
|
||||
#endif
|
||||
|
||||
if (@available(iOS 15.0, *)) {
|
||||
self.feedTitlesTable.sectionHeaderTopPadding = 0;
|
||||
}
|
||||
|
@ -228,7 +254,7 @@ static NSArray<NSString *> *NewsBlurTopSectionNames;
|
|||
|
||||
[self resetRowHeights];
|
||||
|
||||
// if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad &&
|
||||
// if (!self.isPhone &&
|
||||
// !self.interactiveFeedDetailTransition) {
|
||||
//
|
||||
// [appDelegate.masterContainerViewController transitionFromFeedDetail];
|
||||
|
@ -236,6 +262,16 @@ static NSArray<NSString *> *NewsBlurTopSectionNames;
|
|||
// NSLog(@"Feed List timing 0: %f", [NSDate timeIntervalSinceReferenceDate] - start);
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
#if TARGET_OS_MACCATALYST
|
||||
UINavigationController *navController = self.navigationController;
|
||||
UITitlebar *titlebar = navController.navigationBar.window.windowScene.titlebar;
|
||||
|
||||
titlebar.titleVisibility = UITitlebarTitleVisibilityHidden;
|
||||
|
||||
[self.navigationController setNavigationBarHidden:YES animated:animated];
|
||||
[self.navigationController setToolbarHidden:YES animated:animated];
|
||||
#endif
|
||||
|
||||
NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults];
|
||||
NSInteger intelligenceLevel = [userPreferences integerForKey:@"selectedIntelligence"];
|
||||
|
||||
|
@ -425,7 +461,7 @@ static NSArray<NSString *> *NewsBlurTopSectionNames;
|
|||
|
||||
- (void)layoutForInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||
// CGSize toolbarSize = [self.feedViewToolbar sizeThatFits:self.view.frame.size];
|
||||
// if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
// if (!self.isPhone) {
|
||||
// self.feedViewToolbar.frame = CGRectMake(-10.0f,
|
||||
// CGRectGetHeight(self.view.frame) - toolbarSize.height,
|
||||
// toolbarSize.width + 20, toolbarSize.height);
|
||||
|
@ -434,7 +470,7 @@ static NSArray<NSString *> *NewsBlurTopSectionNames;
|
|||
// }
|
||||
// self.innerView.frame = (CGRect){CGPointZero, CGSizeMake(CGRectGetWidth(self.view.frame), CGRectGetMinY(self.feedViewToolbar.frame))};
|
||||
|
||||
// if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad && !appDelegate.isCompactWidth) {
|
||||
// if (!self.isPhone && !appDelegate.isCompactWidth) {
|
||||
// CGRect navFrame = appDelegate.navigationController.view.frame;
|
||||
// CGFloat limit = appDelegate.masterContainerViewController.rightBorder.frame.origin.x + 1;
|
||||
//
|
||||
|
@ -456,7 +492,7 @@ static NSArray<NSString *> *NewsBlurTopSectionNames;
|
|||
orientation = self.view.window.windowScene.interfaceOrientation;
|
||||
}
|
||||
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad && !UIInterfaceOrientationIsLandscape(orientation)) {
|
||||
if (!self.isPhone && !UIInterfaceOrientationIsLandscape(orientation)) {
|
||||
[self.intelligenceControl setImage:[UIImage imageNamed:@"unread_yellow_icn.png"] forSegmentAtIndex:1];
|
||||
[self.intelligenceControl setImage:[Utilities imageNamed:@"indicator-focus" sized:14] forSegmentAtIndex:2];
|
||||
[self.intelligenceControl setImage:[Utilities imageNamed:@"unread_blue_icn.png" sized:14] forSegmentAtIndex:3];
|
||||
|
@ -494,6 +530,10 @@ static NSArray<NSString *> *NewsBlurTopSectionNames;
|
|||
return YES;
|
||||
}
|
||||
|
||||
- (void)buildMenuWithBuilder:(id<UIMenuBuilder>)builder {
|
||||
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark State Restoration
|
||||
|
||||
|
@ -686,18 +726,19 @@ static NSArray<NSString *> *NewsBlurTopSectionNames;
|
|||
// [settingsBarButton setCustomView:settingsButton];
|
||||
|
||||
UIImage *activityImage = [Utilities templateImageNamed:@"dialog-notifications" sized:32];
|
||||
NBBarButtonItem *activityButton = [NBBarButtonItem buttonWithType:UIButtonTypeCustom];
|
||||
activityButton.accessibilityLabel = @"Activities";
|
||||
[activityButton setImage:activityImage forState:UIControlStateNormal];
|
||||
activityButton.tintColor = UIColorFromRGB(0x8F918B);
|
||||
[activityButton setImageEdgeInsets:UIEdgeInsetsMake(4, 0, 4, 0)];
|
||||
[activityButton addTarget:self
|
||||
[self.activityButton removeFromSuperview];
|
||||
self.activityButton = [NBBarButtonItem buttonWithType:UIButtonTypeCustom];
|
||||
self.activityButton.accessibilityLabel = @"Activities";
|
||||
[self.activityButton setImage:activityImage forState:UIControlStateNormal];
|
||||
self.activityButton.tintColor = UIColorFromRGB(0x8F918B);
|
||||
[self.activityButton setImageEdgeInsets:UIEdgeInsetsMake(4, 0, 4, 0)];
|
||||
[self.activityButton addTarget:self
|
||||
action:@selector(showInteractionsPopover:)
|
||||
forControlEvents:UIControlEventTouchUpInside];
|
||||
activitiesButton = [[UIBarButtonItem alloc]
|
||||
initWithCustomView:activityButton];
|
||||
initWithCustomView:self.activityButton];
|
||||
activitiesButton.width = 32;
|
||||
// activityButton.backgroundColor = UIColor.redColor;
|
||||
// self.activityButton.backgroundColor = UIColor.redColor;
|
||||
self.navigationItem.rightBarButtonItem = activitiesButton;
|
||||
|
||||
NSMutableDictionary *sortedFolders = [[NSMutableDictionary alloc] init];
|
||||
|
@ -901,7 +942,7 @@ static NSArray<NSString *> *NewsBlurTopSectionNames;
|
|||
[self refreshHeaderCounts];
|
||||
[appDelegate checkForFeedNotifications];
|
||||
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad && finished) {
|
||||
if (!self.isPhone && finished) {
|
||||
[self cacheFeedRowLocations];
|
||||
}
|
||||
|
||||
|
@ -1035,7 +1076,11 @@ static NSArray<NSString *> *NewsBlurTopSectionNames;
|
|||
appDelegate.activeUserProfileId = [NSString stringWithFormat:@"%@", [appDelegate.dictSocialProfile objectForKey:@"user_id"]];
|
||||
appDelegate.activeUserProfileName = [NSString stringWithFormat:@"%@", [appDelegate.dictSocialProfile objectForKey:@"username"]];
|
||||
// appDelegate.activeUserProfileName = @"You";
|
||||
[appDelegate showUserProfileModal:self.navigationItem.titleView];
|
||||
#if TARGET_OS_MACCATALYST
|
||||
[appDelegate showUserProfileModal:self.userAvatarButton];
|
||||
#else
|
||||
[appDelegate showUserProfileModal:self.navigationItem.titleView];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (IBAction)tapAddSite:(id)sender {
|
||||
|
@ -1056,9 +1101,11 @@ static NSArray<NSString *> *NewsBlurTopSectionNames;
|
|||
|
||||
MenuViewController *viewController = [MenuViewController new];
|
||||
|
||||
[viewController addTitle:@"Preferences" iconName:@"dialog-preferences" iconColor:UIColorFromRGB(0xDF8566) selectionShouldDismiss:YES handler:^{
|
||||
[self.appDelegate showPreferences];
|
||||
}];
|
||||
if (!self.isMac) {
|
||||
[viewController addTitle:@"Preferences" iconName:@"dialog-preferences" iconColor:UIColorFromRGB(0xDF8566) selectionShouldDismiss:YES handler:^{
|
||||
[self.appDelegate showPreferences];
|
||||
}];
|
||||
}
|
||||
|
||||
[viewController addTitle:@"Mute Sites" iconName:@"menu_icn_mute.png" selectionShouldDismiss:YES handler:^{
|
||||
[self.appDelegate showMuteSites];
|
||||
|
@ -1275,14 +1322,21 @@ static NSArray<NSString *> *NewsBlurTopSectionNames;
|
|||
[appDelegate.feedDetailViewController reloadWithSizing];
|
||||
}
|
||||
|
||||
- (void)systemAppearanceDidChange:(BOOL)isDark {
|
||||
[super systemAppearanceDidChange:isDark];
|
||||
|
||||
#if TARGET_OS_MACCATALYST
|
||||
if (ThemeManager.themeManager.isLikeSystem) {
|
||||
self.view.backgroundColor = UIColor.clearColor;
|
||||
} else {
|
||||
self.view.backgroundColor = UIColorFromRGB(0xf4f4f4);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)updateTheme {
|
||||
[super updateTheme];
|
||||
|
||||
// CATALYST: This prematurely dismisses the login view controller; is it really appropriate?
|
||||
// if (![self.presentedViewController isKindOfClass:[UINavigationController class]] || (((UINavigationController *)self.presentedViewController).topViewController != (UIViewController *)self.appDelegate.fontSettingsViewController && ![((UINavigationController *)self.presentedViewController).topViewController conformsToProtocol:@protocol(IASKViewController)])) {
|
||||
// [self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
|
||||
// }
|
||||
|
||||
[self.appDelegate hidePopoverAnimated:YES];
|
||||
|
||||
UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] initWithIdiom:[[UIDevice currentDevice] userInterfaceIdiom]];
|
||||
|
@ -1299,16 +1353,24 @@ static NSArray<NSString *> *NewsBlurTopSectionNames;
|
|||
self.feedViewToolbar.barTintColor = [UINavigationBar appearance].barTintColor;
|
||||
self.addBarButton.tintColor = UIColorFromRGB(0x8F918B);
|
||||
self.settingsBarButton.tintColor = UIColorFromRGB(0x8F918B);
|
||||
#if TARGET_OS_MACCATALYST
|
||||
if (ThemeManager.themeManager.isLikeSystem) {
|
||||
self.view.backgroundColor = UIColor.clearColor;
|
||||
} else {
|
||||
self.view.backgroundColor = UIColorFromRGB(0xf4f4f4);
|
||||
}
|
||||
#else
|
||||
self.refreshControl.tintColor = UIColorFromLightDarkRGB(0x0, 0xffffff);
|
||||
self.refreshControl.backgroundColor = UIColorFromRGB(0xE3E6E0);
|
||||
self.view.backgroundColor = UIColorFromRGB(0xf4f4f4);
|
||||
#endif
|
||||
|
||||
[[ThemeManager themeManager] updateSegmentedControl:self.intelligenceControl];
|
||||
|
||||
NBBarButtonItem *barButton = self.addBarButton.customView;
|
||||
[barButton setImage:[[ThemeManager themeManager] themedImage:[UIImage imageNamed:@"nav_icn_add.png"]] forState:UIControlStateNormal];
|
||||
|
||||
self.settingsBarButton.image = [Utilities imageNamed:@"settings" sized:30];
|
||||
self.settingsBarButton.image = [Utilities imageNamed:@"settings" sized:self.isMac ? 24 : 30];
|
||||
|
||||
[self layoutHeaderCounts:0];
|
||||
[self refreshHeaderCounts];
|
||||
|
@ -1327,6 +1389,7 @@ static NSArray<NSString *> *NewsBlurTopSectionNames;
|
|||
}
|
||||
|
||||
self.feedTitlesTable.backgroundColor = UIColorFromRGB(0xf4f4f4);
|
||||
|
||||
[self reloadFeedTitlesTable];
|
||||
|
||||
[self resetupGestures];
|
||||
|
@ -1682,7 +1745,7 @@ static NSArray<NSString *> *NewsBlurTopSectionNames;
|
|||
|
||||
- (CGFloat)calculateHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (appDelegate.hasNoSites) {
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!self.isPhone) {
|
||||
return kBlurblogTableViewRowHeight;
|
||||
} else {
|
||||
return kPhoneBlurblogTableViewRowHeight;
|
||||
|
@ -1726,13 +1789,13 @@ static NSArray<NSString *> *NewsBlurTopSectionNames;
|
|||
|
||||
if ([folderName isEqualToString:@"river_blurblogs"] ||
|
||||
[folderName isEqualToString:@"river_global"]) { // blurblogs
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!self.isPhone) {
|
||||
height = kBlurblogTableViewRowHeight;
|
||||
} else {
|
||||
height = kPhoneBlurblogTableViewRowHeight;
|
||||
}
|
||||
} else {
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!self.isPhone) {
|
||||
height = kTableViewRowHeight;
|
||||
} else {
|
||||
height = kPhoneTableViewRowHeight;
|
||||
|
@ -2386,6 +2449,10 @@ heightForHeaderInSection:(NSInteger)section {
|
|||
hud.mode = MBProgressHUDModeText;
|
||||
hud.removeFromSuperViewOnHide = YES;
|
||||
|
||||
if (!self.appDelegate.isPhone) {
|
||||
hud.xOffset = 50;
|
||||
}
|
||||
|
||||
NSIndexPath *topRow;
|
||||
if ([[self.feedTitlesTable indexPathsForVisibleRows] count]) {
|
||||
topRow = [[self.feedTitlesTable indexPathsForVisibleRows] objectAtIndex:0];
|
||||
|
@ -2452,7 +2519,7 @@ heightForHeaderInSection:(NSInteger)section {
|
|||
[hud hide:YES afterDelay:0.5];
|
||||
[self showExplainerOnEmptyFeedlist];
|
||||
|
||||
// if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
// if (!self.isPhone) {
|
||||
// FeedDetailViewController *storiesModule = self.appDelegate.dashboardViewController.storiesModule;
|
||||
//
|
||||
// storiesModule.storiesCollection.feedPage = 0;
|
||||
|
@ -2681,15 +2748,19 @@ heightForHeaderInSection:(NSInteger)section {
|
|||
#pragma mark -
|
||||
#pragma mark PullToRefresh
|
||||
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
- (void)refresh:(UIRefreshControl *)refreshControl {
|
||||
self.inPullToRefresh_ = YES;
|
||||
[appDelegate reloadFeedsView:NO];
|
||||
[appDelegate donateRefresh];
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)finishRefresh {
|
||||
self.inPullToRefresh_ = NO;
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
[self.refreshControl endRefreshing];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)refreshFeedList {
|
||||
|
@ -2814,6 +2885,11 @@ heightForHeaderInSection:(NSInteger)section {
|
|||
});
|
||||
}
|
||||
|
||||
//- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
|
||||
// NSLog(@"canPerformAction: %@ withSender: %@", NSStringFromSelector(action, sender); // log
|
||||
// return YES;
|
||||
//}
|
||||
|
||||
- (void)resetToolbar {
|
||||
// self.navigationItem.leftBarButtonItem = nil;
|
||||
self.navigationItem.titleView = nil;
|
||||
|
@ -2821,6 +2897,16 @@ heightForHeaderInSection:(NSInteger)section {
|
|||
}
|
||||
|
||||
- (void)layoutHeaderCounts:(UIInterfaceOrientation)orientation {
|
||||
#if TARGET_OS_MACCATALYST
|
||||
int xOffset = 60;
|
||||
int yOffset = 10;
|
||||
|
||||
[self.userInfoView removeFromSuperview];
|
||||
|
||||
self.userInfoView = [[UIView alloc]
|
||||
initWithFrame:CGRectMake(0, 0, self.innerView.bounds.size.width, 50)];
|
||||
self.userInfoView.backgroundColor = UIColorFromLightSepiaMediumDarkRGB(0xE0E0E0, 0xFFF8CA, 0x4F4F4F, 0x292B2C);
|
||||
#else
|
||||
if (!orientation) {
|
||||
orientation = self.view.window.windowScene.interfaceOrientation;
|
||||
}
|
||||
|
@ -2831,22 +2917,33 @@ heightForHeaderInSection:(NSInteger)section {
|
|||
isShort = YES;
|
||||
}
|
||||
|
||||
int xOffset = 50;
|
||||
int yOffset = isShort ? 0 : 6;
|
||||
UIView *userInfoView = [[UIView alloc]
|
||||
initWithFrame:CGRectMake(0, 0,
|
||||
self.navigationController.navigationBar.frame.size.width,
|
||||
self.navigationController.navigationBar.frame.size.height)];
|
||||
|
||||
self.userInfoView = [[UIView alloc]
|
||||
initWithFrame:CGRectMake(0, 0,
|
||||
self.navigationController.navigationBar.frame.size.width,
|
||||
self.navigationController.navigationBar.frame.size.height)];
|
||||
#endif
|
||||
|
||||
// adding user avatar to left
|
||||
NSURL *imageURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@",
|
||||
[appDelegate.dictSocialProfile
|
||||
objectForKey:@"large_photo_url"]]];
|
||||
userAvatarButton = [UIButton systemButtonWithImage:[UIImage imageNamed:@"user"]
|
||||
target:self action:@selector((showUserProfile))];
|
||||
target:self action:@selector(showUserProfile)];
|
||||
userAvatarButton.pointerInteractionEnabled = YES;
|
||||
userAvatarButton.accessibilityLabel = @"User info";
|
||||
#if TARGET_OS_MACCATALYST
|
||||
userAvatarButton.accessibilityHint = @"Double-click for information about your account.";
|
||||
CGRect frame = userAvatarButton.frame;
|
||||
userAvatarButton.frame = frame;
|
||||
#else
|
||||
userAvatarButton.accessibilityHint = @"Double-tap for information about your account.";
|
||||
UIEdgeInsets insets = UIEdgeInsetsMake(0, -10, 10, 0);
|
||||
userAvatarButton.contentEdgeInsets = insets;
|
||||
#endif
|
||||
// userAvatarButton.backgroundColor = UIColor.blueColor;
|
||||
|
||||
NSMutableURLRequest *avatarRequest = [NSMutableURLRequest requestWithURL:imageURL];
|
||||
[avatarRequest addValue:@"image/*" forHTTPHeaderField:@"Accept"];
|
||||
|
@ -2857,49 +2954,61 @@ heightForHeaderInSection:(NSInteger)section {
|
|||
typeof(weakSelf) __strong strongSelf = weakSelf;
|
||||
image = [Utilities roundCorneredImage:image radius:6 convertToSize:CGSizeMake(38, 38)];
|
||||
image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
|
||||
[(UIButton *)strongSelf.userAvatarButton setImage:image forState:UIControlStateNormal];
|
||||
|
||||
UIButton *button = strongSelf.userAvatarButton;
|
||||
[button setImage:image forState:UIControlStateNormal];
|
||||
} failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nonnull response, NSError * _Nonnull error) {
|
||||
NSLog(@"Could not fetch user avatar: %@", error);
|
||||
}];
|
||||
|
||||
[userInfoView addSubview:userAvatarButton];
|
||||
[self.userInfoView addSubview:userAvatarButton];
|
||||
|
||||
userLabel = [[UILabel alloc] initWithFrame:CGRectMake(50, yOffset, userInfoView.frame.size.width, 16)];
|
||||
userLabel = [[UILabel alloc] initWithFrame:CGRectMake(xOffset, yOffset, self.userInfoView.frame.size.width, 16)];
|
||||
userLabel.text = appDelegate.activeUsername;
|
||||
userLabel.font = userLabelFont;
|
||||
userLabel.textColor = UIColorFromRGB(0x404040);
|
||||
userLabel.backgroundColor = [UIColor clearColor];
|
||||
userLabel.accessibilityLabel = [NSString stringWithFormat:@"Logged in as %@", appDelegate.activeUsername];
|
||||
[userLabel sizeToFit];
|
||||
[userInfoView addSubview:userLabel];
|
||||
[self.userInfoView addSubview:userLabel];
|
||||
|
||||
[appDelegate.folderCountCache removeObjectForKey:@"everything"];
|
||||
yellowIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"g_icn_unread"]];
|
||||
[userInfoView addSubview:yellowIcon];
|
||||
[self.userInfoView addSubview:yellowIcon];
|
||||
yellowIcon.hidden = YES;
|
||||
|
||||
neutralCount = [[UILabel alloc] init];
|
||||
neutralCount.font = [UIFont fontWithName:@"WhitneySSm-Book" size:12];
|
||||
neutralCount.textColor = UIColorFromRGB(0x707070);
|
||||
neutralCount.backgroundColor = [UIColor clearColor];
|
||||
[userInfoView addSubview:neutralCount];
|
||||
[self.userInfoView addSubview:neutralCount];
|
||||
|
||||
greenIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"g_icn_focus"]];
|
||||
[userInfoView addSubview:greenIcon];
|
||||
[self.userInfoView addSubview:greenIcon];
|
||||
greenIcon.hidden = YES;
|
||||
|
||||
positiveCount = [[UILabel alloc] init];
|
||||
positiveCount.font = [UIFont fontWithName:@"WhitneySSm-Book" size:12];
|
||||
positiveCount.textColor = UIColorFromRGB(0x707070);
|
||||
positiveCount.backgroundColor = [UIColor clearColor];
|
||||
[userInfoView addSubview:positiveCount];
|
||||
[self.userInfoView addSubview:positiveCount];
|
||||
|
||||
[userInfoView sizeToFit];
|
||||
// self.userInfoView.backgroundColor = UIColor.blueColor;
|
||||
|
||||
// userInfoView.backgroundColor = UIColor.blueColor;
|
||||
#if TARGET_OS_MACCATALYST
|
||||
self.activityButton.frame = CGRectMake(self.innerView.bounds.size.width - 36, 10, 32, 32);
|
||||
|
||||
self.navigationItem.titleView = userInfoView;
|
||||
[self.userInfoView addSubview:self.activityButton];
|
||||
|
||||
[self.innerView addSubview:self.userInfoView];
|
||||
|
||||
self.activityButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
|
||||
self.userInfoView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||
|
||||
self.feedTitlesTopConstraint.constant = 50;
|
||||
#else
|
||||
[self.userInfoView sizeToFit];
|
||||
self.navigationItem.titleView = self.userInfoView;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)refreshHeaderCounts {
|
||||
|
@ -2908,6 +3017,12 @@ heightForHeaderInSection:(NSInteger)section {
|
|||
return;
|
||||
}
|
||||
|
||||
#if TARGET_OS_MACCATALYST
|
||||
int yOffset = 2;
|
||||
#else
|
||||
int yOffset = 0;
|
||||
#endif
|
||||
|
||||
userAvatarButton.hidden = NO;
|
||||
[appDelegate.folderCountCache removeObjectForKey:@"everything"];
|
||||
|
||||
|
@ -2924,13 +3039,13 @@ heightForHeaderInSection:(NSInteger)section {
|
|||
yellowIcon.frame = CGRectMake(CGRectGetMinX(userLabel.frame), CGRectGetMaxY(userLabel.frame) + 4, 8, 8);
|
||||
|
||||
neutralCount.frame = CGRectMake(CGRectGetMaxX(yellowIcon.frame) + 2,
|
||||
CGRectGetMinY(yellowIcon.frame) - 2, 100, 16);
|
||||
CGRectGetMinY(yellowIcon.frame) - 2 - yOffset, 100, 16);
|
||||
[neutralCount sizeToFit];
|
||||
|
||||
greenIcon.frame = CGRectMake(CGRectGetMaxX(neutralCount.frame) + 8,
|
||||
CGRectGetMinY(yellowIcon.frame), 8, 8);
|
||||
positiveCount.frame = CGRectMake(CGRectGetMaxX(greenIcon.frame) + 2,
|
||||
CGRectGetMinY(greenIcon.frame) - 2, 100, 16);
|
||||
CGRectGetMinY(greenIcon.frame) - 2 - yOffset, 100, 16);
|
||||
[positiveCount sizeToFit];
|
||||
|
||||
yellowIcon.hidden = NO;
|
||||
|
|
|
@ -11,11 +11,8 @@
|
|||
#import "NewsBlurAppDelegate.h"
|
||||
#import "NewsBlur-Swift.h"
|
||||
|
||||
@interface FirstTimeUserAddFriendsViewController : BaseViewController {
|
||||
NewsBlurAppDelegate *appDelegate;
|
||||
}
|
||||
@interface FirstTimeUserAddFriendsViewController : BaseViewController
|
||||
|
||||
@property (nonatomic) IBOutlet NewsBlurAppDelegate *appDelegate;
|
||||
@property (nonatomic) IBOutlet UIBarButtonItem *nextButton;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *facebookButton;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *twitterButton;
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
@implementation FirstTimeUserAddFriendsViewController
|
||||
|
||||
@synthesize appDelegate;
|
||||
@synthesize nextButton;
|
||||
@synthesize facebookButton;
|
||||
@synthesize twitterButton;
|
||||
|
@ -36,8 +35,6 @@
|
|||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
self.appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
|
||||
|
||||
UIBarButtonItem *next = [[UIBarButtonItem alloc] initWithTitle:@"Skip this step" style:UIBarButtonItemStyleDone target:self action:@selector(tapNextButton)];
|
||||
self.nextButton = next;
|
||||
self.navigationItem.rightBarButtonItem = next;
|
||||
|
@ -53,7 +50,7 @@
|
|||
|
||||
//- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||
// // Return YES for supported orientations
|
||||
// if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
// if (!self.isPhone) {
|
||||
// return YES;
|
||||
// } else if (UIInterfaceOrientationIsPortrait(interfaceOrientation)) {
|
||||
// return YES;
|
||||
|
|
|
@ -9,11 +9,8 @@
|
|||
#import <UIKit/UIKit.h>
|
||||
#import "NewsBlurAppDelegate.h"
|
||||
|
||||
@interface FirstTimeUserAddNewsBlurViewController : BaseViewController {
|
||||
NewsBlurAppDelegate *appDelegate;
|
||||
}
|
||||
@interface FirstTimeUserAddNewsBlurViewController : BaseViewController
|
||||
|
||||
@property (nonatomic) IBOutlet NewsBlurAppDelegate *appDelegate;
|
||||
@property (nonatomic) IBOutlet UIBarButtonItem *nextButton;
|
||||
@property (strong, nonatomic) IBOutlet UILabel *instructionsLabel;
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
@implementation FirstTimeUserAddNewsBlurViewController
|
||||
|
||||
@synthesize appDelegate;
|
||||
@synthesize nextButton;
|
||||
@synthesize instructionsLabel;
|
||||
|
||||
|
@ -27,8 +26,6 @@
|
|||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
self.appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
|
||||
|
||||
UIBarButtonItem *next = [[UIBarButtonItem alloc] initWithTitle:@"Start reading" style:UIBarButtonItemStyleDone target:self action:@selector(tapNextButton)];
|
||||
self.nextButton = next;
|
||||
self.navigationItem.rightBarButtonItem = next;
|
||||
|
@ -51,7 +48,7 @@
|
|||
|
||||
//- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||
// // Return YES for supported orientations
|
||||
// if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
// if (!self.isPhone) {
|
||||
// return YES;
|
||||
// } else if (UIInterfaceOrientationIsPortrait(interfaceOrientation)) {
|
||||
// return YES;
|
||||
|
|
|
@ -10,11 +10,8 @@
|
|||
#import "NewsBlurAppDelegate.h"
|
||||
|
||||
@interface FirstTimeUserAddSitesViewController : BaseViewController
|
||||
<UITableViewDataSource, UITableViewDelegate> {
|
||||
NewsBlurAppDelegate *appDelegate;
|
||||
}
|
||||
<UITableViewDataSource, UITableViewDelegate>
|
||||
|
||||
@property (nonatomic) IBOutlet NewsBlurAppDelegate *appDelegate;
|
||||
@property (nonatomic) IBOutlet UIButton *googleReaderButton;
|
||||
@property (nonatomic) IBOutlet UIView *googleReaderButtonWrapper;
|
||||
@property (nonatomic) IBOutlet UIBarButtonItem *nextButton;
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
|
||||
@implementation FirstTimeUserAddSitesViewController
|
||||
|
||||
@synthesize appDelegate;
|
||||
@synthesize googleReaderButton;
|
||||
@synthesize nextButton;
|
||||
@synthesize activityIndicator;
|
||||
|
@ -50,8 +49,6 @@
|
|||
|
||||
[super viewDidLoad];
|
||||
|
||||
self.appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
|
||||
|
||||
UIBarButtonItem *next = [[UIBarButtonItem alloc] initWithTitle:@"Next step" style:UIBarButtonItemStyleDone target:self action:@selector(tapNextButton)];
|
||||
self.nextButton = next;
|
||||
self.nextButton.enabled = YES;
|
||||
|
@ -89,7 +86,7 @@
|
|||
|
||||
//- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||
// // Return YES for supported orientations
|
||||
// if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
// if (!self.isPhone) {
|
||||
// return YES;
|
||||
// } else if (UIInterfaceOrientationIsPortrait(interfaceOrientation)) {
|
||||
// return YES;
|
||||
|
|
|
@ -98,7 +98,7 @@
|
|||
|
||||
//- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||
// // Return YES for supported orientations
|
||||
// if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
// if (!self.isPhone) {
|
||||
// return YES;
|
||||
// } else if (UIInterfaceOrientationIsPortrait(interfaceOrientation)) {
|
||||
// return YES;
|
||||
|
|
|
@ -213,7 +213,7 @@
|
|||
|
||||
if (section == NewsBlurTopSectionInfrequentSiteStories) {
|
||||
folderImage = [UIImage imageNamed:@"ak-icon-infrequent.png"];
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!appDelegate.isPhone) {
|
||||
folderImageViewX = 10;
|
||||
} else {
|
||||
folderImageViewX = 7;
|
||||
|
@ -221,7 +221,7 @@
|
|||
allowLongPress = YES;
|
||||
} else if (section == NewsBlurTopSectionAllStories) {
|
||||
folderImage = [UIImage imageNamed:@"all-stories"];
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!appDelegate.isPhone) {
|
||||
folderImageViewX = 10;
|
||||
} else {
|
||||
folderImageViewX = 7;
|
||||
|
@ -229,42 +229,42 @@
|
|||
allowLongPress = NO;
|
||||
} else if ([folderName isEqual:@"river_global"]) {
|
||||
folderImage = [UIImage imageNamed:@"global-shares"];
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!appDelegate.isPhone) {
|
||||
folderImageViewX = 10;
|
||||
} else {
|
||||
folderImageViewX = 8;
|
||||
}
|
||||
} else if ([folderName isEqual:@"river_blurblogs"]) {
|
||||
folderImage = [UIImage imageNamed:@"all-shares"];
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!appDelegate.isPhone) {
|
||||
folderImageViewX = 10;
|
||||
} else {
|
||||
folderImageViewX = 8;
|
||||
}
|
||||
} else if ([folderName isEqual:@"saved_searches"]) {
|
||||
folderImage = [UIImage imageNamed:@"search"];
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!appDelegate.isPhone) {
|
||||
folderImageViewX = 10;
|
||||
} else {
|
||||
folderImageViewX = 7;
|
||||
}
|
||||
} else if ([folderName isEqual:@"saved_stories"]) {
|
||||
folderImage = [UIImage imageNamed:@"saved-stories"];
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!appDelegate.isPhone) {
|
||||
folderImageViewX = 10;
|
||||
} else {
|
||||
folderImageViewX = 7;
|
||||
}
|
||||
} else if ([folderName isEqual:@"read_stories"]) {
|
||||
folderImage = [UIImage imageNamed:@"indicator-unread"];
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!appDelegate.isPhone) {
|
||||
folderImageViewX = 10;
|
||||
} else {
|
||||
folderImageViewX = 7;
|
||||
}
|
||||
} else if ([folderName isEqual:@"widget_stories"]) {
|
||||
folderImage = [UIImage imageNamed:@"g_icn_folder_widget.png"];
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!appDelegate.isPhone) {
|
||||
folderImageViewX = 10;
|
||||
} else {
|
||||
folderImageViewX = 7;
|
||||
|
@ -275,7 +275,7 @@
|
|||
} else {
|
||||
folderImage = [UIImage imageNamed:@"folder-open"];
|
||||
}
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!appDelegate.isPhone) {
|
||||
} else {
|
||||
folderImageViewX = 7;
|
||||
}
|
||||
|
|
|
@ -439,7 +439,9 @@
|
|||
[self.fontSizeSegment setTitle:@"M" forSegmentAtIndex:2];
|
||||
[self.fontSizeSegment setTitle:@"L" forSegmentAtIndex:3];
|
||||
[self.fontSizeSegment setTitle:@"XL" forSegmentAtIndex:4];
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
self.fontSizeSegment.backgroundColor = UIColorFromRGB(0xeeeeee);
|
||||
#endif
|
||||
[self.fontSizeSegment setTitleTextAttributes:@{NSFontAttributeName:[UIFont fontWithName:@"WhitneySSm-Medium" size:12.0f]} forState:UIControlStateNormal];
|
||||
[self.fontSizeSegment setContentOffset:CGSizeMake(0, 1) forSegmentAtIndex:0];
|
||||
[self.fontSizeSegment setContentOffset:CGSizeMake(0, 1) forSegmentAtIndex:1];
|
||||
|
@ -467,7 +469,9 @@
|
|||
[self.lineSpacingSegment setImage:[UIImage imageNamed:@"line_spacing_m"] forSegmentAtIndex:2];
|
||||
[self.lineSpacingSegment setImage:[UIImage imageNamed:@"line_spacing_l"] forSegmentAtIndex:3];
|
||||
[self.lineSpacingSegment setImage:[UIImage imageNamed:@"line_spacing_xl"] forSegmentAtIndex:4];
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
self.lineSpacingSegment.backgroundColor = UIColorFromRGB(0xeeeeee);
|
||||
#endif
|
||||
|
||||
[[ThemeManager themeManager] updateSegmentedControl:self.lineSpacingSegment];
|
||||
|
||||
|
@ -486,7 +490,9 @@
|
|||
self.fullscreenSegment.frame = CGRectMake(8, 7, cell.frame.size.width - 8*2, kMenuOptionHeight - 7*2);
|
||||
[self.fullscreenSegment setTitle:@"Full Screen" forSegmentAtIndex:0];
|
||||
[self.fullscreenSegment setTitle:@"Toolbar" forSegmentAtIndex:1];
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
self.fullscreenSegment.backgroundColor = UIColorFromRGB(0xeeeeee);
|
||||
#endif
|
||||
[self.fullscreenSegment setTitleTextAttributes:@{NSFontAttributeName:[UIFont fontWithName:@"WhitneySSm-Medium" size:12.0f]} forState:UIControlStateNormal];
|
||||
[self.fullscreenSegment setContentOffset:CGSizeMake(0, 1) forSegmentAtIndex:0];
|
||||
[self.fullscreenSegment setContentOffset:CGSizeMake(0, 1) forSegmentAtIndex:1];
|
||||
|
@ -508,7 +514,9 @@
|
|||
self.autoscrollSegment.frame = CGRectMake(8, 7, cell.frame.size.width - 8*2, kMenuOptionHeight - 7*2);
|
||||
[self.autoscrollSegment setTitle:@"Manual scroll" forSegmentAtIndex:0];
|
||||
[self.autoscrollSegment setTitle:@"Auto scroll" forSegmentAtIndex:1];
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
self.autoscrollSegment.backgroundColor = UIColorFromRGB(0xeeeeee);
|
||||
#endif
|
||||
[self.autoscrollSegment setTitleTextAttributes:@{NSFontAttributeName:[UIFont fontWithName:@"WhitneySSm-Medium" size:12.0f]} forState:UIControlStateNormal];
|
||||
[self.autoscrollSegment setContentOffset:CGSizeMake(0, 1) forSegmentAtIndex:0];
|
||||
[self.autoscrollSegment setContentOffset:CGSizeMake(0, 1) forSegmentAtIndex:1];
|
||||
|
@ -530,7 +538,9 @@
|
|||
self.scrollOrientationSegment.frame = CGRectMake(8, 7, cell.frame.size.width - 8*2, kMenuOptionHeight - 7*2);
|
||||
[self.scrollOrientationSegment setTitle:@"⏩ Horizontal" forSegmentAtIndex:0];
|
||||
[self.scrollOrientationSegment setTitle:@"⏬ Vertical" forSegmentAtIndex:1];
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
self.scrollOrientationSegment.backgroundColor = UIColorFromRGB(0xeeeeee);
|
||||
#endif
|
||||
[self.scrollOrientationSegment setTitleTextAttributes:@{NSFontAttributeName:[UIFont fontWithName:@"WhitneySSm-Medium" size:12.0f]} forState:UIControlStateNormal];
|
||||
[self.scrollOrientationSegment setContentOffset:CGSizeMake(0, 1) forSegmentAtIndex:0];
|
||||
[self.scrollOrientationSegment setContentOffset:CGSizeMake(0, 1) forSegmentAtIndex:1];
|
||||
|
@ -566,7 +576,9 @@
|
|||
|
||||
[self.themeSegment setDividerImage:blankImage forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
|
||||
self.themeSegment.tintColor = [UIColor clearColor];
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
self.themeSegment.backgroundColor = [UIColor clearColor];
|
||||
#endif
|
||||
|
||||
[[ThemeManager themeManager] updateThemeSegmentedControl:self.themeSegment];
|
||||
|
||||
|
@ -580,7 +592,14 @@
|
|||
name = [name stringByAppendingString:@"-sel"];
|
||||
}
|
||||
|
||||
return [[UIImage imageNamed:name] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
|
||||
UIImage *image = [[UIImage imageNamed:name] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
|
||||
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomMac) {
|
||||
image = [Utilities imageWithImage:image convertToSize:CGSizeMake(20.0, 20.0)];
|
||||
image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
@class NewsBlurAppDelegate;
|
||||
|
||||
@interface FriendsListViewController : BaseViewController <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate> {
|
||||
NewsBlurAppDelegate *appDelegate;
|
||||
UISearchBar *friendSearchBar;
|
||||
UITableView *friendsTable;
|
||||
NSArray *suggestedUserProfiles;
|
||||
|
@ -21,7 +20,6 @@
|
|||
NSArray *userProfileIds;
|
||||
}
|
||||
|
||||
@property (nonatomic) IBOutlet NewsBlurAppDelegate *appDelegate;
|
||||
@property (nonatomic) IBOutlet UISearchBar *friendSearchBar;
|
||||
@property (nonatomic) IBOutlet UITableView *friendsTable;
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
|
||||
@implementation FriendsListViewController
|
||||
|
||||
@synthesize appDelegate;
|
||||
@synthesize friendSearchBar;
|
||||
@synthesize friendsTable;
|
||||
@synthesize suggestedUserProfiles;
|
||||
|
@ -45,8 +44,6 @@
|
|||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
self.appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
|
||||
|
||||
self.navigationItem.title = @"Find Friends";
|
||||
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle: @"Done"
|
||||
style: UIBarButtonItemStylePlain
|
||||
|
@ -156,7 +153,7 @@
|
|||
// if (self.inSearch_){
|
||||
// return 0;
|
||||
// } else {
|
||||
// if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad){
|
||||
// if (!self.isPhone){
|
||||
// return 28;
|
||||
// }else{
|
||||
// return 21;
|
||||
|
@ -168,7 +165,7 @@
|
|||
viewForHeaderInSection:(NSInteger)section {
|
||||
int headerLabelHeight, folderImageViewY;
|
||||
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!self.isPhone) {
|
||||
headerLabelHeight = 28;
|
||||
folderImageViewY = 3;
|
||||
} else {
|
||||
|
@ -280,7 +277,7 @@ viewForHeaderInSection:(NSInteger)section {
|
|||
|
||||
// add a NO FRIENDS TO SUGGEST message on either the first or second row depending on iphone/ipad
|
||||
int row = 0;
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!self.isPhone) {
|
||||
row = 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -154,7 +154,7 @@
|
|||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSInteger userInteractions = [appDelegate.userInteractionsArray count];
|
||||
int minimumHeight;
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!appDelegate.isPhone) {
|
||||
minimumHeight = MINIMUM_INTERACTION_HEIGHT_IPAD;
|
||||
} else {
|
||||
minimumHeight = MINIMUM_INTERACTION_HEIGHT_IPHONE;
|
||||
|
@ -165,7 +165,7 @@
|
|||
}
|
||||
|
||||
InteractionCell *interactionCell;
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!appDelegate.isPhone) {
|
||||
interactionCell = [[InteractionCell alloc] init];
|
||||
} else {
|
||||
interactionCell = [[SmallInteractionCell alloc] init];
|
||||
|
@ -190,7 +190,7 @@
|
|||
InteractionCell *cell = [tableView
|
||||
dequeueReusableCellWithIdentifier:@"InteractionCell"];
|
||||
if (cell == nil) {
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!appDelegate.isPhone) {
|
||||
cell = [[InteractionCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"InteractionCell"];
|
||||
} else {
|
||||
cell = [[SmallInteractionCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"InteractionCell"];
|
||||
|
@ -276,7 +276,7 @@
|
|||
UIImageView *fleuron = [[UIImageView alloc] initWithImage:img];
|
||||
|
||||
int height;
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!appDelegate.isPhone) {
|
||||
height = MINIMUM_INTERACTION_HEIGHT_IPAD;
|
||||
} else {
|
||||
height = MINIMUM_INTERACTION_HEIGHT_IPHONE;
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
#define LANDSCAPE_MARGIN 128
|
||||
|
||||
@interface LoginViewController : BaseViewController {
|
||||
NewsBlurAppDelegate *appDelegate;
|
||||
|
||||
BOOL isOnSignUpScreen;
|
||||
UITextField *usernameInput;
|
||||
UITextField *passwordInput;
|
||||
|
@ -46,8 +44,6 @@
|
|||
|
||||
- (void)animateLoop;
|
||||
|
||||
@property (nonatomic) IBOutlet NewsBlurAppDelegate *appDelegate;
|
||||
|
||||
@property (nonatomic) IBOutlet UITextField *usernameInput;
|
||||
@property (nonatomic) IBOutlet UITextField *passwordInput;
|
||||
@property (nonatomic) IBOutlet UITextField *emailInput;
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
@implementation LoginViewController
|
||||
|
||||
@synthesize appDelegate;
|
||||
@synthesize usernameInput;
|
||||
@synthesize passwordInput;
|
||||
@synthesize emailInput;
|
||||
|
@ -44,8 +43,6 @@
|
|||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
self.appDelegate = NewsBlurAppDelegate.sharedAppDelegate;
|
||||
|
||||
self.usernameInput.borderStyle = UITextBorderStyleRoundedRect;
|
||||
self.passwordInput.borderStyle = UITextBorderStyleRoundedRect;
|
||||
self.emailInput.borderStyle = UITextBorderStyleRoundedRect;
|
||||
|
@ -71,7 +68,7 @@
|
|||
}
|
||||
|
||||
- (void)rearrangeViews {
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!self.isPhone) {
|
||||
CGSize viewSize = self.view.bounds.size;
|
||||
CGFloat viewWidth = viewSize.width;
|
||||
CGFloat yOffset = 0;
|
||||
|
@ -98,7 +95,7 @@
|
|||
|
||||
//- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||
// // Return YES for supported orientations
|
||||
// if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
// if (!self.isPhone) {
|
||||
// return YES;
|
||||
// }
|
||||
// return NO;
|
||||
|
@ -108,7 +105,7 @@
|
|||
[MBProgressHUD hideHUDForView:self.view animated:YES];
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!self.isPhone) {
|
||||
[self updateControls];
|
||||
[self rearrangeViews];
|
||||
}
|
||||
|
@ -141,7 +138,7 @@
|
|||
self.errorLabel.hidden = !hasError;
|
||||
self.forgotPasswordButton.hidden = !hasError;
|
||||
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!self.isPhone) {
|
||||
self.loginOptionalLabel.hidden = hasError;
|
||||
}
|
||||
}
|
||||
|
@ -166,7 +163,7 @@
|
|||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
|
||||
[textField resignFirstResponder];
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!self.isPhone) {
|
||||
if(textField == usernameInput) {
|
||||
[passwordInput becomeFirstResponder];
|
||||
} else if (textField == passwordInput) {
|
||||
|
@ -244,7 +241,7 @@
|
|||
setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
|
||||
|
||||
NSMutableDictionary *params = [NSMutableDictionary dictionary];
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!self.isPhone) {
|
||||
[params setObject:[signUpUsernameInput text] forKey:@"username"];
|
||||
[params setObject:[signUpPasswordInput text] forKey:@"password"];
|
||||
} else {
|
||||
|
|
|
@ -7,11 +7,12 @@
|
|||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "BaseViewController.h"
|
||||
|
||||
typedef void (^MenuItemHandler)(void);
|
||||
typedef void (^MenuItemSegmentedHandler)(NSUInteger selectedIndex);
|
||||
|
||||
@interface MenuViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
|
||||
@interface MenuViewController : BaseViewController <UITableViewDataSource, UITableViewDelegate>
|
||||
|
||||
@property (weak) IBOutlet UITableView *menuTableView;
|
||||
|
||||
|
@ -29,5 +30,6 @@ typedef void (^MenuItemSegmentedHandler)(NSUInteger selectedIndex);
|
|||
|
||||
- (void)showFromNavigationController:(UINavigationController *)navigationController barButtonItem:(UIBarButtonItem *)barButtonItem;
|
||||
- (void)showFromNavigationController:(UINavigationController *)navigationController barButtonItem:(UIBarButtonItem *)barButtonItem permittedArrowDirections:(UIPopoverArrowDirection)permittedArrowDirections;
|
||||
- (void)showFromNavigationController:(UINavigationController *)navigationController barButtonItem:(UIBarButtonItem *)barButtonItem sourceView:(UIView *)sourceView sourceRect:(CGRect)sourceRect permittedArrowDirections:(UIPopoverArrowDirection)permittedArrowDirections;
|
||||
|
||||
@end
|
||||
|
|
|
@ -157,7 +157,14 @@ NSString * const MenuHandler = @"handler";
|
|||
name = [name stringByAppendingString:@"-sel"];
|
||||
}
|
||||
|
||||
return [[UIImage imageNamed:name] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
|
||||
UIImage *image = [[UIImage imageNamed:name] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
|
||||
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomMac) {
|
||||
image = [Utilities imageWithImage:image convertToSize:CGSizeMake(20.0, 20.0)];
|
||||
image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)makeThemeSegmentedTableCell {
|
||||
|
@ -197,7 +204,9 @@ NSString * const MenuHandler = @"handler";
|
|||
|
||||
[segmentedControl setDividerImage:blankImage forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
|
||||
segmentedControl.tintColor = [UIColor clearColor];
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
segmentedControl.backgroundColor = [UIColor clearColor];
|
||||
#endif
|
||||
|
||||
segmentedControl.selectedSegmentIndex = valueIndex;
|
||||
|
||||
|
@ -243,7 +252,9 @@ NSString * const MenuHandler = @"handler";
|
|||
segmentedControl.apportionsSegmentWidthsByContent = YES;
|
||||
segmentedControl.selectedSegmentIndex = [item[MenuSegmentIndex] integerValue];
|
||||
segmentedControl.tag = row;
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
segmentedControl.backgroundColor = UIColorFromRGB(0xeeeeee);
|
||||
#endif
|
||||
[segmentedControl setTitleTextAttributes:@{NSFontAttributeName : [UIFont fontWithName:@"WhitneySSm-Medium" size:12.0]} forState:UIControlStateNormal];
|
||||
[segmentedControl addTarget:self action:@selector(segmentedValueChanged:) forControlEvents:UIControlEventValueChanged];
|
||||
|
||||
|
@ -277,6 +288,10 @@ NSString * const MenuHandler = @"handler";
|
|||
}
|
||||
|
||||
- (void)showFromNavigationController:(UINavigationController *)navigationController barButtonItem:(UIBarButtonItem *)barButtonItem permittedArrowDirections:(UIPopoverArrowDirection)permittedArrowDirections {
|
||||
[self showFromNavigationController:navigationController barButtonItem:barButtonItem sourceView:nil sourceRect:CGRectZero permittedArrowDirections:permittedArrowDirections];
|
||||
}
|
||||
|
||||
- (void)showFromNavigationController:(UINavigationController *)navigationController barButtonItem:(UIBarButtonItem *)barButtonItem sourceView:(UIView *)sourceView sourceRect:(CGRect)sourceRect permittedArrowDirections:(UIPopoverArrowDirection)permittedArrowDirections {
|
||||
UIViewController *presentedViewController = navigationController.presentedViewController;
|
||||
if (presentedViewController && presentedViewController.presentationController.presentationStyle == UIModalPresentationPopover) {
|
||||
[presentedViewController dismissViewControllerAnimated:YES completion:nil];
|
||||
|
@ -293,6 +308,8 @@ NSString * const MenuHandler = @"handler";
|
|||
popoverPresentationController.backgroundColor = UIColorFromRGB(NEWSBLUR_WHITE_COLOR);
|
||||
popoverPresentationController.permittedArrowDirections = permittedArrowDirections;
|
||||
popoverPresentationController.barButtonItem = barButtonItem;
|
||||
popoverPresentationController.sourceView = sourceView;
|
||||
popoverPresentationController.sourceRect = sourceRect;
|
||||
|
||||
[navigationController presentViewController:embeddedNavController animated:YES completion:nil];
|
||||
}
|
||||
|
|
|
@ -9,16 +9,12 @@
|
|||
#import <UIKit/UIKit.h>
|
||||
#import "NewsBlurAppDelegate.h"
|
||||
|
||||
@class NewsBlurAppDelegate;
|
||||
|
||||
@interface FolderTextField : UITextField
|
||||
|
||||
@end
|
||||
|
||||
@interface MoveSiteViewController : BaseViewController
|
||||
<UITextFieldDelegate, UIPickerViewDelegate, UIPickerViewDataSource> {
|
||||
NewsBlurAppDelegate *appDelegate;
|
||||
}
|
||||
<UITextFieldDelegate, UIPickerViewDelegate, UIPickerViewDataSource>
|
||||
|
||||
- (void)reload;
|
||||
- (IBAction)moveSite;
|
||||
|
@ -27,7 +23,6 @@
|
|||
- (IBAction)doMoveButton;
|
||||
- (NSArray *)pickerFolders;
|
||||
|
||||
@property (nonatomic) IBOutlet NewsBlurAppDelegate *appDelegate;
|
||||
@property (nonatomic) IBOutlet UITextField *fromFolderInput;
|
||||
@property (nonatomic) IBOutlet FolderTextField *toFolderInput;
|
||||
@property (nonatomic) IBOutlet UILabel *titleLabel;
|
||||
|
|
|
@ -7,13 +7,11 @@
|
|||
//
|
||||
|
||||
#import "MoveSiteViewController.h"
|
||||
#import "NewsBlurAppDelegate.h"
|
||||
#import "StringHelper.h"
|
||||
#import "StoriesCollection.h"
|
||||
|
||||
@implementation MoveSiteViewController
|
||||
|
||||
@synthesize appDelegate;
|
||||
@synthesize toFolderInput;
|
||||
@synthesize fromFolderInput;
|
||||
@synthesize titleLabel;
|
||||
|
@ -34,8 +32,6 @@
|
|||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
self.appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
|
||||
|
||||
UIImageView *folderImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"folder-open"]];
|
||||
folderImage.frame = CGRectMake(0, 0, 24, 16);
|
||||
[folderImage setContentMode:UIViewContentModeRight];
|
||||
|
@ -54,14 +50,12 @@
|
|||
frame.size.height += 20;
|
||||
self.navBar.frame = frame;
|
||||
|
||||
appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
|
||||
|
||||
[super viewDidLoad];
|
||||
}
|
||||
|
||||
//- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||
// // Return YES for supported orientations
|
||||
// if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
// if (!self.isPhone) {
|
||||
// return YES;
|
||||
// } else if (UIInterfaceOrientationIsPortrait(interfaceOrientation)) {
|
||||
// return YES;
|
||||
|
|
|
@ -287,7 +287,6 @@ SFSafariViewControllerDelegate> {
|
|||
@property (nonatomic, readwrite) BOOL hasQueuedReadStories;
|
||||
@property (nonatomic, readwrite) BOOL hasQueuedSavedStories;
|
||||
@property (nonatomic, readonly) BOOL showingSafariViewController;
|
||||
@property (nonatomic, readonly) BOOL isCompactWidth;
|
||||
//@property (nonatomic) CGFloat compactWidth;
|
||||
|
||||
@property (nonatomic, strong) BGAppRefreshTask *backgroundAppRefreshTask;
|
||||
|
@ -296,6 +295,9 @@ SFSafariViewControllerDelegate> {
|
|||
|
||||
- (void)registerDefaultsFromSettingsBundle;
|
||||
- (void)finishBackground;
|
||||
- (void)prepareViewControllers;
|
||||
|
||||
- (BOOL)openURL:(NSURL *)url;
|
||||
|
||||
- (void)showFirstTimeUser;
|
||||
- (void)showLogin;
|
||||
|
@ -395,7 +397,6 @@ SFSafariViewControllerDelegate> {
|
|||
- (BOOL)isSavedStoriesIntelligenceMode;
|
||||
- (NSArray *)allFeedIds;
|
||||
- (NSArray *)feedIdsForFolderTitle:(NSString *)folderTitle;
|
||||
- (BOOL)isPortrait;
|
||||
- (void)confirmLogout;
|
||||
- (void)showConnectToService:(NSString *)serviceName;
|
||||
- (void)showAlert:(UIAlertController *)alert withViewController:(UIViewController *)vc;
|
||||
|
@ -439,6 +440,7 @@ SFSafariViewControllerDelegate> {
|
|||
- (void)renameFolder:(NSString *)newTitle;
|
||||
|
||||
- (void)showMarkReadMenuWithFeedIds:(NSArray *)feedIds collectionTitle:(NSString *)collectionTitle visibleUnreadCount:(NSInteger)visibleUnreadCount barButtonItem:(UIBarButtonItem *)barButtonItem completionHandler:(void (^)(BOOL marked))completionHandler;
|
||||
- (void)showMarkReadMenuWithFeedIds:(NSArray *)feedIds collectionTitle:(NSString *)collectionTitle visibleUnreadCount:(NSInteger)visibleUnreadCount sourceView:(UIView *)sourceView sourceRect:(CGRect)sourceRect completionHandler:(void (^)(BOOL marked))completionHandler;
|
||||
- (void)showMarkReadMenuWithFeedIds:(NSArray *)feedIds collectionTitle:(NSString *)collectionTitle sourceView:(UIView *)sourceView sourceRect:(CGRect)sourceRect completionHandler:(void (^)(BOOL marked))completionHandler;
|
||||
- (void)showMarkOlderNewerReadMenuWithStoriesCollection:(StoriesCollection *)olderNewerCollection story:(NSDictionary *)olderNewerStory sourceView:(UIView *)sourceView sourceRect:(CGRect)sourceRect extraItems:(NSArray *)extraItems completionHandler:(void (^)(BOOL marked))completionHandler;
|
||||
|
||||
|
@ -446,6 +448,7 @@ SFSafariViewControllerDelegate> {
|
|||
- (void)showPopoverWithViewController:(UIViewController *)viewController contentSize:(CGSize)contentSize barButtonItem:(UIBarButtonItem *)barButtonItem;
|
||||
- (void)showPopoverWithViewController:(UIViewController *)viewController contentSize:(CGSize)contentSize sourceView:(UIView *)sourceView sourceRect:(CGRect)sourceRect;
|
||||
- (void)showPopoverWithViewController:(UIViewController *)viewController contentSize:(CGSize)contentSize sourceView:(UIView *)sourceView sourceRect:(CGRect)sourceRect permittedArrowDirections:(UIPopoverArrowDirection)permittedArrowDirections;
|
||||
|
||||
- (void)hidePopoverAnimated:(BOOL)animated completion:(void (^)(void))completion;
|
||||
- (BOOL)hidePopoverAnimated:(BOOL)animated;
|
||||
- (void)hidePopover;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,11 +13,9 @@
|
|||
@class NewsBlurAppDelegate;
|
||||
|
||||
@interface NotificationsViewController : BaseViewController <UITableViewDelegate, UITableViewDataSource> {
|
||||
NewsBlurAppDelegate *appDelegate;
|
||||
NSArray *notificationFeedIds;
|
||||
}
|
||||
|
||||
@property (nonatomic) IBOutlet NewsBlurAppDelegate *appDelegate;
|
||||
@property (nonatomic) IBOutlet UITableView *notificationsTable;
|
||||
@property (nonatomic) NSString *feedId;
|
||||
|
||||
|
|
|
@ -16,14 +16,11 @@
|
|||
@implementation NotificationsViewController
|
||||
|
||||
@synthesize notificationsTable;
|
||||
@synthesize appDelegate;
|
||||
@synthesize feedId;
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
self.appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
|
||||
|
||||
self.navigationItem.title = @"Notifications";
|
||||
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle: @"Done"
|
||||
style: UIBarButtonItemStylePlain
|
||||
|
@ -31,9 +28,6 @@
|
|||
action: @selector(doCancelButton)];
|
||||
[self.navigationItem setRightBarButtonItem:cancelButton];
|
||||
|
||||
// Do any additional setup after loading the view from its nib.
|
||||
self.appDelegate = (NewsBlurAppDelegate *)[[UIApplication sharedApplication] delegate];
|
||||
|
||||
notificationsTable = [[UITableView alloc] init];
|
||||
notificationsTable.delegate = self;
|
||||
notificationsTable.dataSource = self;
|
||||
|
@ -85,7 +79,7 @@
|
|||
viewForHeaderInSection:(NSInteger)section {
|
||||
int headerLabelHeight, folderImageViewY;
|
||||
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!self.isPhone) {
|
||||
headerLabelHeight = 36;
|
||||
folderImageViewY = 8;
|
||||
} else {
|
||||
|
|
|
@ -10,13 +10,10 @@
|
|||
#import "BaseViewController.h"
|
||||
#import <WebKit/WebKit.h>
|
||||
|
||||
@class NewsBlurAppDelegate;
|
||||
|
||||
@interface OriginalStoryViewController : BaseViewController
|
||||
<UITextFieldDelegate, WKNavigationDelegate, WKUIDelegate,
|
||||
UIGestureRecognizerDelegate> {
|
||||
|
||||
NewsBlurAppDelegate *appDelegate;
|
||||
NSString *activeUrl;
|
||||
NSMutableArray *visitedUrls;
|
||||
WKWebView *webView;
|
||||
|
@ -27,7 +24,6 @@ UIGestureRecognizerDelegate> {
|
|||
BOOL finishedLoading;
|
||||
}
|
||||
|
||||
@property (nonatomic) IBOutlet NewsBlurAppDelegate *appDelegate;
|
||||
@property (nonatomic) IBOutlet WKWebView *webView;
|
||||
//@property (strong, nonatomic) SloppySwiper *swiper;
|
||||
@property (nonatomic) UIProgressView *progressView;
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
@implementation OriginalStoryViewController
|
||||
|
||||
@synthesize appDelegate;
|
||||
@synthesize webView;
|
||||
//@synthesize swiper;
|
||||
@synthesize progressView;
|
||||
|
@ -25,14 +24,12 @@
|
|||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
self.appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
|
||||
|
||||
self.view.layer.masksToBounds = NO;
|
||||
self.view.layer.shadowRadius = 5;
|
||||
self.view.layer.shadowOpacity = 0.5;
|
||||
self.view.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.view.bounds].CGPath;
|
||||
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!self.isPhone) {
|
||||
closeButton = [UIBarButtonItem barItemWithImage:[UIImage imageNamed:@"ios7_back_button"]
|
||||
target:self
|
||||
action:@selector(closeOriginalView)];
|
||||
|
@ -70,7 +67,7 @@
|
|||
// UIGestureRecognizer *themeGesture = [[ThemeManager themeManager] addThemeGestureRecognizerToView:self.webView];
|
||||
// [self.webView.scrollView.panGestureRecognizer requireGestureRecognizerToFail:themeGesture];
|
||||
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!self.isPhone) {
|
||||
UIPanGestureRecognizer *gesture = [[UIPanGestureRecognizer alloc]
|
||||
initWithTarget:self action:@selector(handlePanGesture:)];
|
||||
gesture.delegate = self;
|
||||
|
@ -215,7 +212,7 @@
|
|||
center.y);
|
||||
self.view.center = center;
|
||||
[recognizer setTranslation:CGPointZero inView:self.view];
|
||||
// if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
// if (!self.isPhone) {
|
||||
// [appDelegate.masterContainerViewController interactiveTransitionFromOriginalView:percentage];
|
||||
// } else {
|
||||
//
|
||||
|
@ -231,7 +228,7 @@
|
|||
[self transitionToFeedDetail:recognizer];
|
||||
} else {
|
||||
// NSLog(@"Original velocity: %f (at %.2f%%)", velocity, percentage*100);
|
||||
// if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
// if (!self.isPhone) {
|
||||
// [appDelegate.masterContainerViewController transitionToOriginalView:NO];
|
||||
// } else {
|
||||
//
|
||||
|
@ -241,7 +238,7 @@
|
|||
}
|
||||
|
||||
- (void)transitionToFeedDetail:(UIGestureRecognizer *)recognizer {
|
||||
// if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
// if (!self.isPhone) {
|
||||
// [appDelegate.masterContainerViewController transitionFromOriginalView];
|
||||
// } else {
|
||||
//
|
||||
|
@ -365,7 +362,7 @@
|
|||
|
||||
- (void)updateTitle:(WKWebView*)aWebView
|
||||
{
|
||||
if (self.customPageTitle != nil) {
|
||||
if (self.customPageTitle.length > 0) {
|
||||
titleView.text = self.customPageTitle;
|
||||
} else {
|
||||
NSString *pageTitleValue = webView.title;
|
||||
|
@ -373,6 +370,10 @@
|
|||
}
|
||||
|
||||
[titleView sizeToFit];
|
||||
|
||||
#if TARGET_OS_MACCATALYST
|
||||
self.view.window.windowScene.title = titleView.text;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (IBAction)loadAddress:(id)sender {
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
@interface PremiumViewController : BaseViewController <UITableViewDelegate, UITableViewDataSource>
|
||||
|
||||
@property (nonatomic) IBOutlet NewsBlurAppDelegate *appDelegate;
|
||||
@property (nonatomic) IBOutlet UITableView *premiumTable;
|
||||
|
||||
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
self.appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
|
||||
|
||||
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle: @"Done"
|
||||
style: UIBarButtonItemStylePlain
|
||||
target: self
|
||||
|
|
66
clients/ios/Classes/SceneDelegate.swift
Normal file
66
clients/ios/Classes/SceneDelegate.swift
Normal file
|
@ -0,0 +1,66 @@
|
|||
//
|
||||
// SceneDelegate.swift
|
||||
// NewsBlur
|
||||
//
|
||||
// Created by David Sinclair on 2023-11-15.
|
||||
// Copyright © 2023 NewsBlur. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
let appDelegate: NewsBlurAppDelegate = .shared
|
||||
|
||||
var window: UIWindow?
|
||||
#if targetEnvironment(macCatalyst)
|
||||
var toolbar = NSToolbar(identifier: "main")
|
||||
var toolbarDelegate = ToolbarDelegate()
|
||||
#endif
|
||||
|
||||
@objc(closeAuxWindows) class func closeAuxWindows() {
|
||||
for window in UIApplication.shared.windows {
|
||||
if window.windowScene?.delegate is AuxSceneDelegate, let session = window.windowScene?.session {
|
||||
window.isHidden = true
|
||||
UIApplication.shared.requestSceneSessionDestruction(session, options: .none)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
|
||||
if appDelegate.window != nil {
|
||||
DispatchQueue.main.async {
|
||||
self.window?.isHidden = true
|
||||
UIApplication.shared.requestSceneSessionDestruction(session, options: .none)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
appDelegate.window = window
|
||||
|
||||
#if targetEnvironment(macCatalyst)
|
||||
guard let windowScene = scene as? UIWindowScene, let titlebar = windowScene.titlebar else {
|
||||
return
|
||||
}
|
||||
|
||||
if #available(macCatalyst 16.0, *) {
|
||||
windowScene.windowingBehaviors?.isClosable = false
|
||||
}
|
||||
|
||||
toolbar.delegate = toolbarDelegate
|
||||
toolbar.displayMode = .iconOnly
|
||||
|
||||
titlebar.toolbar = toolbar
|
||||
titlebar.toolbarStyle = .automatic
|
||||
#endif
|
||||
|
||||
appDelegate.prepareViewControllers()
|
||||
}
|
||||
|
||||
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
|
||||
guard let url = URLContexts.first?.url else {
|
||||
return
|
||||
}
|
||||
|
||||
appDelegate.open(url)
|
||||
}
|
||||
}
|
|
@ -15,7 +15,6 @@
|
|||
}
|
||||
|
||||
@property (nonatomic) IBOutlet UITextView *commentField;
|
||||
@property (nonatomic) IBOutlet NewsBlurAppDelegate *appDelegate;
|
||||
@property (nonatomic) IBOutlet UIButton *facebookButton;
|
||||
@property (nonatomic) IBOutlet UIButton *twitterButton;
|
||||
@property (nonatomic) IBOutlet UIBarButtonItem *submitButton;
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
@synthesize twitterButton;
|
||||
@synthesize submitButton;
|
||||
@synthesize commentField;
|
||||
@synthesize appDelegate;
|
||||
@synthesize activeReplyId;
|
||||
@synthesize activeCommentId;
|
||||
@synthesize activeStoryId;
|
||||
|
@ -38,9 +37,7 @@
|
|||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
self.appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self
|
||||
selector:@selector(onTextChange:)
|
||||
name:UITextViewTextDidChangeNotification
|
||||
|
@ -202,7 +199,7 @@
|
|||
self.storyTitle.frame = CGRectMake(20, 8, v.width - 20*2, 24);
|
||||
stOffset = self.storyTitle.frame.origin.y + self.storyTitle.frame.size.height;
|
||||
stHeight = self.storyTitle.frame.size.height;
|
||||
} else if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
} else if (!self.isPhone) {
|
||||
k = 0;
|
||||
}
|
||||
NSLog(@"Share type: %@", self.currentType);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#import "SmallActivityCell.h"
|
||||
#import "UIImageView+AFNetworking.h"
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import "NewsBlurAppDelegate.h"
|
||||
|
||||
@implementation SmallActivityCell
|
||||
|
||||
|
@ -62,7 +63,7 @@
|
|||
labelFrame.size.height = contentRect.size.height;
|
||||
self.activityLabel.frame = labelFrame;
|
||||
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!((NewsBlurAppDelegate *)[[UIApplication sharedApplication] delegate]).isPhone) {
|
||||
self.activityLabel.backgroundColor = UIColorFromRGB(0xd7dadf);
|
||||
} else {
|
||||
self.activityLabel.backgroundColor = UIColorFromRGB(0xf6f6f6);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#import "SmallInteractionCell.h"
|
||||
#import "UIImageView+AFNetworking.h"
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import "NewsBlurAppDelegate.h"
|
||||
|
||||
@implementation SmallInteractionCell
|
||||
|
||||
|
@ -57,8 +58,8 @@
|
|||
labelFrame.size.width = contentRect.size.width - leftMargin - avatarSize - leftMargin - rightMargin - 20;
|
||||
labelFrame.size.height = contentRect.size.height;
|
||||
self.interactionLabel.frame = labelFrame;
|
||||
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
|
||||
if (!((NewsBlurAppDelegate *)[[UIApplication sharedApplication] delegate]).isPhone) {
|
||||
self.interactionLabel.backgroundColor = UIColorFromRGB(0xd7dadf);
|
||||
} else {
|
||||
self.interactionLabel.backgroundColor = UIColorFromRGB(0xf6f6f6);
|
||||
|
|
|
@ -10,6 +10,10 @@ import UIKit
|
|||
|
||||
/// Subclass of `UISplitViewController` to enable customizations.
|
||||
class SplitViewController: UISplitViewController {
|
||||
@objc var isFeedListHidden: Bool {
|
||||
return [.oneBesideSecondary, .oneOverSecondary, .secondaryOnly].contains(displayMode)
|
||||
}
|
||||
|
||||
/// Update the theme of the split view controller.
|
||||
@objc func updateTheme() {
|
||||
|
||||
|
@ -24,4 +28,10 @@ class SplitViewController: UISplitViewController {
|
|||
override var childForStatusBarStyle: UIViewController? {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Can do menu validation here.
|
||||
// override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
|
||||
// print("canPerformAction: \(action) with \(sender ?? "nil")")
|
||||
// return true
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -59,10 +59,15 @@
|
|||
@property (nonatomic, readwrite) BOOL transferredFromDashboard;
|
||||
@property (nonatomic, readwrite) BOOL showHiddenStories;
|
||||
@property (nonatomic, readwrite) BOOL inSearch;
|
||||
@property (nonatomic, readonly) BOOL isEverything;
|
||||
@property (nonatomic, readonly) BOOL isInfrequent;
|
||||
@property (nonatomic, readonly) BOOL isRiverOrSocial;
|
||||
@property (nonatomic, readonly) BOOL isCustomFolder;
|
||||
@property (nonatomic, readonly) BOOL isCustomFolderOrFeed;
|
||||
@property (nonatomic) NSString *searchQuery;
|
||||
@property (nonatomic) NSString *savedSearchQuery;
|
||||
|
||||
@property (nonatomic, readonly) NSString *activeFeedIdStr;
|
||||
@property (nonatomic, readonly) NSString *activeOrder;
|
||||
@property (nonatomic, readonly) NSString *activeReadFilter;
|
||||
@property (nonatomic, readonly) NSString *activeStoryTitlesPosition;
|
||||
|
|
|
@ -97,10 +97,26 @@
|
|||
self.savedSearchQuery = fromCollection.savedSearchQuery;
|
||||
}
|
||||
|
||||
- (BOOL)isEverything {
|
||||
return [activeFolder isEqualToString:@"everything"];
|
||||
}
|
||||
|
||||
- (BOOL)isInfrequent {
|
||||
return [activeFolder isEqualToString:@"infrequent"];
|
||||
}
|
||||
|
||||
- (BOOL)isRiverOrSocial {
|
||||
return self.isRiverView || self.isSavedView || self.isReadView || self.isWidgetView || self.isSocialView || self.isSocialRiverView;
|
||||
}
|
||||
|
||||
- (BOOL)isCustomFolder {
|
||||
return self.isRiverView && !self.isEverything && !self.isInfrequent && !self.isSavedView && !self.isReadView && !self.isSocialView && !self.isWidgetView;
|
||||
}
|
||||
|
||||
- (BOOL)isCustomFolderOrFeed {
|
||||
return !self.isRiverView || self.isCustomFolder;
|
||||
}
|
||||
|
||||
#pragma mark - Story Traversal
|
||||
|
||||
- (BOOL)isStoryUnread:(NSDictionary *)story {
|
||||
|
@ -232,6 +248,10 @@
|
|||
return [[activeFeedStoryLocations objectAtIndex:location] intValue];
|
||||
}
|
||||
|
||||
- (NSString *)activeFeedIdStr {
|
||||
return [NSString stringWithFormat:@"%@", [activeFeed objectForKey:@"id"]];
|
||||
}
|
||||
|
||||
- (NSString *)activeOrder {
|
||||
NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults];
|
||||
NSString *orderPrefDefault = [userPreferences stringForKey:@"default_order"];
|
||||
|
|
|
@ -8,17 +8,17 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
// The Story and StoryCache classes could be quite useful going forward; Rather than calling getStory() to get the dictionary, could have a variation that returns a Story instance. Could fetch from the cache if available, or make and cache one from the dictionary. Would need to remove it from the cache when changing anything about a story. Could perhaps make the cache part of StoriesCollection.
|
||||
// The Feed, Story, and StoryCache classes could be quite useful going forward; Rather than calling getStory() to get the dictionary, could have a variation that returns a Story instance. Could fetch from the cache if available, or make and cache one from the dictionary. Would need to remove it from the cache when changing anything about a story. Could perhaps make the cache part of StoriesCollection.
|
||||
|
||||
/// A story, wrapping the dictionary representation.
|
||||
class Story: Identifiable {
|
||||
let id = UUID()
|
||||
let index: Int
|
||||
|
||||
var dictionary = [String : Any]()
|
||||
var dictionary = AnyDictionary()
|
||||
|
||||
var feed: Feed?
|
||||
|
||||
var feedID = ""
|
||||
var feedName = ""
|
||||
var title = ""
|
||||
var content = ""
|
||||
var dateString = ""
|
||||
|
@ -35,9 +35,34 @@ class Story: Identifiable {
|
|||
return author.isEmpty ? dateString : "\(dateString) · \(author)"
|
||||
}
|
||||
|
||||
var isRiverOrSocial = true
|
||||
var feedColorBarLeft: UIColor?
|
||||
var feedColorBarRight: UIColor?
|
||||
var titles: [Feed.Training] {
|
||||
guard let classifiers = feed?.classifiers(for: "titles") else {
|
||||
return []
|
||||
}
|
||||
|
||||
let lowercasedTitle = title.lowercased()
|
||||
let keys = classifiers.keys.compactMap { $0 as? String }
|
||||
let words = keys.filter { lowercasedTitle.contains($0.lowercased()) }
|
||||
let sorted = words.sorted()
|
||||
|
||||
return sorted.map { Feed.Training(name: $0, count: 0, score: Feed.Score(rawValue: classifiers[$0] as? Int ?? 0) ?? .none) }
|
||||
}
|
||||
|
||||
var authors: [Feed.Training] {
|
||||
guard let classifiers = feed?.classifiers(for: "authors") else {
|
||||
return []
|
||||
}
|
||||
|
||||
return [Feed.Training(name: author, count: 0, score: Feed.Score(rawValue: classifiers[author] as? Int ?? 0) ?? .none)]
|
||||
}
|
||||
|
||||
var tags: [Feed.Training] {
|
||||
guard let tags = dictionary["story_tags"] as? [String], let classifiers = feed?.classifiers(for: "tags") else {
|
||||
return []
|
||||
}
|
||||
|
||||
return tags.map { Feed.Training(name: $0, count: 0, score: Feed.Score(rawValue: classifiers[$0] as? Int ?? 0) ?? .none) }
|
||||
}
|
||||
|
||||
var isSelected: Bool {
|
||||
return index == NewsBlurAppDelegate.shared!.storiesCollection.locationOfActiveStory()
|
||||
|
@ -79,24 +104,13 @@ class Story: Identifiable {
|
|||
|
||||
dictionary = story
|
||||
|
||||
if let id = dictionary["story_feed_id"] {
|
||||
feedID = appDelegate.feedIdWithoutSearchQuery("\(id)")
|
||||
}
|
||||
|
||||
var feed: [String : Any]?
|
||||
|
||||
if storiesCollection.isRiverOrSocial {
|
||||
feed = appDelegate.dictActiveFeeds[feedID] as? [String : Any]
|
||||
}
|
||||
|
||||
if feed == nil {
|
||||
feed = appDelegate.dictFeeds[feedID] as? [String : Any]
|
||||
}
|
||||
|
||||
if let feed {
|
||||
feedName = feed["feed_title"] as? String ?? ""
|
||||
feedColorBarLeft = color(for: "favicon_fade", from: feed, default: "707070")
|
||||
feedColorBarRight = color(for: "favicon_color", from: feed, default: "505050")
|
||||
if let dictID = dictionary["story_feed_id"], let id = appDelegate.feedIdWithoutSearchQuery("\(dictID)") {
|
||||
if let cachedFeed = StoryCache.feeds[id] {
|
||||
feed = cachedFeed
|
||||
} else {
|
||||
feed = Feed(id: id)
|
||||
StoryCache.feeds[id] = feed
|
||||
}
|
||||
}
|
||||
|
||||
title = (string(for: "story_title") as NSString).decodingHTMLEntities()
|
||||
|
@ -114,17 +128,6 @@ class Story: Identifiable {
|
|||
|
||||
isRead = !storiesCollection .isStoryUnread(dictionary)
|
||||
isReadAvailable = storiesCollection.activeFolder != "saved_stories"
|
||||
isRiverOrSocial = storiesCollection.isRiverOrSocial
|
||||
}
|
||||
|
||||
func color(for key: String, from feed: [String : Any], default defaultHex: String) -> UIColor {
|
||||
let hex = feed[key] as? String ?? defaultHex
|
||||
let scanner = Scanner(string: hex)
|
||||
var color: Int64 = 0
|
||||
scanner.scanHexInt64(&color)
|
||||
let value = Int(color)
|
||||
|
||||
return ThemeManager.shared.fixedColor(fromRGB: value) ?? UIColor.gray
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,235 +139,6 @@ extension Story: Equatable {
|
|||
|
||||
extension Story: CustomDebugStringConvertible {
|
||||
var debugDescription: String {
|
||||
return "Story #\(index) \"\(title)\" in \(feedName)"
|
||||
}
|
||||
}
|
||||
|
||||
/// A cache of stories for the feed detail grid view.
|
||||
class StoryCache: ObservableObject {
|
||||
let appDelegate = NewsBlurAppDelegate.shared!
|
||||
|
||||
let settings = StorySettings()
|
||||
|
||||
var isDarkTheme: Bool {
|
||||
return ThemeManager.shared.isDarkTheme
|
||||
}
|
||||
|
||||
var isGrid: Bool {
|
||||
return appDelegate.detailViewController.layout == .grid
|
||||
}
|
||||
|
||||
var isPhone: Bool {
|
||||
return appDelegate.detailViewController.isPhone
|
||||
}
|
||||
|
||||
var canPullToRefresh: Bool {
|
||||
return appDelegate.feedDetailViewController.canPullToRefresh
|
||||
}
|
||||
|
||||
@Published var before = [Story]()
|
||||
@Published var selected: Story?
|
||||
@Published var after = [Story]()
|
||||
|
||||
var all: [Story] {
|
||||
if let selected {
|
||||
return before + [selected] + after
|
||||
} else {
|
||||
return before + after
|
||||
}
|
||||
}
|
||||
|
||||
func story(with index: Int) -> Story? {
|
||||
return all.first(where: { $0.index == index } )
|
||||
}
|
||||
|
||||
func reload() {
|
||||
let storyCount = Int(appDelegate.storiesCollection.storyLocationsCount)
|
||||
var beforeSelection = [Int]()
|
||||
var selectedIndex = -999
|
||||
var afterSelection = [Int]()
|
||||
|
||||
if storyCount > 0 {
|
||||
selectedIndex = appDelegate.storiesCollection.locationOfActiveStory()
|
||||
|
||||
if selectedIndex < 0 {
|
||||
beforeSelection = Array(0..<storyCount)
|
||||
} else {
|
||||
beforeSelection = Array(0..<selectedIndex)
|
||||
|
||||
if selectedIndex + 1 < storyCount {
|
||||
afterSelection = Array(selectedIndex + 1..<storyCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
before = beforeSelection.map { Story(index: $0) }
|
||||
selected = selectedIndex >= 0 ? Story(index: selectedIndex) : nil
|
||||
after = afterSelection.map { Story(index: $0) }
|
||||
|
||||
print("🪿 Reload: \(before.count) before, \(selected == nil ? "none" : selected!.debugTitle) selected, \(after.count) after")
|
||||
|
||||
|
||||
//
|
||||
// #warning("hack")
|
||||
//
|
||||
// print("🪿 ... count: \(storyCount), index: \(selectedIndex)")
|
||||
// print("🪿 ... before: \(before)")
|
||||
// print("🪿 ... selection: \(selected == nil ? "none" : selected!.debugTitle)")
|
||||
// print("🪿 ... after: \(after)")
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
func reload(story: Story) {
|
||||
if story == selected {
|
||||
selected = Story(index: story.index)
|
||||
} else if let index = before.firstIndex(of: story) {
|
||||
before[index] = Story(index: story.index)
|
||||
} else if let index = after.firstIndex(of: story) {
|
||||
after[index] = Story(index: story.index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class StorySettings {
|
||||
let defaults = UserDefaults.standard
|
||||
|
||||
enum Content: String, RawRepresentable {
|
||||
case title
|
||||
case short
|
||||
case medium
|
||||
case long
|
||||
|
||||
static let titleLimit = 6
|
||||
|
||||
static let contentLimit = 10
|
||||
|
||||
var limit: Int {
|
||||
switch self {
|
||||
case .title:
|
||||
return 6
|
||||
case .short:
|
||||
return 2
|
||||
case .medium:
|
||||
return 4
|
||||
case .long:
|
||||
return 6
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var content: Content {
|
||||
if let string = defaults.string(forKey: "story_list_preview_text_size"), let value = Content(rawValue: string) {
|
||||
return value
|
||||
} else {
|
||||
return .short
|
||||
}
|
||||
}
|
||||
|
||||
enum Preview: String, RawRepresentable {
|
||||
case none
|
||||
case smallLeft = "small_left"
|
||||
case largeLeft = "large_left"
|
||||
case largeRight = "large_right"
|
||||
case smallRight = "small_right"
|
||||
|
||||
var isLeft: Bool {
|
||||
return [.smallLeft, .largeLeft].contains(self)
|
||||
}
|
||||
|
||||
var isSmall: Bool {
|
||||
return [.smallLeft, .smallRight].contains(self)
|
||||
}
|
||||
}
|
||||
|
||||
var preview: Preview {
|
||||
if let string = defaults.string(forKey: "story_list_preview_images_size"), let value = Preview(rawValue: string) {
|
||||
return value
|
||||
} else {
|
||||
return .smallRight
|
||||
}
|
||||
}
|
||||
|
||||
enum FontSize: String, RawRepresentable {
|
||||
case xs
|
||||
case small
|
||||
case medium
|
||||
case large
|
||||
case xl
|
||||
|
||||
var offset: CGFloat {
|
||||
switch self {
|
||||
case .xs:
|
||||
return -2
|
||||
case .small:
|
||||
return -1
|
||||
case .medium:
|
||||
return 0
|
||||
case .large:
|
||||
return 1
|
||||
case .xl:
|
||||
return 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var fontSize: FontSize {
|
||||
if let string = defaults.string(forKey: "feed_list_font_size"), let value = FontSize(rawValue: string) {
|
||||
return value
|
||||
} else {
|
||||
return .medium
|
||||
}
|
||||
}
|
||||
|
||||
enum Spacing: String, RawRepresentable {
|
||||
case compact
|
||||
case comfortable
|
||||
}
|
||||
|
||||
var spacing: Spacing {
|
||||
if let string = defaults.string(forKey: "feed_list_spacing"), let value = Spacing(rawValue: string) {
|
||||
return value
|
||||
} else {
|
||||
return .comfortable
|
||||
}
|
||||
}
|
||||
|
||||
var gridColumns: Int {
|
||||
guard let pref = UserDefaults.standard.string(forKey: "grid_columns"), let columns = Int(pref) else {
|
||||
if NewsBlurAppDelegate.shared.isCompactWidth {
|
||||
return 1
|
||||
} else if NewsBlurAppDelegate.shared.isPortrait() {
|
||||
return 2
|
||||
} else {
|
||||
return 4
|
||||
}
|
||||
}
|
||||
|
||||
if NewsBlurAppDelegate.shared.isPortrait(), columns > 3 {
|
||||
return 3
|
||||
}
|
||||
|
||||
return columns
|
||||
}
|
||||
|
||||
var gridHeight: CGFloat {
|
||||
guard let pref = UserDefaults.standard.string(forKey: "grid_height") else {
|
||||
return 400
|
||||
}
|
||||
|
||||
switch pref {
|
||||
case "xs":
|
||||
return 250
|
||||
case "short":
|
||||
return 300
|
||||
case "tall":
|
||||
return 500
|
||||
case "xl":
|
||||
return 600
|
||||
default:
|
||||
return 400
|
||||
}
|
||||
return "Story #\(index) \"\(title)\" in \(feed?.name ?? "<none>")"
|
||||
}
|
||||
}
|
||||
|
|
114
clients/ios/Classes/StoryCache.swift
Normal file
114
clients/ios/Classes/StoryCache.swift
Normal file
|
@ -0,0 +1,114 @@
|
|||
//
|
||||
// StoryCache.swift
|
||||
// NewsBlur
|
||||
//
|
||||
// Created by David Sinclair on 2024-04-04.
|
||||
// Copyright © 2024 NewsBlur. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// The Feed, Story, and StoryCache classes could be quite useful going forward; Rather than calling getStory() to get the dictionary, could have a variation that returns a Story instance. Could fetch from the cache if available, or make and cache one from the dictionary. Would need to remove it from the cache when changing anything about a story. Could perhaps make the cache part of StoriesCollection.
|
||||
|
||||
/// A cache of stories for the feed detail grid view.
|
||||
class StoryCache: ObservableObject {
|
||||
let appDelegate = NewsBlurAppDelegate.shared!
|
||||
|
||||
let settings = StorySettings()
|
||||
|
||||
var isDarkTheme: Bool {
|
||||
return ThemeManager.shared.isDarkTheme
|
||||
}
|
||||
|
||||
var isGrid: Bool {
|
||||
return appDelegate.detailViewController.layout == .grid
|
||||
}
|
||||
|
||||
var isPhone: Bool {
|
||||
return appDelegate.detailViewController.isPhone
|
||||
}
|
||||
|
||||
var canPullToRefresh: Bool {
|
||||
return appDelegate.feedDetailViewController.canPullToRefresh
|
||||
}
|
||||
|
||||
@Published var before = [Story]()
|
||||
@Published var selected: Story?
|
||||
@Published var after = [Story]()
|
||||
|
||||
var all: [Story] {
|
||||
if let selected {
|
||||
return before + [selected] + after
|
||||
} else {
|
||||
return before + after
|
||||
}
|
||||
}
|
||||
|
||||
func story(with index: Int) -> Story? {
|
||||
return all.first(where: { $0.index == index } )
|
||||
}
|
||||
|
||||
static var feeds = [String : Feed]()
|
||||
|
||||
var currentFeed: Feed?
|
||||
|
||||
func reload() {
|
||||
let debug = Date()
|
||||
let storyCount = Int(appDelegate.storiesCollection.storyLocationsCount)
|
||||
var beforeSelection = [Int]()
|
||||
var selectedIndex = -999
|
||||
var afterSelection = [Int]()
|
||||
|
||||
if storyCount > 0 {
|
||||
selectedIndex = appDelegate.storiesCollection.locationOfActiveStory()
|
||||
|
||||
if selectedIndex < 0 {
|
||||
beforeSelection = Array(0..<storyCount)
|
||||
} else {
|
||||
beforeSelection = Array(0..<selectedIndex)
|
||||
|
||||
if selectedIndex + 1 < storyCount {
|
||||
afterSelection = Array(selectedIndex + 1..<storyCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Self.feeds.removeAll()
|
||||
|
||||
if let dictionary = appDelegate.storiesCollection.activeFeed {
|
||||
let feed = Feed(dictionary: dictionary)
|
||||
Self.feeds[feed.id] = feed
|
||||
currentFeed = feed
|
||||
} else {
|
||||
currentFeed = nil
|
||||
}
|
||||
|
||||
before = beforeSelection.map { Story(index: $0) }
|
||||
selected = selectedIndex >= 0 ? Story(index: selectedIndex) : nil
|
||||
after = afterSelection.map { Story(index: $0) }
|
||||
|
||||
print("🪿 Reload: \(before.count) before, \(selected == nil ? "none" : selected!.debugTitle) selected, \(after.count) after, took \(-debug.timeIntervalSinceNow) seconds")
|
||||
|
||||
|
||||
//
|
||||
// #warning("hack")
|
||||
//
|
||||
// print("🪿 ... count: \(storyCount), index: \(selectedIndex)")
|
||||
// print("🪿 ... before: \(before)")
|
||||
// print("🪿 ... selection: \(selected == nil ? "none" : selected!.debugTitle)")
|
||||
// print("🪿 ... after: \(after)")
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
func reload(story: Story) {
|
||||
if story == selected {
|
||||
selected = Story(index: story.index)
|
||||
} else if let index = before.firstIndex(of: story) {
|
||||
before[index] = Story(index: story.index)
|
||||
} else if let index = after.firstIndex(of: story) {
|
||||
after[index] = Story(index: story.index)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,13 +11,9 @@
|
|||
#import "BaseViewController.h"
|
||||
@import WebKit;
|
||||
|
||||
@class NewsBlurAppDelegate;
|
||||
|
||||
@interface StoryDetailObjCViewController : BaseViewController
|
||||
<UIScrollViewDelegate, UIGestureRecognizerDelegate,
|
||||
UIActionSheetDelegate, WKNavigationDelegate> {
|
||||
NewsBlurAppDelegate *appDelegate;
|
||||
|
||||
NSString *activeStoryId;
|
||||
NSMutableDictionary *activeStory;
|
||||
UIView *innerView;
|
||||
|
@ -34,7 +30,6 @@ UIActionSheetDelegate, WKNavigationDelegate> {
|
|||
UIInterfaceOrientation _orientation;
|
||||
}
|
||||
|
||||
@property (nonatomic) IBOutlet NewsBlurAppDelegate *appDelegate;
|
||||
@property (nonatomic) NSString *activeStoryId;
|
||||
@property (nonatomic, readwrite) NSMutableDictionary *activeStory;
|
||||
@property (nonatomic) IBOutlet UIView *innerView;
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
#import "JNWThrottledBlock.h"
|
||||
#import "NewsBlur-Swift.h"
|
||||
|
||||
#define iPadPro12 ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad && ([UIScreen mainScreen].bounds.size.height == 1366 || [UIScreen mainScreen].bounds.size.width == 1366))
|
||||
#define iPadPro10 ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad && ([UIScreen mainScreen].bounds.size.height == 1112 || [UIScreen mainScreen].bounds.size.width == 1112))
|
||||
#define iPadPro12 (!self.isPhone && ([UIScreen mainScreen].bounds.size.height == 1366 || [UIScreen mainScreen].bounds.size.width == 1366))
|
||||
#define iPadPro10 (!self.isPhone && ([UIScreen mainScreen].bounds.size.height == 1112 || [UIScreen mainScreen].bounds.size.width == 1112))
|
||||
|
||||
@interface StoryDetailObjCViewController ()
|
||||
|
||||
|
@ -35,7 +35,6 @@
|
|||
|
||||
@implementation StoryDetailObjCViewController
|
||||
|
||||
@synthesize appDelegate;
|
||||
@synthesize activeStoryId;
|
||||
@synthesize activeStory;
|
||||
@synthesize innerView;
|
||||
|
@ -71,8 +70,6 @@
|
|||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
self.appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
|
||||
|
||||
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
|
||||
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
|
||||
|
@ -99,7 +96,7 @@
|
|||
[self.webView.scrollView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth |
|
||||
UIViewAutoresizingFlexibleHeight)];
|
||||
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!self.isPhone) {
|
||||
self.webView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
||||
}
|
||||
|
||||
|
@ -314,6 +311,11 @@
|
|||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
#if TARGET_OS_MACCATALYST
|
||||
[self.navigationController setNavigationBarHidden:YES animated:animated];
|
||||
[self.navigationController setToolbarHidden:YES animated:animated];
|
||||
#endif
|
||||
|
||||
if (!self.isPhoneOrCompact) {
|
||||
[appDelegate.feedDetailViewController.view endEditing:YES];
|
||||
}
|
||||
|
@ -401,9 +403,13 @@
|
|||
static NSURL *baseURL;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
#if TARGET_OS_MACCATALYST
|
||||
baseURL = [NSBundle mainBundle].resourceURL;
|
||||
#else
|
||||
baseURL = [NSBundle mainBundle].bundleURL;
|
||||
#endif
|
||||
});
|
||||
|
||||
|
||||
[self.webView loadHTMLString:html baseURL:baseURL];
|
||||
}
|
||||
|
||||
|
@ -480,7 +486,7 @@
|
|||
|
||||
#if TARGET_OS_MACCATALYST
|
||||
// CATALYST: probably will want to add custom CSS for Macs.
|
||||
contentWidthClass = @"NB-ipad-wide NB-ipad-pro-12-wide NB-width-768";
|
||||
contentWidthClass = @"NB-mac NB-ipad-pro-12-wide";
|
||||
#else
|
||||
if (UIInterfaceOrientationIsLandscape(orientation) && !self.isPhoneOrCompact) {
|
||||
if (iPadPro12) {
|
||||
|
@ -503,14 +509,15 @@
|
|||
} else {
|
||||
contentWidthClass = @"NB-iphone";
|
||||
}
|
||||
#endif
|
||||
|
||||
contentWidthClass = [NSString stringWithFormat:@"%@ NB-width-%d",
|
||||
contentWidthClass, (int)floorf(CGRectGetWidth(self.view.frame))];
|
||||
#endif
|
||||
|
||||
if (appDelegate.feedsViewController.isOffline) {
|
||||
// if (appDelegate.feedsViewController.isOffline) {
|
||||
NSString *storyHash = [self.activeStory objectForKey:@"story_hash"];
|
||||
NSArray *imageUrls = [appDelegate.activeCachedImages objectForKey:storyHash];
|
||||
// NSLog(@"📚 imageUrls: %@", imageUrls);
|
||||
if (imageUrls) {
|
||||
NSString *storyImagesDirectory = [appDelegate.documentsURL.path
|
||||
stringByAppendingPathComponent:@"story_images"];
|
||||
|
@ -524,7 +531,7 @@
|
|||
withString:cachedUrl.absoluteString];
|
||||
}
|
||||
}
|
||||
}
|
||||
// }
|
||||
|
||||
NSString *feedIdStr = [NSString stringWithFormat:@"%@",
|
||||
[self.activeStory
|
||||
|
@ -614,7 +621,7 @@
|
|||
|
||||
NSString *htmlTopAndBottom = [htmlTop stringByAppendingString:htmlBottom];
|
||||
|
||||
// NSLog(@"\n\n\n\nStory html (%@):\n\n\n%@\n\n\n", self.activeStory[@"story_title"], htmlContent);
|
||||
// NSLog(@"\n\n\n\nStory html (%@):\n\n\n%@\n\n\n", self.activeStory[@"story_title"], htmlContent);
|
||||
self.hasStory = NO;
|
||||
self.fullStoryHTML = htmlContent;
|
||||
|
||||
|
@ -1399,9 +1406,11 @@
|
|||
int bottomPosition = webpageHeight - topPosition - viewportHeight;
|
||||
BOOL singlePage = webpageHeight - 200 <= viewportHeight;
|
||||
BOOL atBottom = bottomPosition < 150;
|
||||
BOOL pullingDown = topPosition < 0;
|
||||
BOOL atTop = topPosition < 50;
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
BOOL pullingDown = topPosition < 0;
|
||||
BOOL nearTop = topPosition < 100;
|
||||
#endif
|
||||
|
||||
if (!hasScrolled && topPosition != 0) {
|
||||
hasScrolled = YES;
|
||||
|
@ -1417,6 +1426,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
if (!isNavBarHidden && self.canHideNavigationBar && !nearTop) {
|
||||
[appDelegate.storyPagesViewController setNavigationBarHidden:YES];
|
||||
}
|
||||
|
@ -1424,6 +1434,7 @@
|
|||
if (isNavBarHidden && pullingDown) {
|
||||
[appDelegate.storyPagesViewController setNavigationBarHidden:NO];
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!atTop && !atBottom && !singlePage) {
|
||||
BOOL traversalVisible = appDelegate.storyPagesViewController.traverseView.alpha > 0;
|
||||
|
@ -1878,6 +1889,12 @@
|
|||
[self scrollToLastPosition:YES];
|
||||
}
|
||||
|
||||
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView {
|
||||
NSLog(@"Web content process did terminate: %@", webView); // log
|
||||
|
||||
[self drawStory];
|
||||
}
|
||||
|
||||
- (void)checkTryFeedStory {
|
||||
// see if it's a tryfeed for animation
|
||||
if (!self.webView.hidden &&
|
||||
|
@ -2241,9 +2258,11 @@
|
|||
}
|
||||
|
||||
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
|
||||
if ([self respondsToSelector:action])
|
||||
return self.noStoryMessage.hidden;
|
||||
return [super canPerformAction:action withSender:sender];
|
||||
if ([self respondsToSelector:action]) {
|
||||
return [super canPerformAction:action withSender:sender] && self.noStoryMessage.hidden;
|
||||
} else {
|
||||
return [super canPerformAction:action withSender:sender];
|
||||
}
|
||||
}
|
||||
|
||||
# pragma mark -
|
||||
|
@ -2409,7 +2428,7 @@
|
|||
|
||||
#if TARGET_OS_MACCATALYST
|
||||
// CATALYST: probably will want to add custom CSS for Macs.
|
||||
contentWidthClass = @"NB-ipad-wide NB-ipad-pro-12-wide NB-width-768";
|
||||
contentWidthClass = @"NB-mac NB-ipad-pro-12-wide";
|
||||
#else
|
||||
UIInterfaceOrientation orientation = self.view.window.windowScene.interfaceOrientation;
|
||||
|
||||
|
@ -2434,10 +2453,10 @@
|
|||
} else {
|
||||
contentWidthClass = @"NB-iphone";
|
||||
}
|
||||
#endif
|
||||
|
||||
contentWidthClass = [NSString stringWithFormat:@"%@ NB-width-%d",
|
||||
contentWidthClass, (int)floorf(CGRectGetWidth(webView.scrollView.bounds))];
|
||||
#endif
|
||||
|
||||
NSString *alternateViewClass = @"";
|
||||
if (!self.isPhoneOrCompact) {
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
@interface StoryPagesObjCViewController : BaseViewController
|
||||
<UIScrollViewDelegate, UIPopoverControllerDelegate, UIPopoverPresentationControllerDelegate, UIGestureRecognizerDelegate> {
|
||||
NewsBlurAppDelegate *appDelegate;
|
||||
THCircularProgressView *circularProgressView;
|
||||
UIButton *buttonPrevious;
|
||||
UIButton *buttonNext;
|
||||
|
@ -37,7 +36,6 @@
|
|||
CGFloat scrollPct;
|
||||
}
|
||||
|
||||
@property (nonatomic, strong) NewsBlurAppDelegate *appDelegate;
|
||||
@property (nonatomic) StoryDetailViewController *currentPage;
|
||||
@property (nonatomic) StoryDetailViewController *nextPage;
|
||||
@property (nonatomic) StoryDetailViewController *previousPage;
|
||||
|
@ -153,9 +151,14 @@
|
|||
- (IBAction)openSendToDialog:(id)sender;
|
||||
- (IBAction)doNextUnreadStory:(id)sender;
|
||||
- (IBAction)doPreviousStory:(id)sender;
|
||||
- (void)changeToNextPage:(id)sender;
|
||||
- (void)changeToPreviousPage:(id)sender;
|
||||
- (IBAction)tapProgressBar:(id)sender;
|
||||
- (IBAction)toggleTextView:(id)sender;
|
||||
|
||||
- (IBAction)toggleStorySaved:(id)sender;
|
||||
- (IBAction)toggleStoryUnread:(id)sender;
|
||||
|
||||
- (void)finishMarkAsSaved:(NSDictionary *)params;
|
||||
- (BOOL)failedMarkAsSaved:(NSDictionary *)params;
|
||||
- (void)finishMarkAsUnsaved:(NSDictionary *)params;
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
|
||||
@implementation StoryPagesObjCViewController
|
||||
|
||||
@synthesize appDelegate;
|
||||
@synthesize currentPage, nextPage, previousPage;
|
||||
@synthesize circularProgressView;
|
||||
@synthesize separatorBarButton;
|
||||
|
@ -76,7 +75,6 @@
|
|||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
|
||||
currentPage = [[StoryDetailViewController alloc]
|
||||
initWithNibName:@"StoryDetailViewController"
|
||||
bundle:nil];
|
||||
|
@ -109,7 +107,11 @@
|
|||
[self.scrollView setAlwaysBounceHorizontal:self.isHorizontal];
|
||||
[self.scrollView setAlwaysBounceVertical:!self.isHorizontal];
|
||||
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (@available(macCatalyst 17.0, *)) {
|
||||
self.scrollView.allowsKeyboardScrolling = NO;
|
||||
}
|
||||
|
||||
if (!self.isPhone) {
|
||||
self.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
||||
}
|
||||
|
||||
|
@ -172,13 +174,13 @@
|
|||
[separatorBarButton setEnabled:NO];
|
||||
separatorBarButton.isAccessibilityElement = NO;
|
||||
|
||||
UIImage *settingsImage = [Utilities imageNamed:@"settings" sized:30];
|
||||
UIImage *settingsImage = [Utilities imageNamed:@"settings" sized:self.isMac ? 24 : 30];
|
||||
fontSettingsButton = [UIBarButtonItem barItemWithImage:settingsImage
|
||||
target:self
|
||||
action:@selector(toggleFontSize:)];
|
||||
fontSettingsButton.accessibilityLabel = @"Story settings";
|
||||
|
||||
UIImage *markreadImage = [UIImage imageNamed:@"original_button.png"];
|
||||
UIImage *markreadImage = [Utilities imageNamed:@"original_button.png" sized:self.isMac ? 24 : 30];
|
||||
originalStoryButton = [UIBarButtonItem barItemWithImage:markreadImage
|
||||
target:self
|
||||
action:@selector(showOriginalSubview:)];
|
||||
|
@ -251,6 +253,11 @@
|
|||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
#if TARGET_OS_MACCATALYST
|
||||
[self.navigationController setNavigationBarHidden:YES animated:animated];
|
||||
[self.navigationController setToolbarHidden:YES animated:animated];
|
||||
#endif
|
||||
|
||||
[self updateTheme];
|
||||
|
||||
[self updateAutoscrollButtons];
|
||||
|
@ -374,6 +381,10 @@
|
|||
self.scrollView.frame = CGRectMake(frame.origin.x, frame.origin.y, floor(frame.size.width), floor(frame.size.height));
|
||||
}
|
||||
|
||||
if (self.scrollView.subviews.lastObject != self.currentPage.view) {
|
||||
[self.scrollView bringSubviewToFront:self.currentPage.view];
|
||||
}
|
||||
|
||||
[super viewDidLayoutSubviews];
|
||||
}
|
||||
|
||||
|
@ -390,7 +401,10 @@
|
|||
|
||||
previousPage.view.hidden = YES;
|
||||
appDelegate.detailViewController.parentNavigationController.interactivePopGestureRecognizer.enabled = YES;
|
||||
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
[appDelegate.detailViewController.parentNavigationController setNavigationBarHidden:NO animated:YES];
|
||||
#endif
|
||||
|
||||
self.autoscrollActive = NO;
|
||||
}
|
||||
|
@ -484,7 +498,7 @@
|
|||
}
|
||||
|
||||
- (void)setNavigationBarHidden:(BOOL)hide alsoTraverse:(BOOL)alsoTraverse {
|
||||
if (self.navigationController == nil || self.navigationController.navigationBarHidden == hide || self.currentlyTogglingNavigationBar) {
|
||||
if (appDelegate.isMac || self.navigationController == nil || self.navigationController.navigationBarHidden == hide || self.currentlyTogglingNavigationBar) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -662,7 +676,7 @@
|
|||
[MBProgressHUD hideHUDForView:self.view animated:YES];
|
||||
[self hideNotifier];
|
||||
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!self.isPhone) {
|
||||
[currentPage realignScroll];
|
||||
}
|
||||
}
|
||||
|
@ -771,7 +785,7 @@
|
|||
|
||||
if (pageIndex >= 0) {
|
||||
[self changePage:pageIndex animated:NO];
|
||||
} else if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
} else if (!self.isPhone) {
|
||||
// If the story can't be found, don't show anything; uncomment this to instead show the first unread story:
|
||||
// [self doNextUnreadStory:nil];
|
||||
} else {
|
||||
|
@ -1080,9 +1094,12 @@
|
|||
}
|
||||
|
||||
self.scrollingToPage = pageIndex;
|
||||
[self.currentPage hideNoStoryMessage];
|
||||
[self.nextPage hideNoStoryMessage];
|
||||
[self.previousPage hideNoStoryMessage];
|
||||
|
||||
if (pageIndex >= 0) {
|
||||
[self.currentPage hideNoStoryMessage];
|
||||
[self.nextPage hideNoStoryMessage];
|
||||
[self.previousPage hideNoStoryMessage];
|
||||
}
|
||||
|
||||
// Check if already on the selected page
|
||||
if (self.isHorizontal ? offset.x == frame.origin.x : offset.y == frame.origin.y) {
|
||||
|
@ -1225,7 +1242,11 @@
|
|||
|
||||
[appDelegate.storiesCollection pushReadStory:[appDelegate.activeStory objectForKey:@"story_hash"]];
|
||||
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
#if TARGET_OS_MACCATALYST
|
||||
self.appDelegate.detailViewController.navigationItem.leftBarButtonItems = @[[[UIBarButtonItem alloc] initWithCustomView:[UIView new]]];
|
||||
#endif
|
||||
|
||||
if (!self.isPhone) {
|
||||
if (appDelegate.detailViewController.storyTitlesOnLeft) {
|
||||
appDelegate.detailViewController.navigationItem.rightBarButtonItems = [NSArray arrayWithObjects:
|
||||
originalStoryButton,
|
||||
|
@ -1327,6 +1348,13 @@
|
|||
|
||||
fontSettingsButton.enabled = YES;
|
||||
originalStoryButton.enabled = YES;
|
||||
|
||||
#if TARGET_OS_MACCATALYST
|
||||
if (@available(macCatalyst 16.0, *)) {
|
||||
fontSettingsButton.hidden = NO;
|
||||
originalStoryButton.hidden = NO;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
[buttonText setEnabled:NO];
|
||||
[buttonText setAlpha:.4];
|
||||
|
@ -1335,6 +1363,13 @@
|
|||
|
||||
fontSettingsButton.enabled = NO;
|
||||
originalStoryButton.enabled = NO;
|
||||
|
||||
#if TARGET_OS_MACCATALYST
|
||||
if (@available(macCatalyst 16.0, *)) {
|
||||
fontSettingsButton.hidden = YES;
|
||||
originalStoryButton.hidden = YES;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
[buttonSend setBackgroundImage:[[ThemeManager themeManager] themedImage:[UIImage imageNamed:@"traverse_send.png"]]
|
||||
|
@ -1455,11 +1490,11 @@
|
|||
// [self.appDelegate.feedDetailViewController changedStoryHeight:currentPage.webView.scrollView.contentSize.height];
|
||||
}
|
||||
|
||||
- (void)toggleStorySaved:(id)sender {
|
||||
- (IBAction)toggleStorySaved:(id)sender {
|
||||
[appDelegate.storiesCollection toggleStorySaved];
|
||||
}
|
||||
|
||||
- (void)toggleStoryUnread:(id)sender {
|
||||
- (IBAction)toggleStoryUnread:(id)sender {
|
||||
[appDelegate.storiesCollection toggleStoryUnread];
|
||||
[appDelegate.feedDetailViewController reload]; // XXX only if successful?
|
||||
}
|
||||
|
@ -1482,12 +1517,26 @@
|
|||
#pragma mark -
|
||||
#pragma mark Styles
|
||||
|
||||
//- (BOOL)validateToolbarItem:(NSToolbarItem *)item {
|
||||
// if item.itemIdentifier ==
|
||||
// return !self.currentPage.view.isHidden;
|
||||
//}
|
||||
|
||||
- (IBAction)toggleFontSize:(id)sender {
|
||||
UINavigationController *fontSettingsNavigationController = appDelegate.fontSettingsNavigationController;
|
||||
|
||||
[fontSettingsNavigationController popToRootViewControllerAnimated:NO];
|
||||
// [appDelegate showPopoverWithViewController:fontSettingsNavigationController contentSize:CGSizeZero sourceNavigationController:self.navigationController barButtonItem:self.fontSettingsButton sourceView:nil sourceRect:CGRectZero permittedArrowDirections:UIPopoverArrowDirectionAny];
|
||||
|
||||
#if TARGET_OS_MACCATALYST
|
||||
UINavigationController *storiesNavController = appDelegate.storyPagesViewController.navigationController;
|
||||
UIView *sourceView = storiesNavController.view;
|
||||
CGRect sourceRect = CGRectMake(storiesNavController.view.frame.size.width - 59, 0, 20, 20);
|
||||
|
||||
[appDelegate showPopoverWithViewController:fontSettingsNavigationController contentSize:CGSizeZero sourceView:sourceView sourceRect:sourceRect];
|
||||
#else
|
||||
[appDelegate showPopoverWithViewController:fontSettingsNavigationController contentSize:CGSizeZero barButtonItem:self.fontSettingsButton];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)setFontStyle:(NSString *)fontStyle {
|
||||
|
|
|
@ -20,6 +20,16 @@ class StoryPagesViewController: StoryPagesObjCViewController {
|
|||
|
||||
/// Reload the widget timeline.
|
||||
@objc func reloadWidget() {
|
||||
WidgetCenter.shared.reloadTimelines(ofKind: "Latest")
|
||||
WidgetCenter.shared.reloadAllTimelines()
|
||||
}
|
||||
|
||||
#if targetEnvironment(macCatalyst)
|
||||
@objc func validateToolbarItem(_ item: NSToolbarItem) -> Bool {
|
||||
if [.storyPagesSettings, .storyPagesBrowser].contains(item.itemIdentifier) {
|
||||
return self.isStoryShown
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
150
clients/ios/Classes/StorySettings.swift
Normal file
150
clients/ios/Classes/StorySettings.swift
Normal file
|
@ -0,0 +1,150 @@
|
|||
//
|
||||
// StorySettings.swift
|
||||
// NewsBlur
|
||||
//
|
||||
// Created by David Sinclair on 2024-04-04.
|
||||
// Copyright © 2024 NewsBlur. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class StorySettings {
|
||||
let defaults = UserDefaults.standard
|
||||
|
||||
enum Content: String, RawRepresentable {
|
||||
case title
|
||||
case short
|
||||
case medium
|
||||
case long
|
||||
|
||||
static let titleLimit = 6
|
||||
|
||||
static let contentLimit = 10
|
||||
|
||||
var limit: Int {
|
||||
switch self {
|
||||
case .title:
|
||||
return 6
|
||||
case .short:
|
||||
return 2
|
||||
case .medium:
|
||||
return 4
|
||||
case .long:
|
||||
return 6
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var content: Content {
|
||||
if let string = defaults.string(forKey: "story_list_preview_text_size"), let value = Content(rawValue: string) {
|
||||
return value
|
||||
} else {
|
||||
return .short
|
||||
}
|
||||
}
|
||||
|
||||
enum Preview: String, RawRepresentable {
|
||||
case none
|
||||
case smallLeft = "small_left"
|
||||
case largeLeft = "large_left"
|
||||
case largeRight = "large_right"
|
||||
case smallRight = "small_right"
|
||||
|
||||
var isLeft: Bool {
|
||||
return [.smallLeft, .largeLeft].contains(self)
|
||||
}
|
||||
|
||||
var isSmall: Bool {
|
||||
return [.smallLeft, .smallRight].contains(self)
|
||||
}
|
||||
}
|
||||
|
||||
var preview: Preview {
|
||||
if let string = defaults.string(forKey: "story_list_preview_images_size"), let value = Preview(rawValue: string) {
|
||||
return value
|
||||
} else {
|
||||
return .smallRight
|
||||
}
|
||||
}
|
||||
|
||||
enum FontSize: String, RawRepresentable {
|
||||
case xs
|
||||
case small
|
||||
case medium
|
||||
case large
|
||||
case xl
|
||||
|
||||
var offset: CGFloat {
|
||||
switch self {
|
||||
case .xs:
|
||||
return -2
|
||||
case .small:
|
||||
return -1
|
||||
case .medium:
|
||||
return 0
|
||||
case .large:
|
||||
return 1
|
||||
case .xl:
|
||||
return 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var fontSize: FontSize {
|
||||
if let string = defaults.string(forKey: "feed_list_font_size"), let value = FontSize(rawValue: string) {
|
||||
return value
|
||||
} else {
|
||||
return .medium
|
||||
}
|
||||
}
|
||||
|
||||
enum Spacing: String, RawRepresentable {
|
||||
case compact
|
||||
case comfortable
|
||||
}
|
||||
|
||||
var spacing: Spacing {
|
||||
if let string = defaults.string(forKey: "feed_list_spacing"), let value = Spacing(rawValue: string) {
|
||||
return value
|
||||
} else {
|
||||
return .comfortable
|
||||
}
|
||||
}
|
||||
|
||||
var gridColumns: Int {
|
||||
guard let pref = UserDefaults.standard.string(forKey: "grid_columns"), let columns = Int(pref) else {
|
||||
if NewsBlurAppDelegate.shared.isCompactWidth {
|
||||
return 1
|
||||
} else if NewsBlurAppDelegate.shared.isPortrait || NewsBlurAppDelegate.shared.isPhone {
|
||||
return 2
|
||||
} else {
|
||||
return 4
|
||||
}
|
||||
}
|
||||
|
||||
if NewsBlurAppDelegate.shared.isPortrait, columns > 3 {
|
||||
return 3
|
||||
}
|
||||
|
||||
return columns
|
||||
}
|
||||
|
||||
var gridHeight: CGFloat {
|
||||
guard let pref = UserDefaults.standard.string(forKey: "grid_height") else {
|
||||
return 400
|
||||
}
|
||||
|
||||
switch pref {
|
||||
case "xs":
|
||||
return 250
|
||||
case "short":
|
||||
return 300
|
||||
case "tall":
|
||||
return 500
|
||||
case "xl":
|
||||
return 600
|
||||
default:
|
||||
return 400
|
||||
}
|
||||
}
|
||||
}
|
|
@ -38,6 +38,16 @@ extension View {
|
|||
}
|
||||
}
|
||||
|
||||
extension Text {
|
||||
func colored(_ color: Color) -> Text {
|
||||
if #available(iOS 17.0, *) {
|
||||
self.foregroundStyle(color)
|
||||
} else {
|
||||
self.foregroundColor(color)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct RoundedCorner: Shape {
|
||||
var radius: CGFloat = .infinity
|
||||
var corners: UIRectCorner = .allCorners
|
||||
|
@ -131,3 +141,70 @@ struct OffsetObservingScrollView<Content: View>: View {
|
|||
.coordinateSpace(name: coordinateSpaceName)
|
||||
}
|
||||
}
|
||||
|
||||
struct WrappingHStack<Model, V>: View where Model: Hashable, V: View {
|
||||
typealias ViewGenerator = (Model) -> V
|
||||
|
||||
var models: [Model]
|
||||
var horizontalSpacing: CGFloat = 2
|
||||
var verticalSpacing: CGFloat = 0
|
||||
var viewGenerator: ViewGenerator
|
||||
|
||||
@State private var totalHeight
|
||||
= CGFloat.zero // << variant for ScrollView/List
|
||||
// = CGFloat.infinity // << variant for VStack
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
GeometryReader { geometry in
|
||||
self.generateContent(in: geometry)
|
||||
}
|
||||
}
|
||||
.frame(height: totalHeight)// << variant for ScrollView/List
|
||||
//.frame(maxHeight: totalHeight) // << variant for VStack
|
||||
}
|
||||
|
||||
private func generateContent(in geometry: GeometryProxy) -> some View {
|
||||
var width = CGFloat.zero
|
||||
var height = CGFloat.zero
|
||||
|
||||
return ZStack(alignment: .topLeading) {
|
||||
ForEach(self.models, id: \.self) { models in
|
||||
viewGenerator(models)
|
||||
.padding(.horizontal, horizontalSpacing)
|
||||
.padding(.vertical, verticalSpacing)
|
||||
.alignmentGuide(.leading, computeValue: { dimension in
|
||||
if (abs(width - dimension.width) > geometry.size.width)
|
||||
{
|
||||
width = 0
|
||||
height -= dimension.height
|
||||
}
|
||||
let result = width
|
||||
if models == self.models.last! {
|
||||
width = 0 //last item
|
||||
} else {
|
||||
width -= dimension.width
|
||||
}
|
||||
return result
|
||||
})
|
||||
.alignmentGuide(.top, computeValue: {dimension in
|
||||
let result = height
|
||||
if models == self.models.last! {
|
||||
height = 0 // last item
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
}.background(viewHeightReader($totalHeight))
|
||||
}
|
||||
|
||||
private func viewHeightReader(_ binding: Binding<CGFloat>) -> some View {
|
||||
return GeometryReader { geometry -> Color in
|
||||
let rect = geometry.frame(in: .local)
|
||||
DispatchQueue.main.async {
|
||||
binding.wrappedValue = rect.size.height
|
||||
}
|
||||
return .clear
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,8 @@ extern NSString * const ThemeStyleDark;
|
|||
@property (nonatomic, readonly) NSString *themeDisplayName;
|
||||
@property (nonatomic, readonly) NSString *themeCSSSuffix;
|
||||
@property (nonatomic, readonly) BOOL isDarkTheme;
|
||||
@property (nonatomic, readonly) BOOL isSystemDark;
|
||||
@property (nonatomic, readonly) BOOL isLikeSystem;
|
||||
|
||||
+ (instancetype)themeManager;
|
||||
|
||||
|
|
|
@ -136,6 +136,14 @@ NSString * const ThemeStyleDark = @"dark";
|
|||
return [theme isEqualToString:ThemeStyleDark] || [theme isEqualToString:ThemeStyleMedium];
|
||||
}
|
||||
|
||||
- (BOOL)isSystemDark {
|
||||
return self.appDelegate.window.windowScene.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark;
|
||||
}
|
||||
|
||||
- (BOOL)isLikeSystem {
|
||||
return self.isDarkTheme == self.isSystemDark;
|
||||
}
|
||||
|
||||
- (BOOL)isValidTheme:(NSString *)theme {
|
||||
return [theme isEqualToString:ThemeStyleLight] || [theme isEqualToString:ThemeStyleSepia] || [theme isEqualToString:ThemeStyleMedium] || [theme isEqualToString:ThemeStyleDark];
|
||||
}
|
||||
|
@ -266,7 +274,9 @@ NSString * const ThemeStyleDark = @"dark";
|
|||
|
||||
- (void)updateSegmentedControl:(UISegmentedControl *)segmentedControl {
|
||||
segmentedControl.tintColor = UIColorFromRGB(0x8F918B);
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
segmentedControl.backgroundColor = UIColorFromLightDarkRGB(0xe7e6e7, 0x303030);
|
||||
#endif
|
||||
segmentedControl.selectedSegmentTintColor = UIColorFromLightDarkRGB(0xffffff, 0x6f6f75);
|
||||
|
||||
[self updateTextAttributesForSegmentedControl:segmentedControl forState:UIControlStateNormal foregroundColor:UIColorFromLightDarkRGB(0x909090, 0xaaaaaa)];
|
||||
|
@ -275,7 +285,9 @@ NSString * const ThemeStyleDark = @"dark";
|
|||
|
||||
- (void)updateThemeSegmentedControl:(UISegmentedControl *)segmentedControl {
|
||||
segmentedControl.tintColor = [UIColor clearColor];
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
segmentedControl.backgroundColor = [UIColor clearColor];
|
||||
#endif
|
||||
segmentedControl.selectedSegmentTintColor = [UIColor clearColor];
|
||||
}
|
||||
|
||||
|
@ -440,9 +452,7 @@ NSString * const ThemeStyleDark = @"dark";
|
|||
}
|
||||
|
||||
- (void)updateForSystemAppearance {
|
||||
BOOL isDark = self.appDelegate.window.windowScene.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark;
|
||||
|
||||
[self systemAppearanceDidChange:isDark];
|
||||
[self systemAppearanceDidChange:self.isSystemDark];
|
||||
}
|
||||
|
||||
- (void)systemAppearanceDidChange:(BOOL)isDark {
|
||||
|
|
97
clients/ios/Classes/ToolbarDelegate.swift
Normal file
97
clients/ios/Classes/ToolbarDelegate.swift
Normal file
|
@ -0,0 +1,97 @@
|
|||
//
|
||||
// ToolbarDelegate.swift
|
||||
// NewsBlur
|
||||
//
|
||||
// Created by David Sinclair on 2024-01-05.
|
||||
// Copyright © 2024 NewsBlur. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
#if targetEnvironment(macCatalyst)
|
||||
class ToolbarDelegate: NSObject {
|
||||
}
|
||||
|
||||
extension NSToolbarItem.Identifier {
|
||||
static let reloadFeeds = NSToolbarItem.Identifier("com.newsblur.reloadFeeds")
|
||||
static let feedDetailUnread = NSToolbarItem.Identifier("com.newsblur.feedDetailUnread")
|
||||
static let feedDetailSettings = NSToolbarItem.Identifier("com.newsblur.feedDetailSettings")
|
||||
static let storyPagesSettings = NSToolbarItem.Identifier("com.newsblur.storyPagesSettings")
|
||||
static let storyPagesBrowser = NSToolbarItem.Identifier("com.newsblur.storyPagesBrowser")
|
||||
}
|
||||
|
||||
extension ToolbarDelegate: NSToolbarDelegate {
|
||||
func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
|
||||
let identifiers: [NSToolbarItem.Identifier] = [
|
||||
.toggleSidebar,
|
||||
.space,
|
||||
.reloadFeeds,
|
||||
.space,
|
||||
.feedDetailUnread,
|
||||
.feedDetailSettings,
|
||||
.flexibleSpace,
|
||||
.storyPagesSettings,
|
||||
.storyPagesBrowser
|
||||
]
|
||||
return identifiers
|
||||
}
|
||||
|
||||
func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
|
||||
return toolbarDefaultItemIdentifiers(toolbar)
|
||||
}
|
||||
|
||||
func toolbar(_ toolbar: NSToolbar,
|
||||
itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier,
|
||||
willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? {
|
||||
switch itemIdentifier {
|
||||
case .reloadFeeds:
|
||||
return makeToolbarItem(itemIdentifier,
|
||||
image: UIImage(systemName: "arrow.clockwise"),
|
||||
label: "Reload Sites",
|
||||
action: #selector(BaseViewController.reloadFeeds(_:)))
|
||||
|
||||
case .feedDetailUnread:
|
||||
return makeToolbarItem(itemIdentifier,
|
||||
image: Utilities.imageNamed("mark-read", sized: 24),
|
||||
label: "Mark as Read",
|
||||
action: #selector(BaseViewController.openMarkReadMenu(_:)))
|
||||
|
||||
case .feedDetailSettings:
|
||||
return makeToolbarItem(itemIdentifier,
|
||||
image: Utilities.imageNamed("settings", sized: 24),
|
||||
label: "Site Settings",
|
||||
action: #selector(BaseViewController.openSettingsMenu(_:)))
|
||||
|
||||
case .storyPagesSettings:
|
||||
return makeToolbarItem(itemIdentifier,
|
||||
image: Utilities.imageNamed("settings", sized: 24),
|
||||
label: "Story Settings",
|
||||
action: #selector(StoryPagesViewController.toggleFontSize(_:)))
|
||||
|
||||
case .storyPagesBrowser:
|
||||
return makeToolbarItem(itemIdentifier,
|
||||
image: Utilities.imageNamed("original_button.png", sized: 24),
|
||||
label: "Show Original Story",
|
||||
action: #selector(StoryPagesViewController.showOriginalSubview(_:)))
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func makeToolbarItem(_ identifier: NSToolbarItem.Identifier,
|
||||
image: UIImage?,
|
||||
label: String,
|
||||
action: Selector,
|
||||
target: AnyObject? = nil) -> NSToolbarItem {
|
||||
let item = NSToolbarItem(itemIdentifier: identifier)
|
||||
|
||||
item.image = image
|
||||
item.label = label
|
||||
item.action = action
|
||||
item.target = target
|
||||
|
||||
return item
|
||||
}
|
||||
}
|
||||
#endif
|
67
clients/ios/Classes/TrainerCapsule.swift
Normal file
67
clients/ios/Classes/TrainerCapsule.swift
Normal file
|
@ -0,0 +1,67 @@
|
|||
//
|
||||
// TrainerCapsule.swift
|
||||
// NewsBlur
|
||||
//
|
||||
// Created by David Sinclair on 2024-04-02.
|
||||
// Copyright © 2024 NewsBlur. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct TrainerCapsule: View {
|
||||
var score: Feed.Score
|
||||
|
||||
var header: String
|
||||
|
||||
var image: UIImage?
|
||||
|
||||
var value: String
|
||||
|
||||
var count: Int = 0
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
HStack {
|
||||
Image(systemName: score.imageName)
|
||||
.foregroundColor(.white)
|
||||
|
||||
content
|
||||
}
|
||||
.padding([.top, .bottom], 5)
|
||||
.padding([.leading, .trailing], 10)
|
||||
.background(score == .like ? Color(red: 0, green: 0.5, blue: 0.0) : score == .dislike ? Color.red : Color(white: ThemeManager.shared.isSystemDark ? 0.35 : 0.6))
|
||||
.clipShape(Capsule())
|
||||
|
||||
if count > 0 {
|
||||
Text("x \(count)")
|
||||
.colored(.gray)
|
||||
.padding([.trailing], 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var content: Text {
|
||||
Text("\(Text("\(header):").colored(.init(white: 0.85))) \(imageText)\(value)")
|
||||
.colored(.white)
|
||||
}
|
||||
|
||||
var imageText: Text {
|
||||
if let image {
|
||||
Text(Image(uiImage: image)).baselineOffset(-3) + Text(" ")
|
||||
} else {
|
||||
Text("")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
TrainerCapsule(score: .none, header: "Tag", value: "None Example")
|
||||
}
|
||||
|
||||
#Preview {
|
||||
TrainerCapsule(score: .like, header: "Tag", value: "Liked Example")
|
||||
}
|
||||
|
||||
#Preview {
|
||||
TrainerCapsule(score: .dislike, header: "Tag", value: "Disliked Example")
|
||||
}
|
218
clients/ios/Classes/TrainerView.swift
Normal file
218
clients/ios/Classes/TrainerView.swift
Normal file
|
@ -0,0 +1,218 @@
|
|||
//
|
||||
// TrainerView.swift
|
||||
// NewsBlur
|
||||
//
|
||||
// Created by David Sinclair on 2024-04-02.
|
||||
// Copyright © 2024 NewsBlur. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
/// A protocol of interaction between the trainer view and the enclosing view controller.
|
||||
protocol TrainerInteraction {
|
||||
var isStoryTrainer: Bool { get set }
|
||||
}
|
||||
|
||||
struct TrainerView: View {
|
||||
var interaction: TrainerInteraction
|
||||
|
||||
@ObservedObject var cache: StoryCache
|
||||
|
||||
let columns = [GridItem(.adaptive(minimum: 50))]
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
Text("What do you 👍 \(Text("like").colored(.green)) and 👎 \(Text("dislike").colored(.red)) about this \(feedOrStoryLowercase)?")
|
||||
.font(font(named: "WhitneySSm-Medium", size: 16))
|
||||
.padding()
|
||||
|
||||
List {
|
||||
Section(content: {
|
||||
VStack(alignment: .leading) {
|
||||
if interaction.isStoryTrainer {
|
||||
Text("Choose one or more words from the title:")
|
||||
.font(font(named: "WhitneySSm-Medium", size: 12))
|
||||
.padding([.top], 10)
|
||||
|
||||
WrappingHStack(models: titleWords, horizontalSpacing: 1) { word in
|
||||
Button(action: {
|
||||
if addingTitle.isEmpty {
|
||||
addingTitle = word
|
||||
} else {
|
||||
addingTitle.append(" \(word)")
|
||||
}
|
||||
}, label: {
|
||||
TrainerWord(word: word)
|
||||
})
|
||||
.buttonStyle(BorderlessButtonStyle())
|
||||
.padding([.top, .bottom], 5)
|
||||
}
|
||||
|
||||
if !addingTitle.isEmpty {
|
||||
HStack {
|
||||
Button(action: {
|
||||
cache.appDelegate.toggleTitleClassifier(addingTitle, feedId: feed?.id, score: 0)
|
||||
addingTitle = ""
|
||||
}, label: {
|
||||
TrainerCapsule(score: .none, header: "Title", value: addingTitle)
|
||||
})
|
||||
.buttonStyle(BorderlessButtonStyle())
|
||||
.padding([.top, .bottom], 5)
|
||||
|
||||
Button {
|
||||
addingTitle = ""
|
||||
} label: {
|
||||
Image(systemName: "xmark.circle.fill")
|
||||
.imageScale(.large)
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WrappingHStack(models: titles) { title in
|
||||
Button(action: {
|
||||
cache.appDelegate.toggleTitleClassifier(title.name, feedId: feed?.id, score: 0)
|
||||
}, label: {
|
||||
TrainerCapsule(score: title.score, header: "Title", value: title.name, count: title.count)
|
||||
})
|
||||
.buttonStyle(BorderlessButtonStyle())
|
||||
.padding([.top, .bottom], 5)
|
||||
}
|
||||
}
|
||||
}, header: {
|
||||
header(story: "Story Title", feed: "Titles & Phrases")
|
||||
})
|
||||
|
||||
Section(content: {
|
||||
WrappingHStack(models: authors) { author in
|
||||
Button(action: {
|
||||
cache.appDelegate.toggleAuthorClassifier(author.name, feedId: feed?.id)
|
||||
}, label: {
|
||||
TrainerCapsule(score: author.score, header: "Author", value: author.name, count: author.count)
|
||||
})
|
||||
.buttonStyle(BorderlessButtonStyle())
|
||||
.padding([.top, .bottom], 5)
|
||||
}
|
||||
}, header: {
|
||||
header(story: "Story Author", feed: "Authors")
|
||||
})
|
||||
|
||||
Section(content: {
|
||||
WrappingHStack(models: tags) { tag in
|
||||
Button(action: {
|
||||
cache.appDelegate.toggleTagClassifier(tag.name, feedId: feed?.id)
|
||||
}, label: {
|
||||
TrainerCapsule(score: tag.score, header: "Tag", value: tag.name, count: tag.count)
|
||||
})
|
||||
.buttonStyle(BorderlessButtonStyle())
|
||||
.padding([.top, .bottom], 5)
|
||||
}
|
||||
}, header: {
|
||||
header(story: "Story Categories & Tags", feed: "Categories & Tags")
|
||||
})
|
||||
|
||||
Section(content: {
|
||||
HStack {
|
||||
if let feed = feed {
|
||||
Button(action: {
|
||||
cache.appDelegate.toggleFeedClassifier(feed.id)
|
||||
}, label: {
|
||||
TrainerCapsule(score: score(key: "feeds", value: feed.id), header: "Site", image: feed.image, value: feed.name)
|
||||
})
|
||||
.buttonStyle(BorderlessButtonStyle())
|
||||
.padding([.top, .bottom], 5)
|
||||
}
|
||||
}
|
||||
}, header: {
|
||||
header(feed: "Everything by This Publisher")
|
||||
})
|
||||
}
|
||||
.font(font(named: "WhitneySSm-Medium", size: 12))
|
||||
}
|
||||
.onAppear {
|
||||
addingTitle = ""
|
||||
}
|
||||
}
|
||||
|
||||
func font(named: String, size: CGFloat) -> Font {
|
||||
return Font.custom(named, size: size + cache.settings.fontSize.offset, relativeTo: .caption)
|
||||
}
|
||||
|
||||
func reload() {
|
||||
cache.reload()
|
||||
addingTitle = ""
|
||||
}
|
||||
|
||||
var feedOrStoryLowercase: String {
|
||||
return interaction.isStoryTrainer ? "story" : "site"
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func header(story: String? = nil, feed: String) -> some View {
|
||||
if let story {
|
||||
Text(interaction.isStoryTrainer ? story : feed)
|
||||
.font(font(named: "WhitneySSm-Medium", size: 16))
|
||||
} else {
|
||||
Text(feed)
|
||||
.font(font(named: "WhitneySSm-Medium", size: 16))
|
||||
}
|
||||
}
|
||||
|
||||
func score(key: String, value: String) -> Feed.Score {
|
||||
guard let classifiers = feed?.classifiers(for: key),
|
||||
let score = classifiers[value] as? Int else {
|
||||
return .none
|
||||
}
|
||||
|
||||
if score > 0 {
|
||||
return .like
|
||||
} else if score < 0 {
|
||||
return .dislike
|
||||
} else {
|
||||
return .none
|
||||
}
|
||||
}
|
||||
|
||||
var titleWords: [String] {
|
||||
if interaction.isStoryTrainer, let story = cache.selected {
|
||||
return story.title.components(separatedBy: .whitespaces)
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
@State private var addingTitle = ""
|
||||
|
||||
var feed: Feed? {
|
||||
return cache.currentFeed ?? cache.selected?.feed
|
||||
}
|
||||
|
||||
var titles: [Feed.Training] {
|
||||
if interaction.isStoryTrainer {
|
||||
return cache.selected?.titles ?? []
|
||||
} else {
|
||||
return feed?.titles ?? []
|
||||
}
|
||||
}
|
||||
|
||||
var authors: [Feed.Training] {
|
||||
if interaction.isStoryTrainer {
|
||||
return cache.selected?.authors ?? []
|
||||
} else {
|
||||
return feed?.authors ?? []
|
||||
}
|
||||
}
|
||||
|
||||
var tags: [Feed.Training] {
|
||||
if interaction.isStoryTrainer {
|
||||
return cache.selected?.tags ?? []
|
||||
} else {
|
||||
return feed?.tags ?? []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#Preview {
|
||||
// TrainerViewController()
|
||||
//}
|
|
@ -6,6 +6,10 @@
|
|||
// Copyright (c) 2012 NewsBlur. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
#warning This code is obsolete, and will be removed once the SwiftUI implementation is complete.
|
||||
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "BaseViewController.h"
|
||||
#import "NewsBlurAppDelegate.h"
|
||||
|
@ -21,9 +25,7 @@
|
|||
@end
|
||||
|
||||
|
||||
@interface TrainerViewController : BaseViewController <WKNavigationDelegate> {
|
||||
NewsBlurAppDelegate *appDelegate;
|
||||
|
||||
@interface OldTrainerViewController : BaseViewController <WKNavigationDelegate> {
|
||||
IBOutlet UIBarButtonItem * closeButton;
|
||||
TrainerWebView *webView;
|
||||
IBOutlet UINavigationBar *navBar;
|
||||
|
@ -33,7 +35,6 @@
|
|||
BOOL storyTrainer;
|
||||
}
|
||||
|
||||
@property (nonatomic) IBOutlet NewsBlurAppDelegate *appDelegate;
|
||||
@property (nonatomic) IBOutlet UIBarButtonItem *closeButton;
|
||||
@property (nonatomic) IBOutlet TrainerWebView *webView;
|
||||
@property (nonatomic) IBOutlet UINavigationBar *navBar;
|
||||
|
|
|
@ -6,18 +6,21 @@
|
|||
// Copyright (c) 2012 NewsBlur. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
#warning This code is obsolete, and will be removed once the SwiftUI implementation is complete.
|
||||
|
||||
|
||||
#import "TrainerViewController.h"
|
||||
#import "StringHelper.h"
|
||||
#import "Utilities.h"
|
||||
#import "AFNetworking.h"
|
||||
#import "StoriesCollection.h"
|
||||
|
||||
@implementation TrainerViewController
|
||||
@implementation OldTrainerViewController
|
||||
|
||||
@synthesize closeButton;
|
||||
@synthesize webView;
|
||||
@synthesize navBar;
|
||||
@synthesize appDelegate;
|
||||
@synthesize feedTrainer;
|
||||
@synthesize storyTrainer;
|
||||
@synthesize feedLoaded;
|
||||
|
@ -35,8 +38,6 @@
|
|||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
self.appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
|
||||
|
||||
UIBarButtonItem *done = [[UIBarButtonItem alloc]
|
||||
initWithTitle:@"Done Training"
|
||||
style:UIBarButtonItemStyleDone
|
||||
|
@ -99,7 +100,7 @@
|
|||
[self informError:@"Could not load trainer"];
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC),
|
||||
dispatch_get_main_queue(), ^() {
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!self.isPhone) {
|
||||
[self.appDelegate hidePopover];
|
||||
} else {
|
||||
[self.appDelegate.feedsNavigationController dismissViewControllerAnimated:YES completion:nil];
|
||||
|
@ -162,6 +163,9 @@
|
|||
int contentWidth = self.view.frame.size.width;
|
||||
NSString *contentWidthClass;
|
||||
|
||||
#if TARGET_OS_MACCATALYST
|
||||
contentWidthClass = @"NB-mac";
|
||||
#else
|
||||
if (contentWidth > 700) {
|
||||
contentWidthClass = @"NB-ipad-wide";
|
||||
} else if (contentWidth > 480) {
|
||||
|
@ -169,6 +173,7 @@
|
|||
} else {
|
||||
contentWidthClass = @"NB-iphone";
|
||||
}
|
||||
#endif
|
||||
|
||||
// set up layout values based on iPad/iPhone
|
||||
NSString *headerString = [NSString stringWithFormat:@
|
||||
|
@ -542,7 +547,7 @@
|
|||
|
||||
- (IBAction)doCloseDialog:(id)sender {
|
||||
[appDelegate hidePopover];
|
||||
[appDelegate.trainerViewController dismissViewControllerAnimated:YES completion:nil];
|
||||
// [appDelegate.trainerViewController dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)changeTitle:(id)sender score:(int)score {
|
||||
|
@ -603,12 +608,12 @@
|
|||
|
||||
- (void)focusTitle:(id)sender {
|
||||
NewsBlurAppDelegate *appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
|
||||
[appDelegate.trainerViewController changeTitle:sender score:1];
|
||||
// [appDelegate.trainerViewController changeTitle:sender score:1];
|
||||
}
|
||||
|
||||
- (void)hideTitle:(id)sender {
|
||||
NewsBlurAppDelegate *appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
|
||||
[appDelegate.trainerViewController changeTitle:sender score:-1];
|
||||
// [appDelegate.trainerViewController changeTitle:sender score:-1];
|
||||
}
|
||||
|
||||
// Work around iOS 9 issue where menu doesn't appear the first time
|
||||
|
|
58
clients/ios/Classes/TrainerViewController.swift
Normal file
58
clients/ios/Classes/TrainerViewController.swift
Normal file
|
@ -0,0 +1,58 @@
|
|||
//
|
||||
// TrainerViewController.swift
|
||||
// NewsBlur
|
||||
//
|
||||
// Created by David Sinclair on 2024-04-01.
|
||||
// Copyright © 2024 NewsBlur. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
@objc class TrainerViewController: BaseViewController {
|
||||
@objc var isStoryTrainer = false
|
||||
|
||||
@objc var isFeedLoaded = false
|
||||
|
||||
lazy var hostingController = makeHostingController()
|
||||
|
||||
var trainerView: TrainerView {
|
||||
return hostingController.rootView
|
||||
}
|
||||
|
||||
var storyCache: StoryCache {
|
||||
return appDelegate.feedDetailViewController.storyCache
|
||||
}
|
||||
|
||||
private func makeHostingController() -> UIHostingController<TrainerView> {
|
||||
let trainerView = TrainerView(interaction: self, cache: storyCache)
|
||||
let trainerController = UIHostingController(rootView: trainerView)
|
||||
trainerController.view.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
return trainerController
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
addChild(hostingController)
|
||||
view.addSubview(hostingController.view)
|
||||
hostingController.didMove(toParent: self)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
hostingController.view.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
hostingController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
hostingController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
hostingController.view.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
|
||||
])
|
||||
|
||||
// changedLayout()
|
||||
}
|
||||
|
||||
@objc func reload() {
|
||||
trainerView.reload()
|
||||
}
|
||||
}
|
||||
|
||||
extension TrainerViewController: TrainerInteraction {
|
||||
//TODO: 🚧
|
||||
}
|
28
clients/ios/Classes/TrainerWord.swift
Normal file
28
clients/ios/Classes/TrainerWord.swift
Normal file
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// TrainerWord.swift
|
||||
// NewsBlur
|
||||
//
|
||||
// Created by David Sinclair on 2024-04-03.
|
||||
// Copyright © 2024 NewsBlur. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct TrainerWord: View {
|
||||
var word: String
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
Text(word)
|
||||
.colored(Color(white: ThemeManager.shared.isSystemDark ? 0.8 : 0.1))
|
||||
.padding([.top, .bottom], 1)
|
||||
.padding([.leading, .trailing], 1)
|
||||
.background(Color(white: ThemeManager.shared.isSystemDark ? 0.35 : 0.95))
|
||||
.clipShape(RoundedRectangle(cornerRadius: 5))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
TrainerWord(word: "Example")
|
||||
}
|
|
@ -54,7 +54,7 @@ const int COUNT_HEIGHT = 18;
|
|||
CGRect rr;
|
||||
|
||||
if (listType == NBFeedListSocial) {
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!appDelegate.isPhone) {
|
||||
rr = CGRectMake(rect.size.width + rect.origin.x - psOffset, CGRectGetMidY(r)-COUNT_HEIGHT/2, psWidth, COUNT_HEIGHT);
|
||||
} else {
|
||||
rr = CGRectMake(rect.size.width + rect.origin.x - psOffset, CGRectGetMidY(r)-COUNT_HEIGHT/2, psWidth, COUNT_HEIGHT);
|
||||
|
@ -98,7 +98,7 @@ const int COUNT_HEIGHT = 18;
|
|||
if (nt > 0 && appDelegate.selectedIntelligence <= 0) {
|
||||
CGRect rr;
|
||||
if (listType == NBFeedListSocial) {
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
if (!appDelegate.isPhone) {
|
||||
rr = CGRectMake(rect.size.width + rect.origin.x - psWidth - psPadding - ntOffset, CGRectGetMidY(r)-COUNT_HEIGHT/2, ntWidth, COUNT_HEIGHT);
|
||||
} else {
|
||||
rr = CGRectMake(rect.size.width + rect.origin.x - psWidth - psPadding - ntOffset, CGRectGetMidY(r)-COUNT_HEIGHT/2, ntWidth, COUNT_HEIGHT);
|
||||
|
|
|
@ -10,13 +10,10 @@
|
|||
#import "NewsBlurAppDelegate.h"
|
||||
#import "NewsBlur-Swift.h"
|
||||
|
||||
@class NewsBlurAppDelegate;
|
||||
@class ProfileBadge;
|
||||
|
||||
@interface UserProfileViewController : BaseViewController
|
||||
<UITableViewDataSource, UITableViewDelegate> {
|
||||
NewsBlurAppDelegate *appDelegate;
|
||||
|
||||
UILabel *followingCount;
|
||||
UILabel *followersCount;
|
||||
ProfileBadge *profileBadge;
|
||||
|
@ -26,7 +23,6 @@
|
|||
NSDictionary *userProfile;
|
||||
}
|
||||
|
||||
@property (nonatomic) NewsBlurAppDelegate *appDelegate;
|
||||
@property (nonatomic) ProfileBadge *profileBadge;
|
||||
@property (nonatomic) UITableView *profileTable;
|
||||
@property (nonatomic) NSArray *activitiesArray;
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
@implementation UserProfileViewController
|
||||
|
||||
@synthesize appDelegate;
|
||||
@synthesize profileBadge;
|
||||
@synthesize profileTable;
|
||||
@synthesize activitiesArray;
|
||||
|
@ -40,9 +39,7 @@
|
|||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view from its nib.
|
||||
self.appDelegate = (NewsBlurAppDelegate *)[[UIApplication sharedApplication] delegate];
|
||||
|
||||
|
||||
UITableView *profiles = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) style:UITableViewStyleGrouped];
|
||||
self.profileTable = profiles;
|
||||
self.profileTable.dataSource = self;
|
||||
|
@ -89,7 +86,6 @@
|
|||
// self.view.frame = self.view.bounds;
|
||||
self.preferredContentSize = CGSizeMake(320, 454);
|
||||
|
||||
self.appDelegate = (NewsBlurAppDelegate *)[[UIApplication sharedApplication] delegate];
|
||||
[MBProgressHUD hideHUDForView:self.view animated:YES];
|
||||
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
|
||||
HUD.labelText = @"Profiling...";
|
||||
|
|
|
@ -17,7 +17,15 @@
|
|||
170E3CD124F8A664009CE819 /* SplitViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 170E3CD024F8A664009CE819 /* SplitViewDelegate.swift */; };
|
||||
170E3CD324F8A89B009CE819 /* HorizontalPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 170E3CD224F8A89B009CE819 /* HorizontalPageViewController.swift */; };
|
||||
170E3CD724F8AB0D009CE819 /* FeedDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 170E3CD624F8AB0D009CE819 /* FeedDetailViewController.swift */; };
|
||||
17150E1E2B05775A004D5309 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17150E1D2B05775A004D5309 /* SceneDelegate.swift */; };
|
||||
17150E1F2B05775A004D5309 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17150E1D2B05775A004D5309 /* SceneDelegate.swift */; };
|
||||
1715D02B2166B3F900227731 /* PremiumManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1715D02A2166B3F900227731 /* PremiumManager.m */; };
|
||||
17179E292BD6F86C006B18D5 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 17179E282BD6F86C006B18D5 /* PrivacyInfo.xcprivacy */; };
|
||||
17179E2A2BD6F86D006B18D5 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 17179E282BD6F86C006B18D5 /* PrivacyInfo.xcprivacy */; };
|
||||
171904B52BBC8D4E004CCC96 /* TrainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171904B42BBC8D4E004CCC96 /* TrainerView.swift */; };
|
||||
171904B62BBC8D4E004CCC96 /* TrainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171904B42BBC8D4E004CCC96 /* TrainerView.swift */; };
|
||||
171904B82BBCA712004CCC96 /* TrainerCapsule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171904B72BBCA712004CCC96 /* TrainerCapsule.swift */; };
|
||||
171904B92BBCA712004CCC96 /* TrainerCapsule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171904B72BBCA712004CCC96 /* TrainerCapsule.swift */; };
|
||||
171B6FFD25C4C7C8008638A9 /* StoryPagesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171B6FFC25C4C7C8008638A9 /* StoryPagesViewController.swift */; };
|
||||
1721C9D12497F91A00B0EDC4 /* mute_gray.png in Resources */ = {isa = PBXBuildFile; fileRef = 1721C9D02497F91900B0EDC4 /* mute_gray.png */; };
|
||||
1723388B26BE43EB00610784 /* WidgetLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1723388A26BE43EB00610784 /* WidgetLoader.swift */; };
|
||||
|
@ -503,7 +511,7 @@
|
|||
1757920A2930605500490924 /* g_icn_textview_black.png in Resources */ = {isa = PBXBuildFile; fileRef = FF83FF0F1FB54691008DAC0F /* g_icn_textview_black.png */; };
|
||||
1757920B2930605500490924 /* logo_58.png in Resources */ = {isa = PBXBuildFile; fileRef = FF322234185BC1AA004078AA /* logo_58.png */; };
|
||||
1757920C2930605500490924 /* logo_144.png in Resources */ = {isa = PBXBuildFile; fileRef = FFC486A619CA40B700F4758F /* logo_144.png */; };
|
||||
1757920D2930605500490924 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = FFF1E4C717750BDD00BF59D3 /* Settings.bundle */; };
|
||||
1757920D2930605500490924 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = FFF1E4C717750BDD00BF59D3 /* Settings.bundle */; platformFilter = ios; };
|
||||
1757920E2930605500490924 /* menu_icn_preferences.png in Resources */ = {isa = PBXBuildFile; fileRef = FFF1E4C917750D2C00BF59D3 /* menu_icn_preferences.png */; };
|
||||
1757920F2930605500490924 /* menu_icn_preferences@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFF1E4CA17750D2C00BF59D3 /* menu_icn_preferences@2x.png */; };
|
||||
175792102930605500490924 /* checkmark.png in Resources */ = {isa = PBXBuildFile; fileRef = FF855B541794A53A0098D48A /* checkmark.png */; };
|
||||
|
@ -708,6 +716,8 @@
|
|||
175792DA2930605500490924 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 78095E3E128EF35400230C8E /* CFNetwork.framework */; };
|
||||
175792E72930611C00490924 /* LaunchScreenDev.xib in Resources */ = {isa = PBXBuildFile; fileRef = 175792E62930611B00490924 /* LaunchScreenDev.xib */; };
|
||||
175792E92930617600490924 /* logo_newsblur_512-dev.png in Resources */ = {isa = PBXBuildFile; fileRef = 175792E82930617600490924 /* logo_newsblur_512-dev.png */; };
|
||||
175DC6AF2BBB87D200B3708F /* TrainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 175DC6AE2BBB87D200B3708F /* TrainerViewController.swift */; };
|
||||
175DC6B02BBB87D200B3708F /* TrainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 175DC6AE2BBB87D200B3708F /* TrainerViewController.swift */; };
|
||||
175FAC4C23AB34EB002AC38C /* menu_icn_widget.png in Resources */ = {isa = PBXBuildFile; fileRef = 175FAC4A23AB34EB002AC38C /* menu_icn_widget.png */; };
|
||||
175FAC4D23AB34EB002AC38C /* menu_icn_widget@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 175FAC4B23AB34EB002AC38C /* menu_icn_widget@2x.png */; };
|
||||
176129601C630AEB00702FE4 /* mute_feed_off.png in Resources */ = {isa = PBXBuildFile; fileRef = 1761295C1C630AEB00702FE4 /* mute_feed_off.png */; };
|
||||
|
@ -716,6 +726,20 @@
|
|||
176129631C630AEB00702FE4 /* mute_feed_on@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1761295F1C630AEB00702FE4 /* mute_feed_on@2x.png */; };
|
||||
1763E2A123B1BCC900BA080C /* WidgetFeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1763E2A023B1BCC900BA080C /* WidgetFeed.swift */; };
|
||||
1763E2A323B1CEB600BA080C /* WidgetBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1763E2A223B1CEB600BA080C /* WidgetBarView.swift */; };
|
||||
17654E332B02C08700F61B2B /* WidgetLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1723388A26BE43EB00610784 /* WidgetLoader.swift */; };
|
||||
17654E342B02C08700F61B2B /* WidgetCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1723389026BF7CFE00610784 /* WidgetCache.swift */; };
|
||||
17654E352B02C08700F61B2B /* WidgetExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 173CB31326BCE94700BA872A /* WidgetExtension.swift */; };
|
||||
17654E362B02C08700F61B2B /* WidgetStory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1723388C26BE440400610784 /* WidgetStory.swift */; };
|
||||
17654E372B02C08700F61B2B /* WidgetBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1723389326C3775A00610784 /* WidgetBarView.swift */; };
|
||||
17654E382B02C08700F61B2B /* WidgetDebugTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17997C5727A8FDD100483E69 /* WidgetDebugTimer.swift */; };
|
||||
17654E392B02C08700F61B2B /* WidgetFeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1723388D26BE440400610784 /* WidgetFeed.swift */; };
|
||||
17654E3A2B02C08700F61B2B /* WidgetStoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1791C21426C4C7BC00D815AA /* WidgetStoryView.swift */; };
|
||||
17654E3C2B02C08700F61B2B /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 173CB31026BCE94700BA872A /* SwiftUI.framework */; };
|
||||
17654E3D2B02C08700F61B2B /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 173CB30E26BCE94700BA872A /* WidgetKit.framework */; };
|
||||
17654E3F2B02C08700F61B2B /* WhitneySSm-Medium-Bas.otf in Resources */ = {isa = PBXBuildFile; fileRef = FF3A3E051BFBBAC600ADC01A /* WhitneySSm-Medium-Bas.otf */; };
|
||||
17654E402B02C08700F61B2B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 173CB31526BCE94A00BA872A /* Assets.xcassets */; };
|
||||
17654E412B02C08700F61B2B /* WhitneySSm-Book-Bas.otf in Resources */ = {isa = PBXBuildFile; fileRef = FF3A3E011BFBBAC600ADC01A /* WhitneySSm-Book-Bas.otf */; };
|
||||
17654E472B02C0A700F61B2B /* NewsBlur Alpha Widget.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 17654E452B02C08700F61B2B /* NewsBlur Alpha Widget.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
176A5C7A24F8BD1B009E8DF9 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 176A5C7924F8BD1B009E8DF9 /* DetailViewController.swift */; };
|
||||
17731A9D23DFAD3D00759A7D /* ImportExportPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17731A9C23DFAD3D00759A7D /* ImportExportPreferences.swift */; };
|
||||
177551D5238E228A00E27818 /* NotificationCenter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 177551D4238E228A00E27818 /* NotificationCenter.framework */; platformFilter = ios; };
|
||||
|
@ -737,7 +761,13 @@
|
|||
1788939D249332E6004CBA4E /* g_icn_search.png in Resources */ = {isa = PBXBuildFile; fileRef = 1788939C249332E6004CBA4E /* g_icn_search.png */; };
|
||||
1791C21526C4C7BC00D815AA /* WidgetStoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1791C21426C4C7BC00D815AA /* WidgetStoryView.swift */; };
|
||||
17997C5827A8FDD100483E69 /* WidgetDebugTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17997C5727A8FDD100483E69 /* WidgetDebugTimer.swift */; };
|
||||
179A88022B48E64A00916CF4 /* ToolbarDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 179A88012B48E64900916CF4 /* ToolbarDelegate.swift */; };
|
||||
179A88032B48E64A00916CF4 /* ToolbarDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 179A88012B48E64900916CF4 /* ToolbarDelegate.swift */; };
|
||||
179DD9CF23DFDD51007BFD21 /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 179DD9CE23DFDD51007BFD21 /* CloudKit.framework */; };
|
||||
17A0518A2C095B20000994E9 /* AuxSceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17A051892C095B20000994E9 /* AuxSceneDelegate.swift */; };
|
||||
17A0518B2C095B20000994E9 /* AuxSceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17A051892C095B20000994E9 /* AuxSceneDelegate.swift */; };
|
||||
17A0518D2C095E78000994E9 /* AuxInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 17A0518C2C095E78000994E9 /* AuxInterface.storyboard */; };
|
||||
17A0518E2C095E78000994E9 /* AuxInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 17A0518C2C095E78000994E9 /* AuxInterface.storyboard */; };
|
||||
17A396D924F86A8F0023C9E2 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 17A396D824F86A8F0023C9E2 /* MainInterface.storyboard */; };
|
||||
17A92A3C289B7C6B00AB0A78 /* saved-stories@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 17A92A3B289B7C6B00AB0A78 /* saved-stories@2x.png */; };
|
||||
17AACFE122279A3C00DE6EA4 /* autoscroll_resume@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 17AACFD722279A3900DE6EA4 /* autoscroll_resume@2x.png */; };
|
||||
|
@ -754,6 +784,14 @@
|
|||
17B14BDD23E24B4E00CF8D2C /* menu_icn_statistics@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 17B14BDB23E24B4E00CF8D2C /* menu_icn_statistics@2x.png */; };
|
||||
17B33D1827D97282009108AD /* g_icn_folder_widget.png in Resources */ = {isa = PBXBuildFile; fileRef = 17B33D1627D97281009108AD /* g_icn_folder_widget.png */; };
|
||||
17B33D1927D97282009108AD /* g_icn_folder_widget@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 17B33D1727D97282009108AD /* g_icn_folder_widget@2x.png */; };
|
||||
17BC56A72BBE4A5600A30C41 /* TrainerWord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17BC56A62BBE4A5600A30C41 /* TrainerWord.swift */; };
|
||||
17BC56A82BBE4A5600A30C41 /* TrainerWord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17BC56A62BBE4A5600A30C41 /* TrainerWord.swift */; };
|
||||
17BC56AA2BBF6BC000A30C41 /* Feed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17BC56A92BBF6BC000A30C41 /* Feed.swift */; };
|
||||
17BC56AB2BBF6BC000A30C41 /* Feed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17BC56A92BBF6BC000A30C41 /* Feed.swift */; };
|
||||
17BC56AD2BBF6C0000A30C41 /* StoryCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17BC56AC2BBF6C0000A30C41 /* StoryCache.swift */; };
|
||||
17BC56AE2BBF6C0000A30C41 /* StoryCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17BC56AC2BBF6C0000A30C41 /* StoryCache.swift */; };
|
||||
17BC56B02BBF6C2200A30C41 /* StorySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17BC56AF2BBF6C2200A30C41 /* StorySettings.swift */; };
|
||||
17BC56B12BBF6C2200A30C41 /* StorySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17BC56AF2BBF6C2200A30C41 /* StorySettings.swift */; };
|
||||
17BD3BA52271102500F615EC /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 17BD3BA42271102500F615EC /* Intents.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
|
||||
17BD3BA72271122800F615EC /* CoreSpotlight.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 17BD3BA62271122800F615EC /* CoreSpotlight.framework */; };
|
||||
17BD3BA92271125400F615EC /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 17BD3BA82271125400F615EC /* CoreServices.framework */; };
|
||||
|
@ -830,6 +868,10 @@
|
|||
17EB505D1BE4411E0021358B /* choose_font@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 17EB505B1BE4411E0021358B /* choose_font@2x.png */; };
|
||||
17EB50601BE46A900021358B /* FontListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 17EB505F1BE46A900021358B /* FontListViewController.m */; };
|
||||
17EB50621BE46BB00021358B /* FontListViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 17EB50611BE46BB00021358B /* FontListViewController.xib */; };
|
||||
17EE11C82B27FA0C00E7C0CC /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 17EE11C72B27FA0C00E7C0CC /* Settings.bundle */; platformFilter = maccatalyst; };
|
||||
17EE11C92B27FA0C00E7C0CC /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 17EE11C72B27FA0C00E7C0CC /* Settings.bundle */; platformFilter = maccatalyst; };
|
||||
17EE11CE2B28011D00E7C0CC /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 17EE11CD2B28011D00E7C0CC /* Credits.rtf */; };
|
||||
17EE11CF2B28011D00E7C0CC /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 17EE11CD2B28011D00E7C0CC /* Credits.rtf */; };
|
||||
17F156711BDABBF60092EBFD /* safari_shadow@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 17F156701BDABBF60092EBFD /* safari_shadow@2x.png */; };
|
||||
17F363F2238E417300D5379D /* WidgetExtensionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17F363EF238E417300D5379D /* WidgetExtensionViewController.swift */; };
|
||||
17F39EAA264754CD004B46D1 /* image_preview_large_left.png in Resources */ = {isa = PBXBuildFile; fileRef = 17F39EA6264754CC004B46D1 /* image_preview_large_left.png */; };
|
||||
|
@ -1320,7 +1362,7 @@
|
|||
FFEA5AEC19D340BC00ED87A0 /* logo_newsblur_512.png in Resources */ = {isa = PBXBuildFile; fileRef = FFEA5AEB19D340BC00ED87A0 /* logo_newsblur_512.png */; };
|
||||
FFECD019172B105800D45A62 /* UIActivitySafari.png in Resources */ = {isa = PBXBuildFile; fileRef = FFECD017172B105800D45A62 /* UIActivitySafari.png */; };
|
||||
FFECD01A172B105800D45A62 /* UIActivitySafari@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFECD018172B105800D45A62 /* UIActivitySafari@2x.png */; };
|
||||
FFF1E4C817750BDD00BF59D3 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = FFF1E4C717750BDD00BF59D3 /* Settings.bundle */; };
|
||||
FFF1E4C817750BDD00BF59D3 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = FFF1E4C717750BDD00BF59D3 /* Settings.bundle */; platformFilter = ios; };
|
||||
FFF1E4CB17750D2C00BF59D3 /* menu_icn_preferences.png in Resources */ = {isa = PBXBuildFile; fileRef = FFF1E4C917750D2C00BF59D3 /* menu_icn_preferences.png */; };
|
||||
FFF1E4CC17750D2C00BF59D3 /* menu_icn_preferences@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFF1E4CA17750D2C00BF59D3 /* menu_icn_preferences@2x.png */; };
|
||||
FFF8B3AF1F847505001AB95E /* NBDashboardNavigationBar.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF8B3AE1F847505001AB95E /* NBDashboardNavigationBar.m */; };
|
||||
|
@ -1342,6 +1384,13 @@
|
|||
remoteGlobalIDString = 1749390F1C251BFE003D98AA;
|
||||
remoteInfo = "Share Extension";
|
||||
};
|
||||
17654E482B02C0A800F61B2B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 17654E312B02C08700F61B2B;
|
||||
remoteInfo = "NewsBlur Alpha Widget";
|
||||
};
|
||||
177551DD238E228A00E27818 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
|
||||
|
@ -1359,6 +1408,17 @@
|
|||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
17654E4A2B02C0A800F61B2B /* Embed Foundation Extensions */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 13;
|
||||
files = (
|
||||
17654E472B02C0A700F61B2B /* NewsBlur Alpha Widget.appex in Embed Foundation Extensions */,
|
||||
);
|
||||
name = "Embed Foundation Extensions";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
FF8A94A31DE3BB77000A4C31 /* Embed Foundation Extensions */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
@ -1397,8 +1457,12 @@
|
|||
170E3CD024F8A664009CE819 /* SplitViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplitViewDelegate.swift; sourceTree = "<group>"; };
|
||||
170E3CD224F8A89B009CE819 /* HorizontalPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HorizontalPageViewController.swift; sourceTree = "<group>"; };
|
||||
170E3CD624F8AB0D009CE819 /* FeedDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedDetailViewController.swift; sourceTree = "<group>"; };
|
||||
17150E1D2B05775A004D5309 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
||||
1715D0292166B3F900227731 /* PremiumManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PremiumManager.h; sourceTree = "<group>"; };
|
||||
1715D02A2166B3F900227731 /* PremiumManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PremiumManager.m; sourceTree = "<group>"; };
|
||||
17179E282BD6F86C006B18D5 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
|
||||
171904B42BBC8D4E004CCC96 /* TrainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrainerView.swift; sourceTree = "<group>"; };
|
||||
171904B72BBCA712004CCC96 /* TrainerCapsule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrainerCapsule.swift; sourceTree = "<group>"; };
|
||||
171B6FFC25C4C7C8008638A9 /* StoryPagesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoryPagesViewController.swift; sourceTree = "<group>"; };
|
||||
1721C9D02497F91900B0EDC4 /* mute_gray.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = mute_gray.png; sourceTree = "<group>"; };
|
||||
1723388A26BE43EB00610784 /* WidgetLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetLoader.swift; sourceTree = "<group>"; };
|
||||
|
@ -1465,6 +1529,7 @@
|
|||
175792E42930605500490924 /* NB Alpha.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "NB Alpha.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
175792E62930611B00490924 /* LaunchScreenDev.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LaunchScreenDev.xib; sourceTree = "<group>"; };
|
||||
175792E82930617600490924 /* logo_newsblur_512-dev.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "logo_newsblur_512-dev.png"; sourceTree = "<group>"; };
|
||||
175DC6AE2BBB87D200B3708F /* TrainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrainerViewController.swift; sourceTree = "<group>"; };
|
||||
175FAC4A23AB34EB002AC38C /* menu_icn_widget.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu_icn_widget.png; sourceTree = "<group>"; };
|
||||
175FAC4B23AB34EB002AC38C /* menu_icn_widget@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu_icn_widget@2x.png"; sourceTree = "<group>"; };
|
||||
1761295C1C630AEB00702FE4 /* mute_feed_off.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = mute_feed_off.png; sourceTree = "<group>"; };
|
||||
|
@ -1473,6 +1538,7 @@
|
|||
1761295F1C630AEB00702FE4 /* mute_feed_on@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "mute_feed_on@2x.png"; sourceTree = "<group>"; };
|
||||
1763E2A023B1BCC900BA080C /* WidgetFeed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetFeed.swift; sourceTree = "<group>"; };
|
||||
1763E2A223B1CEB600BA080C /* WidgetBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetBarView.swift; sourceTree = "<group>"; };
|
||||
17654E452B02C08700F61B2B /* NewsBlur Alpha Widget.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "NewsBlur Alpha Widget.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
176A5C7924F8BD1B009E8DF9 /* DetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = "<group>"; };
|
||||
17731A9C23DFAD3D00759A7D /* ImportExportPreferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportExportPreferences.swift; sourceTree = "<group>"; };
|
||||
177551D3238E228A00E27818 /* Old NewsBlur Latest.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Old NewsBlur Latest.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
@ -1494,8 +1560,11 @@
|
|||
1788939C249332E6004CBA4E /* g_icn_search.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = g_icn_search.png; sourceTree = "<group>"; };
|
||||
1791C21426C4C7BC00D815AA /* WidgetStoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetStoryView.swift; sourceTree = "<group>"; };
|
||||
17997C5727A8FDD100483E69 /* WidgetDebugTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetDebugTimer.swift; sourceTree = "<group>"; };
|
||||
179A88012B48E64900916CF4 /* ToolbarDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolbarDelegate.swift; sourceTree = "<group>"; };
|
||||
179DD9CC23DFD20E007BFD21 /* BridgingHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = BridgingHeader.h; path = "Other Sources/BridgingHeader.h"; sourceTree = "<group>"; };
|
||||
179DD9CE23DFDD51007BFD21 /* CloudKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CloudKit.framework; path = System/Library/Frameworks/CloudKit.framework; sourceTree = SDKROOT; };
|
||||
17A051892C095B20000994E9 /* AuxSceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuxSceneDelegate.swift; sourceTree = "<group>"; };
|
||||
17A0518C2C095E78000994E9 /* AuxInterface.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = AuxInterface.storyboard; sourceTree = "<group>"; };
|
||||
17A396D824F86A8F0023C9E2 /* MainInterface.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = MainInterface.storyboard; sourceTree = "<group>"; };
|
||||
17A92A3B289B7C6B00AB0A78 /* saved-stories@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "saved-stories@2x.png"; sourceTree = "<group>"; };
|
||||
17AACFD722279A3900DE6EA4 /* autoscroll_resume@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "autoscroll_resume@2x.png"; sourceTree = "<group>"; };
|
||||
|
@ -1513,6 +1582,10 @@
|
|||
17B33D1627D97281009108AD /* g_icn_folder_widget.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = g_icn_folder_widget.png; sourceTree = "<group>"; };
|
||||
17B33D1727D97282009108AD /* g_icn_folder_widget@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "g_icn_folder_widget@2x.png"; sourceTree = "<group>"; };
|
||||
17B96BE624304F72009A8EED /* Story Notification Service Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Story Notification Service Extension.entitlements"; sourceTree = "<group>"; };
|
||||
17BC56A62BBE4A5600A30C41 /* TrainerWord.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrainerWord.swift; sourceTree = "<group>"; };
|
||||
17BC56A92BBF6BC000A30C41 /* Feed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Feed.swift; sourceTree = "<group>"; };
|
||||
17BC56AC2BBF6C0000A30C41 /* StoryCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoryCache.swift; sourceTree = "<group>"; };
|
||||
17BC56AF2BBF6C2200A30C41 /* StorySettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorySettings.swift; sourceTree = "<group>"; };
|
||||
17BD3BA42271102500F615EC /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; };
|
||||
17BD3BA62271122800F615EC /* CoreSpotlight.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreSpotlight.framework; path = System/Library/Frameworks/CoreSpotlight.framework; sourceTree = SDKROOT; };
|
||||
17BD3BA82271125400F615EC /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; };
|
||||
|
@ -1593,6 +1666,8 @@
|
|||
17EB505E1BE46A900021358B /* FontListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FontListViewController.h; sourceTree = "<group>"; };
|
||||
17EB505F1BE46A900021358B /* FontListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FontListViewController.m; sourceTree = "<group>"; };
|
||||
17EB50611BE46BB00021358B /* FontListViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = FontListViewController.xib; path = Classes/FontListViewController.xib; sourceTree = SOURCE_ROOT; };
|
||||
17EE11C72B27FA0C00E7C0CC /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = Settings.bundle; path = mac/Settings.bundle; sourceTree = "<group>"; };
|
||||
17EE11CD2B28011D00E7C0CC /* Credits.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; name = Credits.rtf; path = mac/Credits.rtf; sourceTree = "<group>"; };
|
||||
17F156701BDABBF60092EBFD /* safari_shadow@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "safari_shadow@2x.png"; sourceTree = "<group>"; };
|
||||
17F363EF238E417300D5379D /* WidgetExtensionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WidgetExtensionViewController.swift; sourceTree = "<group>"; };
|
||||
17F39EA6264754CC004B46D1 /* image_preview_large_left.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = image_preview_large_left.png; sourceTree = "<group>"; };
|
||||
|
@ -1766,7 +1841,7 @@
|
|||
784B50EA127E3F68008F90EA /* LoginViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoginViewController.h; sourceTree = "<group>"; };
|
||||
784B50EB127E3F68008F90EA /* LoginViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LoginViewController.m; sourceTree = "<group>"; };
|
||||
788EF355127E5BC80088EDC5 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
|
||||
8D1107310486CEB800E47090 /* NewsBlur-iPhone-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "NewsBlur-iPhone-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = "<group>"; };
|
||||
8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = "<group>"; };
|
||||
E160F0551C9DAC2C00CB96DF /* UIViewController+HidePopover.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIViewController+HidePopover.h"; path = "Other Sources/UIViewController+HidePopover.h"; sourceTree = "<group>"; };
|
||||
E160F0561C9DAC2C00CB96DF /* UIViewController+HidePopover.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIViewController+HidePopover.m"; path = "Other Sources/UIViewController+HidePopover.m"; sourceTree = "<group>"; };
|
||||
E1C44B09200147ED002128AD /* StoryTitleAttributedString.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StoryTitleAttributedString.h; sourceTree = "<group>"; };
|
||||
|
@ -2071,7 +2146,7 @@
|
|||
FF8A949A1DE3BB77000A4C31 /* NotificationService.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NotificationService.m; sourceTree = "<group>"; };
|
||||
FF8A949C1DE3BB77000A4C31 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
FF8AFE561CAC73C9005D9B40 /* unread_blue@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "unread_blue@3x.png"; sourceTree = "<group>"; };
|
||||
FF8C49921BBC9D140010D894 /* NewsBlur.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = NewsBlur.entitlements; path = NewsBlur/NewsBlur.entitlements; sourceTree = "<group>"; };
|
||||
FF8C49921BBC9D140010D894 /* App.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = App.entitlements; sourceTree = "<group>"; };
|
||||
FF8D1EA51BAA304E00725D8A /* Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reachability.h; sourceTree = "<group>"; };
|
||||
FF8D1EA61BAA304E00725D8A /* Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Reachability.m; sourceTree = "<group>"; };
|
||||
FF8D1EBD1BAA311000725D8A /* SBJson4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJson4.h; sourceTree = "<group>"; };
|
||||
|
@ -2313,6 +2388,15 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
17654E3B2B02C08700F61B2B /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
17654E3C2B02C08700F61B2B /* SwiftUI.framework in Frameworks */,
|
||||
17654E3D2B02C08700F61B2B /* WidgetKit.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
177551D0238E228A00E27818 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
@ -2513,6 +2597,7 @@
|
|||
177551D3238E228A00E27818 /* Old NewsBlur Latest.appex */,
|
||||
173CB30D26BCE94700BA872A /* NewsBlur Widget.appex */,
|
||||
175792E42930605500490924 /* NB Alpha.app */,
|
||||
17654E452B02C08700F61B2B /* NewsBlur Alpha Widget.appex */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
|
@ -2531,8 +2616,6 @@
|
|||
173CB31226BCE94700BA872A /* Widget Extension */,
|
||||
29B97323FDCFA39411CA2CEA /* Frameworks */,
|
||||
19C28FACFE9D520D11CA2CBB /* Products */,
|
||||
FF8C49921BBC9D140010D894 /* NewsBlur.entitlements */,
|
||||
8D1107310486CEB800E47090 /* NewsBlur-iPhone-Info.plist */,
|
||||
);
|
||||
name = CustomTemplate;
|
||||
sourceTree = "<group>";
|
||||
|
@ -2636,14 +2719,20 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
17A396D824F86A8F0023C9E2 /* MainInterface.storyboard */,
|
||||
17A0518C2C095E78000994E9 /* AuxInterface.storyboard */,
|
||||
FF191E4E18A323F400473252 /* Images.xcassets */,
|
||||
17EE11CD2B28011D00E7C0CC /* Credits.rtf */,
|
||||
430C4BBE15D7208000B9F63B /* FTUX */,
|
||||
431B857815A132C500DCE497 /* js */,
|
||||
431B857715A132BE00DCE497 /* css */,
|
||||
1753696F1BE535CF00904D00 /* fonts */,
|
||||
431B857615A132B600DCE497 /* Images */,
|
||||
FFF1E4C717750BDD00BF59D3 /* Settings.bundle */,
|
||||
17EE11C72B27FA0C00E7C0CC /* Settings.bundle */,
|
||||
E1D123FD1C66753D00434F40 /* Localizable.stringsdict */,
|
||||
FF8C49921BBC9D140010D894 /* App.entitlements */,
|
||||
8D1107310486CEB800E47090 /* Info.plist */,
|
||||
17179E282BD6F86C006B18D5 /* PrivacyInfo.xcprivacy */,
|
||||
);
|
||||
path = Resources;
|
||||
sourceTree = "<group>";
|
||||
|
@ -2769,6 +2858,10 @@
|
|||
17EB505F1BE46A900021358B /* FontListViewController.m */,
|
||||
78095EC6128F30B500230C8E /* OriginalStoryViewController.h */,
|
||||
78095EC7128F30B500230C8E /* OriginalStoryViewController.m */,
|
||||
175DC6AE2BBB87D200B3708F /* TrainerViewController.swift */,
|
||||
171904B42BBC8D4E004CCC96 /* TrainerView.swift */,
|
||||
171904B72BBCA712004CCC96 /* TrainerCapsule.swift */,
|
||||
17BC56A62BBE4A5600A30C41 /* TrainerWord.swift */,
|
||||
FF67D3B0168924C40057A7DA /* TrainerViewController.h */,
|
||||
FF67D3B1168924C40057A7DA /* TrainerViewController.m */,
|
||||
FF6282131A11613900271FDB /* UserTagsViewController.h */,
|
||||
|
@ -3230,7 +3323,10 @@
|
|||
43D8189F15B9404D00733444 /* Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
17BC56A92BBF6BC000A30C41 /* Feed.swift */,
|
||||
172ECBF6298B1239006371BC /* Story.swift */,
|
||||
17BC56AC2BBF6C0000A30C41 /* StoryCache.swift */,
|
||||
17BC56AF2BBF6C2200A30C41 /* StorySettings.swift */,
|
||||
);
|
||||
name = Models;
|
||||
sourceTree = "<group>";
|
||||
|
@ -3274,6 +3370,9 @@
|
|||
175792E62930611B00490924 /* LaunchScreenDev.xib */,
|
||||
1D3623240D0F684500981E51 /* NewsBlurAppDelegate.h */,
|
||||
1D3623250D0F684500981E51 /* NewsBlurAppDelegate.m */,
|
||||
17150E1D2B05775A004D5309 /* SceneDelegate.swift */,
|
||||
17A051892C095B20000994E9 /* AuxSceneDelegate.swift */,
|
||||
179A88012B48E64900916CF4 /* ToolbarDelegate.swift */,
|
||||
FFD1D72F1459B63500E46F89 /* BaseViewController.h */,
|
||||
FFD1D7301459B63500E46F89 /* BaseViewController.m */,
|
||||
17C074941C14C46B00CFCDB7 /* ThemeManager.h */,
|
||||
|
@ -3696,10 +3795,12 @@
|
|||
175790622930605500490924 /* Resources */,
|
||||
175792252930605500490924 /* Sources */,
|
||||
175792C12930605500490924 /* Frameworks */,
|
||||
17654E4A2B02C0A800F61B2B /* Embed Foundation Extensions */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
17654E492B02C0A800F61B2B /* PBXTargetDependency */,
|
||||
);
|
||||
name = "NewsBlur Alpha";
|
||||
packageProductDependencies = (
|
||||
|
@ -3708,6 +3809,23 @@
|
|||
productReference = 175792E42930605500490924 /* NB Alpha.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
17654E312B02C08700F61B2B /* NewsBlur Alpha Widget */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 17654E422B02C08700F61B2B /* Build configuration list for PBXNativeTarget "NewsBlur Alpha Widget" */;
|
||||
buildPhases = (
|
||||
17654E322B02C08700F61B2B /* Sources */,
|
||||
17654E3B2B02C08700F61B2B /* Frameworks */,
|
||||
17654E3E2B02C08700F61B2B /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "NewsBlur Alpha Widget";
|
||||
productName = WidgetExtension;
|
||||
productReference = 17654E452B02C08700F61B2B /* NewsBlur Alpha Widget.appex */;
|
||||
productType = "com.apple.product-type.app-extension";
|
||||
};
|
||||
177551D2238E228A00E27818 /* Old Widget Extension */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 177551E2238E228A00E27818 /* Build configuration list for PBXNativeTarget "Old Widget Extension" */;
|
||||
|
@ -3773,8 +3891,9 @@
|
|||
29B97313FDCFA39411CA2CEA /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastSwiftUpdateCheck = 1120;
|
||||
LastUpgradeCheck = 1420;
|
||||
LastUpgradeCheck = 1540;
|
||||
ORGANIZATIONNAME = NewsBlur;
|
||||
TargetAttributes = {
|
||||
173CB30C26BCE94700BA872A = {
|
||||
|
@ -3864,6 +3983,7 @@
|
|||
FF8A94961DE3BB77000A4C31 /* Story Notification Service Extension */,
|
||||
177551D2238E228A00E27818 /* Old Widget Extension */,
|
||||
173CB30C26BCE94700BA872A /* NewsBlur Widget */,
|
||||
17654E312B02C08700F61B2B /* NewsBlur Alpha Widget */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
@ -3895,10 +4015,13 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
175790632930605500490924 /* ChronicleSSm-Book.otf in Resources */,
|
||||
1757920D2930605500490924 /* Settings.bundle in Resources */,
|
||||
175790642930605500490924 /* WhitneySSm-Book-Bas.otf in Resources */,
|
||||
175790652930605500490924 /* ChronicleSSm-BookItalic.otf in Resources */,
|
||||
175790662930605500490924 /* WhitneySSm-Medium-Bas.otf in Resources */,
|
||||
17A0518E2C095E78000994E9 /* AuxInterface.storyboard in Resources */,
|
||||
175790672930605500490924 /* icons8-stack-of-paper-100.png in Resources */,
|
||||
17EE11C92B27FA0C00E7C0CC /* Settings.bundle in Resources */,
|
||||
175790682930605500490924 /* WhitneySSm-MediumItalic-Bas.otf in Resources */,
|
||||
175790692930605500490924 /* WhitneySSm-BookItalic-Bas.otf in Resources */,
|
||||
1757906A2930605500490924 /* barbutton_sort_desc@3x.png in Resources */,
|
||||
|
@ -4106,6 +4229,7 @@
|
|||
175791342930605500490924 /* g_icn_greensun@2x.png in Resources */,
|
||||
175791352930605500490924 /* ak-icon-infrequent.png in Resources */,
|
||||
175791362930605500490924 /* nav_icn_add.png in Resources */,
|
||||
17EE11CF2B28011D00E7C0CC /* Credits.rtf in Resources */,
|
||||
175791372930605500490924 /* icons8-pyramids-100.png in Resources */,
|
||||
175791382930605500490924 /* ak-icon-global.png in Resources */,
|
||||
175791392930605500490924 /* content_preview_large@2x.png in Resources */,
|
||||
|
@ -4284,6 +4408,7 @@
|
|||
175791E42930605500490924 /* train@2x.png in Resources */,
|
||||
175791E52930605500490924 /* logo_40.png in Resources */,
|
||||
175791E62930605500490924 /* menu_icn_share.png in Resources */,
|
||||
17179E2A2BD6F86D006B18D5 /* PrivacyInfo.xcprivacy in Resources */,
|
||||
175791E72930605500490924 /* autoscroll_pause.png in Resources */,
|
||||
175791E82930605500490924 /* safari@3x.png in Resources */,
|
||||
175791E92930605500490924 /* g_icn_eating.png in Resources */,
|
||||
|
@ -4322,7 +4447,6 @@
|
|||
1757920A2930605500490924 /* g_icn_textview_black.png in Resources */,
|
||||
1757920B2930605500490924 /* logo_58.png in Resources */,
|
||||
1757920C2930605500490924 /* logo_144.png in Resources */,
|
||||
1757920D2930605500490924 /* Settings.bundle in Resources */,
|
||||
1757920E2930605500490924 /* menu_icn_preferences.png in Resources */,
|
||||
1757920F2930605500490924 /* menu_icn_preferences@2x.png in Resources */,
|
||||
175792102930605500490924 /* checkmark.png in Resources */,
|
||||
|
@ -4349,6 +4473,16 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
17654E3E2B02C08700F61B2B /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
17654E3F2B02C08700F61B2B /* WhitneySSm-Medium-Bas.otf in Resources */,
|
||||
17654E402B02C08700F61B2B /* Assets.xcassets in Resources */,
|
||||
17654E412B02C08700F61B2B /* WhitneySSm-Book-Bas.otf in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
177551D1238E228A00E27818 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
@ -4410,6 +4544,7 @@
|
|||
433323B9158901A40025064D /* fountain_pen@2x.png in Resources */,
|
||||
433323BB158901C10025064D /* login_background.png in Resources */,
|
||||
FF83FF151FB54693008DAC0F /* g_icn_lightning.png in Resources */,
|
||||
17EE11CE2B28011D00E7C0CC /* Credits.rtf in Resources */,
|
||||
17BE5A761C5DDA8C0075F92C /* barbutton_sort_desc@2x.png in Resources */,
|
||||
433323BE1589022C0025064D /* user.png in Resources */,
|
||||
433323BF1589022C0025064D /* user@2x.png in Resources */,
|
||||
|
@ -4615,6 +4750,7 @@
|
|||
17EB505D1BE4411E0021358B /* choose_font@2x.png in Resources */,
|
||||
FFC5F30C16E2D2C2007AC72C /* story_share_appnet_active@2x.png in Resources */,
|
||||
FFC5F30D16E2D2C2007AC72C /* story_share_appnet.png in Resources */,
|
||||
17EE11C82B27FA0C00E7C0CC /* Settings.bundle in Resources */,
|
||||
FFC5F30E16E2D2C2007AC72C /* story_share_appnet@2x.png in Resources */,
|
||||
1740C6A11C1110BA005EA453 /* theme_color_medium-sel@2x.png in Resources */,
|
||||
17876BA01C9911D40055DD15 /* g_icn_folder_sm.png in Resources */,
|
||||
|
@ -4661,6 +4797,7 @@
|
|||
FF22FE6E16E554540046165A /* barbutton_refresh.png in Resources */,
|
||||
FF22FE6F16E554540046165A /* barbutton_refresh@2x.png in Resources */,
|
||||
FF22FE7216E554FD0046165A /* barbutton_sendto.png in Resources */,
|
||||
17A0518D2C095E78000994E9 /* AuxInterface.storyboard in Resources */,
|
||||
FFB9BE4D17F4B65B00FE0A36 /* logo_120@2x.png in Resources */,
|
||||
FF03AFFF19F881380063002A /* ARChromeActivity@2x.png in Resources */,
|
||||
FF83FF1B1FB54693008DAC0F /* g_icn_privacy.png in Resources */,
|
||||
|
@ -4689,6 +4826,7 @@
|
|||
FF03AFE419F87A770063002A /* g_icn_folder_read.png in Resources */,
|
||||
FFDD845E16E8871A000AA0A2 /* menu_icn_fetch_subscribers.png in Resources */,
|
||||
FF5ACC211DE5ED7500FBD044 /* menu_icn_notifications.png in Resources */,
|
||||
17179E292BD6F86C006B18D5 /* PrivacyInfo.xcprivacy in Resources */,
|
||||
FFDD845F16E8871A000AA0A2 /* menu_icn_fetch_subscribers@2x.png in Resources */,
|
||||
FFDD846016E8871A000AA0A2 /* menu_icn_fetch.png in Resources */,
|
||||
FFDD846116E8871A000AA0A2 /* menu_icn_fetch@2x.png in Resources */,
|
||||
|
@ -4911,6 +5049,7 @@
|
|||
175792542930605500490924 /* IASKPSTextFieldSpecifierViewCell.m in Sources */,
|
||||
175792552930605500490924 /* SBJson4StreamWriter.m in Sources */,
|
||||
175792562930605500490924 /* FontSettingsViewController.m in Sources */,
|
||||
17BC56B12BBF6C2200A30C41 /* StorySettings.swift in Sources */,
|
||||
175792572930605500490924 /* IASKAppSettingsViewController.m in Sources */,
|
||||
175792582930605500490924 /* MarkReadMenuViewController.m in Sources */,
|
||||
175792592930605500490924 /* SSWAnimator.m in Sources */,
|
||||
|
@ -4932,10 +5071,14 @@
|
|||
175792692930605500490924 /* main.m in Sources */,
|
||||
1757926A2930605500490924 /* MBProgressHUD.m in Sources */,
|
||||
1757926B2930605500490924 /* NSString+HTML.m in Sources */,
|
||||
171904B92BBCA712004CCC96 /* TrainerCapsule.swift in Sources */,
|
||||
1757926C2930605500490924 /* IASKSettingsReader.m in Sources */,
|
||||
1757926D2930605500490924 /* UserTagsViewController.m in Sources */,
|
||||
1757926E2930605500490924 /* StringHelper.m in Sources */,
|
||||
1757926F2930605500490924 /* TransparentToolbar.m in Sources */,
|
||||
179A88032B48E64A00916CF4 /* ToolbarDelegate.swift in Sources */,
|
||||
175DC6B02BBB87D200B3708F /* TrainerViewController.swift in Sources */,
|
||||
171904B62BBC8D4E004CCC96 /* TrainerView.swift in Sources */,
|
||||
175792702930605500490924 /* THCircularProgressView.m in Sources */,
|
||||
175792712930605500490924 /* IASKSpecifier.m in Sources */,
|
||||
175792722930605500490924 /* UIView+ViewController.m in Sources */,
|
||||
|
@ -4970,6 +5113,7 @@
|
|||
1757928C2930605500490924 /* PINMemoryCache.m in Sources */,
|
||||
1757928D2930605500490924 /* SiteCell.m in Sources */,
|
||||
1757928E2930605500490924 /* SloppySwiper.m in Sources */,
|
||||
17BC56A82BBE4A5600A30C41 /* TrainerWord.swift in Sources */,
|
||||
1757928F2930605500490924 /* UIViewController+HidePopover.m in Sources */,
|
||||
175792902930605500490924 /* FolderTitleView.m in Sources */,
|
||||
175792912930605500490924 /* HorizontalPageDelegate.swift in Sources */,
|
||||
|
@ -5008,16 +5152,20 @@
|
|||
175792B02930605500490924 /* FMResultSet.m in Sources */,
|
||||
175792B12930605500490924 /* NBNotifier.m in Sources */,
|
||||
175792B22930605500490924 /* TUSafariActivity.m in Sources */,
|
||||
17BC56AE2BBF6C0000A30C41 /* StoryCache.swift in Sources */,
|
||||
175792B32930605500490924 /* PremiumViewController.m in Sources */,
|
||||
175792B42930605500490924 /* NBLoadingCell.m in Sources */,
|
||||
175792B52930605500490924 /* IASKTextViewCell.m in Sources */,
|
||||
175792B62930605500490924 /* StoriesCollection.m in Sources */,
|
||||
175792B72930605500490924 /* IASKTextView.m in Sources */,
|
||||
17A0518B2C095B20000994E9 /* AuxSceneDelegate.swift in Sources */,
|
||||
175792B82930605500490924 /* OfflineSyncUnreads.m in Sources */,
|
||||
175792B92930605500490924 /* IASKPSSliderSpecifierViewCell.m in Sources */,
|
||||
17BC56AB2BBF6BC000A30C41 /* Feed.swift in Sources */,
|
||||
175792BA2930605500490924 /* OfflineFetchStories.m in Sources */,
|
||||
175792BB2930605500490924 /* OfflineFetchText.m in Sources */,
|
||||
175792BC2930605500490924 /* OfflineFetchImages.m in Sources */,
|
||||
17150E1F2B05775A004D5309 /* SceneDelegate.swift in Sources */,
|
||||
175792BD2930605500490924 /* SplitViewDelegate.swift in Sources */,
|
||||
175792BE2930605500490924 /* Reachability.m in Sources */,
|
||||
175792BF2930605500490924 /* NBSwipeableCell.m in Sources */,
|
||||
|
@ -5025,6 +5173,21 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
17654E322B02C08700F61B2B /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
17654E332B02C08700F61B2B /* WidgetLoader.swift in Sources */,
|
||||
17654E342B02C08700F61B2B /* WidgetCache.swift in Sources */,
|
||||
17654E352B02C08700F61B2B /* WidgetExtension.swift in Sources */,
|
||||
17654E362B02C08700F61B2B /* WidgetStory.swift in Sources */,
|
||||
17654E372B02C08700F61B2B /* WidgetBarView.swift in Sources */,
|
||||
17654E382B02C08700F61B2B /* WidgetDebugTimer.swift in Sources */,
|
||||
17654E392B02C08700F61B2B /* WidgetFeed.swift in Sources */,
|
||||
17654E3A2B02C08700F61B2B /* WidgetStoryView.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
177551CF238E228A00E27818 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
@ -5095,6 +5258,7 @@
|
|||
FF34FD6B1E9D93CB0062F8ED /* IASKPSTextFieldSpecifierViewCell.m in Sources */,
|
||||
FF8D1ED01BAA311000725D8A /* SBJson4StreamWriter.m in Sources */,
|
||||
43763AD1158F90B100B3DBE2 /* FontSettingsViewController.m in Sources */,
|
||||
17BC56B02BBF6C2200A30C41 /* StorySettings.swift in Sources */,
|
||||
FF34FD601E9D93CB0062F8ED /* IASKAppSettingsViewController.m in Sources */,
|
||||
17CBD3BF1BF66B6C003FCCAE /* MarkReadMenuViewController.m in Sources */,
|
||||
FFA045B519CA49D700618DC4 /* SSWAnimator.m in Sources */,
|
||||
|
@ -5116,10 +5280,14 @@
|
|||
43A4C3DC15B00966008787B5 /* main.m in Sources */,
|
||||
43A4C3DD15B00966008787B5 /* MBProgressHUD.m in Sources */,
|
||||
43A4C3E115B00966008787B5 /* NSString+HTML.m in Sources */,
|
||||
171904B82BBCA712004CCC96 /* TrainerCapsule.swift in Sources */,
|
||||
FF34FD641E9D93CB0062F8ED /* IASKSettingsReader.m in Sources */,
|
||||
FF6282151A11613900271FDB /* UserTagsViewController.m in Sources */,
|
||||
43A4C3E315B00966008787B5 /* StringHelper.m in Sources */,
|
||||
43A4C3E415B00966008787B5 /* TransparentToolbar.m in Sources */,
|
||||
179A88022B48E64A00916CF4 /* ToolbarDelegate.swift in Sources */,
|
||||
175DC6AF2BBB87D200B3708F /* TrainerViewController.swift in Sources */,
|
||||
171904B52BBC8D4E004CCC96 /* TrainerView.swift in Sources */,
|
||||
FFD6604C1BACA45D006E4B8D /* THCircularProgressView.m in Sources */,
|
||||
FF34FD681E9D93CB0062F8ED /* IASKSpecifier.m in Sources */,
|
||||
FFA0484419CA73B700618DC4 /* UIView+ViewController.m in Sources */,
|
||||
|
@ -5154,6 +5322,7 @@
|
|||
FF2924E71E932D2900FCFA63 /* PINMemoryCache.m in Sources */,
|
||||
43CE0F5F15DADB7F00608ED8 /* SiteCell.m in Sources */,
|
||||
FFA045B419CA49D700618DC4 /* SloppySwiper.m in Sources */,
|
||||
17BC56A72BBE4A5600A30C41 /* TrainerWord.swift in Sources */,
|
||||
E160F0571C9DAC2C00CB96DF /* UIViewController+HidePopover.m in Sources */,
|
||||
FFDE35CC161B8F870034BFDE /* FolderTitleView.m in Sources */,
|
||||
172AD264251D901D000BB264 /* HorizontalPageDelegate.swift in Sources */,
|
||||
|
@ -5192,16 +5361,20 @@
|
|||
FF753CD3175858FC00344EC9 /* FMResultSet.m in Sources */,
|
||||
FF6618C8176184560039913B /* NBNotifier.m in Sources */,
|
||||
FF03AFF319F87F2E0063002A /* TUSafariActivity.m in Sources */,
|
||||
17BC56AD2BBF6C0000A30C41 /* StoryCache.swift in Sources */,
|
||||
FF83FF051FB52565008DAC0F /* PremiumViewController.m in Sources */,
|
||||
FF11045F176950F900502C29 /* NBLoadingCell.m in Sources */,
|
||||
FF34FD701E9D93CB0062F8ED /* IASKTextViewCell.m in Sources */,
|
||||
FFAD89C218AC45A100D68567 /* StoriesCollection.m in Sources */,
|
||||
FF34FD6F1E9D93CB0062F8ED /* IASKTextView.m in Sources */,
|
||||
17A0518A2C095B20000994E9 /* AuxSceneDelegate.swift in Sources */,
|
||||
FF855B5B1794B0670098D48A /* OfflineSyncUnreads.m in Sources */,
|
||||
FF34FD6A1E9D93CB0062F8ED /* IASKPSSliderSpecifierViewCell.m in Sources */,
|
||||
17BC56AA2BBF6BC000A30C41 /* Feed.swift in Sources */,
|
||||
FF855B5E1794B0760098D48A /* OfflineFetchStories.m in Sources */,
|
||||
17362ADD23639B4E00A0FCCC /* OfflineFetchText.m in Sources */,
|
||||
FF855B611794B0830098D48A /* OfflineFetchImages.m in Sources */,
|
||||
17150E1E2B05775A004D5309 /* SceneDelegate.swift in Sources */,
|
||||
170E3CD124F8A664009CE819 /* SplitViewDelegate.swift in Sources */,
|
||||
FF8D1EA71BAA304E00725D8A /* Reachability.m in Sources */,
|
||||
FFCDD90117F65A71000C6483 /* NBSwipeableCell.m in Sources */,
|
||||
|
@ -5231,6 +5404,11 @@
|
|||
target = 1749390F1C251BFE003D98AA /* Share Extension */;
|
||||
targetProxy = 174939191C251BFE003D98AA /* PBXContainerItemProxy */;
|
||||
};
|
||||
17654E492B02C0A800F61B2B /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 17654E312B02C08700F61B2B /* NewsBlur Alpha Widget */;
|
||||
targetProxy = 17654E482B02C0A800F61B2B /* PBXContainerItemProxy */;
|
||||
};
|
||||
177551DE238E228A00E27818 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
platformFilter = ios;
|
||||
|
@ -5327,6 +5505,7 @@
|
|||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
INFOPLIST_FILE = "Widget Extension/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
|
@ -5337,8 +5516,7 @@
|
|||
PRODUCT_BUNDLE_IDENTIFIER = com.newsblur.NewsBlur.widget;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,6";
|
||||
|
@ -5371,6 +5549,7 @@
|
|||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
INFOPLIST_FILE = "Widget Extension/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
|
@ -5381,8 +5560,7 @@
|
|||
PRODUCT_BUNDLE_IDENTIFIER = com.newsblur.NewsBlur.widget;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,6";
|
||||
|
@ -5438,8 +5616,7 @@
|
|||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE = "";
|
||||
SKIP_INSTALL = YES;
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,6";
|
||||
};
|
||||
name = Debug;
|
||||
|
@ -5486,8 +5663,7 @@
|
|||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE = "";
|
||||
SKIP_INSTALL = YES;
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,6";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
|
@ -5499,11 +5675,10 @@
|
|||
ALWAYS_SEARCH_USER_PATHS = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIconDev;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = NewsBlur/NewsBlur.entitlements;
|
||||
CODE_SIGN_ENTITLEMENTS = Resources/App.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 152;
|
||||
DEVELOPMENT_TEAM = HR7P97SD72;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
|
@ -5516,7 +5691,7 @@
|
|||
GCC_THUMB_SUPPORT = NO;
|
||||
GCC_VERSION = "";
|
||||
HEADER_SEARCH_PATHS = "";
|
||||
INFOPLIST_FILE = "NewsBlur-iPhone-Info.plist";
|
||||
INFOPLIST_FILE = Resources/Info.plist;
|
||||
LAUNCH_SCREEN_NAME = LaunchScreenDev;
|
||||
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
|
@ -5535,9 +5710,9 @@
|
|||
PRODUCT_NAME = "NB Alpha";
|
||||
PROVISIONING_PROFILE = "";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
STRIP_INSTALLED_PRODUCT = NO;
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Other Sources/BridgingHeader.h";
|
||||
SWIFT_OBJC_INTERFACE_HEADER_NAME = "NewsBlur-Swift.h";
|
||||
TARGETED_DEVICE_FAMILY = "1,2,6";
|
||||
|
@ -5551,11 +5726,10 @@
|
|||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIconDev;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = NewsBlur/NewsBlur.entitlements;
|
||||
CODE_SIGN_ENTITLEMENTS = Resources/App.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = YES;
|
||||
CURRENT_PROJECT_VERSION = 152;
|
||||
DEVELOPMENT_TEAM = HR7P97SD72;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
|
@ -5567,7 +5741,7 @@
|
|||
GCC_THUMB_SUPPORT = NO;
|
||||
GCC_VERSION = "";
|
||||
HEADER_SEARCH_PATHS = "";
|
||||
INFOPLIST_FILE = "NewsBlur-iPhone-Info.plist";
|
||||
INFOPLIST_FILE = Resources/Info.plist;
|
||||
LAUNCH_SCREEN_NAME = LaunchScreenDev;
|
||||
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
|
@ -5586,7 +5760,8 @@
|
|||
PROVISIONING_PROFILE = "";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Other Sources/BridgingHeader.h";
|
||||
SWIFT_OBJC_INTERFACE_HEADER_NAME = "NewsBlur-Swift.h";
|
||||
TARGETED_DEVICE_FAMILY = "1,2,6";
|
||||
|
@ -5594,6 +5769,101 @@
|
|||
};
|
||||
name = Release;
|
||||
};
|
||||
17654E432B02C08700F61B2B /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = "Widget Extension/WidgetExtension.entitlements";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = HR7P97SD72;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
INFOPLIST_FILE = "Widget Extension/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.newsblur.NB-Alpha.widget";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,6";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
17654E442B02C08700F61B2B /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = "Widget Extension/WidgetExtension.entitlements";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = HR7P97SD72;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
INFOPLIST_FILE = "Widget Extension/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.newsblur.NB-Alpha.widget";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,6";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
177551E0238E228A00E27818 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
|
@ -5694,11 +5964,10 @@
|
|||
ALWAYS_SEARCH_USER_PATHS = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = NewsBlur/NewsBlur.entitlements;
|
||||
CODE_SIGN_ENTITLEMENTS = Resources/App.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 152;
|
||||
DEVELOPMENT_TEAM = HR7P97SD72;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
|
@ -5711,7 +5980,7 @@
|
|||
GCC_THUMB_SUPPORT = NO;
|
||||
GCC_VERSION = "";
|
||||
HEADER_SEARCH_PATHS = "";
|
||||
INFOPLIST_FILE = "NewsBlur-iPhone-Info.plist";
|
||||
INFOPLIST_FILE = Resources/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
|
@ -5728,9 +5997,9 @@
|
|||
PRODUCT_NAME = NewsBlur;
|
||||
PROVISIONING_PROFILE = "";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
STRIP_INSTALLED_PRODUCT = NO;
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Other Sources/BridgingHeader.h";
|
||||
TARGETED_DEVICE_FAMILY = "1,2,6";
|
||||
"WARNING_CFLAGS[arch=*]" = "-Wall";
|
||||
|
@ -5744,11 +6013,10 @@
|
|||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = NewsBlur/NewsBlur.entitlements;
|
||||
CODE_SIGN_ENTITLEMENTS = Resources/App.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = YES;
|
||||
CURRENT_PROJECT_VERSION = 152;
|
||||
DEVELOPMENT_TEAM = HR7P97SD72;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
|
@ -5760,7 +6028,7 @@
|
|||
GCC_THUMB_SUPPORT = NO;
|
||||
GCC_VERSION = "";
|
||||
HEADER_SEARCH_PATHS = "";
|
||||
INFOPLIST_FILE = "NewsBlur-iPhone-Info.plist";
|
||||
INFOPLIST_FILE = Resources/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
|
@ -5777,7 +6045,8 @@
|
|||
PROVISIONING_PROFILE = "";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Other Sources/BridgingHeader.h";
|
||||
TARGETED_DEVICE_FAMILY = "1,2,6";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
|
@ -5788,6 +6057,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = NO;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
|
@ -5810,10 +6080,11 @@
|
|||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 151;
|
||||
CURRENT_PROJECT_VERSION = 153;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = "compiler-default";
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
|
@ -5826,13 +6097,12 @@
|
|||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
LAUNCH_SCREEN_NAME = LaunchScreen;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 13.0;
|
||||
MARKETING_VERSION = 13.1;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PROVISIONING_PROFILE = "";
|
||||
RUN_CLANG_STATIC_ANALYZER = YES;
|
||||
SDKROOT = iphoneos;
|
||||
STRIP_INSTALLED_PRODUCT = NO;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
|
@ -5843,6 +6113,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = NO;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
|
@ -5865,9 +6136,10 @@
|
|||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 151;
|
||||
CURRENT_PROJECT_VERSION = 153;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = "compiler-default";
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
|
@ -5880,13 +6152,12 @@
|
|||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
LAUNCH_SCREEN_NAME = LaunchScreen;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 13.0;
|
||||
MARKETING_VERSION = 13.1;
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PROVISIONING_PROFILE = "";
|
||||
SDKROOT = iphoneos;
|
||||
STRIP_INSTALLED_PRODUCT = NO;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
SWIFT_VERSION = 5.0;
|
||||
|
@ -5932,8 +6203,7 @@
|
|||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SKIP_INSTALL = YES;
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,6";
|
||||
};
|
||||
name = Debug;
|
||||
|
@ -5970,8 +6240,7 @@
|
|||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SKIP_INSTALL = YES;
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,6";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
|
@ -6007,6 +6276,15 @@
|
|||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
17654E422B02C08700F61B2B /* Build configuration list for PBXNativeTarget "NewsBlur Alpha Widget" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
17654E432B02C08700F61B2B /* Debug */,
|
||||
17654E442B02C08700F61B2B /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
177551E2238E228A00E27818 /* Build configuration list for PBXNativeTarget "Old Widget Extension" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1540"
|
||||
version = "2.0">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "17654E312B02C08700F61B2B"
|
||||
BuildableName = "NewsBlur Alpha Widget.appex"
|
||||
BlueprintName = "NewsBlur Alpha Widget"
|
||||
ReferencedContainer = "container:NewsBlur.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "175790592930605500490924"
|
||||
BuildableName = "NB Alpha.app"
|
||||
BlueprintName = "NewsBlur Alpha"
|
||||
ReferencedContainer = "container:NewsBlur.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = ""
|
||||
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
||||
launchStyle = "0"
|
||||
askForAppToLaunch = "Yes"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES"
|
||||
launchAutomaticallySubstyle = "2">
|
||||
<EnvironmentVariables>
|
||||
<EnvironmentVariable
|
||||
key = "_XCWidgetKind"
|
||||
value = ""
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
<EnvironmentVariable
|
||||
key = "_XCWidgetDefaultView"
|
||||
value = "timeline"
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
<EnvironmentVariable
|
||||
key = "_XCWidgetFamily"
|
||||
value = "systemMedium"
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
askForAppToLaunch = "Yes"
|
||||
launchAutomaticallySubstyle = "2">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "17654E312B02C08700F61B2B"
|
||||
BuildableName = "NewsBlur Alpha Widget.appex"
|
||||
BlueprintName = "NewsBlur Alpha Widget"
|
||||
ReferencedContainer = "container:NewsBlur.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1420"
|
||||
LastUpgradeVersion = "1540"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1420"
|
||||
LastUpgradeVersion = "1540"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1420"
|
||||
LastUpgradeVersion = "1540"
|
||||
wasCreatedForAppExtension = "YES"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1420"
|
||||
LastUpgradeVersion = "1540"
|
||||
wasCreatedForAppExtension = "YES"
|
||||
version = "2.0">
|
||||
<BuildAction
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1420"
|
||||
LastUpgradeVersion = "1540"
|
||||
wasCreatedForAppExtension = "YES"
|
||||
version = "2.0">
|
||||
<BuildAction
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1420"
|
||||
LastUpgradeVersion = "1540"
|
||||
wasCreatedForAppExtension = "YES"
|
||||
version = "2.0">
|
||||
<BuildAction
|
||||
|
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
@ -171,7 +171,7 @@ NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value) {
|
|||
|
||||
#pragma mark -
|
||||
|
||||
static NSArray * AFHTTPRequestSerializerObservedKeyPaths() {
|
||||
static NSArray * AFHTTPRequestSerializerObservedKeyPaths(void) {
|
||||
static NSArray *_AFHTTPRequestSerializerObservedKeyPaths = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
|
@ -591,7 +591,7 @@ forHTTPHeaderField:(NSString *)field
|
|||
|
||||
#pragma mark -
|
||||
|
||||
static NSString * AFCreateMultipartFormBoundary() {
|
||||
static NSString * AFCreateMultipartFormBoundary(void) {
|
||||
return [NSString stringWithFormat:@"Boundary+%08X%08X", arc4random(), arc4random()];
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#define NSFoundationVersionNumber_With_Fixed_5871104061079552_bug NSFoundationVersionNumber_iOS_8_0
|
||||
#endif
|
||||
|
||||
static dispatch_queue_t url_session_manager_creation_queue() {
|
||||
static dispatch_queue_t url_session_manager_creation_queue(void) {
|
||||
static dispatch_queue_t af_url_session_manager_creation_queue;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
|
@ -49,7 +49,7 @@ static void url_session_manager_create_task_safely(dispatch_block_t block) {
|
|||
}
|
||||
}
|
||||
|
||||
static dispatch_queue_t url_session_manager_processing_queue() {
|
||||
static dispatch_queue_t url_session_manager_processing_queue(void) {
|
||||
static dispatch_queue_t af_url_session_manager_processing_queue;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
|
@ -59,7 +59,7 @@ static dispatch_queue_t url_session_manager_processing_queue() {
|
|||
return af_url_session_manager_processing_queue;
|
||||
}
|
||||
|
||||
static dispatch_group_t url_session_manager_completion_group() {
|
||||
static dispatch_group_t url_session_manager_completion_group(void) {
|
||||
static dispatch_group_t af_url_session_manager_completion_group;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
#import <TargetConditionals.h>
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#import "UIRefreshControl+AFNetworking.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
|
||||
|
||||
#import "AFURLSessionManager.h"
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "NSString+HTML.h"
|
||||
#import "Utilities.h"
|
||||
#import "NewsBlurAppDelegate.h"
|
||||
#import "ThemeManager.h"
|
||||
#import "StoriesCollection.h"
|
||||
|
|
|
@ -123,7 +123,7 @@ CGRect IASKCGRectSwap(CGRect rect);
|
|||
- (BOOL)isPad {
|
||||
BOOL isPad = NO;
|
||||
#if (__IPHONE_OS_VERSION_MAX_ALLOWED >= 30200)
|
||||
isPad = [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad;
|
||||
isPad = [[UIDevice currentDevice] userInterfaceIdiom] != UIUserInterfaceIdiomPhone;
|
||||
#endif
|
||||
return isPad;
|
||||
}
|
||||
|
|
|
@ -279,7 +279,7 @@
|
|||
switch (interfaceIdiom) {
|
||||
case UIUserInterfaceIdiomPad: return @"~ipad";
|
||||
case UIUserInterfaceIdiomPhone: return @"~iphone";
|
||||
default: return @"~iphone";
|
||||
default: return @"~ipad";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -466,7 +466,7 @@ static NSString *const AppExtensionWebViewPageDetails = @"pageDetails";
|
|||
}
|
||||
|
||||
- (UIActivityViewController *)activityViewControllerForItem:(nonnull NSDictionary *)item viewController:(nonnull UIViewController*)viewController sender:(nullable id)sender typeIdentifier:(nonnull NSString *)typeIdentifier {
|
||||
NSAssert(NO == ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad && sender == nil), @"sender must not be nil on iPad.");
|
||||
NSAssert(NO == ([[UIDevice currentDevice] userInterfaceIdiom] != UIUserInterfaceIdiomPhone && sender == nil), @"sender must not be nil on iPad.");
|
||||
|
||||
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithItem:item typeIdentifier:typeIdentifier];
|
||||
|
||||
|
|
|
@ -1,43 +1,31 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15705" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15706"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22684"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="TrainerViewController">
|
||||
<connections>
|
||||
<outlet property="view" destination="1" id="14"/>
|
||||
<outlet property="webView" destination="GKy-Nf-Wvj" id="zud-uf-diH"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="1">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="504"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<wkWebView contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="GKy-Nf-Wvj" customClass="TrainerWebView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="504"/>
|
||||
<color key="backgroundColor" red="0.36078431370000003" green="0.38823529410000002" blue="0.4039215686" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<wkWebViewConfiguration key="configuration">
|
||||
<audiovisualMediaTypes key="mediaTypesRequiringUserActionForPlayback" none="YES"/>
|
||||
<wkPreferences key="preferences"/>
|
||||
</wkWebViewConfiguration>
|
||||
</wkWebView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" cocoaTouchSystemColor="scrollViewTexturedBackgroundColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="GKy-Nf-Wvj" firstAttribute="top" secondItem="1" secondAttribute="top" id="1a7-1T-kvM"/>
|
||||
<constraint firstItem="GKy-Nf-Wvj" firstAttribute="leading" secondItem="1" secondAttribute="leading" id="TyU-gH-Y2q"/>
|
||||
<constraint firstAttribute="trailing" secondItem="GKy-Nf-Wvj" secondAttribute="trailing" id="awn-3M-7sd"/>
|
||||
<constraint firstAttribute="bottom" secondItem="GKy-Nf-Wvj" secondAttribute="bottom" id="r5q-ka-FVF"/>
|
||||
</constraints>
|
||||
<color key="backgroundColor" systemColor="scrollViewTexturedBackgroundColor"/>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<point key="canvasLocation" x="-548" y="153"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<systemColor name="scrollViewTexturedBackgroundColor">
|
||||
<color red="0.43529411764705883" green="0.44313725490196076" blue="0.47450980392156861" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
</document>
|
||||
|
|
33
clients/ios/Resources/AuxInterface.storyboard
Normal file
33
clients/ios/Resources/AuxInterface.storyboard
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Y6W-OH-hqX">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="s0d-6b-0kx">
|
||||
<objects>
|
||||
<viewController id="Y6W-OH-hqX" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="5EZ-qb-Rvc">
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<viewLayoutGuide key="safeArea" id="vDu-zF-Fre"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="Ief-a0-LHa" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="37" y="-17"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<systemColor name="systemBackgroundColor">
|
||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
</document>
|
|
@ -148,6 +148,25 @@
|
|||
<string>ChronicleSSm-MediumItalic.otf</string>
|
||||
<string>ChronicleSSm-BookItalic.otf</string>
|
||||
</array>
|
||||
<key>UIApplicationSceneManifest</key>
|
||||
<dict>
|
||||
<key>UIApplicationSupportsMultipleScenes</key>
|
||||
<true/>
|
||||
<key>UISceneConfigurations</key>
|
||||
<dict>
|
||||
<key>UIWindowSceneSessionRoleApplication</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>UISceneConfigurationName</key>
|
||||
<string>Default Configuration</string>
|
||||
<key>UISceneDelegateClassName</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
|
||||
<key>UISceneStoryboardFile</key>
|
||||
<string>MainInterface</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>UIApplicationShortcutItems</key>
|
||||
<array>
|
||||
<dict>
|
||||
|
@ -189,8 +208,9 @@
|
|||
</array>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>fetch</string>
|
||||
<string>audio</string>
|
||||
<string>fetch</string>
|
||||
<string>processing</string>
|
||||
</array>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>$(LAUNCH_SCREEN_NAME)</string>
|
|
@ -1,11 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22154" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="6pv-7g-17r">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="6pv-7g-17r" initialMenu="YWi-Ju-M3z">
|
||||
<device id="ipad11_0rounded" orientation="landscape" layout="fullscreen" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22130"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="UIMenu" message="Requires Xcode 11 or later." minToolsVersion="11.0" requiredIntegratedClassName="UICommandDiff"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
|
@ -14,39 +15,39 @@
|
|||
<objects>
|
||||
<viewController storyboardIdentifier="DetailViewController" useStoryboardIdentifierAsRestorationIdentifier="YES" id="djW-7k-haK" customClass="DetailViewController" customModule="NewsBlur" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="jTZ-4O-xyT">
|
||||
<rect key="frame" x="0.0" y="0.0" width="818.5" height="834"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="514" height="834"/>
|
||||
<subviews>
|
||||
<containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bPa-u1-Aml">
|
||||
<rect key="frame" x="0.0" y="74" width="1194" height="580"/>
|
||||
<rect key="frame" x="0.0" y="74" width="1210" height="580"/>
|
||||
<connections>
|
||||
<segue destination="afA-W0-XsQ" kind="embed" id="jh9-xN-7qk"/>
|
||||
</connections>
|
||||
</containerView>
|
||||
<containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5M7-bO-MVK">
|
||||
<rect key="frame" x="0.0" y="666" width="1194" height="168"/>
|
||||
<rect key="frame" x="0.0" y="666" width="1210" height="168"/>
|
||||
<connections>
|
||||
<segue destination="1tQ-fy-A3c" kind="embed" id="VHY-vp-wSt"/>
|
||||
</connections>
|
||||
</containerView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="tFd-Uv-aMP">
|
||||
<rect key="frame" x="0.0" y="654" width="1194" height="12"/>
|
||||
<rect key="frame" x="0.0" y="654" width="1210" height="12"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="qGY-je-8bb">
|
||||
<rect key="frame" x="0.0" y="-1" width="1194" height="1"/>
|
||||
<rect key="frame" x="0.0" y="-1" width="1210" height="1"/>
|
||||
<color key="backgroundColor" red="0.75644385810000003" green="0.75644385810000003" blue="0.75644385810000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="1" id="rXL-Rl-xkq"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bSN-6S-SA0">
|
||||
<rect key="frame" x="0.0" y="12" width="1194" height="1"/>
|
||||
<rect key="frame" x="0.0" y="12" width="1210" height="1"/>
|
||||
<color key="backgroundColor" red="0.75644385810000003" green="0.75644385810000003" blue="0.75644385810000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="1" id="tto-L2-TaQ"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="drag_icon.png" translatesAutoresizingMaskIntoConstraints="NO" id="xeQ-Iz-FR0">
|
||||
<rect key="frame" x="580" y="2" width="34" height="9"/>
|
||||
<rect key="frame" x="588" y="2" width="34" height="9"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="9" id="dFD-2h-iag"/>
|
||||
<constraint firstAttribute="width" constant="34" id="wAd-rJ-dVL"/>
|
||||
|
@ -226,7 +227,10 @@
|
|||
<navigationItem key="navigationItem" id="ejU-V5-SiF"/>
|
||||
<connections>
|
||||
<outlet property="addBarButton" destination="Wu8-MQ-nN6" id="mk5-Nm-bYF"/>
|
||||
<outlet property="feedTitlesLeadingConstraint" destination="mcu-rd-QiB" id="lNY-Ya-6pE"/>
|
||||
<outlet property="feedTitlesTable" destination="Gil-Jz-die" id="Jby-a1-If4"/>
|
||||
<outlet property="feedTitlesTopConstraint" destination="YMn-QK-fCb" id="Bjn-sa-Qdx"/>
|
||||
<outlet property="feedTitlesTrailingConstraint" destination="YOq-sh-lXt" id="nLy-3P-sgq"/>
|
||||
<outlet property="feedViewToolbar" destination="pWr-U1-GMQ" id="FFI-k8-5iO"/>
|
||||
<outlet property="innerView" destination="hRx-bd-6Da" id="vd8-hw-hZT"/>
|
||||
<outlet property="intelligenceControl" destination="ADC-ot-Aao" id="8EU-ja-Dan"/>
|
||||
|
@ -239,6 +243,605 @@
|
|||
</objects>
|
||||
<point key="canvasLocation" x="180.90452261306532" y="285.61151079136692"/>
|
||||
</scene>
|
||||
<!--Root-->
|
||||
<scene sceneID="eNE-X1-NXV">
|
||||
<objects>
|
||||
<menu isSystemItem="YES" title="Root" identifier="com.apple.menu.root" id="YWi-Ju-M3z" sceneMemberID="viewController">
|
||||
<children>
|
||||
<menu isSystemItem="YES" title="File" identifier="com.apple.menu.file" id="cyC-FU-wa2">
|
||||
<children>
|
||||
<menu anchor="com.apple.menu.close" id="ksZ-gH-4gO">
|
||||
<menuOptions key="menuOptions" displayInline="YES"/>
|
||||
<children>
|
||||
<command title="New Site" input="n" id="Y3F-bj-KeX">
|
||||
<keyModifierFlags key="modifierFlags" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="newSite:" destination="J28-e1-gcC" id="eEX-pv-sl0"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Reload Sites" input="r" id="9ee-Z4-HxV">
|
||||
<keyModifierFlags key="modifierFlags" command="YES"/>
|
||||
<connections>
|
||||
<action selector="reloadFeeds:" destination="J28-e1-gcC" id="Mn6-7w-6qY"/>
|
||||
</connections>
|
||||
</command>
|
||||
</children>
|
||||
</menu>
|
||||
<menu anchor="com.apple.menu.close" id="6cc-W3-a06">
|
||||
<menuOptions key="menuOptions" displayInline="YES"/>
|
||||
<children>
|
||||
<command title="Mute Sites" input="M" id="M7P-gv-spA">
|
||||
<keyModifierFlags key="modifierFlags" command="YES"/>
|
||||
<connections>
|
||||
<action selector="showMuteSites:" destination="J28-e1-gcC" id="sE9-iR-0dr"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Organize Sites" input="O" id="Wte-kG-AH2">
|
||||
<keyModifierFlags key="modifierFlags" command="YES"/>
|
||||
<connections>
|
||||
<action selector="showOrganizeSites:" destination="J28-e1-gcC" id="9cl-DR-gBb"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Widget Sites" input="W" id="4CD-Pc-fDT">
|
||||
<keyModifierFlags key="modifierFlags" command="YES"/>
|
||||
<connections>
|
||||
<action selector="showWidgetSites:" destination="J28-e1-gcC" id="V7w-If-8Cv"/>
|
||||
</connections>
|
||||
</command>
|
||||
</children>
|
||||
</menu>
|
||||
<menu anchor="com.apple.menu.close" id="obB-Ib-5UM">
|
||||
<menuOptions key="menuOptions" displayInline="YES"/>
|
||||
<children>
|
||||
<command title="Notifications" input="N" id="2ax-3D-3zm">
|
||||
<keyModifierFlags key="modifierFlags" command="YES"/>
|
||||
<connections>
|
||||
<action selector="showNotifications:" destination="J28-e1-gcC" id="GHY-vF-j44"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Find Friends" input="F" id="0eN-vR-Gok">
|
||||
<keyModifierFlags key="modifierFlags" command="YES"/>
|
||||
<connections>
|
||||
<action selector="showFindFriends:" destination="J28-e1-gcC" id="b0r-KD-HkV"/>
|
||||
</connections>
|
||||
</command>
|
||||
</children>
|
||||
</menu>
|
||||
<menu anchor="com.apple.menu.close" id="WdP-hc-0fU">
|
||||
<menuOptions key="menuOptions" displayInline="YES"/>
|
||||
<children>
|
||||
<command title="NewsBlur Premium" id="HGH-9Q-Dzh">
|
||||
<connections>
|
||||
<action selector="showPremium:" destination="J28-e1-gcC" id="adm-3i-APm"/>
|
||||
</connections>
|
||||
</command>
|
||||
</children>
|
||||
</menu>
|
||||
<menu anchor="com.apple.menu.close" id="cRW-qu-7aj">
|
||||
<menuOptions key="menuOptions" displayInline="YES"/>
|
||||
<children>
|
||||
<command title="Logout NewsBlur" input="L" id="kvb-M9-tEl">
|
||||
<keyModifierFlags key="modifierFlags" command="YES"/>
|
||||
<connections>
|
||||
<action selector="showLogout:" destination="J28-e1-gcC" id="wkE-Rx-OAt"/>
|
||||
</connections>
|
||||
</command>
|
||||
</children>
|
||||
</menu>
|
||||
<menu isSystemItem="YES" title="Print" identifier="com.apple.menu.print" id="L8Z-gR-6rG">
|
||||
<menuOptions key="menuOptions" displayInline="YES"/>
|
||||
<systemMenuChildDeletions>
|
||||
<itemDeletion anchorAction="_saveDocumentToPDF:"/>
|
||||
<itemDeletion anchorAction="_printDocument:"/>
|
||||
</systemMenuChildDeletions>
|
||||
</menu>
|
||||
</children>
|
||||
<systemMenuChildDeletions>
|
||||
<menuDeletion anchor="com.apple.menu.new-scene"/>
|
||||
<menuDeletion anchor="com.apple.menu.open"/>
|
||||
<menuDeletion anchor="com.apple.menu.document"/>
|
||||
</systemMenuChildDeletions>
|
||||
</menu>
|
||||
<menu isSystemItem="YES" title="Edit" identifier="com.apple.menu.edit" id="a13-uu-myc">
|
||||
<children>
|
||||
<menu anchor="com.apple.menu.standard-edit" id="rH8-0t-SpF">
|
||||
<menuOptions key="menuOptions" displayInline="YES"/>
|
||||
<children>
|
||||
<command title="Find in Sites" input="f" id="Oy9-Js-Eoz">
|
||||
<keyModifierFlags key="modifierFlags" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="findInFeeds:" destination="J28-e1-gcC" id="3J9-2o-DYH"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Find in Feed" input="f" id="2M3-xa-Uu2">
|
||||
<keyModifierFlags key="modifierFlags" command="YES"/>
|
||||
<connections>
|
||||
<action selector="findInFeedDetail:" destination="J28-e1-gcC" id="KMi-J9-3OA"/>
|
||||
</connections>
|
||||
</command>
|
||||
</children>
|
||||
</menu>
|
||||
</children>
|
||||
<systemMenuChildDeletions>
|
||||
<menuDeletion anchor="com.apple.menu.find"/>
|
||||
</systemMenuChildDeletions>
|
||||
</menu>
|
||||
<menu isSystemItem="YES" title="View" identifier="com.apple.menu.view" id="pdl-gx-X6C">
|
||||
<children>
|
||||
<menu title="Columns" id="Zsw-UK-Yxk">
|
||||
<children>
|
||||
<command title="Automatic" propertyListString="auto" menuElementState="on" input="4" id="6Vl-Xq-5Ko">
|
||||
<keyModifierFlags key="modifierFlags" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="chooseColumns:" destination="J28-e1-gcC" id="vNz-nO-9sE"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Three" propertyListString="tile" input="3" id="UGQ-RS-mbs">
|
||||
<keyModifierFlags key="modifierFlags" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="chooseColumns:" destination="J28-e1-gcC" id="ihd-Wz-zxe"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Two" propertyListString="displace" input="2" id="coF-9M-sfo">
|
||||
<keyModifierFlags key="modifierFlags" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="chooseColumns:" destination="J28-e1-gcC" id="ejV-aM-O5L"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="One" propertyListString="overlay" input="1" id="uQ4-TQ-9rv">
|
||||
<keyModifierFlags key="modifierFlags" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="chooseColumns:" destination="J28-e1-gcC" id="hwz-R7-v1M"/>
|
||||
</connections>
|
||||
</command>
|
||||
</children>
|
||||
</menu>
|
||||
<menu title="Layout" id="2UT-ZB-x5H">
|
||||
<children>
|
||||
<command title="Left" propertyListString="titles_on_left" menuElementState="on" id="SHF-Gm-yHM">
|
||||
<connections>
|
||||
<action selector="chooseLayout:" destination="J28-e1-gcC" id="v7b-YA-qHb"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Top" propertyListString="titles_on_top" id="Zeq-Nu-dqs">
|
||||
<connections>
|
||||
<action selector="chooseLayout:" destination="J28-e1-gcC" id="E0V-4w-fMx"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Bottom" propertyListString="titles_on_bottom" id="iQo-Uv-UPm">
|
||||
<connections>
|
||||
<action selector="chooseLayout:" destination="J28-e1-gcC" id="APi-KB-zyb"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Grid" propertyListString="titles_in_grid" id="hc6-3c-pEr">
|
||||
<connections>
|
||||
<action selector="chooseLayout:" destination="J28-e1-gcC" id="lPQ-q9-ULB"/>
|
||||
</connections>
|
||||
</command>
|
||||
</children>
|
||||
</menu>
|
||||
<menu title="Show" id="yxK-59-1Mg">
|
||||
<children>
|
||||
<command title="All Stories" propertyListString="0" menuElementState="on" input="1" id="ccO-Ne-aJ2">
|
||||
<keyModifierFlags key="modifierFlags" command="YES"/>
|
||||
<connections>
|
||||
<action selector="chooseIntelligence:" destination="J28-e1-gcC" id="BEW-3n-izO"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Unread Stories" propertyListString="1" input="2" id="Flw-XS-uGO">
|
||||
<keyModifierFlags key="modifierFlags" command="YES"/>
|
||||
<connections>
|
||||
<action selector="chooseIntelligence:" destination="J28-e1-gcC" id="Sjf-mN-l3c"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Focus Stories" propertyListString="2" input="3" id="Pml-hQ-IST">
|
||||
<keyModifierFlags key="modifierFlags" command="YES"/>
|
||||
<connections>
|
||||
<action selector="chooseIntelligence:" destination="J28-e1-gcC" id="O2v-f5-adA"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Saved Stories" propertyListString="3" input="4" id="YTZ-1i-9Qj">
|
||||
<keyModifierFlags key="modifierFlags" command="YES"/>
|
||||
<connections>
|
||||
<action selector="chooseIntelligence:" destination="J28-e1-gcC" id="6Bm-Us-ckr"/>
|
||||
</connections>
|
||||
</command>
|
||||
</children>
|
||||
</menu>
|
||||
<menu title="Inline Menu" id="rEb-O5-WxE">
|
||||
<menuOptions key="menuOptions" displayInline="YES"/>
|
||||
</menu>
|
||||
<menu title="Story Preview" id="11o-Ny-Ay8">
|
||||
<children>
|
||||
<command title="Only Title" propertyListString="title" menuElementState="on" id="3VQ-tS-tca">
|
||||
<connections>
|
||||
<action selector="chooseTitle:" destination="J28-e1-gcC" id="dVZ-e9-eMx"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Short" propertyListString="short" id="kKo-nO-rdD">
|
||||
<connections>
|
||||
<action selector="chooseTitle:" destination="J28-e1-gcC" id="L2L-i9-jJu"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Medium" propertyListString="medium" id="8kl-JH-cAR">
|
||||
<connections>
|
||||
<action selector="chooseTitle:" destination="J28-e1-gcC" id="cHy-Qn-qYA"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Long" propertyListString="long" id="6c5-Aa-VWc">
|
||||
<connections>
|
||||
<action selector="chooseTitle:" destination="J28-e1-gcC" id="laa-aj-lRm"/>
|
||||
</connections>
|
||||
</command>
|
||||
</children>
|
||||
</menu>
|
||||
<menu title="Image Preview" id="JBe-EV-vd0">
|
||||
<children>
|
||||
<command title="None" propertyListString="none" menuElementState="on" id="xUQ-iP-Xav">
|
||||
<keyModifierFlags key="modifierFlags" command="YES"/>
|
||||
<connections>
|
||||
<action selector="choosePreview:" destination="J28-e1-gcC" id="ydY-6y-Vu7"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Small Left" propertyListString="small_left" id="pgV-T3-JgP">
|
||||
<connections>
|
||||
<action selector="choosePreview:" destination="J28-e1-gcC" id="6bd-eh-Jkf"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Large Left" propertyListString="large_left" id="rJC-gP-ub8">
|
||||
<connections>
|
||||
<action selector="choosePreview:" destination="J28-e1-gcC" id="dXF-jY-GB9"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Large Right" propertyListString="large_right" id="DHS-T6-h9f">
|
||||
<connections>
|
||||
<action selector="choosePreview:" destination="J28-e1-gcC" id="ZrD-28-3r7"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Small Right" propertyListString="small_right" id="0ZJ-kc-nG7">
|
||||
<connections>
|
||||
<action selector="choosePreview:" destination="J28-e1-gcC" id="yQ3-7h-2eZ"/>
|
||||
</connections>
|
||||
</command>
|
||||
</children>
|
||||
</menu>
|
||||
<menu title="Inline Menu" id="uRc-h2-2ur">
|
||||
<menuOptions key="menuOptions" displayInline="YES"/>
|
||||
</menu>
|
||||
<menu title="Grid Columns" id="gPp-Vp-Aqb">
|
||||
<children>
|
||||
<command title="Automatic" propertyListString="auto" menuElementState="on" id="W9M-jz-7Wo">
|
||||
<connections>
|
||||
<action selector="chooseGridColumns:" destination="J28-e1-gcC" id="r7t-6H-NdZ"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="1" propertyListString="1" id="COJ-8T-jFG">
|
||||
<connections>
|
||||
<action selector="chooseGridColumns:" destination="J28-e1-gcC" id="sg6-ao-Ca6"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="2" propertyListString="2" id="Enn-ac-qRo">
|
||||
<connections>
|
||||
<action selector="chooseGridColumns:" destination="J28-e1-gcC" id="9uC-A2-7y3"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="3" propertyListString="3" id="LL9-1i-7gs">
|
||||
<connections>
|
||||
<action selector="chooseGridColumns:" destination="J28-e1-gcC" id="7Ki-1P-JNN"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="4" propertyListString="4" id="TAe-RC-Isj">
|
||||
<connections>
|
||||
<action selector="chooseGridColumns:" destination="J28-e1-gcC" id="8rE-3w-9G0"/>
|
||||
</connections>
|
||||
</command>
|
||||
</children>
|
||||
</menu>
|
||||
<menu title="Grid Height" id="YgQ-8j-p4J">
|
||||
<children>
|
||||
<command title="Extra Short" propertyListString="xs" id="QkE-4U-qCZ">
|
||||
<connections>
|
||||
<action selector="chooseGridHeight:" destination="J28-e1-gcC" id="gM2-NN-oey"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Short" propertyListString="short" id="QiP-55-H7Q">
|
||||
<connections>
|
||||
<action selector="chooseGridHeight:" destination="J28-e1-gcC" id="ayB-De-Drm"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Medium" propertyListString="medium" id="Z1h-b3-VUc">
|
||||
<connections>
|
||||
<action selector="chooseGridHeight:" destination="J28-e1-gcC" id="2L5-oA-LRA"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Tall" propertyListString="tall" id="nuu-UE-jx7">
|
||||
<connections>
|
||||
<action selector="chooseGridHeight:" destination="J28-e1-gcC" id="NWu-Lm-Mcy"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Extra Tall" propertyListString="xl" id="7pm-OP-kNf">
|
||||
<connections>
|
||||
<action selector="chooseGridHeight:" destination="J28-e1-gcC" id="rZo-Hs-UjD"/>
|
||||
</connections>
|
||||
</command>
|
||||
</children>
|
||||
</menu>
|
||||
<menu title="Inline Menu" id="gSR-Tp-3Cp">
|
||||
<menuOptions key="menuOptions" displayInline="YES"/>
|
||||
</menu>
|
||||
<menu title="Text Size" id="si2-4b-JdU">
|
||||
<children>
|
||||
<command title="Extra Small" propertyListString="xs" input="5" id="1J1-HG-ovw">
|
||||
<keyModifierFlags key="modifierFlags" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="chooseFontSize:" destination="J28-e1-gcC" id="Fq4-fK-3Bs"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Small" propertyListString="small" input="6" id="M7K-32-93Q">
|
||||
<keyModifierFlags key="modifierFlags" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="chooseFontSize:" destination="J28-e1-gcC" id="syn-70-bmd"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Medium" propertyListString="medium" input="7" id="EOM-3c-Cjp">
|
||||
<keyModifierFlags key="modifierFlags" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="chooseFontSize:" destination="J28-e1-gcC" id="Qe4-E0-Qhz"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Large" propertyListString="large" input="8" id="PWP-X9-KBw">
|
||||
<keyModifierFlags key="modifierFlags" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="chooseFontSize:" destination="J28-e1-gcC" id="Lnl-mp-hOV"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Extra Large" propertyListString="xl" input="9" id="yfW-eZ-Rax">
|
||||
<keyModifierFlags key="modifierFlags" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="chooseFontSize:" destination="J28-e1-gcC" id="cl8-ay-saj"/>
|
||||
</connections>
|
||||
</command>
|
||||
</children>
|
||||
</menu>
|
||||
<menu title="Spacing" id="MQ7-6f-UwT">
|
||||
<children>
|
||||
<command title="Compact" propertyListString="compact" id="FEf-Wk-caC">
|
||||
<connections>
|
||||
<action selector="chooseSpacing:" destination="J28-e1-gcC" id="qx2-aa-FAd"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Comfortable" propertyListString="comfortable" id="A5r-hu-lBP">
|
||||
<connections>
|
||||
<action selector="chooseSpacing:" destination="J28-e1-gcC" id="Idm-Ge-25T"/>
|
||||
</connections>
|
||||
</command>
|
||||
</children>
|
||||
</menu>
|
||||
<menu title="Theme" id="k0L-se-kpA">
|
||||
<children>
|
||||
<command title="Light" propertyListString="light" menuElementState="on" id="nvf-Kg-GEz">
|
||||
<connections>
|
||||
<action selector="chooseTheme:" destination="J28-e1-gcC" id="AGW-N1-hqV"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Sepia" propertyListString="sepia" id="Nvo-zG-r0S">
|
||||
<connections>
|
||||
<action selector="chooseTheme:" destination="J28-e1-gcC" id="F6m-fp-d1B"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Medium" propertyListString="medium" id="u5z-am-9MT">
|
||||
<connections>
|
||||
<action selector="chooseTheme:" destination="J28-e1-gcC" id="fOO-Pu-NR6"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Dark" propertyListString="dark" id="roz-8B-xfb">
|
||||
<connections>
|
||||
<action selector="chooseTheme:" destination="J28-e1-gcC" id="Zpe-za-poM"/>
|
||||
</connections>
|
||||
</command>
|
||||
</children>
|
||||
</menu>
|
||||
</children>
|
||||
<systemMenuChildDeletions>
|
||||
<menuDeletion anchor="com.apple.menu.toolbar"/>
|
||||
</systemMenuChildDeletions>
|
||||
</menu>
|
||||
<menu title="Site" identifier="site" anchor="com.apple.menu.view" id="Kg8-V5-XsH">
|
||||
<children>
|
||||
<menu title="Manage" id="uU0-yq-BC8">
|
||||
<children>
|
||||
<command title="Rename Site…" id="ogl-RU-MAV">
|
||||
<connections>
|
||||
<action selector="openRenameSite:" destination="J28-e1-gcC" id="uUs-SK-j71"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Mute Site…" id="USf-x7-etD">
|
||||
<connections>
|
||||
<action selector="muteSite:" destination="J28-e1-gcC" id="J7R-Wr-qZZ"/>
|
||||
</connections>
|
||||
</command>
|
||||
<menu id="HKb-sW-DLl">
|
||||
<menuOptions key="menuOptions" displayInline="YES"/>
|
||||
<children>
|
||||
<command title="Delete Site…" id="RuQ-ea-MNw">
|
||||
<menuElementAttributes key="attributes" destructive="YES"/>
|
||||
<connections>
|
||||
<action selector="deleteSite:" destination="J28-e1-gcC" id="iu8-R6-1oB"/>
|
||||
</connections>
|
||||
</command>
|
||||
</children>
|
||||
</menu>
|
||||
</children>
|
||||
</menu>
|
||||
<menu id="CCe-ei-YVh">
|
||||
<menuOptions key="menuOptions" displayInline="YES"/>
|
||||
</menu>
|
||||
<command title="Train…" id="hIh-yf-xP8">
|
||||
<connections>
|
||||
<action selector="openTrainSite:" destination="J28-e1-gcC" id="5Ka-Ra-khJ"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Notifications…" id="zeT-bO-F72">
|
||||
<connections>
|
||||
<action selector="openNotifications:" destination="J28-e1-gcC" id="4dl-l2-1n6"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Statistics…" id="IRg-Uz-w76">
|
||||
<connections>
|
||||
<action selector="openStatistics:" destination="J28-e1-gcC" id="4ps-fi-6FI"/>
|
||||
</connections>
|
||||
</command>
|
||||
<menu id="ffV-Jd-hmj">
|
||||
<menuOptions key="menuOptions" displayInline="YES"/>
|
||||
</menu>
|
||||
<command title="Insta-Fetch Stories" input="r" id="skD-1M-foi">
|
||||
<keyModifierFlags key="modifierFlags" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="instaFetchFeed:" destination="J28-e1-gcC" id="soI-a3-gDT"/>
|
||||
</connections>
|
||||
</command>
|
||||
<menu id="ze6-Sa-c31">
|
||||
<menuOptions key="menuOptions" displayInline="YES"/>
|
||||
<children>
|
||||
<command title="Mark All as Read" input="a" id="BDX-7T-oPE">
|
||||
<keyModifierFlags key="modifierFlags" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="doMarkAllRead:" destination="J28-e1-gcC" id="2eI-UY-pbY"/>
|
||||
</connections>
|
||||
</command>
|
||||
</children>
|
||||
</menu>
|
||||
<menu id="dAb-4p-3Qc">
|
||||
<menuOptions key="menuOptions" displayInline="YES"/>
|
||||
<children>
|
||||
<command title="Next Site" input="j" id="Ux2-qi-iV3">
|
||||
<keyModifierFlags key="modifierFlags" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="nextSite:" destination="J28-e1-gcC" id="p14-gh-luF"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Previous Site" input="k" id="cvB-e9-ie9">
|
||||
<keyModifierFlags key="modifierFlags" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="previousSite:" destination="J28-e1-gcC" id="9N0-gQ-7bR"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Next Folder" input="J" id="dcy-Oz-PFw">
|
||||
<keyModifierFlags key="modifierFlags" command="YES"/>
|
||||
<connections>
|
||||
<action selector="nextFolder:" destination="J28-e1-gcC" id="fbT-o2-ZNT"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Previous Folder" input="K" id="CEJ-G9-fRi">
|
||||
<keyModifierFlags key="modifierFlags" command="YES"/>
|
||||
<connections>
|
||||
<action selector="previousFolder:" destination="J28-e1-gcC" id="ynW-dP-UuT"/>
|
||||
</connections>
|
||||
</command>
|
||||
</children>
|
||||
</menu>
|
||||
<menu id="IGD-cP-sh8">
|
||||
<menuOptions key="menuOptions" displayInline="YES"/>
|
||||
<children>
|
||||
<command title="Open All Stories" input="E" id="sW2-Jm-pRP">
|
||||
<keyModifierFlags key="modifierFlags" command="YES"/>
|
||||
<connections>
|
||||
<action selector="openAllStories:" destination="J28-e1-gcC" id="m4I-zj-Kta"/>
|
||||
</connections>
|
||||
</command>
|
||||
</children>
|
||||
</menu>
|
||||
</children>
|
||||
</menu>
|
||||
<menu title="Story" identifier="story" anchor="com.apple.menu.view" id="KgH-xe-mTD">
|
||||
<children>
|
||||
<command title="Save This Story" input="s" id="mRM-X6-xCI">
|
||||
<keyModifierFlags key="modifierFlags" command="YES"/>
|
||||
<connections>
|
||||
<action selector="toggleStorySaved:" destination="J28-e1-gcC" id="w9j-wM-yXJ"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Mark as Read" input="m" id="MOV-1R-tmb">
|
||||
<keyModifierFlags key="modifierFlags" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="toggleStoryUnread:" destination="J28-e1-gcC" id="iNX-pg-hgT"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Send To…" id="d3Y-Ik-PAB">
|
||||
<connections>
|
||||
<action selector="showSendTo:" destination="J28-e1-gcC" id="XJ8-Tz-tG6"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Train This Story…" id="GJC-ae-c80">
|
||||
<connections>
|
||||
<action selector="showTrain:" destination="J28-e1-gcC" id="pr3-BS-f2g"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Share This Story…" id="wmQ-3e-8h8">
|
||||
<connections>
|
||||
<action selector="showShare:" destination="J28-e1-gcC" id="UGy-Xo-sDK"/>
|
||||
</connections>
|
||||
</command>
|
||||
<menu id="nKV-Y3-j73">
|
||||
<menuOptions key="menuOptions" displayInline="YES"/>
|
||||
<children>
|
||||
<command title="Next Unread Story" input="n" id="ofa-dG-qfi">
|
||||
<keyModifierFlags key="modifierFlags" command="YES"/>
|
||||
<connections>
|
||||
<action selector="nextUnreadStory:" destination="J28-e1-gcC" id="us7-1R-z9P"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Next Story" input="j" id="FyB-cA-EZJ">
|
||||
<keyModifierFlags key="modifierFlags" command="YES"/>
|
||||
<connections>
|
||||
<action selector="nextStory:" destination="J28-e1-gcC" id="yl9-dW-g5i"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Previous Story" input="k" id="Tfg-Wu-4wp">
|
||||
<keyModifierFlags key="modifierFlags" command="YES"/>
|
||||
<connections>
|
||||
<action selector="previousStory:" destination="J28-e1-gcC" id="Ymu-C3-BYE"/>
|
||||
</connections>
|
||||
</command>
|
||||
</children>
|
||||
</menu>
|
||||
<menu id="XRI-fA-vEa">
|
||||
<menuOptions key="menuOptions" displayInline="YES"/>
|
||||
<children>
|
||||
<command title="Text View" input="t" id="G4z-4B-Qeb">
|
||||
<keyModifierFlags key="modifierFlags" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="toggleTextStory:" destination="J28-e1-gcC" id="QJp-Jw-8hd"/>
|
||||
</connections>
|
||||
</command>
|
||||
<command title="Open in Browser" input="o" id="Dvp-0s-e2A">
|
||||
<keyModifierFlags key="modifierFlags" command="YES"/>
|
||||
<connections>
|
||||
<action selector="openInBrowser:" destination="J28-e1-gcC" id="ZIJ-IW-Ybq"/>
|
||||
</connections>
|
||||
</command>
|
||||
</children>
|
||||
</menu>
|
||||
</children>
|
||||
</menu>
|
||||
<menu isSystemItem="YES" title="Help" identifier="com.apple.menu.help" id="2fJ-ya-vwD">
|
||||
<children>
|
||||
<command title="Support Forum" anchorAction="showHelp:" id="eDw-yh-3PE">
|
||||
<connections>
|
||||
<action selector="showSupportForum:" destination="J28-e1-gcC" id="sW1-ne-jja"/>
|
||||
</connections>
|
||||
</command>
|
||||
</children>
|
||||
</menu>
|
||||
</children>
|
||||
<systemMenuChildDeletions>
|
||||
<menuDeletion anchor="com.apple.menu.format"/>
|
||||
</systemMenuChildDeletions>
|
||||
</menu>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="J28-e1-gcC" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-1484" y="632"/>
|
||||
</scene>
|
||||
<!--Navigation Controller-->
|
||||
<scene sceneID="gvC-iq-nYU">
|
||||
<objects>
|
||||
|
@ -292,7 +895,7 @@
|
|||
<objects>
|
||||
<navigationController storyboardIdentifier="DetailNavigationController" useStoryboardIdentifierAsRestorationIdentifier="YES" id="HsP-cn-nIY" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="Noh-2M-34G">
|
||||
<rect key="frame" x="0.0" y="24" width="818.5" height="50"/>
|
||||
<rect key="frame" x="0.0" y="24" width="514" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
|
@ -405,7 +1008,7 @@
|
|||
<objects>
|
||||
<viewController id="afA-W0-XsQ" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="jBw-7b-YGl">
|
||||
<rect key="frame" x="0.0" y="0.0" width="1194" height="580"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1210" height="580"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<viewLayoutGuide key="safeArea" id="xqp-qa-ugn"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
|
@ -420,7 +1023,7 @@
|
|||
<objects>
|
||||
<viewController id="1tQ-fy-A3c" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="jdW-Cp-Pkg">
|
||||
<rect key="frame" x="0.0" y="0.0" width="1194" height="168"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1210" height="168"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<viewLayoutGuide key="safeArea" id="k4r-Od-mPr"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
|
|
18
clients/ios/Resources/PrivacyInfo.xcprivacy
Normal file
18
clients/ios/Resources/PrivacyInfo.xcprivacy
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPITypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPIType</key>
|
||||
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
|
||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||
<array>
|
||||
<string></string>
|
||||
<string>1C8F.1</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
13
clients/ios/Resources/mac/Credits.rtf
Normal file
13
clients/ios/Resources/mac/Credits.rtf
Normal file
|
@ -0,0 +1,13 @@
|
|||
{\rtf1\ansi\ansicpg1252\cocoartf2758
|
||||
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
|
||||
{\colortbl;\red255\green255\blue255;}
|
||||
{\*\expandedcolortbl;;}
|
||||
\margl1440\margr1440\vieww28800\viewh21020\viewkind0
|
||||
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\qc\partightenfactor0
|
||||
{\field{\*\fldinst{HYPERLINK "https://www.newsblur.com/"}}{\fldrslt
|
||||
\f0\fs22 \cf0 newsblur.com}}
|
||||
\f0\fs22 \
|
||||
\
|
||||
{\field{\*\fldinst{HYPERLINK "https://newsblur.com/privacy"}}{\fldrslt Privacy Policy}} \'95 {\field{\*\fldinst{HYPERLINK "https://newsblur.com/tos"}}{\fldrslt Terms of Service}}\
|
||||
\
|
||||
Copyright NewsBlur, Inc.}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue