Add sort control for macOS
This commit is contained in:
parent
3a67f2cd8e
commit
17e1247ff0
|
@ -1,7 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="16096" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="17132" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="16096"/>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17132"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
|
@ -185,7 +186,7 @@
|
|||
<toolbarItem implicitItemIdentifier="ACB5604B-4543-4985-BA1A-54ADA9DF5845" label="Clean UP" paletteLabel="Clean Up" toolTip="Clean Up" image="cleanUp" sizingBehavior="auto" id="SsT-iS-pKE" customClass="RSToolbarItem" customModule="RSCore">
|
||||
<button key="view" verticalHuggingPriority="750" id="9At-yP-WNY">
|
||||
<rect key="frame" x="7" y="14" width="42" height="25"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<buttonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" image="cleanUp" imagePosition="only" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Zwg-74-ZkZ">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
|
@ -318,16 +319,16 @@
|
|||
<rect key="frame" x="0.0" y="0.0" width="166" height="283"/>
|
||||
<clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="2eU-Wz-F9g">
|
||||
<rect key="frame" x="0.0" y="0.0" width="166" height="283"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="firstColumnOnly" selectionHighlightStyle="sourceList" columnReordering="NO" columnResizing="NO" autosaveColumns="NO" typeSelect="NO" rowHeight="26" viewBased="YES" floatsGroupRows="NO" indentationPerLevel="23" outlineTableColumn="ih9-mJ-EA7" id="cnV-kg-Dn2" customClass="SidebarOutlineView" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="167" height="283"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="166" height="283"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<size key="intercellSpacing" width="3" height="0.0"/>
|
||||
<color key="backgroundColor" name="_sourceListBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
||||
<tableColumns>
|
||||
<tableColumn width="164" minWidth="23" maxWidth="1000" id="ih9-mJ-EA7">
|
||||
<tableColumn width="134" minWidth="23" maxWidth="1000" id="ih9-mJ-EA7">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
|
@ -340,7 +341,7 @@
|
|||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView identifier="HeaderCell" id="qkt-WA-5tB">
|
||||
<rect key="frame" x="1" y="0.0" width="164" height="17"/>
|
||||
<rect key="frame" x="11" y="0.0" width="143" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fNJ-z1-0Up">
|
||||
|
@ -358,7 +359,7 @@
|
|||
</connections>
|
||||
</tableCellView>
|
||||
<tableCellView identifier="DataCell" id="HJn-Tm-YNO" customClass="SidebarCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="1" y="17" width="164" height="17"/>
|
||||
<rect key="frame" x="11" y="17" width="143" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
</tableCellView>
|
||||
</prototypeCellViews>
|
||||
|
@ -616,9 +617,9 @@
|
|||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="NSAddTemplate" width="11" height="11"/>
|
||||
<image name="NSRefreshTemplate" width="11" height="15"/>
|
||||
<image name="NSShareTemplate" width="11" height="16"/>
|
||||
<image name="NSAddTemplate" width="15" height="11"/>
|
||||
<image name="NSRefreshTemplate" width="14" height="14"/>
|
||||
<image name="NSShareTemplate" width="16" height="15"/>
|
||||
<image name="cleanUp" width="149" height="113"/>
|
||||
<image name="filterInactive" width="100" height="101"/>
|
||||
<image name="markAllRead" width="22" height="19"/>
|
||||
|
|
|
@ -70,6 +70,10 @@ struct AppAssets {
|
|||
return Image("ArticleExtractorOn")
|
||||
}()
|
||||
|
||||
static var checkmarkImage: Image = {
|
||||
return Image(systemName: "checkmark")
|
||||
}()
|
||||
|
||||
static var copyImage: Image = {
|
||||
return Image(systemName: "doc.on.doc")
|
||||
}()
|
||||
|
|
|
@ -170,7 +170,11 @@ final class AppDefaults: ObservableObject {
|
|||
}
|
||||
|
||||
// MARK: Timeline
|
||||
@AppStorage(wrappedValue: false, Key.timelineGroupByFeed, store: store) var timelineGroupByFeed: Bool
|
||||
@AppStorage(wrappedValue: false, Key.timelineGroupByFeed, store: store) var timelineGroupByFeed: Bool {
|
||||
didSet {
|
||||
objectWillChange.send()
|
||||
}
|
||||
}
|
||||
|
||||
@AppStorage(wrappedValue: 2.0, Key.timelineNumberOfLines, store: store) var timelineNumberOfLines: Double {
|
||||
didSet {
|
||||
|
@ -185,7 +189,11 @@ final class AppDefaults: ObservableObject {
|
|||
}
|
||||
|
||||
/// Set to `true` to sort oldest to newest, `false` for newest to oldest. Default is `false`.
|
||||
@AppStorage(wrappedValue: false, Key.timelineSortDirection, store: store) var timelineSortDirection: Bool
|
||||
@AppStorage(wrappedValue: false, Key.timelineSortDirection, store: store) var timelineSortDirection: Bool {
|
||||
didSet {
|
||||
objectWillChange.send()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Refresh
|
||||
@AppStorage(wrappedValue: false, Key.refreshClearsReadArticles, store: store) var refreshClearsReadArticles: Bool
|
||||
|
|
|
@ -55,24 +55,17 @@ class TimelineModel: ObservableObject, UndoableCommandRunner {
|
|||
return _idToArticleDictionary
|
||||
}
|
||||
|
||||
private var sortDirection = AppDefaults.shared.timelineSortDirection {
|
||||
didSet {
|
||||
if sortDirection != oldValue {
|
||||
sortParametersDidChange()
|
||||
}
|
||||
}
|
||||
private var sortDirection: Bool {
|
||||
AppDefaults.shared.timelineSortDirection
|
||||
}
|
||||
|
||||
private var groupByFeed = AppDefaults.shared.timelineGroupByFeed {
|
||||
didSet {
|
||||
if groupByFeed != oldValue {
|
||||
sortParametersDidChange()
|
||||
}
|
||||
}
|
||||
private var groupByFeed: Bool {
|
||||
AppDefaults.shared.timelineGroupByFeed
|
||||
}
|
||||
|
||||
init() {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(statusesDidChange(_:)), name: .StatusesDidChange, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(userDefaultsDidChange(_:)), name: UserDefaults.didChangeNotification, object: nil)
|
||||
|
||||
// TODO: This should be rewritten to use Combine correctly
|
||||
selectedArticleIDsCancellable = $selectedArticleIDs.sink { [weak self] articleIDs in
|
||||
|
@ -213,6 +206,13 @@ private extension TimelineModel {
|
|||
}
|
||||
}
|
||||
|
||||
@objc func userDefaultsDidChange(_ note: Notification) {
|
||||
performBlockAndRestoreSelection {
|
||||
articles = articles.sortedByDate(sortDirection ? .orderedDescending : .orderedAscending, groupByFeed: groupByFeed)
|
||||
rebuildTimelineItems()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Timeline Management
|
||||
|
||||
func resetReadFilter() {
|
||||
|
@ -233,13 +233,6 @@ private extension TimelineModel {
|
|||
}
|
||||
}
|
||||
|
||||
func sortParametersDidChange() {
|
||||
performBlockAndRestoreSelection {
|
||||
let unsortedArticles = Set(articles)
|
||||
replaceArticles(with: unsortedArticles)
|
||||
}
|
||||
}
|
||||
|
||||
func performBlockAndRestoreSelection(_ block: (() -> Void)) {
|
||||
// let savedSelection = selectedArticleIDs()
|
||||
block()
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// TimelineSortOrderView.swift
|
||||
// Multiplatform macOS
|
||||
//
|
||||
// Created by Maurice Parker on 7/12/20.
|
||||
// Copyright © 2020 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct TimelineSortOrderView: View {
|
||||
|
||||
@EnvironmentObject var settings: AppDefaults
|
||||
@State var selection: Int = 1
|
||||
|
||||
var body: some View {
|
||||
Menu {
|
||||
Button {
|
||||
settings.timelineSortDirection = true
|
||||
} label: {
|
||||
HStack {
|
||||
Text("Newest to Oldest")
|
||||
if settings.timelineSortDirection {
|
||||
Spacer()
|
||||
AppAssets.checkmarkImage
|
||||
}
|
||||
}
|
||||
}
|
||||
Button {
|
||||
settings.timelineSortDirection = false
|
||||
} label: {
|
||||
HStack {
|
||||
Text("Oldest to Newest")
|
||||
if !settings.timelineSortDirection {
|
||||
Spacer()
|
||||
AppAssets.checkmarkImage
|
||||
}
|
||||
}
|
||||
}
|
||||
Divider()
|
||||
Button {
|
||||
settings.timelineGroupByFeed.toggle()
|
||||
} label: {
|
||||
HStack {
|
||||
Text("Group by Feed")
|
||||
if settings.timelineGroupByFeed {
|
||||
Spacer()
|
||||
AppAssets.checkmarkImage
|
||||
}
|
||||
}
|
||||
}
|
||||
} label : {
|
||||
if settings.timelineSortDirection {
|
||||
Text("Sort Newest to Oldest")
|
||||
} else {
|
||||
Text("Sort Oldest to Newest")
|
||||
}
|
||||
}
|
||||
.font(.subheadline)
|
||||
.frame(width: 150)
|
||||
.padding(.top, 8).padding(.leading)
|
||||
.menuStyle(BorderlessButtonMenuStyle())
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@ struct TimelineView: View {
|
|||
#if os(macOS)
|
||||
VStack {
|
||||
HStack {
|
||||
TimelineSortOrderView()
|
||||
Spacer()
|
||||
Button (action: {
|
||||
withAnimation {
|
||||
|
|
|
@ -298,6 +298,7 @@
|
|||
5193CD5A245E44A90092735E /* RedditFeedProvider-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5193CD57245E44A90092735E /* RedditFeedProvider-Extensions.swift */; };
|
||||
5194736E24BBB937001A2939 /* HiddenModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5194736D24BBB937001A2939 /* HiddenModifier.swift */; };
|
||||
5194736F24BBB937001A2939 /* HiddenModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5194736D24BBB937001A2939 /* HiddenModifier.swift */; };
|
||||
5194737124BBCAF4001A2939 /* TimelineSortOrderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5194737024BBCAF4001A2939 /* TimelineSortOrderView.swift */; };
|
||||
519B8D332143397200FA689C /* SharingServiceDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519B8D322143397200FA689C /* SharingServiceDelegate.swift */; };
|
||||
519E743D22C663F900A78E47 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519E743422C663F900A78E47 /* SceneDelegate.swift */; };
|
||||
519ED456244828C3007F8E94 /* AddExtensionPointViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519ED455244828C3007F8E94 /* AddExtensionPointViewController.swift */; };
|
||||
|
@ -1963,6 +1964,7 @@
|
|||
51938DF1231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchTimelineFeedDelegate.swift; sourceTree = "<group>"; };
|
||||
5193CD57245E44A90092735E /* RedditFeedProvider-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RedditFeedProvider-Extensions.swift"; sourceTree = "<group>"; };
|
||||
5194736D24BBB937001A2939 /* HiddenModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HiddenModifier.swift; sourceTree = "<group>"; };
|
||||
5194737024BBCAF4001A2939 /* TimelineSortOrderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineSortOrderView.swift; sourceTree = "<group>"; };
|
||||
519B8D322143397200FA689C /* SharingServiceDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharingServiceDelegate.swift; sourceTree = "<group>"; };
|
||||
519E743422C663F900A78E47 /* SceneDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
||||
519ED455244828C3007F8E94 /* AddExtensionPointViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddExtensionPointViewController.swift; sourceTree = "<group>"; };
|
||||
|
@ -2833,13 +2835,14 @@
|
|||
51919FCB24AB855000541E64 /* Timeline */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5177470224B2657F00EB0F74 /* TimelineToolbarModifier.swift */,
|
||||
51919FED24AB85E400541E64 /* TimelineContainerView.swift */,
|
||||
51919FF324AB869C00541E64 /* TimelineItem.swift */,
|
||||
514E6C0124AD29A300AC6F6E /* TimelineItemStatusView.swift */,
|
||||
514E6BD924ACEA0400AC6F6E /* TimelineItemView.swift */,
|
||||
51919FF024AB864A00541E64 /* TimelineModel.swift */,
|
||||
5194737024BBCAF4001A2939 /* TimelineSortOrderView.swift */,
|
||||
517B2EEA24B40E09001AC46C /* TimelineTitleModifier.swift */,
|
||||
5177470224B2657F00EB0F74 /* TimelineToolbarModifier.swift */,
|
||||
51919FF624AB8B7700541E64 /* TimelineView.swift */,
|
||||
);
|
||||
path = Timeline;
|
||||
|
@ -5200,6 +5203,7 @@
|
|||
514E6BDB24ACEA0400AC6F6E /* TimelineItemView.swift in Sources */,
|
||||
51E4996E24A8764C00B667CB /* ActivityManager.swift in Sources */,
|
||||
51E4995A24A873F900B667CB /* ErrorHandler.swift in Sources */,
|
||||
5194737124BBCAF4001A2939 /* TimelineSortOrderView.swift in Sources */,
|
||||
51E4991F24A8094300B667CB /* RSImage-AppIcons.swift in Sources */,
|
||||
51A5769724AE617200078888 /* ArticleContainerView.swift in Sources */,
|
||||
51E4991224A808FB00B667CB /* AddWebFeedDefaultContainer.swift in Sources */,
|
||||
|
|
Loading…
Reference in New Issue