mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Merge pull request #3710 from stuartbreckenridge/main
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<menuItem title="About NetNewsWire" id="5kV-Vb-QxS">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="orderFrontStandardAboutPanel:" target="Ady-hI-5gd" id="Exp-CZ-Vem"/>
|
||||
<action selector="showAbout:" target="Voe-Tx-rLC" id="rb3-Tt-EZ4"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
|
||||
|
||||
55
Mac/MainWindow/About/AboutNetNewsWireView.swift
Normal file
55
Mac/MainWindow/About/AboutNetNewsWireView.swift
Normal file
@@ -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()
|
||||
}
|
||||
}
|
||||
131
Mac/MainWindow/About/AboutWindowController.swift
Normal file
131
Mac/MainWindow/About/AboutWindowController.swift
Normal file
@@ -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<AnyView>, 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())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
79
Mac/MainWindow/About/CreditsNetNewsWireView.swift
Normal file
79
Mac/MainWindow/About/CreditsNetNewsWireView.swift
Normal file
@@ -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..<about.PrimaryContributors.count, id: \.self) { i in
|
||||
contributorView(about.PrimaryContributors[i])
|
||||
.padding(.vertical, 2)
|
||||
.listRowInsets(EdgeInsets(top: 0, leading: 12, bottom: 0, trailing: 12))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Section("Additional Contributors") {
|
||||
GroupBox {
|
||||
ForEach(0..<about.AdditionalContributors.count, id: \.self) { i in
|
||||
contributorView(about.AdditionalContributors[i])
|
||||
.padding(.vertical, 2)
|
||||
.listRowInsets(EdgeInsets(top: 0, leading: 12, bottom: 0, trailing: 12))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Section("Thanks") {
|
||||
GroupBox {
|
||||
Text(about.ThanksMarkdown)
|
||||
.multilineTextAlignment(.center)
|
||||
.font(.callout)
|
||||
.padding(.vertical, 2)
|
||||
}
|
||||
|
||||
}
|
||||
Spacer()
|
||||
.frame(height: 12)
|
||||
}
|
||||
.padding(.horizontal)
|
||||
}
|
||||
|
||||
func contributorView(_ appCredit: AboutData.Contributor) -> 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()
|
||||
}
|
||||
}
|
||||
22
Mac/Resources/Assets.xcassets/About.imageset/Contents.json
vendored
Normal file
22
Mac/Resources/Assets.xcassets/About.imageset/Contents.json
vendored
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
BIN
Mac/Resources/Assets.xcassets/About.imageset/Icon-MacOS-512x512@2x 1.png
vendored
Normal file
BIN
Mac/Resources/Assets.xcassets/About.imageset/Icon-MacOS-512x512@2x 1.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 682 KiB |
BIN
Mac/Resources/Assets.xcassets/About.imageset/Icon-MacOS-512x512@2x.png
vendored
Normal file
BIN
Mac/Resources/Assets.xcassets/About.imageset/Icon-MacOS-512x512@2x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 682 KiB |
@@ -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 = "<group>"; };
|
||||
DD82AB09231003F6002269DF /* SharingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharingTests.swift; sourceTree = "<group>"; };
|
||||
DDF9E1D628EDF2FC000BC355 /* notificationSoundBlip.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = notificationSoundBlip.mp3; sourceTree = "<group>"; };
|
||||
DF790D5F28E9769300455FC7 /* Thanks.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Thanks.md; sourceTree = "<group>"; };
|
||||
DF790D6128E990A900455FC7 /* AboutData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutData.swift; sourceTree = "<group>"; };
|
||||
DFC14F0E28EA55BD00F6EE86 /* AboutWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutWindowController.swift; sourceTree = "<group>"; };
|
||||
DFC14F1428EB177000F6EE86 /* AboutNetNewsWireView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutNetNewsWireView.swift; sourceTree = "<group>"; };
|
||||
DFC14F1628EB17A800F6EE86 /* CreditsNetNewsWireView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreditsNetNewsWireView.swift; sourceTree = "<group>"; };
|
||||
DFCE4F9028EF26F000405869 /* About.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = About.plist; sourceTree = "<group>"; };
|
||||
DFCE4F9328EF278300405869 /* Thanks.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = Thanks.md; sourceTree = "<group>"; };
|
||||
DFD6AACB27ADE80900463FAD /* NewsFax.nnwtheme */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = NewsFax.nnwtheme; sourceTree = "<group>"; };
|
||||
DFD6AACD27ADE86E00463FAD /* NewsFax.nnwtheme */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = NewsFax.nnwtheme; sourceTree = "<group>"; };
|
||||
DFFC199727A0D0D7004B7AEF /* NotificationsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsViewController.swift; sourceTree = "<group>"; };
|
||||
DFFC199927A0D32A004B7AEF /* NotificationsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsTableViewCell.swift; sourceTree = "<group>"; };
|
||||
DFFC4E7328E95C01006B82AF /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = "<group>"; };
|
||||
DFFC4E7528E95F78006B82AF /* About.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = About.plist; sourceTree = "<group>"; };
|
||||
FF3ABF09232599450074C542 /* ArticleSorterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleSorterTests.swift; sourceTree = "<group>"; };
|
||||
FF3ABF1423259DDB0074C542 /* ArticleSorter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleSorter.swift; sourceTree = "<group>"; };
|
||||
FFD43E372340F320009E5CA3 /* MarkAsReadAlertController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarkAsReadAlertController.swift; sourceTree = "<group>"; };
|
||||
@@ -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 = "<group>";
|
||||
};
|
||||
DFC14F0928EA51AB00F6EE86 /* About */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DFC14F0E28EA55BD00F6EE86 /* AboutWindowController.swift */,
|
||||
DFC14F1428EB177000F6EE86 /* AboutNetNewsWireView.swift */,
|
||||
DFC14F1628EB17A800F6EE86 /* CreditsNetNewsWireView.swift */,
|
||||
);
|
||||
path = About;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* 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 */,
|
||||
|
||||
@@ -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?
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,15 +2,23 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>AppCredits</key>
|
||||
<key>PrimaryContributors</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>role</key>
|
||||
<string>Lead Developer</string>
|
||||
<key>name</key>
|
||||
<string>Maurice Parker</string>
|
||||
<key>url</key>
|
||||
<string>https://vincode.io</string>
|
||||
<key>role</key>
|
||||
<string>Lead Developer</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Stuart Breckenridge</string>
|
||||
<key>url</key>
|
||||
<string>https://stuartbreckenridge.net</string>
|
||||
<key>role</key>
|
||||
<string>Contributing Developer</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>url</key>
|
||||
@@ -50,7 +58,7 @@
|
||||
<key>name</key>
|
||||
<string>Andrew Brehaut</string>
|
||||
<key>role</key>
|
||||
<string>Newsfoot (JS footnote displayer)</string>
|
||||
<string>Newsfoot Footnotes</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>url</key>
|
||||
@@ -87,12 +95,6 @@
|
||||
<key>url</key>
|
||||
<string>https://blog.rizwan.dev/</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Stuart Breckenridge</string>
|
||||
<key>url</key>
|
||||
<string>https://stuartbreckenridge.net</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Phil Viso</string>
|
||||
@@ -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.
|
||||
@@ -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..<about.AppCredits.count, id: \.self) { i in
|
||||
creditView(about.AppCredits[i])
|
||||
Section(header: Text("Primary Contributors")) {
|
||||
ForEach(0..<about.PrimaryContributors.count, id: \.self) { i in
|
||||
contributorView(about.PrimaryContributors[i])
|
||||
}
|
||||
}
|
||||
Section(header: Text("Additional Contributors")) {
|
||||
ForEach(0..<about.AdditionalContributors.count, id: \.self) { i in
|
||||
contributorView(about.AdditionalContributors[i])
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Section(header: Text("Thanks"), footer: thanks, content: {})
|
||||
Section(footer: copyright, content: {})
|
||||
@@ -54,6 +41,10 @@ struct AboutView: View {
|
||||
|
||||
Text(Bundle.main.appName)
|
||||
.font(.headline)
|
||||
|
||||
Text("\(Bundle.main.versionNumber) (\(Bundle.main.buildNumber))")
|
||||
.foregroundColor(.secondary)
|
||||
.font(.callout)
|
||||
|
||||
Text("By Brent Simmons and the Ranchero Software team.")
|
||||
.font(.subheadline)
|
||||
@@ -67,12 +58,20 @@ struct AboutView: View {
|
||||
.multilineTextAlignment(.center)
|
||||
}
|
||||
|
||||
func creditView(_ appCredit: AboutData.AppCredit) -> 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()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user