Merge pull request #2330 from stuartbreckenridge/ios-multiplat-updates

Multiplatform updates
This commit is contained in:
Maurice Parker 2020-08-14 15:59:42 -05:00 committed by GitHub
commit 9218b4d95c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 255 additions and 140 deletions

View File

@ -12,31 +12,29 @@ import RSCore
struct AddFolderView: View {
@Environment(\.presentationMode) private var presentationMode
@ObservedObject private var viewModel = AddFolderModel()
@Binding var isPresented: Bool
@ViewBuilder var body: some View {
var body: some View {
#if os(iOS)
iosForm
.onReceive(viewModel.$shouldDismiss, perform: {
dismiss in
if dismiss == true {
presentationMode
.wrappedValue
.dismiss()
isPresented = false
}
})
#else
macForm
.onReceive(viewModel.$shouldDismiss, perform: { dismiss in
if dismiss == true {
presentationMode.wrappedValue.dismiss()
isPresented = false
}
})
#endif
}
#if os(iOS)
@ViewBuilder var iosForm: some View {
var iosForm: some View {
NavigationView {
Form {
Section {
@ -50,7 +48,7 @@ struct AddFolderView: View {
.navigationBarTitleDisplayMode(.inline)
.navigationBarItems(
leading:Button("Cancel", action: {
presentationMode.wrappedValue.dismiss()
isPresented = false
}
)
.help("Cancel Adding Folder"),
@ -67,7 +65,7 @@ struct AddFolderView: View {
#endif
#if os(macOS)
@ViewBuilder var macForm: some View {
var macForm: some View {
Form {
HStack {
Spacer()
@ -113,7 +111,7 @@ struct AddFolderView: View {
}
Spacer()
Button("Cancel", action: {
presentationMode.wrappedValue.dismiss()
isPresented = false
})
.help("Cancel Adding Folder")
@ -125,9 +123,3 @@ struct AddFolderView: View {
}
}
}
struct AddFolderView_Previews: PreviewProvider {
static var previews: some View {
AddFolderView()
}
}

View File

@ -13,10 +13,10 @@ import RSCore
struct AddWebFeedView: View {
@Environment(\.presentationMode) private var presentationMode
@StateObject private var viewModel = AddWebFeedModel()
@Binding var isPresented: Bool
@ViewBuilder var body: some View {
var body: some View {
#if os(iOS)
iosForm
.onAppear {
@ -24,7 +24,7 @@ struct AddWebFeedView: View {
}
.onReceive(viewModel.$shouldDismiss, perform: { dismiss in
if dismiss == true {
presentationMode.wrappedValue.dismiss()
isPresented = false
}
})
#else
@ -37,9 +37,10 @@ struct AddWebFeedView: View {
dismissButton: Alert.Button.cancel({
viewModel.addFeedError = AddWebFeedError.none
}))
}.onReceive(viewModel.$shouldDismiss, perform: { dismiss in
}
.onChange(of: viewModel.shouldDismiss, perform: { dismiss in
if dismiss == true {
presentationMode.wrappedValue.dismiss()
isPresented = false
}
})
#endif
@ -80,7 +81,7 @@ struct AddWebFeedView: View {
#endif
#if os(iOS)
@ViewBuilder var iosForm: some View {
var iosForm: some View {
NavigationView {
List {
urlTextField
@ -92,7 +93,7 @@ struct AddWebFeedView: View {
.navigationBarTitleDisplayMode(.inline)
.navigationBarItems(leading:
Button("Cancel", action: {
presentationMode.wrappedValue.dismiss()
isPresented = false
})
.help("Cancel Add Feed")
, trailing:
@ -188,7 +189,7 @@ struct AddWebFeedView: View {
}
Spacer()
Button("Cancel", action: {
presentationMode.wrappedValue.dismiss()
isPresented = false
})
.help("Cancel Add Feed")
@ -205,8 +206,4 @@ struct AddWebFeedView: View {
}
struct AddFeedView_Previews: PreviewProvider {
static var previews: some View {
AddWebFeedView()
}
}

View File

@ -11,7 +11,7 @@ import Articles
struct ArticleContainerView: View {
@ViewBuilder var body: some View {
var body: some View {
ArticleView()
.modifier(ArticleToolbarModifier())
}

View File

@ -13,7 +13,7 @@ struct IconImageView: View {
@Environment(\.colorScheme) var colorScheme
var iconImage: IconImage
@ViewBuilder var body: some View {
var body: some View {
GeometryReader { proxy in
let newSize = newImageSize(viewSize: proxy.size)

View File

@ -16,17 +16,13 @@ struct InspectorPlatformModifier: ViewModifier {
@ViewBuilder func body(content: Content) -> some View {
#if os(macOS)
Form {
content
}
content
.textFieldStyle(RoundedBorderTextFieldStyle())
.frame(width: 300)
.padding()
#else
NavigationView {
List {
content
}
content
.listStyle(InsetGroupedListStyle())
.navigationBarTitle("Inspector", displayMode: .inline)
.navigationBarItems(

View File

@ -17,7 +17,6 @@ struct InspectorView: View {
@StateObject private var inspectorModel = InspectorModel()
var sidebarItem: SidebarItem
@ViewBuilder
var body: some View {
switch sidebarItem.representedType {
case .webFeed:
@ -36,9 +35,9 @@ struct InspectorView: View {
// MARK: WebFeed Inspector
@ViewBuilder
var WebFeedInspectorView: some View {
Group {
Form {
Section(header: webFeedHeader) {
TextField("", text: $inspectorModel.editedName)
}
@ -85,13 +84,13 @@ struct InspectorView: View {
Text("Copy Home Page URL")
})
}))
}
.sheet(isPresented: $inspectorModel.showHomePage, onDismiss: { inspectorModel.showHomePage = false }) {
#if os(macOS)
EmptyView()
#else
SafariView(url: URL(string: (sidebarItem.feed as! WebFeed).homePageURL!)!)
#endif
.sheet(isPresented: $inspectorModel.showHomePage, onDismiss: { inspectorModel.showHomePage = false }) {
#if os(macOS)
EmptyView()
#else
SafariView(url: URL(string: (sidebarItem.feed as! WebFeed).homePageURL!)!)
#endif
}
}
}
@ -101,9 +100,9 @@ struct InspectorView: View {
Section(header: Text("Feed URL")) {
VStack {
#if os(macOS)
Spacer() // This shouldn't be necessary, but for some reason macOS doesn't put the space in itself
#endif
// #if os(macOS)
// Spacer() // This shouldn't be necessary, but for some reason macOS doesn't put the space in itself
// #endif
Text(verbatim: (sidebarItem.feed as? WebFeed)?.url ?? "")
.fixedSize(horizontal: false, vertical: true)
.contextMenu(ContextMenu(menuItems: {
@ -127,11 +126,11 @@ struct InspectorView: View {
Spacer()
Button("Cancel", action: {
presentationMode.wrappedValue.dismiss()
}).keyboardShortcut(.cancelAction)
})
Button("Done", action: {
inspectorModel.shouldUpdate = true
}).keyboardShortcut(.defaultAction)
}.padding(.top)
})
}.padding([.top, .bottom], 20)
#endif
}
.onAppear {
@ -155,15 +154,14 @@ struct InspectorView: View {
.frame(width: 50, height: 50)
}
Spacer()
}.padding()
}.padding(.top, 20)
}
// MARK: Folder Inspector
@ViewBuilder
var FolderInspectorView: some View {
Group {
Form {
Section(header: folderHeader) {
TextField("", text: $inspectorModel.editedName)
}
@ -173,13 +171,12 @@ struct InspectorView: View {
Spacer()
Button("Cancel", action: {
presentationMode.wrappedValue.dismiss()
}).keyboardShortcut(.cancelAction)
})
Button("Done", action: {
inspectorModel.shouldUpdate = true
}).keyboardShortcut(.defaultAction)
}.padding(.top)
})
}.padding([.top, .bottom])
#endif
}
.onAppear {
inspectorModel.configure(with: sidebarItem.represented as! Folder)
@ -203,15 +200,14 @@ struct InspectorView: View {
.frame(width: 50, height: 50)
}
Spacer()
}.padding()
}.padding(.top, 20)
}
// MARK: Account Inspector
@ViewBuilder
var AccountInspectorView: some View {
Group {
Form {
Section(header: accountHeader) {
TextField("", text: $inspectorModel.editedName)
Toggle("Active", isOn: $inspectorModel.accountIsActive)

View File

@ -73,6 +73,12 @@ struct MainApp: App {
Button("Open in Browser", action: {})
.keyboardShortcut(.rightArrow, modifiers: [.command])
})
CommandGroup(after: .help, addition: {
Button("Release Notes", action: {
NSWorkspace.shared.open(ReleaseNotes().url)
})
.keyboardShortcut("V", modifiers: [.shift, .command])
})
}
// Mac Preferences

View File

@ -0,0 +1,28 @@
//
// ReleaseNotes.swift
// NetNewsWire
//
// Created by Stuart Breckenridge on 13/8/20.
// Copyright © 2020 Ranchero Software. All rights reserved.
//
import Foundation
struct ReleaseNotes {
var url: URL {
var gitHub = "https://github.com/Ranchero-Software/NetNewsWire/releases/tag/"
#if os(macOS)
gitHub += "mac-\(String(describing: versionString()))"
return URL(string: gitHub)!
#else
gitHub += "ios-\(String(describing: versionString()))"
return URL(string: gitHub)!
#endif
}
private func versionString() -> String {
Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? ""
}
}

View File

@ -0,0 +1,21 @@
//
// SceneNavigationModel.swift
// NetNewsWire
//
// Created by Stuart Breckenridge on 13/8/20.
// Copyright © 2020 Ranchero Software. All rights reserved.
//
import Foundation
class SceneNavigationModel: ObservableObject {
@Published var sheetToShow: SidebarSheets = .none {
didSet {
sheetToShow != .none ? (showSheet = true) : (showSheet = false)
}
}
@Published var showSheet = false
@Published var showShareSheet = false
@Published var showAccountSyncErrorAlert = false
}

View File

@ -12,13 +12,11 @@ import Account
import AppKit
#endif
struct SceneNavigationView: View {
@StateObject private var sceneModel = SceneModel()
@State private var showSheet = false
@State private var showShareSheet = false
@State private var sheetToShow: SidebarSheets = .none
@State private var showAccountSyncErrorAlert = false // multiple sync errors
@StateObject private var sceneNavigationModel = SceneNavigationModel()
#if os(iOS)
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
@ -30,7 +28,7 @@ struct SceneNavigationView: View {
SidebarContainerView()
.frame(minWidth: 100, idealWidth: 150, maxHeight: .infinity)
#else
SidebarContainerView()
SidebarContainerView()
#endif
#if os(iOS)
@ -47,41 +45,38 @@ struct SceneNavigationView: View {
.onAppear {
sceneModel.startup()
}
.onChange(of: sheetToShow) { value in
value != .none ? (showSheet = true) : (showSheet = false)
}
.onReceive(sceneModel.$accountSyncErrors) { errors in
if errors.count == 0 {
showAccountSyncErrorAlert = false
sceneNavigationModel.showAccountSyncErrorAlert = false
} else {
if errors.count > 1 {
showAccountSyncErrorAlert = true
sceneNavigationModel.showAccountSyncErrorAlert = true
} else {
sheetToShow = .fixCredentials
sceneNavigationModel.sheetToShow = .fixCredentials
}
}
}
.sheet(isPresented: $showSheet,
.sheet(isPresented: $sceneNavigationModel.showSheet,
onDismiss: {
sheetToShow = .none
sceneNavigationModel.sheetToShow = .none
sceneModel.accountSyncErrors = []
}) {
if sheetToShow == .web {
AddWebFeedView()
if sceneNavigationModel.sheetToShow == .web {
AddWebFeedView(isPresented: $sceneNavigationModel.showSheet)
}
if sheetToShow == .folder {
AddFolderView()
if sceneNavigationModel.sheetToShow == .folder {
AddFolderView(isPresented: $sceneNavigationModel.showSheet)
}
#if os(iOS)
if sheetToShow == .settings {
if sceneNavigationModel.sheetToShow == .settings {
SettingsView()
}
#endif
if sheetToShow == .fixCredentials {
if sceneNavigationModel.sheetToShow == .fixCredentials {
FixAccountCredentialView(accountSyncError: sceneModel.accountSyncErrors[0])
}
}
.alert(isPresented: $showAccountSyncErrorAlert, content: {
.alert(isPresented: $sceneNavigationModel.showAccountSyncErrorAlert, content: {
#if os(macOS)
return Alert(title: Text("Account Sync Error"),
message: Text("The following accounts failed to sync: ") + Text(sceneModel.accountSyncErrors.map({ $0.account.nameForDisplay }).joined(separator: ", ")) + Text(". You can update credentials in Preferences"),
@ -91,7 +86,7 @@ struct SceneNavigationView: View {
message: Text("The following accounts failed to sync: ") + Text(sceneModel.accountSyncErrors.map({ $0.account.nameForDisplay }).joined(separator: ", ")) + Text(". You can update credentials in Settings"),
primaryButton: .default(Text("Show Settings"), action: {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
sheetToShow = .settings
sceneNavigationModel.sheetToShow = .settings
})
}),
@ -112,10 +107,10 @@ struct SceneNavigationView: View {
}
ToolbarItem() {
Menu {
Button("Add Web Feed", action: { sheetToShow = .web })
Button("Add Web Feed", action: { sceneNavigationModel.sheetToShow = .web })
Button("Add Reddit Feed", action: { })
Button("Add Twitter Feed", action: { })
Button("Add Folder", action: { sheetToShow = .folder})
Button("Add Folder", action: { sceneNavigationModel.sheetToShow = .folder})
} label : {
AppAssets.addMenuImage
}
@ -197,12 +192,12 @@ struct SceneNavigationView: View {
}
ToolbarItem {
ZStack {
if showShareSheet {
SharingServiceView(articles: sceneModel.selectedArticles, showing: $showShareSheet)
if sceneNavigationModel.showShareSheet {
SharingServiceView(articles: sceneModel.selectedArticles, showing: $sceneNavigationModel.showShareSheet)
.frame(width: 20, height: 20)
}
Button {
showShareSheet = true
sceneNavigationModel.showShareSheet = true
} label: {
AppAssets.shareImage
}

View File

@ -15,7 +15,7 @@ struct SidebarContainerView: View {
@State var sidebarItems = [SidebarItem]()
@ViewBuilder var body: some View {
var body: some View {
SidebarView(sidebarItems: $sidebarItems)
.modifier(SidebarToolbarModifier())
.modifier(SidebarListStyleModifier())

View File

@ -19,7 +19,7 @@ struct SidebarContextMenu: View {
var sidebarItem: SidebarItem
@ViewBuilder var body: some View {
var body: some View {
// MARK: Account Context Menu
if sidebarItem.representedType == .account {
Button {

View File

@ -81,10 +81,10 @@ struct SidebarToolbarModifier: ViewModifier {
}
.sheet(isPresented: $viewModel.showSheet, onDismiss: { viewModel.sheetToShow = .none }) {
if viewModel.sheetToShow == .web {
AddWebFeedView()
AddWebFeedView(isPresented: $viewModel.showSheet)
}
if viewModel.sheetToShow == .folder {
AddFolderView()
AddFolderView(isPresented: $viewModel.showSheet)
}
if viewModel.sheetToShow == .settings {
SettingsView()

View File

@ -26,7 +26,7 @@ struct SidebarView: View {
@State var pulling: Bool = false
@State var refreshing: Bool = false
@ViewBuilder var body: some View {
var body: some View {
#if os(macOS)
VStack {
HStack {
@ -182,7 +182,7 @@ struct SidebarView: View {
@EnvironmentObject private var sidebarModel: SidebarModel
var sidebarItem: SidebarItem
@ViewBuilder var body: some View {
var body: some View {
#if os(macOS)
SidebarItemView(sidebarItem: sidebarItem)
.tag(sidebarItem.feed!.feedID!)

View File

@ -17,7 +17,7 @@ struct TimelineContainerView: View {
@State private var timelineItems = TimelineItems()
@State private var isReadFiltered: Bool? = nil
@ViewBuilder var body: some View {
var body: some View {
TimelineView(timelineItems: $timelineItems, isReadFiltered: $isReadFiltered)
.modifier(TimelineToolbarModifier())
.environmentObject(sceneModel.timelineModel)

View File

@ -13,7 +13,7 @@ struct TimelineContextMenu: View {
@EnvironmentObject private var timelineModel: TimelineModel
var timelineItem: TimelineItem
@ViewBuilder var body: some View {
var body: some View {
if timelineModel.canMarkIndicatedArticlesAsRead(timelineItem) {
Button {

View File

@ -13,7 +13,7 @@ struct TimelineItemStatusView: View {
var selected: Bool
var status: TimelineItemStatus
@ViewBuilder var statusView: some View {
var statusView: some View {
ZStack {
Spacer().frame(width: 12)
switch status {

View File

@ -12,6 +12,10 @@ struct TimelineToolbarModifier: ViewModifier {
@EnvironmentObject private var sceneModel: SceneModel
@EnvironmentObject private var timelineModel: TimelineModel
@Environment(\.presentationMode) var presentationMode
#if os(iOS)
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
#endif
@State private var isReadFiltered: Bool? = nil
func body(content: Content) -> some View {
@ -40,6 +44,11 @@ struct TimelineToolbarModifier: ViewModifier {
ToolbarItem(placement: .bottomBar) {
Button {
sceneModel.markAllAsRead()
#if os(iOS)
if horizontalSizeClass == .compact {
presentationMode.wrappedValue.dismiss()
}
#endif
} label: {
AppAssets.markAllAsReadImage
}

View File

@ -17,7 +17,7 @@ struct TimelineView: View {
@State private var timelineItemFrames = [String: CGRect]()
@ViewBuilder var body: some View {
var body: some View {
GeometryReader { geometryReaderProxy in
#if os(macOS)
VStack {

View File

@ -12,7 +12,7 @@ import Account
class SettingsModel: ObservableObject {
enum HelpSites {
case netNewsWireHelp, netNewsWire, supportNetNewsWire, github, bugTracker, technotes, netNewsWireSlack, none
case netNewsWireHelp, netNewsWire, supportNetNewsWire, github, bugTracker, technotes, netNewsWireSlack, releaseNotes, none
var url: URL? {
switch self {
@ -30,6 +30,8 @@ class SettingsModel: ObservableObject {
return URL(string: "https://github.com/brentsimmons/NetNewsWire/tree/main/Technotes")!
case .netNewsWireSlack:
return URL(string: "https://ranchero.com/netnewswire/slack")!
case .releaseNotes:
return ReleaseNotes().url
case .none:
return nil
}

View File

@ -203,6 +203,9 @@ struct SettingsView: View {
Button("NetNewsWire Slack", action: {
viewModel.selectedWebsite = .netNewsWireSlack
}).foregroundColor(.primary)
Button("Release Notes", action: {
viewModel.selectedWebsite = .releaseNotes
}).foregroundColor(.primary)
NavigationLink(
destination: SettingsAboutView(),
label: {
@ -213,9 +216,8 @@ struct SettingsView: View {
}
private func appVersion() -> String {
let dict = NSDictionary(contentsOf: Bundle.main.url(forResource: "Info", withExtension: "plist")!)
let version = dict?.object(forKey: "CFBundleShortVersionString") as? String ?? ""
let build = dict?.object(forKey: "CFBundleVersion") as? String ?? ""
let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? ""
let build = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String ?? ""
return "NetNewsWire \(version) (Build \(build))"
}

View File

@ -31,6 +31,8 @@ struct AccountsPreferencesView: View {
switch viewModel.sheetToShow {
case .add:
AddAccountView(preferencesModel: viewModel)
.frame(width: 300, height: 200)
.padding()
case .credentials:
EditAccountCredentialsView(viewModel: viewModel)
case .none:

View File

@ -15,12 +15,12 @@ struct AddAccountPickerRow: View {
var body: some View {
HStack {
if let img = AppAssets.image(for: accountType) {
Image(rsImage: img)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 15, height: 15)
}
// if let img = AppAssets.image(for: accountType) {
// Image(rsImage: img)
// .resizable()
// .aspectRatio(contentMode: .fit)
// .frame(width: 15, height: 15)
// }
switch accountType {
case .onMyMac:

View File

@ -16,36 +16,35 @@ struct AddAccountView: View {
@StateObject private var viewModel = AddAccountModel()
var body: some View {
VStack(alignment: .leading) {
Form {
Text("Add an Account").font(.headline)
Form {
Picker("Account Type",
selection: $viewModel.selectedAddAccount,
content: {
ForEach(0..<viewModel.addableAccountTypes.count, content: { i in
AddAccountPickerRow(accountType: viewModel.addableAccountTypes[i]).tag(viewModel.addableAccountTypes[i])
})
})
switch viewModel.selectedAddAccount {
case .onMyMac:
addLocalAccountView
case .cloudKit:
iCloudAccountView
case .feedbin:
userNameAndPasswordView
case .feedWrangler:
userNameAndPasswordView
case .freshRSS:
userNamePasswordAndAPIUrlView
case .feedly:
oAuthView
case .newsBlur:
userNameAndPasswordView
}
Picker("Account Type",
selection: $viewModel.selectedAddAccount,
content: {
ForEach(0..<viewModel.addableAccountTypes.count, content: { i in
AddAccountPickerRow(accountType: viewModel.addableAccountTypes[i]).tag(viewModel.addableAccountTypes[i])
})
}).pickerStyle(MenuPickerStyle())
switch viewModel.selectedAddAccount {
case .onMyMac:
addLocalAccountView
case .cloudKit:
iCloudAccountView
case .feedbin:
userNameAndPasswordView
case .feedWrangler:
userNameAndPasswordView
case .freshRSS:
userNamePasswordAndAPIUrlView
case .feedly:
oAuthView
case .newsBlur:
userNameAndPasswordView
}
Spacer()
HStack {
if viewModel.accountIsAuthenticating {
@ -82,8 +81,8 @@ struct AddAccountView: View {
}
}
}
.frame(width: 300, height: 200, alignment: .top)
.padding()
.onChange(of: viewModel.selectedAddAccount) { _ in
viewModel.resetUserEntries()
}

View File

@ -59,7 +59,7 @@ struct LayoutPreferencesView: View {
}
@ViewBuilder
var timelineRowPreview: some View {
HStack(alignment: .top) {
Image(systemName: "circle.fill")

View File

@ -7,6 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
1704053424E5985A00A00787 /* SceneNavigationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1704053324E5985A00A00787 /* SceneNavigationModel.swift */; };
1704053524E5985A00A00787 /* SceneNavigationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1704053324E5985A00A00787 /* SceneNavigationModel.swift */; };
1717535624BADF33004498C6 /* GeneralPreferencesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1717535524BADF33004498C6 /* GeneralPreferencesModel.swift */; };
171BCB8C24CB08A3006E22D9 /* FixAccountCredentialView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171BCB8B24CB08A3006E22D9 /* FixAccountCredentialView.swift */; };
171BCB8D24CB08A3006E22D9 /* FixAccountCredentialView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171BCB8B24CB08A3006E22D9 /* FixAccountCredentialView.swift */; };
@ -44,6 +46,18 @@
1799E6CE24C320D600511E91 /* InspectorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1799E6CC24C320D600511E91 /* InspectorModel.swift */; };
179DB1DFBCF9177104B12E0F /* AccountsNewsBlurWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 179DBBA2B22A659F81EED6F9 /* AccountsNewsBlurWindowController.swift */; };
179DB3CE822BFCC2D774D9F4 /* AccountsNewsBlurWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 179DBBA2B22A659F81EED6F9 /* AccountsNewsBlurWindowController.swift */; };
17A1597C24E3DEDD005DA32A /* RSCore in Frameworks */ = {isa = PBXBuildFile; productRef = 17A1597B24E3DEDD005DA32A /* RSCore */; };
17A1597D24E3DEDD005DA32A /* RSCore in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 17A1597B24E3DEDD005DA32A /* RSCore */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
17A1597F24E3DEDD005DA32A /* RSTree in Frameworks */ = {isa = PBXBuildFile; productRef = 17A1597E24E3DEDD005DA32A /* RSTree */; };
17A1598024E3DEDD005DA32A /* RSTree in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 17A1597E24E3DEDD005DA32A /* RSTree */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
17A1598224E3DEDD005DA32A /* RSWeb in Frameworks */ = {isa = PBXBuildFile; productRef = 17A1598124E3DEDD005DA32A /* RSWeb */; };
17A1598324E3DEDD005DA32A /* RSWeb in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 17A1598124E3DEDD005DA32A /* RSWeb */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
17A1598524E3DEDD005DA32A /* RSDatabase in Frameworks */ = {isa = PBXBuildFile; productRef = 17A1598424E3DEDD005DA32A /* RSDatabase */; };
17A1598624E3DEDD005DA32A /* RSDatabase in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 17A1598424E3DEDD005DA32A /* RSDatabase */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
17A1598824E3DEDD005DA32A /* RSParser in Frameworks */ = {isa = PBXBuildFile; productRef = 17A1598724E3DEDD005DA32A /* RSParser */; };
17A1598924E3DEDD005DA32A /* RSParser in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 17A1598724E3DEDD005DA32A /* RSParser */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
17AC0ABB24E4B65E004C1231 /* ReleaseNotes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17AC0ABA24E4B65E004C1231 /* ReleaseNotes.swift */; };
17AC0ABC24E4B65E004C1231 /* ReleaseNotes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17AC0ABA24E4B65E004C1231 /* ReleaseNotes.swift */; };
17D232A824AFF10A0005F075 /* AddWebFeedModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D232A724AFF10A0005F075 /* AddWebFeedModel.swift */; };
17D232A924AFF10A0005F075 /* AddWebFeedModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D232A724AFF10A0005F075 /* AddWebFeedModel.swift */; };
17D5F17124B0BC6700375168 /* SidebarToolbarModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D5F17024B0BC6700375168 /* SidebarToolbarModel.swift */; };
@ -1323,6 +1337,11 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
17A1598924E3DEDD005DA32A /* RSParser in Embed Frameworks */,
17A1598624E3DEDD005DA32A /* RSDatabase in Embed Frameworks */,
17A1598324E3DEDD005DA32A /* RSWeb in Embed Frameworks */,
17A1597D24E3DEDD005DA32A /* RSCore in Embed Frameworks */,
17A1598024E3DEDD005DA32A /* RSTree in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
@ -1428,6 +1447,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1704053324E5985A00A00787 /* SceneNavigationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneNavigationModel.swift; sourceTree = "<group>"; };
1717535524BADF33004498C6 /* GeneralPreferencesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralPreferencesModel.swift; sourceTree = "<group>"; };
171BCB8B24CB08A3006E22D9 /* FixAccountCredentialView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FixAccountCredentialView.swift; sourceTree = "<group>"; };
172199C824AB228900A31D04 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
@ -1454,6 +1474,7 @@
1799E6A824C2F93F00511E91 /* InspectorPlatformModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InspectorPlatformModifier.swift; sourceTree = "<group>"; };
1799E6CC24C320D600511E91 /* InspectorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InspectorModel.swift; sourceTree = "<group>"; };
179DBBA2B22A659F81EED6F9 /* AccountsNewsBlurWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountsNewsBlurWindowController.swift; sourceTree = "<group>"; };
17AC0ABA24E4B65E004C1231 /* ReleaseNotes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReleaseNotes.swift; sourceTree = "<group>"; };
17B223DB24AC24D2001E4592 /* TimelineLayoutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineLayoutView.swift; sourceTree = "<group>"; };
17D232A724AFF10A0005F075 /* AddWebFeedModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddWebFeedModel.swift; sourceTree = "<group>"; };
17D5F17024B0BC6700375168 /* SidebarToolbarModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarToolbarModel.swift; sourceTree = "<group>"; };
@ -2043,7 +2064,12 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
17A1598224E3DEDD005DA32A /* RSWeb in Frameworks */,
17A1597F24E3DEDD005DA32A /* RSTree in Frameworks */,
17A1598824E3DEDD005DA32A /* RSParser in Frameworks */,
17A1597C24E3DEDD005DA32A /* RSCore in Frameworks */,
516B695D24D2F28E00B5702F /* Account in Frameworks */,
17A1598524E3DEDD005DA32A /* RSDatabase in Frameworks */,
51E4989724A8065700B667CB /* CloudKit.framework in Frameworks */,
51E4989924A8067000B667CB /* WebKit.framework in Frameworks */,
);
@ -2256,6 +2282,14 @@
path = Add;
sourceTree = "<group>";
};
17AC0ACB24E4B66A004C1231 /* Release Notes */ = {
isa = PBXGroup;
children = (
17AC0ABA24E4B65E004C1231 /* ReleaseNotes.swift */,
);
path = "Release Notes";
sourceTree = "<group>";
};
510289CE2451BA1E00426DDF /* Twitter */ = {
isa = PBXGroup;
children = (
@ -2660,6 +2694,7 @@
FF64D0C424AF53EE0084080A /* RefreshProgressModel.swift */,
51E499D724A912C200B667CB /* SceneModel.swift */,
51E49A0224A91FF600B667CB /* SceneNavigationView.swift */,
1704053324E5985A00A00787 /* SceneNavigationModel.swift */,
51C0513824A77DF800194D5E /* Assets.xcassets */,
17930ED224AF10CD00A9BA52 /* Add */,
51A576B924AE617B00078888 /* Article */,
@ -2671,6 +2706,7 @@
514E6C0424AD2B0400AC6F6E /* SwiftUI Extensions */,
51919FCB24AB855000541E64 /* Timeline */,
171BCBB124CBD569006E22D9 /* Account Management */,
17AC0ACB24E4B66A004C1231 /* Release Notes */,
);
path = Shared;
sourceTree = "<group>";
@ -3657,6 +3693,11 @@
name = "Multiplatform iOS";
packageProductDependencies = (
516B695C24D2F28E00B5702F /* Account */,
17A1597B24E3DEDD005DA32A /* RSCore */,
17A1597E24E3DEDD005DA32A /* RSTree */,
17A1598124E3DEDD005DA32A /* RSWeb */,
17A1598424E3DEDD005DA32A /* RSDatabase */,
17A1598724E3DEDD005DA32A /* RSParser */,
);
productName = iOS;
productReference = 51C0513D24A77DF800194D5E /* NetNewsWire.app */;
@ -4493,6 +4534,7 @@
51E498F124A8085D00B667CB /* StarredFeedDelegate.swift in Sources */,
51E498FF24A808BB00B667CB /* SingleFaviconDownloader.swift in Sources */,
51E4997224A8784300B667CB /* DefaultFeedsImporter.swift in Sources */,
1704053424E5985A00A00787 /* SceneNavigationModel.swift in Sources */,
514E6C0924AD39AD00AC6F6E /* ArticleIconImageLoader.swift in Sources */,
6594CA3B24AF6F2A005C7D7C /* OPMLExporter.swift in Sources */,
FA80C13E24B072AA00974098 /* AddFolderModel.swift in Sources */,
@ -4533,6 +4575,7 @@
51E4991724A8090400B667CB /* ArticleUtilities.swift in Sources */,
51E4991B24A8091000B667CB /* IconImage.swift in Sources */,
51E4995424A8734D00B667CB /* ExtensionPointIdentifer.swift in Sources */,
17AC0ABB24E4B65E004C1231 /* ReleaseNotes.swift in Sources */,
51E4996924A8760C00B667CB /* ArticleStylesManager.swift in Sources */,
5177471E24B387E100EB0F74 /* ImageTransition.swift in Sources */,
51E498F324A8085D00B667CB /* PseudoFeed.swift in Sources */,
@ -4716,6 +4759,7 @@
514E6C0324AD29A300AC6F6E /* TimelineItemStatusView.swift in Sources */,
51B54A6524B549B20014348B /* WrapperScriptMessageHandler.swift in Sources */,
51E4996D24A8762D00B667CB /* ArticleExtractor.swift in Sources */,
1704053524E5985A00A00787 /* SceneNavigationModel.swift in Sources */,
51E4994024A8713B00B667CB /* AccountRefreshTimer.swift in Sources */,
51E49A0424A91FF600B667CB /* SceneNavigationView.swift in Sources */,
51E498CC24A8085D00B667CB /* SearchFeedDelegate.swift in Sources */,
@ -4748,6 +4792,7 @@
51E4990724A808C300B667CB /* AuthorAvatarDownloader.swift in Sources */,
51E4997424A8784400B667CB /* DefaultFeedsImporter.swift in Sources */,
51919FF524AB869C00541E64 /* TimelineItem.swift in Sources */,
17AC0ABC24E4B65E004C1231 /* ReleaseNotes.swift in Sources */,
51E4992024A8095000B667CB /* RSImage-Extensions.swift in Sources */,
51E499FE24A9137600B667CB /* SidebarModel.swift in Sources */,
51E498FE24A808BA00B667CB /* FaviconDownloader.swift in Sources */,
@ -5887,6 +5932,31 @@
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
17A1597B24E3DEDD005DA32A /* RSCore */ = {
isa = XCSwiftPackageProductDependency;
package = 5102AE4324D17E820050839C /* XCRemoteSwiftPackageReference "RSCore" */;
productName = RSCore;
};
17A1597E24E3DEDD005DA32A /* RSTree */ = {
isa = XCSwiftPackageProductDependency;
package = 510ECA4024D1DCD0001C31A6 /* XCRemoteSwiftPackageReference "RSTree" */;
productName = RSTree;
};
17A1598124E3DEDD005DA32A /* RSWeb */ = {
isa = XCSwiftPackageProductDependency;
package = 51383A3024D1F90E0027E272 /* XCRemoteSwiftPackageReference "RSWeb" */;
productName = RSWeb;
};
17A1598424E3DEDD005DA32A /* RSDatabase */ = {
isa = XCSwiftPackageProductDependency;
package = 51B0DF0D24D24E3B000AD99E /* XCRemoteSwiftPackageReference "RSDatabase" */;
productName = RSDatabase;
};
17A1598724E3DEDD005DA32A /* RSParser */ = {
isa = XCSwiftPackageProductDependency;
package = 51B0DF2324D2C7FA000AD99E /* XCRemoteSwiftPackageReference "RSParser" */;
productName = RSParser;
};
5102AE6824D17F7C0050839C /* RSCore */ = {
isa = XCSwiftPackageProductDependency;
package = 5102AE4324D17E820050839C /* XCRemoteSwiftPackageReference "RSCore" */;