Update picker for Share Extension to be hierarchical and use icons. Issue #1269

This commit is contained in:
Maurice Parker
2019-11-16 19:44:01 -06:00
parent e74e6cb875
commit 397d8e8ffa
17 changed files with 236 additions and 131 deletions

View File

@@ -1,51 +0,0 @@
//
// AddWebFeedDefaultContainer.swift
// NetNewsWire-iOS
//
// Created by Maurice Parker on 11/16/19.
// Copyright © 2019 Ranchero Software. All rights reserved.
//
import Foundation
import Account
struct AddWebFeedDefaultContainer {
static var defaultContainer: Container? {
if let accountID = AppDefaults.addWebFeedAccountID, let account = AccountManager.shared.activeAccounts.first(where: { $0.accountID == accountID }) {
if let folderName = AppDefaults.addWebFeedFolderName, let folder = account.findFolder(withDisplayName: folderName) {
return folder
} else {
return substituteContainerIfNeeded(account: account)
}
} else if let account = AccountManager.shared.sortedActiveAccounts.first {
return substituteContainerIfNeeded(account: account)
} else {
return nil
}
}
static func storeDefaultContainer(_ container: Container) {
AppDefaults.addWebFeedAccountID = container.account?.accountID
if let folder = container as? Folder {
AppDefaults.addWebFeedFolderName = folder.nameForDisplay
} else {
AppDefaults.addWebFeedFolderName = nil
}
}
private static func substituteContainerIfNeeded(account: Account) -> Container? {
if !account.behaviors.contains(.disallowFeedInRootFolder) {
return account
} else {
if let folder = account.sortedFolders?.first {
return folder
} else {
return nil
}
}
}
}

View File

@@ -62,8 +62,10 @@ class AddWebFeedFolderViewController: UITableViewController {
if let compContainer = initialContainer, container === compContainer {
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}
return cell
}

View File

@@ -138,7 +138,7 @@ extension AddWebFeedViewController: AddWebFeedFolderViewControllerDelegate {
func didSelect(container: Container) {
self.container = container
updateFolderLabel()
AddWebFeedDefaultContainer.storeDefaultContainer(container)
AddWebFeedDefaultContainer.saveDefaultContainer(container)
}
}

View File

