Merge pull request #6 from Ranchero-Software/swiftui

Swiftui
This commit is contained in:
Stuart Breckenridge 2020-07-03 07:34:47 +08:00 committed by GitHub
commit d16105718f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 166 additions and 56 deletions

View File

@ -0,0 +1,31 @@
//
// ArticleContainerView.swift
// NetNewsWire
//
// Created by Maurice Parker on 7/2/20.
// Copyright © 2020 Ranchero Software. All rights reserved.
//
import SwiftUI
import Articles
struct ArticleContainerView: View {
@EnvironmentObject private var sceneModel: SceneModel
@StateObject private var articleModel = ArticleModel()
var article: Article? = nil
@ViewBuilder var body: some View {
if let article = article {
ArticleView()
.environmentObject(articleModel)
.onAppear {
sceneModel.articleModel = articleModel
articleModel.delegate = sceneModel
}
} else {
EmptyView()
}
}
}

View File

@ -0,0 +1,25 @@
//
// ArticleModel.swift
// NetNewsWire
//
// Created by Maurice Parker on 7/2/20.
// Copyright © 2020 Ranchero Software. All rights reserved.
//
import Foundation
import Foundation
import RSCore
import Account
import Articles
protocol ArticleModelDelegate: class {
func timelineRequestedWebFeedSelection(_: TimelineModel, webFeed: WebFeed)
}
class ArticleModel: ObservableObject {
weak var delegate: ArticleModelDelegate?
}

View File

@ -0,0 +1,21 @@
//
// ArticleView.swift
// NetNewsWire
//
// Created by Maurice Parker on 7/2/20.
// Copyright © 2020 Ranchero Software. All rights reserved.
//
import SwiftUI
struct ArticleView: View {
var body: some View {
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
}
}
struct ArticleView_Previews: PreviewProvider {
static var previews: some View {
ArticleView()
}
}

View File

@ -13,6 +13,7 @@ final class SceneModel: ObservableObject {
var sidebarModel: SidebarModel?
var timelineModel: TimelineModel?
var articleModel: ArticleModel?
}
@ -35,3 +36,10 @@ extension SceneModel: TimelineModelDelegate {
}
}
// MARK: ArticleModelDelegate
extension SceneModel: ArticleModelDelegate {
}

View File

