mirror of
https://github.com/samuelclay/NewsBlur.git
synced 2025-09-18 21:50:56 +00:00
#1720 (Grid view)
- Added a Grid layout option to the feed detail menu. - In Grid layout, the title length and image position options are replaced by grid columns and grid height options. - When chosen, the right panes are replaced by a Grid view. - This is a work in progress.
This commit is contained in:
parent
7e572477a5
commit
926181327a
9 changed files with 310 additions and 96 deletions
|
@ -35,6 +35,7 @@ class DetailViewController: BaseViewController {
|
|||
static let left = "titles_on_left"
|
||||
static let top = "titles_on_top"
|
||||
static let bottom = "titles_on_bottom"
|
||||
static let grid = "titles_in_grid"
|
||||
}
|
||||
|
||||
/// How the feed detail and story pages are laid out.
|
||||
|
@ -47,6 +48,9 @@ class DetailViewController: BaseViewController {
|
|||
|
||||
/// The story pages are at the top, the feed detail at the bottom.
|
||||
case bottom
|
||||
|
||||
/// Using a grid view for the story titles and story pages.
|
||||
case grid
|
||||
}
|
||||
|
||||
/// How the feed detail and story pages are laid out.
|
||||
|
@ -57,6 +61,8 @@ class DetailViewController: BaseViewController {
|
|||
return .top
|
||||
case LayoutValue.bottom:
|
||||
return .bottom
|
||||
case LayoutValue.grid:
|
||||
return .grid
|
||||
default:
|
||||
return .left
|
||||
}
|
||||
|
@ -71,6 +77,8 @@ class DetailViewController: BaseViewController {
|
|||
UserDefaults.standard.set(LayoutValue.top, forKey: Key.layout)
|
||||
case .bottom:
|
||||
UserDefaults.standard.set(LayoutValue.bottom, forKey: Key.layout)
|
||||
case .grid:
|
||||
UserDefaults.standard.set(LayoutValue.grid, forKey: Key.layout)
|
||||
default:
|
||||
UserDefaults.standard.set(LayoutValue.left, forKey: Key.layout)
|
||||
}
|
||||
|
@ -89,6 +97,11 @@ class DetailViewController: BaseViewController {
|
|||
return layout == .top
|
||||
}
|
||||
|
||||
/// Whether or not using the grid layout; see also the previous property.
|
||||
@objc var storyTitlesInGrid: Bool {
|
||||
return layout == .grid
|
||||
}
|
||||
|
||||
/// Preference values.
|
||||
enum BehaviorValue {
|
||||
static let auto = "auto"
|
||||
|
@ -183,9 +196,12 @@ class DetailViewController: BaseViewController {
|
|||
/// The feed detail view controller in the supplementary pane, loaded from the storyboard.
|
||||
var supplementaryFeedDetailViewController: FeedDetailViewController?
|
||||
|
||||
/// The feed detail view controller, if using `top` or `bottom` layout. `nil` if using `left` layout.
|
||||
/// The feed detail view controller, if using `top`, `bottom`, or `grid` layout. `nil` if using `left` layout.
|
||||
var feedDetailViewController: FeedDetailViewController?
|
||||
|
||||
/// The grid detail view controller, if using `grid` layout. `nil` for other layouts.
|
||||
var gridDetailViewController: GridDetailViewController?
|
||||
|
||||
/// The horizontal page view controller. [Not currently used; might be used for #1351 (gestures in vertical scrolling).]
|
||||
// var horizontalPageViewController: HorizontalPageViewController?
|
||||
|
||||
|
@ -232,10 +248,6 @@ class DetailViewController: BaseViewController {
|
|||
navigationController?.navigationBar.barStyle = manager.isDarkTheme ? .black : .default
|
||||
|
||||
tidyNavigationController()
|
||||
|
||||
// DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
|
||||
// self.findSplitBackButton()
|
||||
// }
|
||||
}
|
||||
|
||||
/// Adjusts the container when autoscrolling. Only applies to iPhone.
|
||||
|
@ -244,46 +256,6 @@ class DetailViewController: BaseViewController {
|
|||
updateTheme()
|
||||
}
|
||||
|
||||
// @objc func findSplitBackButton() {
|
||||
// guard let navBar = navigationController?.navigationBar else {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// let imageViews = recursiveImageSubviews(of: navBar)
|
||||
//
|
||||
// for view in imageViews {
|
||||
// if let imageView = view as? UIImageView, let image = imageView.image, image.description.contains("BackIndicator"), let button = recursiveButtonSuperview(of: imageView) {
|
||||
// print("image view: \(imageView), image: \(String(describing: imageView.image)), button: \(button)")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// func recursiveImageSubviews(of view: UIView) -> [UIView] {
|
||||
// var subviews = [UIView]()
|
||||
//
|
||||
// for subview in view.subviews {
|
||||
// if subview is UIImageView {
|
||||
// subviews.append(subview)
|
||||
// } else {
|
||||
// subviews.append(contentsOf: recursiveImageSubviews(of: subview))
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return subviews
|
||||
// }
|
||||
//
|
||||
// func recursiveButtonSuperview(of view: UIView) -> UIButton? {
|
||||
// guard let superview = view.superview else {
|
||||
// return nil
|
||||
// }
|
||||
//
|
||||
// if let button = superview as? UIButton {
|
||||
// return button
|
||||
// }
|
||||
//
|
||||
// return recursiveButtonSuperview(of: superview)
|
||||
// }
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
|
@ -359,6 +331,11 @@ private extension DetailViewController {
|
|||
func checkViewControllers() {
|
||||
let isTop = layout == .top
|
||||
|
||||
if layout != .grid, gridDetailViewController != nil {
|
||||
remove(viewController: gridDetailViewController)
|
||||
gridDetailViewController = nil
|
||||
}
|
||||
|
||||
if layout == .left {
|
||||
if feedDetailViewController != nil {
|
||||
remove(viewController: feedDetailViewController)
|
||||
|
@ -371,6 +348,28 @@ private extension DetailViewController {
|
|||
supplementaryFeedDetailViewController = nil
|
||||
}
|
||||
|
||||
dividerViewBottomConstraint.constant = -13
|
||||
} else if layout == .grid {
|
||||
if gridDetailViewController == nil {
|
||||
gridDetailViewController = Storyboards.shared.controller(withIdentifier: .gridDetail) as? GridDetailViewController
|
||||
feedDetailViewController = Storyboards.shared.controller(withIdentifier: .feedDetail) as? FeedDetailViewController
|
||||
|
||||
add(viewController: gridDetailViewController, top: true)
|
||||
add(viewController: feedDetailViewController, top: false)
|
||||
|
||||
supplementaryFeedDetailNavigationController = appDelegate.feedDetailNavigationController
|
||||
supplementaryFeedDetailViewController = appDelegate.feedDetailViewController
|
||||
appDelegate.feedDetailNavigationController = nil
|
||||
appDelegate.feedDetailViewController = feedDetailViewController
|
||||
appDelegate.splitViewController.setViewController(nil, for: .supplementary)
|
||||
} else {
|
||||
let appropriateSuperview = isTop ? topContainerView : bottomContainerView
|
||||
|
||||
if feedDetailViewController?.view.superview != appropriateSuperview {
|
||||
add(viewController: feedDetailViewController, top: true)
|
||||
}
|
||||
}
|
||||
|
||||
dividerViewBottomConstraint.constant = -13
|
||||
} else {
|
||||
if feedDetailViewController == nil {
|
||||
|
@ -396,30 +395,19 @@ private extension DetailViewController {
|
|||
appDelegate.updateSplitBehavior()
|
||||
}
|
||||
|
||||
guard let storyPagesViewController = storyPagesViewController else {
|
||||
return
|
||||
}
|
||||
|
||||
let appropriateSuperview = isTop ? bottomContainerView : topContainerView
|
||||
|
||||
if storyPagesViewController.view.superview != appropriateSuperview {
|
||||
add(viewController: storyPagesViewController, top: !isTop)
|
||||
if layout != .grid {
|
||||
guard let storyPagesViewController = storyPagesViewController else {
|
||||
return
|
||||
}
|
||||
|
||||
adjustForAutoscroll()
|
||||
let appropriateSuperview = isTop ? bottomContainerView : topContainerView
|
||||
|
||||
// if isTop {
|
||||
// bottomContainerView.addSubview(traverseView)
|
||||
// bottomContainerView.addSubview(autoscrollView)
|
||||
// } else {
|
||||
// topContainerView.addSubview(traverseView)
|
||||
// topContainerView.addSubview(autoscrollView)
|
||||
// }
|
||||
if storyPagesViewController.view.superview != appropriateSuperview {
|
||||
add(viewController: storyPagesViewController, top: !isTop)
|
||||
|
||||
adjustForAutoscroll()
|
||||
}
|
||||
}
|
||||
//
|
||||
// traverseTopContainerBottomConstraint.isActive = !isTop
|
||||
// traverseBottomContainerBottomConstraint.isActive = isTop
|
||||
// autoscrollTopContainerBottomConstraint.isActive = !isTop
|
||||
// autoscrollBottomContainerBottomConstraint.isActive = isTop
|
||||
}
|
||||
|
||||
func add(viewController: UIViewController?, top: Bool) {
|
||||
|
|
|
@ -2355,42 +2355,62 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
[appDelegate addSplitControlToMenuController:viewController];
|
||||
|
||||
NSString *preferenceKey = @"story_titles_position";
|
||||
NSArray *titles = @[@"Left", @"Top", @"Bottom"];
|
||||
NSArray *values = @[@"titles_on_left", @"titles_on_top", @"titles_on_bottom"];
|
||||
NSArray *titles = @[@"Left", @"Top", @"Bottom", @"Grid"];
|
||||
NSArray *values = @[@"titles_on_left", @"titles_on_top", @"titles_on_bottom", @"titles_in_grid"];
|
||||
|
||||
[viewController addSegmentedControlWithTitles:titles values:values preferenceKey:preferenceKey selectionShouldDismiss:YES handler:^(NSUInteger selectedIndex) {
|
||||
[self.appDelegate.detailViewController updateLayoutWithReload:YES];
|
||||
}];
|
||||
|
||||
if (self.appDelegate.detailViewController.storyTitlesInGrid) {
|
||||
NSString *preferenceKey = @"grid_columns";
|
||||
NSArray *titles = @[@"Auto Cols", @"2", @"3", @"4"];
|
||||
NSArray *values = @[@"auto", @"2", @"3", @"4"];
|
||||
|
||||
[viewController addSegmentedControlWithTitles:titles values:values defaultValue:@"auto" preferenceKey:preferenceKey selectionShouldDismiss:NO handler:^(NSUInteger selectedIndex) {
|
||||
[self.appDelegate.detailViewController updateLayoutWithReload:YES];
|
||||
}];
|
||||
|
||||
preferenceKey = @"grid_height";
|
||||
titles = @[@"XS", @"Short", @"Medium", @"Tall", @"XL"];
|
||||
values = @[@"xs", @"short", @"medium", @"tall", @"xl"];
|
||||
|
||||
[viewController addSegmentedControlWithTitles:titles values:values defaultValue:@"medium" preferenceKey:preferenceKey selectionShouldDismiss:NO handler:^(NSUInteger selectedIndex) {
|
||||
[self.appDelegate.detailViewController updateLayoutWithReload:YES];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
NSString *preferenceKey = @"story_list_preview_text_size";
|
||||
NSArray *titles = @[@"Title", @"content_preview_small.png", @"content_preview_medium.png", @"content_preview_large.png"];
|
||||
NSArray *values = @[@"title", @"short", @"medium", @"long"];
|
||||
|
||||
[viewController addSegmentedControlWithTitles:titles values:values preferenceKey:preferenceKey selectionShouldDismiss:NO handler:^(NSUInteger selectedIndex) {
|
||||
[self.appDelegate resizePreviewSize];
|
||||
}];
|
||||
|
||||
// Upgrade the prefs; can remove these lines eventually, once most existing users are likely on version 11 or later.
|
||||
NSString *preview = [[NSUserDefaults standardUserDefaults] stringForKey:@"story_list_preview_images_size"];
|
||||
|
||||
if ([preview isEqualToString:@"small"]) {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@"small_right" forKey:@"story_list_preview_images_size"];
|
||||
} else if ([preview isEqualToString:@"large"]) {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@"large_right" forKey:@"story_list_preview_images_size"];
|
||||
if (!self.appDelegate.detailViewController.storyTitlesInGrid) {
|
||||
NSString *preferenceKey = @"story_list_preview_text_size";
|
||||
NSArray *titles = @[@"Title", @"content_preview_small.png", @"content_preview_medium.png", @"content_preview_large.png"];
|
||||
NSArray *values = @[@"title", @"short", @"medium", @"long"];
|
||||
|
||||
[viewController addSegmentedControlWithTitles:titles values:values preferenceKey:preferenceKey selectionShouldDismiss:NO handler:^(NSUInteger selectedIndex) {
|
||||
[self.appDelegate resizePreviewSize];
|
||||
}];
|
||||
|
||||
// Upgrade the prefs; can remove these lines eventually, once most existing users are likely on version 11 or later.
|
||||
NSString *preview = [[NSUserDefaults standardUserDefaults] stringForKey:@"story_list_preview_images_size"];
|
||||
|
||||
if ([preview isEqualToString:@"small"]) {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@"small_right" forKey:@"story_list_preview_images_size"];
|
||||
} else if ([preview isEqualToString:@"large"]) {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@"large_right" forKey:@"story_list_preview_images_size"];
|
||||
}
|
||||
|
||||
preferenceKey = @"story_list_preview_images_size";
|
||||
titles = @[@"No image", @"image_preview_small_left.png", @"image_preview_large_left.png", @"image_preview_large_right.png", @"image_preview_small_right.png"];
|
||||
values = @[@"none", @"small_left", @"large_left", @"large_right", @"small_right"];
|
||||
|
||||
[viewController addSegmentedControlWithTitles:titles values:values preferenceKey:preferenceKey selectionShouldDismiss:NO handler:^(NSUInteger selectedIndex) {
|
||||
[self.appDelegate resizePreviewSize];
|
||||
}];
|
||||
}
|
||||
|
||||
preferenceKey = @"story_list_preview_images_size";
|
||||
titles = @[@"No image", @"image_preview_small_left.png", @"image_preview_large_left.png", @"image_preview_large_right.png", @"image_preview_small_right.png"];
|
||||
values = @[@"none", @"small_left", @"large_left", @"large_right", @"small_right"];
|
||||
|
||||
[viewController addSegmentedControlWithTitles:titles values:values preferenceKey:preferenceKey selectionShouldDismiss:NO handler:^(NSUInteger selectedIndex) {
|
||||
[self.appDelegate resizePreviewSize];
|
||||
}];
|
||||
|
||||
preferenceKey = @"feed_list_font_size";
|
||||
titles = @[@"XS", @"S", @"M", @"L", @"XL"];
|
||||
values = @[@"xs", @"small", @"medium", @"large", @"xl"];
|
||||
NSString *preferenceKey = @"feed_list_font_size";
|
||||
NSArray *titles = @[@"XS", @"S", @"M", @"L", @"XL"];
|
||||
NSArray *values = @[@"xs", @"small", @"medium", @"large", @"xl"];
|
||||
|
||||
[viewController addSegmentedControlWithTitles:titles values:values preferenceKey:preferenceKey selectionShouldDismiss:NO handler:^(NSUInteger selectedIndex) {
|
||||
[self.appDelegate resizeFontSize];
|
||||
|
|
113
clients/ios/Classes/GridDetailViewController.swift
Normal file
113
clients/ios/Classes/GridDetailViewController.swift
Normal file
|
@ -0,0 +1,113 @@
|
|||
//
|
||||
// GridDetailViewController.swift
|
||||
// NewsBlur
|
||||
//
|
||||
// Created by David Sinclair on 2022-08-19.
|
||||
// Copyright © 2022 NewsBlur. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
/// A view controller to manage the Grid layout.
|
||||
class GridDetailViewController: UIViewController {
|
||||
@IBOutlet var collectionView: UICollectionView!
|
||||
|
||||
enum SectionLayoutKind: Int, CaseIterable {
|
||||
/// Feed cell kind.
|
||||
case feed
|
||||
|
||||
/// Story cell kind.
|
||||
case story
|
||||
}
|
||||
|
||||
var feedColumns: Int {
|
||||
guard let pref = UserDefaults.standard.string(forKey: "grid_columns"), let columns = Int(pref) else {
|
||||
return 4
|
||||
}
|
||||
|
||||
return columns
|
||||
}
|
||||
|
||||
var dataSource: UICollectionViewDiffableDataSource<SectionLayoutKind, Int>! = nil
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
collectionView.collectionViewLayout = createLayout()
|
||||
configureDataSource()
|
||||
}
|
||||
}
|
||||
|
||||
extension GridDetailViewController {
|
||||
func createLayout() -> UICollectionViewLayout {
|
||||
let layout = UICollectionViewCompositionalLayout { (sectionIndex: Int,
|
||||
layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
|
||||
|
||||
guard let sectionLayoutKind = SectionLayoutKind(rawValue: sectionIndex) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let columns = sectionLayoutKind == .feed ? self.feedColumns : 1
|
||||
|
||||
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
|
||||
heightDimension: .fractionalHeight(1.0))
|
||||
let item = NSCollectionLayoutItem(layoutSize: itemSize)
|
||||
item.contentInsets = NSDirectionalEdgeInsets(top: 2, leading: 2, bottom: 2, trailing: 2)
|
||||
|
||||
let groupHeight = columns == 1 ?
|
||||
NSCollectionLayoutDimension.absolute(44) :
|
||||
NSCollectionLayoutDimension.fractionalWidth(0.2)
|
||||
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
|
||||
heightDimension: groupHeight)
|
||||
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: columns)
|
||||
|
||||
let section = NSCollectionLayoutSection(group: group)
|
||||
section.contentInsets = NSDirectionalEdgeInsets(top: 20, leading: 20, bottom: 20, trailing: 20)
|
||||
|
||||
return section
|
||||
}
|
||||
|
||||
return layout
|
||||
}
|
||||
}
|
||||
|
||||
extension GridDetailViewController {
|
||||
func configureDataSource() {
|
||||
let feedCellRegistration = UICollectionView.CellRegistration<GridFeedCell, Int> { (cell, indexPath, identifier) in
|
||||
//TODO: 🚧
|
||||
}
|
||||
|
||||
let storyCellRegistration = UICollectionView.CellRegistration<GridStoryCell, Int> { (cell, indexPath, identifier) in
|
||||
//TODO: 🚧
|
||||
cell.contentView.backgroundColor = UIColor.red
|
||||
cell.contentView.layer.borderColor = UIColor.black.cgColor
|
||||
cell.contentView.layer.borderWidth = 1
|
||||
cell.contentView.layer.cornerRadius = SectionLayoutKind(rawValue: indexPath.section)! == .feed ? 8 : 0
|
||||
}
|
||||
|
||||
dataSource = UICollectionViewDiffableDataSource<SectionLayoutKind, Int>(collectionView: collectionView) {
|
||||
(collectionView: UICollectionView, indexPath: IndexPath, identifier: Int) -> UICollectionViewCell? in
|
||||
return SectionLayoutKind(rawValue: indexPath.section)! == .story ?
|
||||
collectionView.dequeueConfiguredReusableCell(using: feedCellRegistration, for: indexPath, item: identifier) :
|
||||
collectionView.dequeueConfiguredReusableCell(using: storyCellRegistration, for: indexPath, item: identifier)
|
||||
}
|
||||
|
||||
let itemsPerSection = 10
|
||||
var snapshot = NSDiffableDataSourceSnapshot<SectionLayoutKind, Int>()
|
||||
|
||||
SectionLayoutKind.allCases.forEach {
|
||||
snapshot.appendSections([$0])
|
||||
let itemOffset = $0.rawValue * itemsPerSection
|
||||
let itemUpperbound = itemOffset + itemsPerSection
|
||||
snapshot.appendItems(Array(itemOffset..<itemUpperbound))
|
||||
}
|
||||
|
||||
dataSource.apply(snapshot, animatingDifferences: false)
|
||||
}
|
||||
}
|
||||
|
||||
extension GridDetailViewController: UICollectionViewDelegate {
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
collectionView.deselectItem(at: indexPath, animated: true)
|
||||
}
|
||||
}
|
15
clients/ios/Classes/GridFeedCell.swift
Normal file
15
clients/ios/Classes/GridFeedCell.swift
Normal file
|
@ -0,0 +1,15 @@
|
|||
//
|
||||
// GridFeedCell.swift
|
||||
// NewsBlur
|
||||
//
|
||||
// Created by David Sinclair on 2022-08-19.
|
||||
// Copyright © 2022 NewsBlur. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
/// Collection view cell for a feed detail title.
|
||||
class GridFeedCell: UICollectionViewCell {
|
||||
static let reuseIdentifier = "GridFeedCell"
|
||||
|
||||
}
|
15
clients/ios/Classes/GridStoryCell.swift
Normal file
15
clients/ios/Classes/GridStoryCell.swift
Normal file
|
@ -0,0 +1,15 @@
|
|||
//
|
||||
// GridStoryCell.swift
|
||||
// NewsBlur
|
||||
//
|
||||
// Created by David Sinclair on 2022-08-19.
|
||||
// Copyright © 2022 NewsBlur. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
/// Collection view cell for a story.
|
||||
class GridStoryCell: UICollectionViewCell {
|
||||
static let reuseIdentifier = "GridStoryCell"
|
||||
|
||||
}
|
|
@ -20,6 +20,7 @@ class Storyboards {
|
|||
/// Main storyboard identifiers.
|
||||
enum Main: String {
|
||||
case feedDetail = "FeedDetailViewController"
|
||||
case gridDetail = "GridDetailViewController"
|
||||
case horizontalPages = "HorizontalPageViewController"
|
||||
case verticalPages = "VerticalPageViewController"
|
||||
// case storyDetail = "StoryDetailViewController" // loading from XIB currently
|
||||
|
|
|
@ -80,6 +80,9 @@
|
|||
177551D5238E228A00E27818 /* NotificationCenter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 177551D4238E228A00E27818 /* NotificationCenter.framework */; platformFilter = ios; };
|
||||
177551DB238E228A00E27818 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 177551D9238E228A00E27818 /* MainInterface.storyboard */; };
|
||||
177551DF238E228A00E27818 /* Old NewsBlur Latest.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 177551D3238E228A00E27818 /* Old NewsBlur Latest.appex */; platformFilter = ios; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
177D017828B056C600F2F2DB /* GridDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 177D017728B056C600F2F2DB /* GridDetailViewController.swift */; };
|
||||
177D017B28B05D2500F2F2DB /* GridFeedCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 177D017A28B05D2500F2F2DB /* GridFeedCell.swift */; };
|
||||
177D017D28B05D9500F2F2DB /* GridStoryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 177D017C28B05D9500F2F2DB /* GridStoryCell.swift */; };
|
||||
17813FB723AC6E450057FB16 /* WidgetErrorTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 17CE3F0523AC529B003152EF /* WidgetErrorTableViewCell.xib */; };
|
||||
1787083024F8B3A50000C82B /* StoryDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1787082F24F8B3A50000C82B /* StoryDetailViewController.swift */; };
|
||||
17876B9E1C9911D40055DD15 /* g_icn_folder_rss_sm.png in Resources */ = {isa = PBXBuildFile; fileRef = 17876B9A1C9911D40055DD15 /* g_icn_folder_rss_sm.png */; };
|
||||
|
@ -823,6 +826,9 @@
|
|||
177551DA238E228A00E27818 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = "<group>"; };
|
||||
177551DC238E228A00E27818 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
177551E3238E26BF00E27818 /* Widget Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Widget Extension.entitlements"; sourceTree = "<group>"; };
|
||||
177D017728B056C600F2F2DB /* GridDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GridDetailViewController.swift; sourceTree = "<group>"; };
|
||||
177D017A28B05D2500F2F2DB /* GridFeedCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GridFeedCell.swift; sourceTree = "<group>"; };
|
||||
177D017C28B05D9500F2F2DB /* GridStoryCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GridStoryCell.swift; sourceTree = "<group>"; };
|
||||
1787082F24F8B3A50000C82B /* StoryDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoryDetailViewController.swift; sourceTree = "<group>"; };
|
||||
17876B9A1C9911D40055DD15 /* g_icn_folder_rss_sm.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = g_icn_folder_rss_sm.png; sourceTree = "<group>"; };
|
||||
17876B9B1C9911D40055DD15 /* g_icn_folder_rss_sm@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "g_icn_folder_rss_sm@2x.png"; sourceTree = "<group>"; };
|
||||
|
@ -1691,6 +1697,7 @@
|
|||
431B857315A131C300DCE497 /* Feeds */,
|
||||
431B857215A131B200DCE497 /* Feed-Detail */,
|
||||
431B857415A1324200DCE497 /* Story */,
|
||||
177D017928B05CBF00F2F2DB /* Grid */,
|
||||
431B857115A1317000DCE497 /* FTUX */,
|
||||
431B857015A1315F00DCE497 /* Social */,
|
||||
FF3FA8871BB26595001F7C32 /* Activities */,
|
||||
|
@ -1802,6 +1809,16 @@
|
|||
path = "Old Widget Extension";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
177D017928B05CBF00F2F2DB /* Grid */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
177D017728B056C600F2F2DB /* GridDetailViewController.swift */,
|
||||
177D017A28B05D2500F2F2DB /* GridFeedCell.swift */,
|
||||
177D017C28B05D9500F2F2DB /* GridStoryCell.swift */,
|
||||
);
|
||||
name = Grid;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
19C28FACFE9D520D11CA2CBB /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -3704,6 +3721,7 @@
|
|||
FF2924E61E932D2900FCFA63 /* PINDiskCache.m in Sources */,
|
||||
7843F50511EEB1A000675F64 /* FeedDetailTableCell.m in Sources */,
|
||||
784B50ED127E3F68008F90EA /* LoginViewController.m in Sources */,
|
||||
177D017D28B05D9500F2F2DB /* GridStoryCell.swift in Sources */,
|
||||
FF5ACC241DE5F0C000FBD044 /* NotificationsViewController.m in Sources */,
|
||||
FFCDD8FE17F6368F000C6483 /* MCSwipeTableViewCell.m in Sources */,
|
||||
78095EC9128F30B500230C8E /* OriginalStoryViewController.m in Sources */,
|
||||
|
@ -3763,6 +3781,7 @@
|
|||
17432C831C53438D003F8FD6 /* FeedChooserViewController.m in Sources */,
|
||||
010EDEFA1B2386B7003B79DE /* OnePasswordExtension.m in Sources */,
|
||||
43ABBCAA15B53A1400EA3111 /* InteractionCell.m in Sources */,
|
||||
177D017828B056C600F2F2DB /* GridDetailViewController.swift in Sources */,
|
||||
FF8D1ECF1BAA311000725D8A /* SBJson4StreamTokeniser.m in Sources */,
|
||||
FF8D1ED81BAA33BA00725D8A /* NSObject+SBJSON.m in Sources */,
|
||||
172AD274251D9F40000BB264 /* Storyboards.swift in Sources */,
|
||||
|
@ -3791,6 +3810,7 @@
|
|||
176A5C7A24F8BD1B009E8DF9 /* DetailViewController.swift in Sources */,
|
||||
17432C7F1C533FBC003F8FD6 /* MenuViewController.m in Sources */,
|
||||
FFF8B3AF1F847505001AB95E /* NBDashboardNavigationBar.m in Sources */,
|
||||
177D017B28B05D2500F2F2DB /* GridFeedCell.swift in Sources */,
|
||||
17E635AF1C548C580075338E /* FeedChooserItem.m in Sources */,
|
||||
FF6A233216448E0700E15989 /* StoryPagesObjCViewController.m in Sources */,
|
||||
FF67D3B2168924C40057A7DA /* TrainerViewController.m in Sources */,
|
||||
|
|
|
@ -303,6 +303,46 @@
|
|||
</objects>
|
||||
<point key="canvasLocation" x="-546" y="1835"/>
|
||||
</scene>
|
||||
<!--Grid Detail View Controller-->
|
||||
<scene sceneID="OXZ-eV-qQz">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="GridDetailViewController" useStoryboardIdentifierAsRestorationIdentifier="YES" id="QmF-fv-1Bp" customClass="GridDetailViewController" customModule="NewsBlur" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="JQ6-ZA-aZb">
|
||||
<rect key="frame" x="0.0" y="0.0" width="1194" height="834"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="vaf-JJ-7oP">
|
||||
<rect key="frame" x="0.0" y="0.0" width="1194" height="834"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="Fmx-jr-pAt">
|
||||
<size key="itemSize" width="128" height="128"/>
|
||||
<size key="headerReferenceSize" width="0.0" height="0.0"/>
|
||||
<size key="footerReferenceSize" width="0.0" height="0.0"/>
|
||||
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
|
||||
</collectionViewFlowLayout>
|
||||
<cells/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="QmF-fv-1Bp" id="UAX-33-p9U"/>
|
||||
</connections>
|
||||
</collectionView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="pwo-OK-kJk"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="vaf-JJ-7oP" firstAttribute="top" secondItem="JQ6-ZA-aZb" secondAttribute="top" id="7F9-cE-mjz"/>
|
||||
<constraint firstAttribute="trailing" secondItem="vaf-JJ-7oP" secondAttribute="trailing" id="Dp9-b5-7mR"/>
|
||||
<constraint firstAttribute="bottom" secondItem="vaf-JJ-7oP" secondAttribute="bottom" id="jin-ea-ii1"/>
|
||||
<constraint firstItem="vaf-JJ-7oP" firstAttribute="leading" secondItem="JQ6-ZA-aZb" secondAttribute="leading" id="uJn-0H-m3i"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="collectionView" destination="vaf-JJ-7oP" id="BkE-3h-foS"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="5kV-BU-lYP" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="181" y="2678"/>
|
||||
</scene>
|
||||
<!--Horizontal Page View Controller-->
|
||||
<scene sceneID="Dnt-lB-G3h">
|
||||
<objects>
|
||||
|
@ -315,7 +355,7 @@
|
|||
<placeholder placeholderIdentifier="IBFirstResponder" id="y78-Tv-B24" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
<customObject id="9g1-OD-yDA" customClass="HorizontalPageDelegate" customModule="NewsBlur" customModuleProvider="target"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="181" y="2603"/>
|
||||
<point key="canvasLocation" x="181" y="3488"/>
|
||||
</scene>
|
||||
<!--Vertical Page View Controller-->
|
||||
<scene sceneID="jpJ-mR-ccR">
|
||||
|
@ -329,7 +369,7 @@
|
|||
<placeholder placeholderIdentifier="IBFirstResponder" id="rdh-By-bOV" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
<customObject id="aFI-Ht-5Fb" customClass="VerticalPageDelegate" customModule="NewsBlur" customModuleProvider="target"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="181" y="3363"/>
|
||||
<point key="canvasLocation" x="181" y="4247"/>
|
||||
</scene>
|
||||
<!--Feed Detail View Controller-->
|
||||
<scene sceneID="P4B-M4-aIa">
|
||||
|
|
|
@ -216,6 +216,7 @@
|
|||
<string>Titles on left</string>
|
||||
<string>Titles on top</string>
|
||||
<string>Titles on bottom</string>
|
||||
<string>Titles in grid</string>
|
||||
</array>
|
||||
<key>DefaultValue</key>
|
||||
<string>titles_on_left</string>
|
||||
|
@ -224,6 +225,7 @@
|
|||
<string>titles_on_left</string>
|
||||
<string>titles_on_top</string>
|
||||
<string>titles_on_bottom</string>
|
||||
<string>titles_in_grid</string>
|
||||
</array>
|
||||
<key>Key</key>
|
||||
<string>story_titles_position</string>
|
||||
|
|
Loading…
Add table
Reference in a new issue