diff --git a/Multiplatform/Shared/Assets.xcassets/markAllAsRead.symbolset/Contents.json b/Multiplatform/Shared/Assets.xcassets/markAllAsRead.symbolset/Contents.json new file mode 100644 index 000000000..81428a2de --- /dev/null +++ b/Multiplatform/Shared/Assets.xcassets/markAllAsRead.symbolset/Contents.json @@ -0,0 +1,12 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + }, + "symbols" : [ + { + "filename" : "markAllAsRead.svg", + "idiom" : "universal" + } + ] +} diff --git a/Multiplatform/Shared/Assets.xcassets/markAllAsRead.symbolset/markAllAsRead.svg b/Multiplatform/Shared/Assets.xcassets/markAllAsRead.symbolset/markAllAsRead.svg new file mode 100644 index 000000000..58170a6ba --- /dev/null +++ b/Multiplatform/Shared/Assets.xcassets/markAllAsRead.symbolset/markAllAsRead.svg @@ -0,0 +1,142 @@ + + + + Untitled + Created with Sketch. + + + + + + + Weight/Scale Variations + + + Ultralight + + + Thin + + + Light + + + Regular + + + Medium + + + Semibold + + + Bold + + + Heavy + + + Black + + + + + + + + + + + + + Design Variations + + + Symbols are supported in up to nine weights and three scales. + + + For optimal layout with text and other symbols, vertically align + + + symbols with the adjacent text. + + + + + + + + Margins + + + Leading and trailing margins on the left and right side of each symbol + + + can be adjusted by modifying the width of the blue rectangles. + + + Modifications are automatically applied proportionally to all + + + scales and weights. + + + + + + Exporting + + + Symbols should be outlined when exporting to ensure the + + + design is preserved when submitting to Xcode. + + + Template v.1.0 + + + Generated from circle + + + Typeset at 100 points + + + Small + + + Medium + + + Large + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Multiplatform/Shared/MainApp.swift b/Multiplatform/Shared/MainApp.swift index 727c978b4..7fe88ed18 100644 --- a/Multiplatform/Shared/MainApp.swift +++ b/Multiplatform/Shared/MainApp.swift @@ -95,10 +95,6 @@ struct MainApp: App { Button("Refresh", action: {}) .keyboardShortcut("R") }) - CommandGroup(before: .sidebar, addition: { - Button("Show Sidebar", action: {}) - .keyboardShortcut("S", modifiers: [.control, .command]) - }) CommandMenu("Subscriptions", content: { Button("Import Subscriptions", action: {}) .keyboardShortcut("I", modifiers: [.shift, .command]) diff --git a/Multiplatform/Shared/Sidebar/CompactSidebarContainerView.swift b/Multiplatform/Shared/Sidebar/CompactSidebarContainerView.swift index ef4d32184..be76f6a48 100644 --- a/Multiplatform/Shared/Sidebar/CompactSidebarContainerView.swift +++ b/Multiplatform/Shared/Sidebar/CompactSidebarContainerView.swift @@ -12,6 +12,7 @@ struct CompactSidebarContainerView: View { @EnvironmentObject private var sceneModel: SceneModel @StateObject private var sidebarModel = SidebarModel() + @State private var showSettings: Bool = false var body: some View { SidebarView() @@ -22,8 +23,42 @@ struct CompactSidebarContainerView: View { sceneModel.sidebarModel = sidebarModel sidebarModel.delegate = sceneModel sidebarModel.rebuildSidebarItems() + }.overlay(Group { + #if os(iOS) + SidebarToolbar() + #endif + },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)) + } diff --git a/Multiplatform/Shared/Sidebar/RegularSidebarContainerView.swift b/Multiplatform/Shared/Sidebar/RegularSidebarContainerView.swift index 91d41e11b..af95dff28 100644 --- a/Multiplatform/Shared/Sidebar/RegularSidebarContainerView.swift +++ b/Multiplatform/Shared/Sidebar/RegularSidebarContainerView.swift @@ -13,7 +13,9 @@ struct RegularSidebarContainerView: View { @EnvironmentObject private var sceneModel: SceneModel @StateObject private var sidebarModel = SidebarModel() - var body: some View { + @State private var showSettings: Bool = false + + @ViewBuilder var body: some View { SidebarView() .environmentObject(sidebarModel) .navigationTitle(Text("Feeds")) @@ -23,7 +25,14 @@ struct RegularSidebarContainerView: View { sidebarModel.delegate = sceneModel sidebarModel.rebuildSidebarItems() } + .overlay(Group { + #if os(iOS) + SidebarToolbar() + #endif + },alignment: .bottom) + } + } struct RegularSidebarContainerView_Previews: PreviewProvider { diff --git a/Multiplatform/Shared/Sidebar/SidebarItem.swift b/Multiplatform/Shared/Sidebar/SidebarItem.swift index 14a1abdb1..796008552 100644 --- a/Multiplatform/Shared/Sidebar/SidebarItem.swift +++ b/Multiplatform/Shared/Sidebar/SidebarItem.swift @@ -16,6 +16,10 @@ public enum SidebarItemIdentifier: Hashable, Equatable { case feed(FeedIdentifier) } +public enum RepresentedType { + case feed, pseudoFeed, account, unknown +} + struct SidebarItem: Identifiable { var id: SidebarItemIdentifier @@ -29,6 +33,25 @@ struct SidebarItem: Identifiable { return displayNameProvider.nameForDisplay } + var feed: Feed? { + represented as? Feed + } + + var representedType: RepresentedType { + switch type(of: represented) { + case is SmartFeed.Type: + return .pseudoFeed + case is UnreadFeed.Type: + return .pseudoFeed + case is WebFeed.Type: + return .feed + case is Account.Type: + return .account + default: + return .unknown + } + } + init(_ smartFeedsController: SmartFeedsController) { self.id = .smartFeedController self.represented = smartFeedsController diff --git a/Multiplatform/Shared/Sidebar/SidebarItemView.swift b/Multiplatform/Shared/Sidebar/SidebarItemView.swift index e1dcaa41b..a50b63414 100644 --- a/Multiplatform/Shared/Sidebar/SidebarItemView.swift +++ b/Multiplatform/Shared/Sidebar/SidebarItemView.swift @@ -26,10 +26,87 @@ struct SidebarItemView: View { } } .onAppear { - if let feed = sidebarItem.represented as? Feed { + if let feed = sidebarItem.feed { feedImageLoader.loadImage(for: feed) } - } + }.contextMenu(menuItems: { + menuItems + }) } + @ViewBuilder var menuItems: some View { + if sidebarItem.representedType == .account { + Button(action: {}) { + HStack { + Text("Mark All As Read in \(sidebarItem.nameForDisplay)") + Spacer() + Image("markAllAsRead") + .resizable() + .aspectRatio(contentMode: .fit) + } + } + } + if sidebarItem.representedType == .feed { + Button(action: {}) { + HStack { + Text("Mark All as Read") + Spacer() + Image("markAllAsRead") + .resizable() + .aspectRatio(contentMode: .fit) + } + } + Divider() + Button(action: { + + }) { + HStack { + Text("Open Home Page") + Spacer() + Image(systemName: "safari") + } + } + Divider() + Button(action: {}) { + HStack { + Text("Copy Feed URL") + Spacer() + Image(systemName: "doc.on.doc") + } + } + Button(action: {}) { + HStack { + Text("Copy Home Page URL") + Spacer() + Image(systemName: "doc.on.doc") + } + } + Divider() + Button(action: {}) { + HStack { + Text("Rename") + Spacer() + Image(systemName: "textformat") + } + } + Button(action: {}) { + HStack { + Text("Delete").foregroundColor(.red) + Spacer() + Image(systemName: "trash").foregroundColor(.red) + } + } + } + if sidebarItem.representedType == .pseudoFeed { + Button(action: {}) { + HStack { + Text("Mark All as Read") + Spacer() + Image("markAllAsRead") + .resizable() + .aspectRatio(contentMode: .fit) + } + } + } + } } diff --git a/Multiplatform/Shared/Sidebar/SidebarToolbar.swift b/Multiplatform/Shared/Sidebar/SidebarToolbar.swift new file mode 100644 index 000000000..e7df534f6 --- /dev/null +++ b/Multiplatform/Shared/Sidebar/SidebarToolbar.swift @@ -0,0 +1,53 @@ +// +// SidebarToolbar.swift +// Multiplatform iOS +// +// Created by Stuart Breckenridge on 30/6/20. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import SwiftUI + +struct SidebarToolbar: View { + + @State private var showSettings: Bool = false + + var body: 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)) + .sheet(isPresented: $showSettings, onDismiss: { showSettings = false }) { + SettingsView() + } + + } +} + +struct SidebarToolbar_Previews: PreviewProvider { + static var previews: some View { + SidebarToolbar() + } +} diff --git a/Multiplatform/iOS/SafariView.swift b/Multiplatform/iOS/SafariView.swift new file mode 100644 index 000000000..2bc9af145 --- /dev/null +++ b/Multiplatform/iOS/SafariView.swift @@ -0,0 +1,65 @@ +// +// SafariView.swift +// Multiplatform iOS +// +// Created by Stuart Breckenridge on 30/6/20. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import SwiftUI +import SafariServices + + +private final class Safari: UIViewControllerRepresentable { + + typealias UIViewControllerType = SFSafariViewController + + var urlToLoad: URL + + init(url: URL) { + self.urlToLoad = url + } + + func makeUIViewController(context: Context) -> SFSafariViewController { + let viewController = SFSafariViewController(url: urlToLoad) + viewController.delegate = context.coordinator + return viewController + } + + func updateUIViewController(_ uiViewController: SFSafariViewController, context: Context) { + + } + + func makeCoordinator() -> Coordinator { + Coordinator(self) + } + + class Coordinator: NSObject, SFSafariViewControllerDelegate { + var parent: Safari + + init(_ parent: Safari) { + self.parent = parent + } + + func safariViewControllerDidFinish(_ controller: SFSafariViewController) { + + } + + } + +} + +struct SafariView: View { + + var url: URL + + var body: some View { + Safari(url: url) + } +} + +struct SafariView_Previews: PreviewProvider { + static var previews: some View { + SafariView(url: URL(string: "https://ranchero.com/netnewswire/")!) + } +} diff --git a/Multiplatform/iOS/Settings/SettingsView.swift b/Multiplatform/iOS/Settings/SettingsView.swift new file mode 100644 index 000000000..a20e8c791 --- /dev/null +++ b/Multiplatform/iOS/Settings/SettingsView.swift @@ -0,0 +1,211 @@ +// +// SettingsView.swift +// Multiplatform iOS +// +// Created by Stuart Breckenridge on 30/6/20. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import SwiftUI +import Account + + + +class SettingsViewModel: ObservableObject { + + enum HelpSites { + case netNewsWireHelp, netNewsWire, supportNetNewsWire, github, bugTracker, technotes, netNewsWireSlack, none + + var url: URL? { + switch self { + case .netNewsWireHelp: + return URL(string: "https://ranchero.com/netnewswire/help/ios/5.0/en/")! + case .netNewsWire: + return URL(string: "https://ranchero.com/netnewswire/")! + case .supportNetNewsWire: + return URL(string: "https://github.com/brentsimmons/NetNewsWire/blob/master/Technotes/HowToSupportNetNewsWire.markdown")! + case .github: + return URL(string: "https://github.com/brentsimmons/NetNewsWire")! + case .bugTracker: + return URL(string: "https://github.com/brentsimmons/NetNewsWire/issues")! + case .technotes: + return URL(string: "https://github.com/brentsimmons/NetNewsWire/tree/master/Technotes")! + case .netNewsWireSlack: + return URL(string: "https://ranchero.com/netnewswire/slack")! + case .none: + return nil + } + } + } + + @Published var presentSheet: Bool = false + var selectedWebsite: HelpSites = .none { + didSet { + if selectedWebsite == .none { + presentSheet = false + } else { + presentSheet = true + } + } + } + +} + +struct SettingsView: View { + + let sortedAccounts = AccountManager.shared.sortedAccounts + @Environment(\.presentationMode) var presentationMode + + @ObservedObject private var viewModel = SettingsViewModel() + + var body: some View { + NavigationView { + List { + systemSettings + accounts + importExport + timeline + articles + appearance + help + } + .listStyle(InsetGroupedListStyle()) + .navigationBarTitle("Settings", displayMode: .inline) + .navigationBarItems(leading: + HStack { + Button("Done") { + presentationMode.wrappedValue.dismiss() + } + } + ) + } + .sheet(isPresented: $viewModel.presentSheet, content: { + SafariView(url: viewModel.selectedWebsite.url!) + }) + } + + var systemSettings: some View { + Section(header: Text("Notifications, Badge, Data, & More"), content: { + Button(action: { + UIApplication.shared.open(URL(string: "\(UIApplication.openSettingsURLString)")!) + }, label: { + Text("Open System Settings").foregroundColor(.primary) + }) + }) + } + + var accounts: some View { + Section(header: Text("Accounts"), content: { + ForEach(0.. 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 ?? "" + return "NetNewsWire \(version) (Build \(build))" + } + +} + +struct SettingsView_Previews: PreviewProvider { + static var previews: some View { + SettingsView() + } +} diff --git a/Multiplatform/iOS/VisualEffectBlur.swift b/Multiplatform/iOS/VisualEffectBlur.swift new file mode 100644 index 000000000..f4aea1ab7 --- /dev/null +++ b/Multiplatform/iOS/VisualEffectBlur.swift @@ -0,0 +1,112 @@ +/* +See LICENSE folder for this sample’s licensing information. + +Abstract: +The iOS implementation of a UIVisualEffectView's blur and vibrancy. +*/ + +import SwiftUI + +// MARK: - VisualEffectBlur + +struct VisualEffectBlur: View { + var blurStyle: UIBlurEffect.Style + var vibrancyStyle: UIVibrancyEffectStyle? + var content: Content + + init(blurStyle: UIBlurEffect.Style = .systemMaterial, vibrancyStyle: UIVibrancyEffectStyle? = nil, @ViewBuilder content: () -> Content) { + self.blurStyle = blurStyle + self.vibrancyStyle = vibrancyStyle + self.content = content() + } + + var body: some View { + Representable(blurStyle: blurStyle, vibrancyStyle: vibrancyStyle, content: ZStack { content }) + .accessibility(hidden: Content.self == EmptyView.self) + } +} + +// MARK: - Representable + +extension VisualEffectBlur { + struct Representable: UIViewRepresentable { + var blurStyle: UIBlurEffect.Style + var vibrancyStyle: UIVibrancyEffectStyle? + var content: Content + + func makeUIView(context: Context) -> UIVisualEffectView { + context.coordinator.blurView + } + + func updateUIView(_ view: UIVisualEffectView, context: Context) { + context.coordinator.update(content: content, blurStyle: blurStyle, vibrancyStyle: vibrancyStyle) + } + + func makeCoordinator() -> Coordinator { + Coordinator(content: content) + } + } +} + +// MARK: - Coordinator + +extension VisualEffectBlur.Representable { + class Coordinator { + let blurView = UIVisualEffectView() + let vibrancyView = UIVisualEffectView() + let hostingController: UIHostingController + + init(content: Content) { + hostingController = UIHostingController(rootView: content) + hostingController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight] + hostingController.view.backgroundColor = nil + blurView.contentView.addSubview(vibrancyView) + blurView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + vibrancyView.contentView.addSubview(hostingController.view) + vibrancyView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + } + + func update(content: Content, blurStyle: UIBlurEffect.Style, vibrancyStyle: UIVibrancyEffectStyle?) { + hostingController.rootView = content + let blurEffect = UIBlurEffect(style: blurStyle) + blurView.effect = blurEffect + if let vibrancyStyle = vibrancyStyle { + vibrancyView.effect = UIVibrancyEffect(blurEffect: blurEffect, style: vibrancyStyle) + } else { + vibrancyView.effect = nil + } + hostingController.view.setNeedsDisplay() + } + } +} + +// MARK: - Content-less Initializer + +extension VisualEffectBlur where Content == EmptyView { + init(blurStyle: UIBlurEffect.Style = .systemMaterial) { + self.init( blurStyle: blurStyle, vibrancyStyle: nil) { + EmptyView() + } + } +} + +// MARK: - Previews + +struct VisualEffectBlur_Previews: PreviewProvider { + static var previews: some View { + ZStack { + LinearGradient( + gradient: Gradient(colors: [.red, .blue]), + startPoint: .topLeading, + endPoint: .bottomTrailing + ) + + VisualEffectBlur(blurStyle: .systemUltraThinMaterial, vibrancyStyle: .fill) { + Text("Hello World!") + .frame(width: 200, height: 100) + } + } + .previewLayout(.sizeThatFits) + } +} + diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index dcc2ebd26..8d476b95b 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -7,6 +7,10 @@ objects = { /* Begin PBXBuildFile section */ + 172199C924AB228900A31D04 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172199C824AB228900A31D04 /* SettingsView.swift */; }; + 172199ED24AB2E0100A31D04 /* SafariView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172199EC24AB2E0100A31D04 /* SafariView.swift */; }; + 172199EF24AB372D00A31D04 /* VisualEffectBlur.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172199EE24AB372D00A31D04 /* VisualEffectBlur.swift */; }; + 172199F124AB716900A31D04 /* SidebarToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172199F024AB716900A31D04 /* SidebarToolbar.swift */; }; 1729528E24AA1A4900D65E66 /* MacPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1729526C24AA1A4900D65E66 /* MacPreferences.swift */; }; 1729529324AA1CAA00D65E66 /* AccountsPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1729529024AA1CAA00D65E66 /* AccountsPreferencesView.swift */; }; 1729529424AA1CAA00D65E66 /* AdvancedPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1729529124AA1CAA00D65E66 /* AdvancedPreferencesView.swift */; }; @@ -1676,6 +1680,10 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 172199C824AB228900A31D04 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; + 172199EC24AB2E0100A31D04 /* SafariView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariView.swift; sourceTree = ""; }; + 172199EE24AB372D00A31D04 /* VisualEffectBlur.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VisualEffectBlur.swift; sourceTree = ""; }; + 172199F024AB716900A31D04 /* SidebarToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarToolbar.swift; sourceTree = ""; }; 1729526C24AA1A4900D65E66 /* MacPreferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MacPreferences.swift; sourceTree = ""; }; 1729529024AA1CAA00D65E66 /* AccountsPreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountsPreferencesView.swift; sourceTree = ""; }; 1729529124AA1CAA00D65E66 /* AdvancedPreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedPreferencesView.swift; sourceTree = ""; }; @@ -2319,6 +2327,14 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 172199EB24AB228E00A31D04 /* Settings */ = { + isa = PBXGroup; + children = ( + 172199C824AB228900A31D04 /* SettingsView.swift */, + ); + path = Settings; + sourceTree = ""; + }; 1729528F24AA1A4F00D65E66 /* Preferences */ = { isa = PBXGroup; children = ( @@ -2623,6 +2639,9 @@ 51C051CE24A7A72100194D5E /* iOS.entitlements */, 51C051CF24A7A72100194D5E /* iOS-dev.entitlements */, 51E4993B24A8709900B667CB /* AppDelegate.swift */, + 172199EB24AB228E00A31D04 /* Settings */, + 172199EC24AB2E0100A31D04 /* SafariView.swift */, + 172199EE24AB372D00A31D04 /* VisualEffectBlur.swift */, ); path = iOS; sourceTree = ""; @@ -2829,6 +2848,7 @@ children = ( 172952AF24AA287100D65E66 /* CompactSidebarContainerView.swift */, 51E499FF24A91FC100B667CB /* RegularSidebarContainerView.swift */, + 172199F024AB716900A31D04 /* SidebarToolbar.swift */, 51408B7D24A9EC6F0073CF4E /* SidebarItem.swift */, 51E499FC24A9137600B667CB /* SidebarModel.swift */, 51919FA524AA64B000541E64 /* SidebarView.swift */, @@ -3841,46 +3861,46 @@ TargetAttributes = { 51314636235A7BBE00387FDC = { CreatedOnToolsVersion = 11.2; - DevelopmentTeam = SHJK2V3AJG; + DevelopmentTeam = FQLBNX3GP7; LastSwiftMigration = 1120; ProvisioningStyle = Automatic; }; 513C5CE5232571C2003D4054 = { CreatedOnToolsVersion = 11.0; - DevelopmentTeam = SHJK2V3AJG; + DevelopmentTeam = FQLBNX3GP7; ProvisioningStyle = Automatic; }; 518B2ED12351B3DD00400001 = { CreatedOnToolsVersion = 11.2; - DevelopmentTeam = SHJK2V3AJG; + DevelopmentTeam = FQLBNX3GP7; ProvisioningStyle = Automatic; TestTargetID = 840D617B2029031C009BC708; }; 51C0513C24A77DF800194D5E = { CreatedOnToolsVersion = 12.0; - DevelopmentTeam = SHJK2V3AJG; + DevelopmentTeam = FQLBNX3GP7; ProvisioningStyle = Automatic; }; 51C0514324A77DF800194D5E = { CreatedOnToolsVersion = 12.0; - DevelopmentTeam = SHJK2V3AJG; + DevelopmentTeam = FQLBNX3GP7; ProvisioningStyle = Automatic; }; 6581C73220CED60000F4AD34 = { - DevelopmentTeam = SHJK2V3AJG; + DevelopmentTeam = FQLBNX3GP7; ProvisioningStyle = Automatic; }; 65ED3FA2235DEF6C0081F399 = { - DevelopmentTeam = SHJK2V3AJG; + DevelopmentTeam = FQLBNX3GP7; ProvisioningStyle = Automatic; }; 65ED4090235DEF770081F399 = { - DevelopmentTeam = SHJK2V3AJG; + DevelopmentTeam = FQLBNX3GP7; ProvisioningStyle = Automatic; }; 840D617B2029031C009BC708 = { CreatedOnToolsVersion = 9.3; - DevelopmentTeam = SHJK2V3AJG; + DevelopmentTeam = FQLBNX3GP7; ProvisioningStyle = Automatic; SystemCapabilities = { com.apple.BackgroundModes = { @@ -3890,7 +3910,7 @@ }; 849C645F1ED37A5D003D8FC0 = { CreatedOnToolsVersion = 8.2.1; - DevelopmentTeam = SHJK2V3AJG; + DevelopmentTeam = FQLBNX3GP7; ProvisioningStyle = Automatic; SystemCapabilities = { com.apple.HardenedRuntime = { @@ -3900,7 +3920,7 @@ }; 849C64701ED37A5D003D8FC0 = { CreatedOnToolsVersion = 8.2.1; - DevelopmentTeam = SHJK2V3AJG; + DevelopmentTeam = FQLBNX3GP7; ProvisioningStyle = Automatic; TestTargetID = 849C645F1ED37A5D003D8FC0; }; @@ -4681,8 +4701,10 @@ 51E4992324A8095700B667CB /* URL-Extensions.swift in Sources */, 51E4993624A867E800B667CB /* UserInfoKey.swift in Sources */, 51E4990924A808C500B667CB /* WebFeedIconDownloader.swift in Sources */, + 172199EF24AB372D00A31D04 /* VisualEffectBlur.swift in Sources */, 51E498F524A8085D00B667CB /* TodayFeedDelegate.swift in Sources */, 172952B024AA287100D65E66 /* CompactSidebarContainerView.swift in Sources */, + 172199F124AB716900A31D04 /* SidebarToolbar.swift in Sources */, 51E4990B24A808C500B667CB /* ImageDownloader.swift in Sources */, 51E498F424A8085D00B667CB /* SmartFeedDelegate.swift in Sources */, 51E4993024A8676400B667CB /* ArticleSorter.swift in Sources */, @@ -4701,6 +4723,7 @@ 51E4991D24A8092100B667CB /* NSAttributedString+NetNewsWire.swift in Sources */, 51E499FD24A9137600B667CB /* SidebarModel.swift in Sources */, 51E4995324A8734D00B667CB /* RedditFeedProvider-Extensions.swift in Sources */, + 172199C924AB228900A31D04 /* SettingsView.swift in Sources */, 51E4994224A8713C00B667CB /* ArticleStatusSyncTimer.swift in Sources */, 51E498F624A8085D00B667CB /* SearchFeedDelegate.swift in Sources */, 51E498F224A8085D00B667CB /* SmartFeedsController.swift in Sources */, @@ -4725,6 +4748,7 @@ 51E4990C24A808C500B667CB /* AuthorAvatarDownloader.swift in Sources */, 51E4992124A8095000B667CB /* RSImage-Extensions.swift in Sources */, 51E4990324A808BB00B667CB /* FaviconDownloader.swift in Sources */, + 172199ED24AB2E0100A31D04 /* SafariView.swift in Sources */, 51E4990224A808BB00B667CB /* ColorHash.swift in Sources */, 51919FAC24AA8CCA00541E64 /* UnreadCountView.swift in Sources */, 51E4991924A8090A00B667CB /* CacheCleaner.swift in Sources */,