diff --git a/Mac/AppDelegate.swift b/Mac/AppDelegate.swift index 29a29dd47..c1b45c983 100644 --- a/Mac/AppDelegate.swift +++ b/Mac/AppDelegate.swift @@ -16,6 +16,7 @@ import RSCore import RSCoreResources import Secrets import CrashReporter +import SwiftUI // If we're not going to import Sparkle, provide dummy protocols to make it easy // for AppDelegate to comply @@ -719,6 +720,21 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, self.softwareUpdater.checkForUpdates() #endif } + + @IBAction func showAbout(_ sender: Any?) { + if #available(macOS 12, *) { + for window in NSApplication.shared.windows { + if window.identifier == .aboutNetNewsWire { + window.makeKeyAndOrderFront(nil) + return + } + } + let controller = AboutWindowController() + controller.window?.makeKeyAndOrderFront(nil) + } else { + NSApplication.shared.orderFrontStandardAboutPanel(self) + } + } } diff --git a/Mac/Base.lproj/Main.storyboard b/Mac/Base.lproj/Main.storyboard index 90758a355..775fa877a 100644 --- a/Mac/Base.lproj/Main.storyboard +++ b/Mac/Base.lproj/Main.storyboard @@ -18,7 +18,7 @@ - + diff --git a/Mac/MainWindow/About/AboutNetNewsWireView.swift b/Mac/MainWindow/About/AboutNetNewsWireView.swift new file mode 100644 index 000000000..94937cc85 --- /dev/null +++ b/Mac/MainWindow/About/AboutNetNewsWireView.swift @@ -0,0 +1,55 @@ +// +// AboutNetNewsWireView.swift +// NetNewsWire +// +// Created by Stuart Breckenridge on 03/10/2022. +// Copyright © 2022 Ranchero Software. All rights reserved. +// + +import SwiftUI + +@available(macOS 12, *) +struct AboutNetNewsWireView: View { + var body: some View { + HStack { + Spacer() + VStack(spacing: 8) { + Spacer() + + Image("About") + .resizable() + .frame(width: 75, height: 75) + + Text("NetNewsWire") + .font(.headline) + + Text("\(Bundle.main.versionNumber) (\(Bundle.main.buildNumber))") + .foregroundColor(.secondary) + .font(.callout) + + Text("By Brent Simmons and the NetNewsWire team.") + .font(.subheadline) + + Text("[netnewswire.com](https://netnewswire.com)") + .font(.callout) + + Spacer() + + Text(verbatim: "Copyright © Brent Simmons 2002 - \(Calendar.current.component(.year, from: .now))") + .font(.callout) + .foregroundColor(.secondary) + .padding(.bottom) + } + Spacer() + } + .multilineTextAlignment(.center) + .frame(width: 400, height: 400) + } +} + +@available(macOS 12, *) +struct AboutNetNewsWireView_Previews: PreviewProvider { + static var previews: some View { + AboutNetNewsWireView() + } +} diff --git a/Mac/MainWindow/About/AboutWindowController.swift b/Mac/MainWindow/About/AboutWindowController.swift new file mode 100644 index 000000000..9fbe83ac2 --- /dev/null +++ b/Mac/MainWindow/About/AboutWindowController.swift @@ -0,0 +1,131 @@ +// +// AboutWindowController.swift +// NetNewsWire +// +// Created by Stuart Breckenridge on 03/10/2022. +// Copyright © 2022 Ranchero Software. All rights reserved. +// + +import AppKit +import SwiftUI +import RSCore + +extension NSToolbarItem.Identifier { + static let aboutGroup = NSToolbarItem.Identifier("about.toolbar.group") +} + +extension NSUserInterfaceItemIdentifier { + static let aboutNetNewsWire = NSUserInterfaceItemIdentifier("about.netnewswire") +} + +// MARK: - AboutWindowController + +@available(macOS 12, *) +class AboutWindowController: NSWindowController, NSToolbarDelegate { + + var hostingController: AboutHostingController + + override init(window: NSWindow?) { + self.hostingController = AboutHostingController(rootView: AnyView(AboutNetNewsWireView())) + super.init(window: window) + let window = NSWindow(contentViewController: hostingController) + window.identifier = .aboutNetNewsWire + window.standardWindowButton(.zoomButton)?.isEnabled = false + window.titleVisibility = .hidden + self.window = window + self.hostingController.configureToolbar() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func windowDidLoad() { + super.windowDidLoad() + } + +} + +// MARK: - AboutHostingController + +@available(macOS 12, *) +class AboutHostingController: NSHostingController, NSToolbarDelegate { + + private lazy var segmentedControl: NSSegmentedControl = { + let control = NSSegmentedControl(labels: ["About", "Credits"], + trackingMode: .selectOne, + target: self, + action: #selector(segmentedControlSelectionChanged(_:))) + control.segmentCount = 2 + control.setSelected(true, forSegment: 0) + return control + }() + + override init(rootView: AnyView) { + super.init(rootView: rootView) + } + + @MainActor required dynamic init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + public func configureToolbar() { + let toolbar = NSToolbar(identifier: NSToolbar.Identifier("netnewswire.about.toolbar")) + toolbar.delegate = self + toolbar.autosavesConfiguration = false + toolbar.allowsUserCustomization = false + view.window?.toolbar = toolbar + view.window?.toolbarStyle = .unified + toolbar.insertItem(withItemIdentifier: .flexibleSpace, at: 0) + toolbar.insertItem(withItemIdentifier: .flexibleSpace, at: 2) + } + + // MARK: NSToolbarDelegate + + func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? { + switch itemIdentifier { + + case .aboutGroup: + let toolbarItem = NSToolbarItem(itemIdentifier: .aboutGroup) + toolbarItem.view = segmentedControl + toolbarItem.autovalidates = true + return toolbarItem + default: + return nil + } + } + + func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { + return [.aboutGroup] + } + + func toolbarWillAddItem(_ notification: Notification) { + // + } + + func toolbarDidRemoveItem(_ notification: Notification) { + // + } + + func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { + return [.aboutGroup] + } + + func toolbarSelectableItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { + return [] + } + + // MARK: - Target/Action + @objc + func segmentedControlSelectionChanged(_ sender: NSSegmentedControl) { + if sender.selectedSegment == 0 { + rootView = AnyView(AboutNetNewsWireView()) + } else { + rootView = AnyView(CreditsNetNewsWireView()) + } + } + +} + + + diff --git a/Mac/MainWindow/About/CreditsNetNewsWireView.swift b/Mac/MainWindow/About/CreditsNetNewsWireView.swift new file mode 100644 index 000000000..1e88be2d9 --- /dev/null +++ b/Mac/MainWindow/About/CreditsNetNewsWireView.swift @@ -0,0 +1,79 @@ +// +// CreditsNetNewsWireView.swift +// NetNewsWire +// +// Created by Stuart Breckenridge on 03/10/2022. +// Copyright © 2022 Ranchero Software. All rights reserved. +// + +import SwiftUI + +@available(macOS 12, *) +struct CreditsNetNewsWireView: View, LoadableAboutData { + var body: some View { + ScrollView(.vertical, showsIndicators: false) { + Spacer() + .frame(height: 12) + Section("Primary Contributors") { + GroupBox { + ForEach(0.. some View { + HStack { + Text(appCredit.name) + Spacer() + if let role = appCredit.role { + Text(role) + .foregroundColor(.secondary) + } + Image(systemName: "info.circle") + .foregroundColor(.secondary) + } + .onTapGesture { + guard let url = appCredit.url else { return } + if let _ = URL(string: url) { + Browser.open(url, inBackground: false) + } + } + } +} + +@available(macOS 12, *) +struct CreditsNetNewsWireView_Previews: PreviewProvider { + static var previews: some View { + CreditsNetNewsWireView() + } +} diff --git a/Mac/Resources/Assets.xcassets/About.imageset/Contents.json b/Mac/Resources/Assets.xcassets/About.imageset/Contents.json new file mode 100644 index 000000000..5d8cba1f4 --- /dev/null +++ b/Mac/Resources/Assets.xcassets/About.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Icon-MacOS-512x512@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Icon-MacOS-512x512@2x 1.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Mac/Resources/Assets.xcassets/About.imageset/Icon-MacOS-512x512@2x 1.png b/Mac/Resources/Assets.xcassets/About.imageset/Icon-MacOS-512x512@2x 1.png new file mode 100644 index 000000000..95a4b1625 Binary files /dev/null and b/Mac/Resources/Assets.xcassets/About.imageset/Icon-MacOS-512x512@2x 1.png differ diff --git a/Mac/Resources/Assets.xcassets/About.imageset/Icon-MacOS-512x512@2x.png b/Mac/Resources/Assets.xcassets/About.imageset/Icon-MacOS-512x512@2x.png new file mode 100644 index 000000000..95a4b1625 Binary files /dev/null and b/Mac/Resources/Assets.xcassets/About.imageset/Icon-MacOS-512x512@2x.png differ diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index a53d072dc..fc8de8e2b 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -852,14 +852,21 @@ DDF9E1D828EDF2FC000BC355 /* notificationSoundBlip.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = DDF9E1D628EDF2FC000BC355 /* notificationSoundBlip.mp3 */; }; DDF9E1D928EDF2FC000BC355 /* notificationSoundBlip.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = DDF9E1D628EDF2FC000BC355 /* notificationSoundBlip.mp3 */; }; DF5AD10128D6922200CA3BF7 /* SmartFeedSummaryWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1768144D2564BCE000D98635 /* SmartFeedSummaryWidget.swift */; }; - DF790D6028E9769300455FC7 /* Thanks.md in Resources */ = {isa = PBXBuildFile; fileRef = DF790D5F28E9769300455FC7 /* Thanks.md */; }; DF790D6228E990A900455FC7 /* AboutData.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF790D6128E990A900455FC7 /* AboutData.swift */; }; + DFC14F0F28EA55BD00F6EE86 /* AboutWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFC14F0E28EA55BD00F6EE86 /* AboutWindowController.swift */; }; + DFC14F1228EA5DC500F6EE86 /* AboutData.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF790D6128E990A900455FC7 /* AboutData.swift */; }; + DFC14F1328EA677C00F6EE86 /* Bundle-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F85BF42273625800C787DC /* Bundle-Extensions.swift */; }; + DFC14F1528EB177000F6EE86 /* AboutNetNewsWireView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFC14F1428EB177000F6EE86 /* AboutNetNewsWireView.swift */; }; + DFC14F1728EB17A800F6EE86 /* CreditsNetNewsWireView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFC14F1628EB17A800F6EE86 /* CreditsNetNewsWireView.swift */; }; + DFCE4F9128EF26F100405869 /* About.plist in Resources */ = {isa = PBXBuildFile; fileRef = DFCE4F9028EF26F000405869 /* About.plist */; }; + DFCE4F9228EF26F100405869 /* About.plist in Resources */ = {isa = PBXBuildFile; fileRef = DFCE4F9028EF26F000405869 /* About.plist */; }; + DFCE4F9428EF278300405869 /* Thanks.md in Resources */ = {isa = PBXBuildFile; fileRef = DFCE4F9328EF278300405869 /* Thanks.md */; }; + DFCE4F9528EF278300405869 /* Thanks.md in Resources */ = {isa = PBXBuildFile; fileRef = DFCE4F9328EF278300405869 /* Thanks.md */; }; DFD6AACF27ADE86E00463FAD /* NewsFax.nnwtheme in Resources */ = {isa = PBXBuildFile; fileRef = DFD6AACD27ADE86E00463FAD /* NewsFax.nnwtheme */; }; DFFB8FC2279B75E300AC21D7 /* Account in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 51BC2F4A24D343A500E90810 /* Account */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; DFFC199827A0D0D7004B7AEF /* NotificationsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFFC199727A0D0D7004B7AEF /* NotificationsViewController.swift */; }; DFFC199A27A0D32A004B7AEF /* NotificationsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFFC199927A0D32A004B7AEF /* NotificationsTableViewCell.swift */; }; DFFC4E7428E95C01006B82AF /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFFC4E7328E95C01006B82AF /* AboutView.swift */; }; - DFFC4E7628E95F78006B82AF /* About.plist in Resources */ = {isa = PBXBuildFile; fileRef = DFFC4E7528E95F78006B82AF /* About.plist */; }; FF3ABF13232599810074C542 /* ArticleSorterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF3ABF09232599450074C542 /* ArticleSorterTests.swift */; }; FF3ABF1523259DDB0074C542 /* ArticleSorter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF3ABF1423259DDB0074C542 /* ArticleSorter.swift */; }; FF3ABF162325AF5D0074C542 /* ArticleSorter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF3ABF1423259DDB0074C542 /* ArticleSorter.swift */; }; @@ -1593,14 +1600,17 @@ D5F4EDB820074D7C00B9E363 /* Folder+Scriptability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Folder+Scriptability.swift"; sourceTree = ""; }; DD82AB09231003F6002269DF /* SharingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharingTests.swift; sourceTree = ""; }; DDF9E1D628EDF2FC000BC355 /* notificationSoundBlip.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = notificationSoundBlip.mp3; sourceTree = ""; }; - DF790D5F28E9769300455FC7 /* Thanks.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Thanks.md; sourceTree = ""; }; DF790D6128E990A900455FC7 /* AboutData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutData.swift; sourceTree = ""; }; + DFC14F0E28EA55BD00F6EE86 /* AboutWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutWindowController.swift; sourceTree = ""; }; + DFC14F1428EB177000F6EE86 /* AboutNetNewsWireView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutNetNewsWireView.swift; sourceTree = ""; }; + DFC14F1628EB17A800F6EE86 /* CreditsNetNewsWireView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreditsNetNewsWireView.swift; sourceTree = ""; }; + DFCE4F9028EF26F000405869 /* About.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = About.plist; sourceTree = ""; }; + DFCE4F9328EF278300405869 /* Thanks.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = Thanks.md; sourceTree = ""; }; DFD6AACB27ADE80900463FAD /* NewsFax.nnwtheme */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = NewsFax.nnwtheme; sourceTree = ""; }; DFD6AACD27ADE86E00463FAD /* NewsFax.nnwtheme */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = NewsFax.nnwtheme; sourceTree = ""; }; DFFC199727A0D0D7004B7AEF /* NotificationsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsViewController.swift; sourceTree = ""; }; DFFC199927A0D32A004B7AEF /* NotificationsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsTableViewCell.swift; sourceTree = ""; }; DFFC4E7328E95C01006B82AF /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = ""; }; - DFFC4E7528E95F78006B82AF /* About.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = About.plist; sourceTree = ""; }; FF3ABF09232599450074C542 /* ArticleSorterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleSorterTests.swift; sourceTree = ""; }; FF3ABF1423259DDB0074C542 /* ArticleSorter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleSorter.swift; sourceTree = ""; }; FFD43E372340F320009E5CA3 /* MarkAsReadAlertController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarkAsReadAlertController.swift; sourceTree = ""; }; @@ -1860,6 +1870,8 @@ 511D43CE231FA51100FB1562 /* Resources */ = { isa = PBXGroup; children = ( + DFCE4F9028EF26F000405869 /* About.plist */, + DFCE4F9328EF278300405869 /* Thanks.md */, DDF9E1D628EDF2FC000BC355 /* notificationSoundBlip.mp3 */, DFD6AACB27ADE80900463FAD /* NewsFax.nnwtheme */, 51DEE81126FB9233006DAA56 /* Appanoose.nnwtheme */, @@ -1995,7 +2007,6 @@ isa = PBXGroup; children = ( DFFC4E7328E95C01006B82AF /* AboutView.swift */, - DF790D6128E990A900455FC7 /* AboutData.swift */, 51A16992235E10D600EB091F /* AddAccountViewController.swift */, 519ED455244828C3007F8E94 /* AddExtensionPointViewController.swift */, 5137C2E926F63AE6009EFEDB /* ArticleThemeImporter.swift */, @@ -2264,6 +2275,7 @@ 842E45E11ED8C681000A8B52 /* MainWindow */ = { isa = PBXGroup; children = ( + DFC14F0928EA51AB00F6EE86 /* About */, 8483630C2262A3FE00DA1D35 /* MainWindow.storyboard */, 51927A0328E28D1C000AE856 /* MainWindow.swift */, 519279FD28E24CCA000AE856 /* MainWindowController.swift */, @@ -2589,6 +2601,7 @@ 84C9FC6822629C9A00D921D6 /* Shared */ = { isa = PBXGroup; children = ( + DF790D6128E990A900455FC7 /* AboutData.swift */, 842E45CD1ED8C308000A8B52 /* AppNotifications.swift */, 51C4CFEF24D37D1F00AF9874 /* Secrets.swift */, 511B9805237DCAC90028BCAA /* UserInfoKey.swift */, @@ -2735,8 +2748,6 @@ 84C9FC9A2262A1A900D921D6 /* Resources */ = { isa = PBXGroup; children = ( - DFFC4E7528E95F78006B82AF /* About.plist */, - DF790D5F28E9769300455FC7 /* Thanks.md */, 5103A9B324216A4200410853 /* blank.html */, 51BB7C302335ACDE008E8144 /* page.html */, 514219572353C28900E07E2C /* main_ios.js */, @@ -2878,6 +2889,16 @@ path = Scriptability; sourceTree = ""; }; + DFC14F0928EA51AB00F6EE86 /* About */ = { + isa = PBXGroup; + children = ( + DFC14F0E28EA55BD00F6EE86 /* AboutWindowController.swift */, + DFC14F1428EB177000F6EE86 /* AboutNetNewsWireView.swift */, + DFC14F1628EB17A800F6EE86 /* CreditsNetNewsWireView.swift */, + ); + path = About; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -3434,6 +3455,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + DFCE4F9228EF26F100405869 /* About.plist in Resources */, 5137C2E626F3F52D009EFEDB /* Sepia.nnwtheme in Resources */, 517630052336215100E15FFF /* main.js in Resources */, 5148F44B2336DB4700F8CD8B /* MasterTimelineTitleView.xib in Resources */, @@ -3441,7 +3463,6 @@ 51C452862265093600C03939 /* Add.storyboard in Resources */, 511D43EF231FBDE900FB1562 /* LaunchScreenPad.storyboard in Resources */, 511D43D2231FA62C00FB1562 /* GlobalKeyboardShortcuts.plist in Resources */, - DFFC4E7628E95F78006B82AF /* About.plist in Resources */, 84C9FCA12262A1B300D921D6 /* Main.storyboard in Resources */, 51BB7C312335ACDE008E8144 /* page.html in Resources */, 512392C324E3451400F11704 /* TwitterAdd.storyboard in Resources */, @@ -3464,11 +3485,11 @@ 51A1699A235E10D700EB091F /* Settings.storyboard in Resources */, 49F40DF92335B71000552BF4 /* newsfoot.js in Resources */, 512392C024E33A3C00F11704 /* RedditAdd.storyboard in Resources */, - DF790D6028E9769300455FC7 /* Thanks.md in Resources */, 5177C21327B07CFE00643901 /* NewsFax.nnwtheme in Resources */, 51CE1C0923621EDA005548FC /* RefreshProgressView.xib in Resources */, 84C9FC9D2262A1A900D921D6 /* Assets.xcassets in Resources */, 514219582353C28900E07E2C /* main_ios.js in Resources */, + DFCE4F9528EF278300405869 /* Thanks.md in Resources */, 51DEE81426FB9233006DAA56 /* Appanoose.nnwtheme in Resources */, 51E36E8C239D6765006F47A5 /* AddFeedSelectFolderTableViewCell.xib in Resources */, ); @@ -3493,6 +3514,7 @@ 51D0214626ED617100FF2E0F /* core.css in Resources */, 51DEE81826FBFF84006DAA56 /* Promenade.nnwtheme in Resources */, 5142194B2353C1CF00E07E2C /* main_mac.js in Resources */, + DFCE4F9128EF26F100405869 /* About.plist in Resources */, 84C9FC8C22629E8F00D921D6 /* KeyboardShortcuts.html in Resources */, B27EEBF9244D15F3000932E6 /* stylesheet.css in Resources */, 5144EA3B227A379E00D19003 /* ImportOPMLSheet.xib in Resources */, @@ -3523,6 +3545,7 @@ 84C9FC8E22629E8F00D921D6 /* Credits.rtf in Resources */, 84BBB12D20142A4700F054F5 /* Inspector.storyboard in Resources */, 848363022262A3BD00DA1D35 /* AddWebFeedSheet.xib in Resources */, + DFCE4F9428EF278300405869 /* Thanks.md in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4305,6 +4328,7 @@ 845A29241FC9255E007B49E3 /* SidebarCellAppearance.swift in Sources */, 515A5107243D0CCD0089E588 /* TwitterFeedProvider-Extensions.swift in Sources */, 845EE7B11FC2366500854A1F /* StarredFeedDelegate.swift in Sources */, + DFC14F1228EA5DC500F6EE86 /* AboutData.swift in Sources */, 848F6AE51FC29CFB002D422E /* FaviconDownloader.swift in Sources */, 511B9806237DCAC90028BCAA /* UserInfoKey.swift in Sources */, 84C9FC7722629E1200D921D6 /* AdvancedPreferencesViewController.swift in Sources */, @@ -4332,12 +4356,15 @@ 849A97801ED9EC42007D329B /* DetailViewController.swift in Sources */, 173A64172547BE0900267F6E /* AccountType+Helpers.swift in Sources */, 518C3193237B00D9004D740F /* DetailIconSchemeHandler.swift in Sources */, + DFC14F1528EB177000F6EE86 /* AboutNetNewsWireView.swift in Sources */, 84C9FC6722629B9000D921D6 /* AppDelegate.swift in Sources */, 510C417F24E5D1AE008226FD /* ExtensionContainersFile.swift in Sources */, 84C9FC7A22629E1200D921D6 /* PreferencesTableViewBackgroundView.swift in Sources */, 84CAFCAF22BC8C35007694F0 /* FetchRequestOperation.swift in Sources */, + DFC14F1328EA677C00F6EE86 /* Bundle-Extensions.swift in Sources */, 8426119E1FCB6ED40086A189 /* HTMLMetadataDownloader.swift in Sources */, 849A976E1ED9EBC8007D329B /* TimelineViewController.swift in Sources */, + DFC14F1728EB17A800F6EE86 /* CreditsNetNewsWireView.swift in Sources */, 5154368B229404D1005E1CDF /* FaviconGenerator.swift in Sources */, 5183CCE6226F4E110010922C /* RefreshInterval.swift in Sources */, 849A97771ED9EC04007D329B /* TimelineCellData.swift in Sources */, @@ -4346,6 +4373,7 @@ 8454C3F8263F3AD400E3F9C7 /* IconImageCache.swift in Sources */, 518651B223555EB20078E021 /* NNW3Document.swift in Sources */, D5F4EDB5200744A700B9E363 /* ScriptingObject.swift in Sources */, + DFC14F0F28EA55BD00F6EE86 /* AboutWindowController.swift in Sources */, D5F4EDB920074D7C00B9E363 /* Folder+Scriptability.swift in Sources */, 849A97781ED9EC04007D329B /* TimelineCellLayout.swift in Sources */, 84E8E0EB202F693600562D8F /* DetailWebView.swift in Sources */, diff --git a/iOS/Settings/AboutData.swift b/Shared/AboutData.swift similarity index 50% rename from iOS/Settings/AboutData.swift rename to Shared/AboutData.swift index 290f5084e..4e76aa141 100644 --- a/iOS/Settings/AboutData.swift +++ b/Shared/AboutData.swift @@ -8,25 +8,41 @@ import Foundation -struct AboutData: Codable { - var AppCredits: [AppCredit] - var AdditionalContributors: [Contributor] +@available(iOS 15, *) +@available(macOS 12, *) +protocol LoadableAboutData { + var about: AboutData { get } +} + +@available(iOS 15, *) +@available(macOS 12, *) +extension LoadableAboutData { + var about: AboutData { + guard let path = Bundle.main.path(forResource: "About", ofType: "plist") else { + fatalError("The about plist really should exist.") + } + let url = URL(fileURLWithPath: path) + let data = try! Data(contentsOf: url) + return try! PropertyListDecoder().decode(AboutData.self, from: data) + } + +} + +@available(iOS 15, *) +@available(macOS 12, *) +struct AboutData: Codable { + var PrimaryContributors: [Contributor] + var AdditionalContributors: [Contributor] var ThanksMarkdown: AttributedString { let dataURL = Bundle.main.url(forResource: "Thanks", withExtension: "md")! return try! AttributedString(markdown: Data(contentsOf: dataURL), options: AttributedString.MarkdownParsingOptions(interpretedSyntax: .inlineOnlyPreservingWhitespace)) } - struct AppCredit: Codable { - var name: String - var role: String - var url: String? - } - struct Contributor: Codable { var name: String var url: String? + var role: String? } - } diff --git a/iOS/Resources/About.plist b/Shared/Resources/About.plist similarity index 95% rename from iOS/Resources/About.plist rename to Shared/Resources/About.plist index 957c66a25..d22e15c65 100644 --- a/iOS/Resources/About.plist +++ b/Shared/Resources/About.plist @@ -2,15 +2,23 @@ - AppCredits + PrimaryContributors - role - Lead Developer name Maurice Parker url https://vincode.io + role + Lead Developer + + + name + Stuart Breckenridge + url + https://stuartbreckenridge.net + role + Contributing Developer url @@ -50,7 +58,7 @@ name Andrew Brehaut role - Newsfoot (JS footnote displayer) + Newsfoot Footnotes url @@ -87,12 +95,6 @@ url https://blog.rizwan.dev/ - - name - Stuart Breckenridge - url - https://stuartbreckenridge.net - name Phil Viso diff --git a/iOS/Resources/Thanks.md b/Shared/Resources/Thanks.md similarity index 97% rename from iOS/Resources/Thanks.md rename to Shared/Resources/Thanks.md index e22aeac28..93b9df1f4 100644 --- a/iOS/Resources/Thanks.md +++ b/Shared/Resources/Thanks.md @@ -2,4 +2,4 @@ Thanks to Sheila and my family; thanks to my friends in Seattle and around the g Thanks to [Gus Mueller](https://shapeof.com/) for [FMDB](https://github.com/ccgus/fmdb) by [Flying Meat Software](http://flyingmeat.com/). Thanks to [GitHub](https://github.com) and [Slack](https://slack.com) for making open source collaboration easy and fun. Thanks to [Ben Ubois](https://benubois.com/) at [Feedbin](https://feedbin.com/) for all the extra help with syncing and article rendering — and for [hosting the server for the Reader view](https://feedbin.com/blog/2019/03/11/the-future-of-full-content/). -NetNewsWire 6 is dedicated to everyone working to save democracy around the world. +NetNewsWire 6 is dedicated to everyone working to save democracy around the world. \ No newline at end of file diff --git a/iOS/Settings/AboutView.swift b/iOS/Settings/AboutView.swift index 0bbb5b2a0..70cd411e2 100644 --- a/iOS/Settings/AboutView.swift +++ b/iOS/Settings/AboutView.swift @@ -8,33 +8,20 @@ import SwiftUI -struct AboutView: View { +struct AboutView: View, LoadableAboutData { - private var about: AboutData! - - init() { - guard let path = Bundle.main.path(forResource: "About", ofType: "plist") else { - fatalError("The about plist really should exist.") - } - let url = URL(fileURLWithPath: path) - let data = try! Data(contentsOf: url) - about = try! PropertyListDecoder().decode(AboutData.self, from: data) - } - var body: some View { List { Section(header: aboutHeaderView) {} - Section(header: Text("Credits")) { - ForEach(0.. some View { + func contributorView(_ appCredit: AboutData.Contributor) -> some View { HStack { - Text(appCredit.role) - Spacer() Text(appCredit.name) - .foregroundColor(.secondary) + Spacer() + if let role = appCredit.role { + Text(role) + .font(.footnote) + .foregroundColor(.secondary) + .multilineTextAlignment(.trailing) + } + if let _ = appCredit.url { + Image(systemName: "info.circle") + .foregroundColor(.secondary) + } } .onTapGesture { guard let url = appCredit.url else { return } @@ -82,18 +81,6 @@ struct AboutView: View { } } - func contributorView(_ contributor: AboutData.Contributor) -> some View { - HStack { - Text(contributor.name) - Spacer() - } - .onTapGesture { - guard let url = contributor.url else { return } - if let contributorURL = URL(string: url) { - UIApplication.shared.open(contributorURL) - } - } - } var thanks: some View { Text(about.ThanksMarkdown) @@ -102,7 +89,11 @@ struct AboutView: View { } var copyright: some View { - Text(verbatim: "Copyright © Brent Simmons 2002 - \(Calendar.current.component(.year, from: .now))") + HStack { + Spacer() + Text(verbatim: "Copyright © Brent Simmons 2002 - \(Calendar.current.component(.year, from: .now))") + Spacer() + } } } diff --git a/iOS/Settings/SettingsViewController.swift b/iOS/Settings/SettingsViewController.swift index 66b789b8f..2112e62dd 100644 --- a/iOS/Settings/SettingsViewController.swift +++ b/iOS/Settings/SettingsViewController.swift @@ -86,18 +86,6 @@ class SettingsViewController: UITableViewController, Logging { colorPaletteDetailLabel.text = String(describing: AppDefaults.userInterfaceColorPalette) openLinksInNetNewsWire.isOn = !AppDefaults.shared.useSystemBrowser - let buildLabel = NonIntrinsicLabel(frame: CGRect(x: 32.0, y: 0.0, width: 0.0, height: 0.0)) - buildLabel.font = UIFont.systemFont(ofSize: 11.0) - buildLabel.textColor = UIColor.gray - buildLabel.text = "\(Bundle.main.appName) \(Bundle.main.versionNumber) (Build \(Bundle.main.buildNumber))" - buildLabel.sizeToFit() - buildLabel.translatesAutoresizingMaskIntoConstraints = false - - let wrapperView = UIView(frame: CGRect(x: 0, y: 0, width: buildLabel.frame.width, height: buildLabel.frame.height + 10.0)) - wrapperView.translatesAutoresizingMaskIntoConstraints = false - wrapperView.addSubview(buildLabel) - tableView.tableFooterView = wrapperView - } override func viewDidAppear(_ animated: Bool) {