From 0df4498fa3d85881764e070f143a8a2986ef089f Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Fri, 8 Nov 2019 17:16:09 -0600 Subject: [PATCH] Add customize timeline layout setting --- NetNewsWire.xcodeproj/project.pbxproj | 12 ++ iOS/AppDefaults.swift | 12 ++ ...asterTimelineAccessibilityCellLayout.swift | 2 +- .../Cell/MasterTimelineCellData.swift | 5 +- .../Cell/MasterTimelineCellLayout.swift | 4 +- .../MasterTimelineDefaultCellLayout.swift | 3 +- .../MasterTimelineIconSize.swift | 32 ++++ .../MasterTimelineViewController.swift | 9 +- iOS/Settings/Settings.storyboard | 176 +++++++++++++++--- iOS/Settings/SettingsViewController.swift | 25 +-- .../TimelineCustomizerViewController.swift | 88 +++++++++ .../TimelinePreviewTableViewController.swift | 77 ++++++++ 12 files changed, 393 insertions(+), 52 deletions(-) create mode 100644 iOS/MasterTimeline/MasterTimelineIconSize.swift create mode 100644 iOS/Settings/TimelineCustomizerViewController.swift create mode 100644 iOS/Settings/TimelinePreviewTableViewController.swift diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 4f4f5439d..b116fdf19 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -11,6 +11,9 @@ 49F40DF92335B71000552BF4 /* newsfoot.js in Resources */ = {isa = PBXBuildFile; fileRef = 49F40DEF2335B71000552BF4 /* newsfoot.js */; }; 5108F6B62375E612001ABC45 /* CacheCleaner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5108F6B52375E612001ABC45 /* CacheCleaner.swift */; }; 5108F6B72375E612001ABC45 /* CacheCleaner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5108F6B52375E612001ABC45 /* CacheCleaner.swift */; }; + 5108F6D22375EED2001ABC45 /* TimelineCustomizerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5108F6D12375EED2001ABC45 /* TimelineCustomizerViewController.swift */; }; + 5108F6D42375EEEF001ABC45 /* TimelinePreviewTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5108F6D32375EEEF001ABC45 /* TimelinePreviewTableViewController.swift */; }; + 5108F6D623762309001ABC45 /* MasterTimelineIconSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5108F6D523762309001ABC45 /* MasterTimelineIconSize.swift */; }; 51102165233A7D6C0007A5F7 /* ArticleExtractorButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51102164233A7D6C0007A5F7 /* ArticleExtractorButton.swift */; }; 5110C37D2373A8D100A9C04F /* InspectorIconHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5110C37C2373A8D100A9C04F /* InspectorIconHeaderView.swift */; }; 51126DA4225FDE2F00722696 /* RSImage-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51126DA3225FDE2F00722696 /* RSImage-Extensions.swift */; }; @@ -1204,6 +1207,9 @@ /* Begin PBXFileReference section */ 49F40DEF2335B71000552BF4 /* newsfoot.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = newsfoot.js; sourceTree = ""; }; 5108F6B52375E612001ABC45 /* CacheCleaner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheCleaner.swift; sourceTree = ""; }; + 5108F6D12375EED2001ABC45 /* TimelineCustomizerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineCustomizerViewController.swift; sourceTree = ""; }; + 5108F6D32375EEEF001ABC45 /* TimelinePreviewTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelinePreviewTableViewController.swift; sourceTree = ""; }; + 5108F6D523762309001ABC45 /* MasterTimelineIconSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterTimelineIconSize.swift; sourceTree = ""; }; 51102164233A7D6C0007A5F7 /* ArticleExtractorButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleExtractorButton.swift; sourceTree = ""; }; 5110C37C2373A8D100A9C04F /* InspectorIconHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InspectorIconHeaderView.swift; sourceTree = ""; }; 51121AA12265430A00BC0EC1 /* NetNewsWire_iOSapp_target.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = NetNewsWire_iOSapp_target.xcconfig; sourceTree = ""; }; @@ -1804,6 +1810,8 @@ 516A091D23609A3600EAE89B /* SettingsAccountTableViewCell.xib */, 516A093A2360A4A000EAE89B /* SettingsTableViewCell.xib */, 51A16993235E10D600EB091F /* SettingsViewController.swift */, + 5108F6D12375EED2001ABC45 /* TimelineCustomizerViewController.swift */, + 5108F6D32375EEEF001ABC45 /* TimelinePreviewTableViewController.swift */, ); path = Settings; sourceTree = ""; @@ -1894,6 +1902,7 @@ 51FD413A2342BD0500880194 /* MasterTimelineUnreadCountView.swift */, FFD43E372340F320009E5CA3 /* UndoAvailableAlertController.swift */, 51C4526F2265091600C03939 /* Cell */, + 5108F6D523762309001ABC45 /* MasterTimelineIconSize.swift */, ); path = MasterTimeline; sourceTree = ""; @@ -3958,6 +3967,7 @@ 51C4528E2265099C00C03939 /* SmartFeedsController.swift in Sources */, 51102165233A7D6C0007A5F7 /* ArticleExtractorButton.swift in Sources */, 5141E7392373C18B0013FF27 /* FeedInspectorViewController.swift in Sources */, + 5108F6D42375EEEF001ABC45 /* TimelinePreviewTableViewController.swift in Sources */, 84CAFCA522BC8C08007694F0 /* FetchRequestQueue.swift in Sources */, 51C4529C22650A1000C03939 /* SingleFaviconDownloader.swift in Sources */, 51E595A6228CC36500FCC42B /* ArticleStatusSyncTimer.swift in Sources */, @@ -3991,6 +4001,7 @@ 51C45268226508F600C03939 /* MasterFeedUnreadCountView.swift in Sources */, 5183CCD0226E1E880010922C /* NonIntrinsicLabel.swift in Sources */, 51C4529F22650A1900C03939 /* AuthorAvatarDownloader.swift in Sources */, + 5108F6D22375EED2001ABC45 /* TimelineCustomizerViewController.swift in Sources */, 519E743D22C663F900A78E47 /* SceneDelegate.swift in Sources */, 51CC9B3E231720B2000E842F /* MasterFeedDataSource.swift in Sources */, FFD43E412340F488009E5CA3 /* UndoAvailableAlertController.swift in Sources */, @@ -4004,6 +4015,7 @@ 51CE1C0B23622007005548FC /* RefreshProgressView.swift in Sources */, 511D4419231FC02D00FB1562 /* KeyboardManager.swift in Sources */, 51A1699D235E10D700EB091F /* SettingsViewController.swift in Sources */, + 5108F6D623762309001ABC45 /* MasterTimelineIconSize.swift in Sources */, 51C45293226509C800C03939 /* StarredFeedDelegate.swift in Sources */, 51D6A5BC23199C85001C27D8 /* MasterTimelineDataSource.swift in Sources */, 51934CCB230F599B006127BE /* ThemedNavigationController.swift in Sources */, diff --git a/iOS/AppDefaults.swift b/iOS/AppDefaults.swift index b70fc710a..d68d1bd48 100644 --- a/iOS/AppDefaults.swift +++ b/iOS/AppDefaults.swift @@ -21,6 +21,7 @@ struct AppDefaults { static let firstRunDate = "firstRunDate" static let timelineGroupByFeed = "timelineGroupByFeed" static let timelineNumberOfLines = "timelineNumberOfLines" + static let timelineIconSize = "timelineIconSize" static let timelineSortDirection = "timelineSortDirection" static let displayUndoAvailableTip = "displayUndoAvailableTip" static let refreshInterval = "refreshInterval" @@ -99,11 +100,22 @@ struct AppDefaults { } } + static var timelineIconSize: MasterTimelineIconSize { + get { + let rawValue = AppDefaults.shared.integer(forKey: Key.timelineIconSize) + return MasterTimelineIconSize(rawValue: rawValue) ?? MasterTimelineIconSize.medium + } + set { + AppDefaults.shared.set(newValue.rawValue, forKey: Key.timelineIconSize) + } + } + static func registerDefaults() { let defaults: [String : Any] = [Key.lastImageCacheFlushDate: Date(), Key.refreshInterval: RefreshInterval.everyHour.rawValue, Key.timelineGroupByFeed: false, Key.timelineNumberOfLines: 2, + Key.timelineIconSize: MasterTimelineIconSize.medium.rawValue, Key.timelineSortDirection: ComparisonResult.orderedDescending.rawValue, Key.displayUndoAvailableTip: true] AppDefaults.shared.register(defaults: defaults) diff --git a/iOS/MasterTimeline/Cell/MasterTimelineAccessibilityCellLayout.swift b/iOS/MasterTimeline/Cell/MasterTimelineAccessibilityCellLayout.swift index e702516b9..f104a2d0e 100644 --- a/iOS/MasterTimeline/Cell/MasterTimelineAccessibilityCellLayout.swift +++ b/iOS/MasterTimeline/Cell/MasterTimelineAccessibilityCellLayout.swift @@ -39,7 +39,7 @@ struct MasterTimelineAccessibilityCellLayout: MasterTimelineCellLayout { // Icon Image if cellData.showIcon { - self.iconImageRect = MasterTimelineAccessibilityCellLayout.rectForIconView(currentPoint) + self.iconImageRect = MasterTimelineAccessibilityCellLayout.rectForIconView(currentPoint, iconSize: cellData.iconSize) currentPoint.y = self.iconImageRect.maxY } else { self.iconImageRect = CGRect.zero diff --git a/iOS/MasterTimeline/Cell/MasterTimelineCellData.swift b/iOS/MasterTimeline/Cell/MasterTimelineCellData.swift index 4edda1db1..c801a4c72 100644 --- a/iOS/MasterTimeline/Cell/MasterTimelineCellData.swift +++ b/iOS/MasterTimeline/Cell/MasterTimelineCellData.swift @@ -22,8 +22,9 @@ struct MasterTimelineCellData { let read: Bool let starred: Bool let numberOfLines: Int + let iconSize: MasterTimelineIconSize - init(article: Article, showFeedName: Bool, feedName: String?, iconImage: IconImage?, showIcon: Bool, featuredImage: UIImage?, numberOfLines: Int) { + init(article: Article, showFeedName: Bool, feedName: String?, iconImage: IconImage?, showIcon: Bool, featuredImage: UIImage?, numberOfLines: Int, iconSize: MasterTimelineIconSize) { self.title = ArticleStringFormatter.truncatedTitle(article) self.summary = ArticleStringFormatter.truncatedSummary(article) @@ -46,6 +47,7 @@ struct MasterTimelineCellData { self.read = article.status.read self.starred = article.status.starred self.numberOfLines = numberOfLines + self.iconSize = iconSize } @@ -61,6 +63,7 @@ struct MasterTimelineCellData { self.read = true self.starred = false self.numberOfLines = 0 + self.iconSize = .medium } } diff --git a/iOS/MasterTimeline/Cell/MasterTimelineCellLayout.swift b/iOS/MasterTimeline/Cell/MasterTimelineCellLayout.swift index bd37476e3..b7d99cc32 100644 --- a/iOS/MasterTimeline/Cell/MasterTimelineCellLayout.swift +++ b/iOS/MasterTimeline/Cell/MasterTimelineCellLayout.swift @@ -42,9 +42,9 @@ extension MasterTimelineCellLayout { return r } - static func rectForIconView(_ point: CGPoint) -> CGRect { + static func rectForIconView(_ point: CGPoint, iconSize: MasterTimelineIconSize) -> CGRect { var r = CGRect.zero - r.size = MasterTimelineDefaultCellLayout.iconImageSize + r.size = iconSize.size r.origin.x = point.x r.origin.y = point.y + 4 return r diff --git a/iOS/MasterTimeline/Cell/MasterTimelineDefaultCellLayout.swift b/iOS/MasterTimeline/Cell/MasterTimelineDefaultCellLayout.swift index 1bbd83cb3..793f6923f 100644 --- a/iOS/MasterTimeline/Cell/MasterTimelineDefaultCellLayout.swift +++ b/iOS/MasterTimeline/Cell/MasterTimelineDefaultCellLayout.swift @@ -21,7 +21,6 @@ struct MasterTimelineDefaultCellLayout: MasterTimelineCellLayout { static let starDimension = CGFloat(integerLiteral: 16) static let starSize = CGSize(width: MasterTimelineDefaultCellLayout.starDimension, height: MasterTimelineDefaultCellLayout.starDimension) - static let iconImageSize = CGSize(width: 32.0, height: 32.0) static let iconMarginRight = CGFloat(integerLiteral: 8) static let iconCornerRadius = CGFloat(integerLiteral: 4) @@ -72,7 +71,7 @@ struct MasterTimelineDefaultCellLayout: MasterTimelineCellLayout { // Icon Image if cellData.showIcon { - self.iconImageRect = MasterTimelineDefaultCellLayout.rectForIconView(currentPoint) + self.iconImageRect = MasterTimelineDefaultCellLayout.rectForIconView(currentPoint, iconSize: cellData.iconSize) currentPoint.x = self.iconImageRect.maxX + MasterTimelineDefaultCellLayout.iconMarginRight } else { self.iconImageRect = CGRect.zero diff --git a/iOS/MasterTimeline/MasterTimelineIconSize.swift b/iOS/MasterTimeline/MasterTimelineIconSize.swift new file mode 100644 index 000000000..d06629e59 --- /dev/null +++ b/iOS/MasterTimeline/MasterTimelineIconSize.swift @@ -0,0 +1,32 @@ +// +// MasterTimelineIconSize.swift +// NetNewsWire-iOS +// +// Created by Maurice Parker on 11/8/19. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +import Foundation +import CoreGraphics + +enum MasterTimelineIconSize: Int, CaseIterable { + case small = 1 + case medium = 2 + case large = 3 + + private static let smallDimension = CGFloat(integerLiteral: 24) + private static let mediumDimension = CGFloat(integerLiteral: 36) + private static let largeDimension = CGFloat(integerLiteral: 48) + + var size: CGSize { + switch self { + case .small: + return CGSize(width: MasterTimelineIconSize.smallDimension, height: MasterTimelineIconSize.smallDimension) + case .medium: + return CGSize(width: MasterTimelineIconSize.mediumDimension, height: MasterTimelineIconSize.mediumDimension) + case .large: + return CGSize(width: MasterTimelineIconSize.largeDimension, height: MasterTimelineIconSize.largeDimension) + } + } + +} diff --git a/iOS/MasterTimeline/MasterTimelineViewController.swift b/iOS/MasterTimeline/MasterTimelineViewController.swift index a96a2edd8..bf23f7dd1 100644 --- a/iOS/MasterTimeline/MasterTimelineViewController.swift +++ b/iOS/MasterTimeline/MasterTimelineViewController.swift @@ -15,6 +15,7 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner private var titleView: MasterTimelineTitleView? private var numberOfTextLines = 0 + private var iconSize = MasterTimelineIconSize.medium @IBOutlet weak var markAllAsReadButton: UIBarButtonItem! @IBOutlet weak var firstUnreadButton: UIBarButtonItem! @@ -63,6 +64,7 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner // Configure the table tableView.dataSource = dataSource numberOfTextLines = AppDefaults.timelineNumberOfLines + iconSize = AppDefaults.timelineIconSize resetEstimatedRowHeight() resetUI() @@ -348,8 +350,9 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner } @objc func userDefaultsDidChange(_ note: Notification) { - if numberOfTextLines != AppDefaults.timelineNumberOfLines { + if numberOfTextLines != AppDefaults.timelineNumberOfLines || iconSize != AppDefaults.timelineIconSize { numberOfTextLines = AppDefaults.timelineNumberOfLines + iconSize = AppDefaults.timelineIconSize resetEstimatedRowHeight() reloadAllVisibleCells() } @@ -392,7 +395,7 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner let status = ArticleStatus(articleID: prototypeID, read: false, starred: false, userDeleted: false, dateArrived: Date()) let prototypeArticle = Article(accountID: prototypeID, articleID: prototypeID, feedID: prototypeID, uniqueID: prototypeID, title: longTitle, contentHTML: nil, contentText: nil, url: nil, externalURL: nil, summary: nil, imageURL: nil, bannerImageURL: nil, datePublished: nil, dateModified: nil, authors: nil, attachments: nil, status: status) - let prototypeCellData = MasterTimelineCellData(article: prototypeArticle, showFeedName: true, feedName: "Prototype Feed Name", iconImage: nil, showIcon: false, featuredImage: nil, numberOfLines: numberOfTextLines) + let prototypeCellData = MasterTimelineCellData(article: prototypeArticle, showFeedName: true, feedName: "Prototype Feed Name", iconImage: nil, showIcon: false, featuredImage: nil, numberOfLines: numberOfTextLines, iconSize: iconSize) if UIApplication.shared.preferredContentSizeCategory.isAccessibilityCategory { let layout = MasterTimelineAccessibilityCellLayout(width: tableView.bounds.width, insets: tableView.safeAreaInsets, cellData: prototypeCellData) @@ -513,7 +516,7 @@ private extension MasterTimelineViewController { let showFeedNames = coordinator.showFeedNames let showIcon = coordinator.showIcons && iconImage != nil - cell.cellData = MasterTimelineCellData(article: article, showFeedName: showFeedNames, feedName: article.feed?.nameForDisplay, iconImage: iconImage, showIcon: showIcon, featuredImage: featuredImage, numberOfLines: numberOfTextLines) + cell.cellData = MasterTimelineCellData(article: article, showFeedName: showFeedNames, feedName: article.feed?.nameForDisplay, iconImage: iconImage, showIcon: showIcon, featuredImage: featuredImage, numberOfLines: numberOfTextLines, iconSize: iconSize) } diff --git a/iOS/Settings/Settings.storyboard b/iOS/Settings/Settings.storyboard index afeda3cc8..8100eb294 100644 --- a/iOS/Settings/Settings.storyboard +++ b/iOS/Settings/Settings.storyboard @@ -4,6 +4,7 @@ + @@ -200,34 +201,21 @@ - + - + - - - - - - - - - @@ -353,8 +341,6 @@ - - @@ -502,7 +488,7 @@ diff --git a/iOS/Settings/SettingsViewController.swift b/iOS/Settings/SettingsViewController.swift index 82fc5a02c..2a36606c8 100644 --- a/iOS/Settings/SettingsViewController.swift +++ b/iOS/Settings/SettingsViewController.swift @@ -17,8 +17,6 @@ class SettingsViewController: UITableViewController { @IBOutlet weak var timelineSortOrderSwitch: UISwitch! @IBOutlet weak var groupByFeedSwitch: UISwitch! - @IBOutlet weak var numberOfTextLinesLabel: UILabel! - @IBOutlet weak var numberOfTextLinesSteppper: UIStepper! weak var presentingParentController: UIViewController? @@ -52,10 +50,6 @@ class SettingsViewController: UITableViewController { groupByFeedSwitch.isOn = false } - let numberOfTextLines = AppDefaults.timelineNumberOfLines - numberOfTextLinesSteppper.value = Double(numberOfTextLines) - updateNumberOfTextLinesLabel(value: numberOfTextLines) - let buildLabel = NonIntrinsicLabel(frame: CGRect(x: 20.0, y: 0.0, width: 0.0, height: 0.0)) buildLabel.font = UIFont.systemFont(ofSize: 11.0) buildLabel.textColor = UIColor.gray @@ -167,6 +161,14 @@ class SettingsViewController: UITableViewController { default: break } + case 3: + switch indexPath.row { + case 2: + let timeline = UIStoryboard.settings.instantiateController(ofType: TimelineCustomizerViewController.self) + self.navigationController?.pushViewController(timeline, animated: true) + default: + break + } case 4: switch indexPath.row { case 0: @@ -245,12 +247,6 @@ class SettingsViewController: UITableViewController { } } - @IBAction func stepNumberOfTextLines(_ sender: UIStepper) { - let numberOfLines = Int(sender.value) - AppDefaults.timelineNumberOfLines = numberOfLines - updateNumberOfTextLinesLabel(value: numberOfLines) - } - // MARK: Notifications @objc func contentSizeCategoryDidChange() { @@ -295,11 +291,6 @@ extension SettingsViewController: UIDocumentPickerDelegate { private extension SettingsViewController { - func updateNumberOfTextLinesLabel(value: Int) { - let localizedText = NSLocalizedString("Number of Text Lines: %d", comment: "Number of Text Lines") - numberOfTextLinesLabel.text = NSString.localizedStringWithFormat(localizedText as NSString, value) as String - } - func addFeed() { self.dismiss(animated: true) diff --git a/iOS/Settings/TimelineCustomizerViewController.swift b/iOS/Settings/TimelineCustomizerViewController.swift new file mode 100644 index 000000000..2a0388777 --- /dev/null +++ b/iOS/Settings/TimelineCustomizerViewController.swift @@ -0,0 +1,88 @@ +// +// TimelineCustomizerViewController.swift +// NetNewsWire-iOS +// +// Created by Maurice Parker on 11/8/19. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +import UIKit + +class TimelineCustomizerViewController: UIViewController { + + @IBOutlet weak var iconSizeSliderContainerView: UIView! + @IBOutlet weak var iconSizeSlider: UISlider! + @IBOutlet weak var numberOfLinesSliderContainerView: UIView! + @IBOutlet weak var numberOfLinesSlider: UISlider! + + @IBOutlet weak var previewWidthConstraint: NSLayoutConstraint! + @IBOutlet weak var previewHeightConstraint: NSLayoutConstraint! + + @IBOutlet weak var previewContainerView: UIView! + var previewController: TimelinePreviewTableViewController { + return children.first as! TimelinePreviewTableViewController + } + + override func viewDidLoad() { + super.viewDidLoad() + + iconSizeSliderContainerView.layer.cornerRadius = 12 + numberOfLinesSliderContainerView.layer.cornerRadius = 12 + + numberOfLinesSlider.value = Float(AppDefaults.timelineNumberOfLines) + iconSizeSlider.value = Float(AppDefaults.timelineIconSize.rawValue) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewDidAppear(animated) + updatePreviewBorder() + updatePreview() + } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + updatePreviewBorder() + updatePreview() + } + + @IBAction func iconSizeChanged(_ sender: Any) { + guard let iconSize = MasterTimelineIconSize(rawValue: Int(iconSizeSlider.value)) else { return } + AppDefaults.timelineIconSize = iconSize + updatePreview() + } + + @IBAction func numberOfLinesChanged(_ sender: Any) { + AppDefaults.timelineNumberOfLines = Int(numberOfLinesSlider.value) + updatePreview() + } + +} + +// MARK: Private + +private extension TimelineCustomizerViewController { + + func updatePreview() { + let previewWidth: CGFloat = { + if traitCollection.userInterfaceIdiom == .phone { + return view.bounds.width + } else { + return view.bounds.width / 1.5 + } + }() + + previewWidthConstraint.constant = previewWidth + previewHeightConstraint.constant = previewController.heightFor(width: previewWidth) + + previewController.reload() + } + + func updatePreviewBorder() { + if traitCollection.userInterfaceStyle == .dark { + previewContainerView.layer.borderColor = UIColor.black.cgColor + previewContainerView.layer.borderWidth = 1 + } else { + previewContainerView.layer.borderWidth = 0 + } + } + +} diff --git a/iOS/Settings/TimelinePreviewTableViewController.swift b/iOS/Settings/TimelinePreviewTableViewController.swift new file mode 100644 index 000000000..2cec5f49d --- /dev/null +++ b/iOS/Settings/TimelinePreviewTableViewController.swift @@ -0,0 +1,77 @@ +// +// TimelinePreviewTableViewController.swift +// NetNewsWire-iOS +// +// Created by Maurice Parker on 11/8/19. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +import UIKit +import Articles + +class TimelinePreviewTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { + + @IBOutlet weak var tableView: UITableView! + + override func viewDidLoad() { + super.viewDidLoad() + + tableView.delegate = self + tableView.dataSource = self + + } + + func heightFor(width: CGFloat) -> CGFloat { + if UIApplication.shared.preferredContentSizeCategory.isAccessibilityCategory { + let layout = MasterTimelineAccessibilityCellLayout(width: width, insets: tableView.safeAreaInsets, cellData: prototypeCellData) + return layout.height + } else { + let layout = MasterTimelineDefaultCellLayout(width: width, insets: tableView.safeAreaInsets, cellData: prototypeCellData) + return layout.height + } + } + + // MARK: - Table view data source + + func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return 1 + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! MasterTimelineTableViewCell + cell.cellData = prototypeCellData + return cell + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.selectRow(at: nil, animated: true, scrollPosition: .none) + } + // MARK: API + + func reload() { + tableView.reloadData() + } + +} + +// MARK: Private + +private extension TimelinePreviewTableViewController { + + var prototypeCellData: MasterTimelineCellData { + let longTitle = "Enim ut tellus elementum sagittis vitae et. Nibh praesent tristique magna sit amet purus gravida quis blandit. Neque volutpat ac tincidunt vitae semper quis lectus nulla. Massa id neque aliquam vestibulum morbi blandit. Ultrices vitae auctor eu augue. Enim eu turpis egestas pretium aenean pharetra magna. Eget gravida cum sociis natoque. Sit amet consectetur adipiscing elit. Auctor eu augue ut lectus arcu bibendum. Maecenas volutpat blandit aliquam etiam erat velit. Ut pharetra sit amet aliquam id diam maecenas ultricies. In hac habitasse platea dictumst quisque sagittis purus sit amet." + + let prototypeID = "prototype" + let status = ArticleStatus(articleID: prototypeID, read: false, starred: false, userDeleted: false, dateArrived: Date()) + let prototypeArticle = Article(accountID: prototypeID, articleID: prototypeID, feedID: prototypeID, uniqueID: prototypeID, title: longTitle, contentHTML: nil, contentText: nil, url: nil, externalURL: nil, summary: nil, imageURL: nil, bannerImageURL: nil, datePublished: nil, dateModified: nil, authors: nil, attachments: nil, status: status) + + let iconImage = IconImage(AppAssets.faviconTemplateImage.withTintColor(AppAssets.secondaryAccentColor)) + + return MasterTimelineCellData(article: prototypeArticle, showFeedName: true, feedName: "Feed Name", iconImage: iconImage, showIcon: true, featuredImage: nil, numberOfLines: AppDefaults.timelineNumberOfLines, iconSize: AppDefaults.timelineIconSize) + } + +}