@ -30,38 +30,6 @@ struct CompactSidebarContainerView: View {
},alignment: .bottom)
}
var compactToolBar: some View {
VStack {
Divider()
HStack(alignment: .center) {
Button(action: {
showSettings = true
}, label: {
Image(systemName: "gear")
.font(.title3)
.foregroundColor(.accentColor)
}).help("Settings")
Spacer()
Text("Last updated")
.font(.caption)
.foregroundColor(.secondary)
Spacer()
Button(action: {}, label: {
Image(systemName: "plus")
.font(.title3)
.foregroundColor(.accentColor)
}).help("Add")
}
.padding(.horizontal, 16)
.padding(.bottom, 12)
.padding(.top, 4)
}
.background(VisualEffectBlur(blurStyle: .systemChromeMaterial).edgesIgnoringSafeArea(.bottom))
}
}
struct CompactSidebarContainerView_Previews: PreviewProvider {

View File

@ -11,6 +11,11 @@ import SwiftUI
struct SidebarToolbar: View {
@State private var showSettings: Bool = false
@State private var showAddSheet: Bool = false
var addActionSheetButtons = [
Button(action: {}, label: { Text("Add Feed") })
]
var body: some View {
VStack {
@ -28,11 +33,23 @@ struct SidebarToolbar: View {
.font(.caption)
.foregroundColor(.secondary)
Spacer()
Button(action: {}, label: {
Button(action: {
showAddSheet = true
}, label: {
Image(systemName: "plus")
.font(.title3)
.foregroundColor(.accentColor)
}).help("Add")
})
.help("Add")
.actionSheet(isPresented: $showAddSheet) {
ActionSheet(title: Text("Add"), buttons: [
.cancel(),
.default(Text("Add Web Feed")),
.default(Text("Add Twitter Feed")),
.default(Text("Add Reddit Feed")),
.default(Text("Add Folder"))
])
}
}
.padding(.horizontal, 16)
.padding(.bottom, 12)

View File

@ -45,7 +45,6 @@ struct TimelineItemView: View {
}
}
}
Divider()
}
.onAppear {
articleIconImageLoader.loadImage(for: timelineItem.article)

View File

@ -55,6 +55,14 @@ class TimelineModel: ObservableObject {
fetchAndReplaceArticlesAsync()
}
// TODO: Replace this with ScrollViewReader if we have to keep it
func loadMoreTimelineItemsIfNecessary(_ timelineItem: TimelineItem) {
let thresholdIndex = timelineItems.index(timelineItems.endIndex, offsetBy: -10)
if timelineItems.firstIndex(where: { $0.id == timelineItem.id }) == thresholdIndex {
nextBatch()
}
}
}
// MARK: Private
@ -112,11 +120,18 @@ private extension TimelineModel {
func replaceArticles(with unsortedArticles: Set<Article>) {
articles = Array(unsortedArticles).sortedByDate(sortDirection ? .orderedDescending : .orderedAscending, groupByFeed: groupByFeed)
timelineItems = articles.map { TimelineItem(article: $0) }
timelineItems = [TimelineItem]()
nextBatch()
// TODO: Update unread counts and other item done in didSet on AppKit
}
func nextBatch() {
let rangeEndIndex = timelineItems.endIndex + 50 > articles.endIndex ? articles.endIndex : timelineItems.endIndex + 50
let range = timelineItems.endIndex..<rangeEndIndex
for i in range {
timelineItems.append(TimelineItem(article: articles[i]))
}
}
// MARK: - Notifications

View File

@ -13,12 +13,11 @@ struct TimelineView: View {
@EnvironmentObject private var timelineModel: TimelineModel
var body: some View {
ScrollView {
LazyVStack() {
ForEach(timelineModel.timelineItems) { timelineItem in
TimelineItemView(timelineItem: timelineItem)
List(timelineModel.timelineItems) { timelineItem in
TimelineItemView(timelineItem: timelineItem)
.onAppear {
timelineModel.loadMoreTimelineItemsIfNecessary(timelineItem)
}
}
}
}

View File

@ -23,7 +23,6 @@
1776E88F24AC5F8A00E78166 /* AppDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1776E88D24AC5F8A00E78166 /* AppDefaults.swift */; };
179DB1DFBCF9177104B12E0F /* AccountsNewsBlurWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 179DBBA2B22A659F81EED6F9 /* AccountsNewsBlurWindowController.swift */; };
179DB3CE822BFCC2D774D9F4 /* AccountsNewsBlurWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 179DBBA2B22A659F81EED6F9 /* AccountsNewsBlurWindowController.swift */; };
17B223DC24AC24D2001E4592 /* TimelineLayoutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17B223DB24AC24D2001E4592 /* TimelineLayoutView.swift */; };
3B3A32A5238B820900314204 /* FeedWranglerAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B3A328B238B820900314204 /* FeedWranglerAccountViewController.swift */; };
3B826DCB2385C84800FC1ADB /* AccountsFeedWrangler.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3B826DB02385C84800FC1ADB /* AccountsFeedWrangler.xib */; };
3B826DCC2385C84800FC1ADB /* AccountsFeedWranglerWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B826DCA2385C84800FC1ADB /* AccountsFeedWranglerWindowController.swift */; };
@ -80,6 +79,7 @@
511D43EF231FBDE900FB1562 /* LaunchScreenPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 511D43ED231FBDE800FB1562 /* LaunchScreenPad.storyboard */; };
511D4419231FC02D00FB1562 /* KeyboardManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 511D4410231FC02D00FB1562 /* KeyboardManager.swift */; };
51236339236915B100951F16 /* RoundedProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 512363372369155100951F16 /* RoundedProgressView.swift */; };
5125E6CA24AE461D002A7562 /* TimelineLayoutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17B223DB24AC24D2001E4592 /* TimelineLayoutView.swift */; };
5126EE97226CB48A00C22AFC /* SceneCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5126EE96226CB48A00C22AFC /* SceneCoordinator.swift */; };
5127B238222B4849006D641D /* DetailKeyboardDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5127B236222B4849006D641D /* DetailKeyboardDelegate.swift */; };
5127B23A222B4849006D641D /* DetailKeyboardShortcuts.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5127B237222B4849006D641D /* DetailKeyboardShortcuts.plist */; };
@ -265,6 +265,12 @@
51A1699D235E10D700EB091F /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A16993235E10D600EB091F /* SettingsViewController.swift */; };
51A1699F235E10D700EB091F /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A16995235E10D600EB091F /* AboutViewController.swift */; };
51A169A0235E10D700EB091F /* FeedbinAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A16996235E10D700EB091F /* FeedbinAccountViewController.swift */; };
51A5769624AE617200078888 /* ArticleContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A5769524AE617200078888 /* ArticleContainerView.swift */; };
51A5769724AE617200078888 /* ArticleContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A5769524AE617200078888 /* ArticleContainerView.swift */; };
51A576BB24AE621800078888 /* ArticleModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A576BA24AE621800078888 /* ArticleModel.swift */; };
51A576BC24AE621800078888 /* ArticleModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A576BA24AE621800078888 /* ArticleModel.swift */; };
51A576BE24AE637400078888 /* ArticleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A576BD24AE637400078888 /* ArticleView.swift */; };
51A576BF24AE637400078888 /* ArticleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A576BD24AE637400078888 /* ArticleView.swift */; };
51A66685238075AE00CB272D /* AddWebFeedDefaultContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A66684238075AE00CB272D /* AddWebFeedDefaultContainer.swift */; };
51A9A5E12380C4FE0033AADF /* AppDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C45255226507D200C03939 /* AppDefaults.swift */; };
51A9A5E42380C8880033AADF /* ShareFolderPickerAccountCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 51A9A5E32380C8870033AADF /* ShareFolderPickerAccountCell.xib */; };
@ -1865,6 +1871,9 @@
51A16993235E10D600EB091F /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = "<group>"; };
51A16995235E10D600EB091F /* AboutViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = "<group>"; };
51A16996235E10D700EB091F /* FeedbinAccountViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedbinAccountViewController.swift; sourceTree = "<group>"; };
51A5769524AE617200078888 /* ArticleContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleContainerView.swift; sourceTree = "<group>"; };
51A576BA24AE621800078888 /* ArticleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleModel.swift; sourceTree = "<group>"; };
51A576BD24AE637400078888 /* ArticleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleView.swift; sourceTree = "<group>"; };
51A66684238075AE00CB272D /* AddWebFeedDefaultContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddWebFeedDefaultContainer.swift; sourceTree = "<group>"; };
51A9A5E32380C8870033AADF /* ShareFolderPickerAccountCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ShareFolderPickerAccountCell.xib; sourceTree = "<group>"; };
51A9A5E52380C8B20033AADF /* ShareFolderPickerFolderCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ShareFolderPickerFolderCell.xib; sourceTree = "<group>"; };
@ -2671,6 +2680,16 @@
path = Activity;
sourceTree = "<group>";
};
51A576B924AE617B00078888 /* Article */ = {
isa = PBXGroup;
children = (
51A5769524AE617200078888 /* ArticleContainerView.swift */,
51A576BA24AE621800078888 /* ArticleModel.swift */,
51A576BD24AE637400078888 /* ArticleView.swift */,
);
path = Article;
sourceTree = "<group>";
};
51B5C85A23F22A7A00032075 /* CommonExtension */ = {
isa = PBXGroup;
children = (
@ -2729,6 +2748,7 @@
51E499D724A912C200B667CB /* SceneModel.swift */,
51E49A0224A91FF600B667CB /* SceneNavigationView.swift */,
51C0513824A77DF800194D5E /* Assets.xcassets */,
51A576B924AE617B00078888 /* Article */,
51919FB124AAB95300541E64 /* Images */,
514E6BFD24AD252400AC6F6E /* Previews */,
51E499FB24A9135A00B667CB /* Sidebar */,
@ -3925,46 +3945,46 @@
TargetAttributes = {
51314636235A7BBE00387FDC = {
CreatedOnToolsVersion = 11.2;
DevelopmentTeam = FQLBNX3GP7;
DevelopmentTeam = SHJK2V3AJG;
LastSwiftMigration = 1120;
ProvisioningStyle = Automatic;
};
513C5CE5232571C2003D4054 = {
CreatedOnToolsVersion = 11.0;
DevelopmentTeam = FQLBNX3GP7;
DevelopmentTeam = SHJK2V3AJG;
ProvisioningStyle = Automatic;
};
518B2ED12351B3DD00400001 = {
CreatedOnToolsVersion = 11.2;
DevelopmentTeam = FQLBNX3GP7;
DevelopmentTeam = SHJK2V3AJG;
ProvisioningStyle = Automatic;
TestTargetID = 840D617B2029031C009BC708;
};
51C0513C24A77DF800194D5E = {
CreatedOnToolsVersion = 12.0;
DevelopmentTeam = FQLBNX3GP7;
DevelopmentTeam = SHJK2V3AJG;
ProvisioningStyle = Automatic;
};
51C0514324A77DF800194D5E = {
CreatedOnToolsVersion = 12.0;
DevelopmentTeam = FQLBNX3GP7;
DevelopmentTeam = SHJK2V3AJG;
ProvisioningStyle = Automatic;
};
6581C73220CED60000F4AD34 = {
DevelopmentTeam = FQLBNX3GP7;
DevelopmentTeam = SHJK2V3AJG;
ProvisioningStyle = Automatic;
};
65ED3FA2235DEF6C0081F399 = {
DevelopmentTeam = FQLBNX3GP7;
DevelopmentTeam = SHJK2V3AJG;
ProvisioningStyle = Automatic;
};
65ED4090235DEF770081F399 = {
DevelopmentTeam = FQLBNX3GP7;
DevelopmentTeam = SHJK2V3AJG;
ProvisioningStyle = Automatic;
};
840D617B2029031C009BC708 = {
CreatedOnToolsVersion = 9.3;
DevelopmentTeam = FQLBNX3GP7;
DevelopmentTeam = SHJK2V3AJG;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.BackgroundModes = {
@ -3974,7 +3994,7 @@
};
849C645F1ED37A5D003D8FC0 = {
CreatedOnToolsVersion = 8.2.1;
DevelopmentTeam = FQLBNX3GP7;
DevelopmentTeam = SHJK2V3AJG;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.HardenedRuntime = {
@ -3984,7 +4004,7 @@
};
849C64701ED37A5D003D8FC0 = {
CreatedOnToolsVersion = 8.2.1;
DevelopmentTeam = FQLBNX3GP7;
DevelopmentTeam = SHJK2V3AJG;
ProvisioningStyle = Automatic;
TestTargetID = 849C645F1ED37A5D003D8FC0;
};
@ -4787,11 +4807,13 @@
51E4995424A8734D00B667CB /* ExtensionPointIdentifer.swift in Sources */,
51E4996924A8760C00B667CB /* ArticleStylesManager.swift in Sources */,
51E498F324A8085D00B667CB /* PseudoFeed.swift in Sources */,
51A5769624AE617200078888 /* ArticleContainerView.swift in Sources */,
51E4996B24A8762D00B667CB /* ArticleExtractor.swift in Sources */,
51E49A0324A91FF600B667CB /* SceneNavigationView.swift in Sources */,
51E4990124A808BB00B667CB /* FaviconURLFinder.swift in Sources */,
51E4991D24A8092100B667CB /* NSAttributedString+NetNewsWire.swift in Sources */,
51E499FD24A9137600B667CB /* SidebarModel.swift in Sources */,
51A576BE24AE637400078888 /* ArticleView.swift in Sources */,
51E4995324A8734D00B667CB /* RedditFeedProvider-Extensions.swift in Sources */,
172199C924AB228900A31D04 /* SettingsView.swift in Sources */,
51E4994224A8713C00B667CB /* ArticleStatusSyncTimer.swift in Sources */,
@ -4805,16 +4827,18 @@
51E4992624A80AAB00B667CB /* AppAssets.swift in Sources */,
514E6C0624AD2B5F00AC6F6E /* Image-Extensions.swift in Sources */,
51E4995624A8734D00B667CB /* TwitterFeedProvider-Extensions.swift in Sources */,
5125E6CA24AE461D002A7562 /* TimelineLayoutView.swift in Sources */,
51E4996824A8760C00B667CB /* ArticleStyle.swift in Sources */,
51E4990024A808BB00B667CB /* FaviconGenerator.swift in Sources */,
51E4997124A8764C00B667CB /* ActivityType.swift in Sources */,
51E4991E24A8094300B667CB /* RSImage-AppIcons.swift in Sources */,
51E499D824A912C200B667CB /* SceneModel.swift in Sources */,
51919FB324AAB97900541E64 /* FeedImageLoader.swift in Sources */,
51919FB324AAB97900541E64 /* FeedIconImageLoader.swift in Sources */,
51919FB324AAB97900541E64 /* FeedIconImageLoader.swift in Sources */,
51E4991324A808FB00B667CB /* AddWebFeedDefaultContainer.swift in Sources */,
51E4993C24A8709900B667CB /* AppDelegate.swift in Sources */,
51E498F924A8085D00B667CB /* SmartFeed.swift in Sources */,
51A576BB24AE621800078888 /* ArticleModel.swift in Sources */,
51E4995124A8734D00B667CB /* ExtensionPointManager.swift in Sources */,
51E4990C24A808C500B667CB /* AuthorAvatarDownloader.swift in Sources */,
51E4992124A8095000B667CB /* RSImage-Extensions.swift in Sources */,
@ -4887,6 +4911,7 @@
51919FB424AAB97900541E64 /* FeedIconImageLoader.swift in Sources */,
51E4994A24A8734C00B667CB /* ExtensionPointManager.swift in Sources */,
514E6C0324AD29A300AC6F6E /* TimelineItemStatusView.swift in Sources */,
51A576BC24AE621800078888 /* ArticleModel.swift in Sources */,
51E4996D24A8762D00B667CB /* ArticleExtractor.swift in Sources */,
51E4994024A8713B00B667CB /* AccountRefreshTimer.swift in Sources */,
51E49A0424A91FF600B667CB /* SceneNavigationView.swift in Sources */,
@ -4905,6 +4930,7 @@
51E4996E24A8764C00B667CB /* ActivityManager.swift in Sources */,
51E4995A24A873F900B667CB /* ErrorHandler.swift in Sources */,
51E4991F24A8094300B667CB /* RSImage-AppIcons.swift in Sources */,
51A5769724AE617200078888 /* ArticleContainerView.swift in Sources */,
51E4991224A808FB00B667CB /* AddWebFeedDefaultContainer.swift in Sources */,
51E4993E24A870F900B667CB /* UserNotificationManager.swift in Sources */,
51E4992E24A8676300B667CB /* FetchRequestQueue.swift in Sources */,
@ -4928,6 +4954,7 @@
51E4992D24A8676300B667CB /* FetchRequestOperation.swift in Sources */,
51E4992424A8098400B667CB /* SmartFeedPasteboardWriter.swift in Sources */,
51E4991424A808FF00B667CB /* ArticleStringFormatter.swift in Sources */,
51A576BF24AE637400078888 /* ArticleView.swift in Sources */,
51E4991024A808DE00B667CB /* SmallIconProvider.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;