@@ -119,10 +119,10 @@ struct AppDefaults {
}
}
static var timelineIconSize: MasterTimelineIconSize {
static var timelineIconSize: IconSize {
get {
let rawValue = AppDefaults.shared.integer(forKey: Key.timelineIconSize)
return MasterTimelineIconSize(rawValue: rawValue) ?? MasterTimelineIconSize.medium
return IconSize(rawValue: rawValue) ?? IconSize.medium
}
set {
AppDefaults.shared.set(newValue.rawValue, forKey: Key.timelineIconSize)
@@ -133,7 +133,7 @@ struct AppDefaults {
let defaults: [String : Any] = [Key.lastImageCacheFlushDate: Date(),
Key.timelineGroupByFeed: false,
Key.timelineNumberOfLines: 2,
Key.timelineIconSize: MasterTimelineIconSize.medium.rawValue,
Key.timelineIconSize: IconSize.medium.rawValue,
Key.timelineSortDirection: ComparisonResult.orderedDescending.rawValue,
Key.displayUndoAvailableTip: true]
AppDefaults.shared.register(defaults: defaults)
@@ -202,5 +202,3 @@ private extension AppDefaults {
}
}

View File

@@ -22,9 +22,9 @@ struct MasterTimelineCellData {
let read: Bool
let starred: Bool
let numberOfLines: Int
let iconSize: MasterTimelineIconSize
let iconSize: IconSize
init(article: Article, showFeedName: Bool, feedName: String?, iconImage: IconImage?, showIcon: Bool, featuredImage: UIImage?, numberOfLines: Int, iconSize: MasterTimelineIconSize) {
init(article: Article, showFeedName: Bool, feedName: String?, iconImage: IconImage?, showIcon: Bool, featuredImage: UIImage?, numberOfLines: Int, iconSize: IconSize) {
self.title = ArticleStringFormatter.truncatedTitle(article)
self.summary = ArticleStringFormatter.truncatedSummary(article)

View File

@@ -42,7 +42,7 @@ extension MasterTimelineCellLayout {
return r
}
static func rectForIconView(_ point: CGPoint, iconSize: MasterTimelineIconSize) -> CGRect {
static func rectForIconView(_ point: CGPoint, iconSize: IconSize) -> CGRect {
var r = CGRect.zero
r.size = iconSize.size
r.origin.x = point.x

View File

@@ -1,32 +0,0 @@
//
// 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)
}
}
}

View File

@@ -15,7 +15,7 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
private var titleView: MasterTimelineTitleView?
private var numberOfTextLines = 0
private var iconSize = MasterTimelineIconSize.medium
private var iconSize = IconSize.medium
@IBOutlet weak var markAllAsReadButton: UIBarButtonItem!
@IBOutlet weak var firstUnreadButton: UIBarButtonItem!

View File

@@ -47,7 +47,7 @@ class TimelineCustomizerViewController: UIViewController {
}
@IBAction func iconSizeChanged(_ sender: Any) {
guard let iconSize = MasterTimelineIconSize(rawValue: Int(iconSizeSlider.value.rounded())) else { return }
guard let iconSize = IconSize(rawValue: Int(iconSizeSlider.value.rounded())) else { return }
AppDefaults.timelineIconSize = iconSize
updatePreview()
}

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15509"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="JCb-QB-CrO" customClass="ShareFolderPickerCell" customModule="NetNewsWire_iOS_Share_Extension" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="JCb-QB-CrO" id="FzD-t2-JGy">
<rect key="frame" x="0.0" y="0.0" width="383" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="yiw-9t-gil" userLabel="Account Icon">
<rect key="frame" x="20" y="11" width="22" height="22"/>
<constraints>
<constraint firstAttribute="width" constant="22" id="43E-Em-Z6O"/>
<constraint firstAttribute="height" constant="22" id="mTY-cQ-1R1"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TRx-RV-za8" userLabel="Account Label">
<rect key="frame" x="50" y="14" width="42" height="16"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="TRx-RV-za8" firstAttribute="leading" secondItem="yiw-9t-gil" secondAttribute="trailing" constant="8" symbolic="YES" id="RUN-Ol-xSl"/>
<constraint firstItem="TRx-RV-za8" firstAttribute="top" secondItem="FzD-t2-JGy" secondAttribute="top" constant="14" id="cze-hi-8Uh"/>
<constraint firstItem="yiw-9t-gil" firstAttribute="leading" secondItem="FzD-t2-JGy" secondAttribute="leading" constant="20" symbolic="YES" id="oU9-E3-lEt"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="TRx-RV-za8" secondAttribute="trailing" constant="8" id="sJ6-wr-JIw"/>
<constraint firstItem="yiw-9t-gil" firstAttribute="centerY" secondItem="FzD-t2-JGy" secondAttribute="centerY" id="tUD-tI-dgr"/>
<constraint firstAttribute="bottom" secondItem="TRx-RV-za8" secondAttribute="bottom" constant="14" id="zls-MW-Ffp"/>
</constraints>
</tableViewCellContentView>
<inset key="separatorInset" minX="50" minY="0.0" maxX="0.0" maxY="0.0"/>
<connections>
<outlet property="icon" destination="yiw-9t-gil" id="uXC-nW-WFl"/>
<outlet property="label" destination="TRx-RV-za8" id="ABN-lc-R1A"/>
</connections>
<point key="canvasLocation" x="7" y="-9"/>
</tableViewCell>
</objects>
</document>

View File

@@ -0,0 +1,15 @@
//
// ShareFolderPickerCell.swift
// NetNewsWire iOS Share Extension
//
// Created by Maurice Parker on 11/16/19.
// Copyright © 2019 Ranchero Software. All rights reserved.
//
import UIKit
class ShareFolderPickerCell: UITableViewCell {
@IBOutlet weak var icon: UIImageView!
@IBOutlet weak var label: UILabel!
}

View File

@@ -7,21 +7,30 @@
//
import UIKit
import RSCore
import Account
protocol ShareFolderPickerControllerDelegate: class {
func shareFolderPickerDidSelect(_ container: Container, _ selectionName: String)
func shareFolderPickerDidSelect(_ container: Container)
}
class ShareFolderPickerController: UITableViewController {
var pickerData: FlattenedAccountFolderPickerData?
var selectedContainer: Container?
var containers = [Container]()
weak var delegate: ShareFolderPickerControllerDelegate?
override func viewDidLoad() {
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
for account in AccountManager.shared.sortedActiveAccounts {
containers.append(account)
if let sortedFolders = account.sortedFolders {
containers.append(contentsOf: sortedFolders)
}
}
tableView.register(UINib(nibName: "ShareFolderPickerAccountCell", bundle: Bundle.main), forCellReuseIdentifier: "AccountCell")
tableView.register(UINib(nibName: "ShareFolderPickerFolderCell", bundle: Bundle.main), forCellReuseIdentifier: "FolderCell")
}
override func numberOfSections(in tableView: UITableView) -> Int {
@@ -29,23 +38,48 @@ class ShareFolderPickerController: UITableViewController {
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return pickerData?.containerNames.count ?? 0
return containers.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = pickerData?.containerNames[indexPath.row] ?? ""
if pickerData?.containers[indexPath.row] === selectedContainer {
let container = containers[indexPath.row]
let cell: ShareFolderPickerCell = {
if container is Account {
return tableView.dequeueReusableCell(withIdentifier: "AccountCell", for: indexPath) as! ShareFolderPickerCell
} else {
return tableView.dequeueReusableCell(withIdentifier: "FolderCell", for: indexPath) as! ShareFolderPickerCell
}
}()
if let account = container as? Account {
cell.icon.image = AppAssets.image(for: account.type)
} else {
cell.icon.image = AppAssets.masterFolderImage.image
}
if let displayNameProvider = container as? DisplayNameProvider {
cell.label?.text = displayNameProvider.nameForDisplay
}
if let compContainer = selectedContainer, container === compContainer {
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}
return cell
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let pickerData = pickerData else { return }
delegate?.shareFolderPickerDidSelect(pickerData.containers[indexPath.row], pickerData.containerNames[indexPath.row])
let container = containers[indexPath.row]
if let account = container as? Account, account.behaviors.contains(.disallowFeedInRootFolder) {
tableView.selectRow(at: nil, animated: false, scrollPosition: .none)
} else {
let cell = tableView.cellForRow(at: indexPath)
cell?.accessoryType = .checkmark
delegate?.shareFolderPickerDidSelect(container)
}
}
}

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15509"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="JCb-QB-CrO" customClass="ShareFolderPickerCell" customModule="NetNewsWire_iOS_Share_Extension" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="JCb-QB-CrO" id="FzD-t2-JGy">
<rect key="frame" x="0.0" y="0.0" width="383" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="yiw-9t-gil" userLabel="Folder Icon">
<rect key="frame" x="50" y="11" width="22" height="22"/>
<constraints>
<constraint firstAttribute="width" constant="22" id="43E-Em-Z6O"/>
<constraint firstAttribute="height" constant="22" id="mTY-cQ-1R1"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TRx-RV-za8" userLabel="Folder Label">
<rect key="frame" x="80" y="14" width="42" height="16"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="TRx-RV-za8" firstAttribute="leading" secondItem="yiw-9t-gil" secondAttribute="trailing" constant="8" symbolic="YES" id="RUN-Ol-xSl"/>
<constraint firstItem="TRx-RV-za8" firstAttribute="top" secondItem="FzD-t2-JGy" secondAttribute="top" constant="14" id="cze-hi-8Uh"/>
<constraint firstItem="yiw-9t-gil" firstAttribute="leading" secondItem="FzD-t2-JGy" secondAttribute="leading" constant="50" id="oU9-E3-lEt"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="TRx-RV-za8" secondAttribute="trailing" constant="8" id="sJ6-wr-JIw"/>
<constraint firstItem="yiw-9t-gil" firstAttribute="centerY" secondItem="FzD-t2-JGy" secondAttribute="centerY" id="tUD-tI-dgr"/>
<constraint firstAttribute="bottom" secondItem="TRx-RV-za8" secondAttribute="bottom" constant="14" id="zls-MW-Ffp"/>
</constraints>
</tableViewCellContentView>
<inset key="separatorInset" minX="80" minY="0.0" maxX="0.0" maxY="0.0"/>
<connections>
<outlet property="icon" destination="yiw-9t-gil" id="adY-cS-RuD"/>
<outlet property="label" destination="TRx-RV-za8" id="lIo-uF-Cle"/>
</connections>
<point key="canvasLocation" x="7" y="-9"/>
</tableViewCell>
</objects>
</document>

View File

@@ -16,8 +16,6 @@ import RSTree
class ShareViewController: SLComposeServiceViewController, ShareFolderPickerControllerDelegate {
private var pickerData: FlattenedAccountFolderPickerData?
private var url: URL?
private var container: Container?
private var folderItem: SLComposeSheetConfigurationItem!
@@ -26,11 +24,7 @@ class ShareViewController: SLComposeServiceViewController, ShareFolderPickerCont
AccountManager.shared = AccountManager()
pickerData = FlattenedAccountFolderPickerData()
if pickerData?.containers.count ?? 0 > 0 {
container = pickerData?.containers[0]
}
container = AddWebFeedDefaultContainer.defaultContainer
title = "NetNewsWire"
placeholder = "Feed Name (Optional)"
@@ -130,9 +124,10 @@ class ShareViewController: SLComposeServiceViewController, ShareFolderPickerCont
}
}
func shareFolderPickerDidSelect(_ container: Container, _ selectionName: String) {
func shareFolderPickerDidSelect(_ container: Container) {
AddWebFeedDefaultContainer.saveDefaultContainer(container)
self.container = container
self.folderItem.value = selectionName
updateFolderItemValue()
self.popConfigurationViewController()
}
@@ -145,10 +140,7 @@ class ShareViewController: SLComposeServiceViewController, ShareFolderPickerCont
folderItem = SLComposeSheetConfigurationItem()
folderItem.title = "Folder"
if let nameProvider = container as? DisplayNameProvider {
folderItem.value = nameProvider.nameForDisplay
}
updateFolderItemValue()
folderItem.tapHandler = {
@@ -156,7 +148,6 @@ class ShareViewController: SLComposeServiceViewController, ShareFolderPickerCont
folderPickerController.navigationController?.title = NSLocalizedString("Folder", comment: "Folder")
folderPickerController.delegate = self
folderPickerController.pickerData = self.pickerData
folderPickerController.selectedContainer = self.container
self.pushConfigurationViewController(folderPickerController)
@@ -168,3 +159,17 @@ class ShareViewController: SLComposeServiceViewController, ShareFolderPickerCont
}
}
private extension ShareViewController {
func updateFolderItemValue() {
if let containerName = (container as? DisplayNameProvider)?.nameForDisplay {
if container is Folder {
self.folderItem.value = "\(container?.account?.nameForDisplay ?? "") / \(containerName)"
} else {
self.folderItem.value = containerName
}
}
}
}