About Views

- Tidied up iOS
- Adds refreshed About view to macOS 12+
- About.plist is now shared
This commit is contained in:
Stuart Breckenridge
2022-10-03 21:16:51 +08:00
parent 2e21018924
commit 05aca1c995
15 changed files with 419 additions and 60 deletions

View File

@@ -30,6 +30,7 @@ public extension Notification.Name {
static let AccountDidDownloadArticles = Notification.Name(rawValue: "AccountDidDownloadArticles")
static let AccountStateDidChange = Notification.Name(rawValue: "AccountStateDidChange")
static let StatusesDidChange = Notification.Name(rawValue: "StatusesDidChange")
static let AboutSelectionDidChange = Notification.Name(rawValue: "AboutSelectionDidChange")
}
public enum AccountType: Int, Codable {

View File

@@ -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,25 @@ 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
}
}
AboutWindowController.default.window?.makeKeyAndOrderFront(nil)
} else {
NSApplication.shared.orderFrontStandardAboutPanel(self)
}
}
@objc
func segmentedControlSelectionChanged(_ sender: NSSegmentedControl) {
NotificationCenter.default.post(name: .AboutSelectionDidChange, object: sender.selectedSegment)
}
}

View File

@@ -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"/>

View File

@@ -0,0 +1,54 @@
//
// 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)
}
}
@available(macOS 12, *)
struct AboutNetNewsWireView_Previews: PreviewProvider {
static var previews: some View {
AboutNetNewsWireView()
}
}

View File

@@ -0,0 +1,42 @@
//
// AboutView.swift
// NetNewsWire
//
// Created by Stuart Breckenridge on 03/10/2022.
// Copyright © 2022 Ranchero Software. All rights reserved.
//
import SwiftUI
@available(macOS 12, *)
struct AboutView: View {
enum AboutSelection: Int {
case about = 0
case credits = 1
}
@State private var selection: AboutSelection = .about
var body: some View {
VStack {
if selection == .about {
AboutNetNewsWireView()
} else {
CreditsNetNewsWireView()
}
}
.onReceive(NotificationCenter.default.publisher(for: .AboutSelectionDidChange)) { newSelection in
selection = AboutSelection(rawValue: newSelection.object as! Int)!
}
.frame(width: 400, height: 400)
}
}
@available(macOS 12, *)
struct AboutView_Previews: PreviewProvider {
static var previews: some View {
AboutView()
}
}

View File

@@ -0,0 +1,101 @@
//
// 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")
}
@available(macOS 12, *)
class AboutWindowController: NSWindowController, NSToolbarDelegate {
static var `default`: AboutWindowController {
let hostingController = NSHostingController(rootView: AboutView())
let window = NSWindow(contentViewController: hostingController)
window.identifier = .aboutNetNewsWire
let controller = AboutWindowController(window: window)
controller.configure()
return controller
}
func configure() {
window?.title = NSLocalizedString("About", comment: "About")
window?.titleVisibility = .hidden
let toolbar = NSToolbar(identifier: NSToolbar.Identifier("netnewswire.about.toolbar"))
toolbar.delegate = self
window?.toolbar = toolbar
window?.toolbarStyle = .unified
toolbar.insertItem(withItemIdentifier: .flexibleSpace, at: 0)
toolbar.insertItem(withItemIdentifier: .flexibleSpace, at: 2)
}
override func windowDidLoad() {
super.windowDidLoad()
}
@objc
func segmentedControlSelectionChanged(_ sender: NSSegmentedControl) {
print(sender)
}
// MARK: NSToolbarDelegate
func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? {
switch itemIdentifier {
case .aboutGroup:
let toolbarItem: NSToolbarItem
let group = NSToolbarItemGroup(itemIdentifier: itemIdentifier)
let segmented = NSSegmentedControl(labels: ["About", "Credits"],
trackingMode: .selectOne,
target: NSApplication.shared.delegate as? AppDelegate,
action: #selector(AppDelegate.segmentedControlSelectionChanged(_:)))
segmented.segmentStyle = .texturedRounded
segmented.segmentCount = 2
segmented.setSelected(true, forSegment: 0)
group.view = segmented
toolbarItem = group
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 [.aboutGroup]
}
}

View 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
creditView(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
creditView(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 creditView(_ 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()
}
}

View 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
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 682 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 682 KiB

View File

@@ -851,6 +851,14 @@
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 */; };
DFC14F0D28EA520E00F6EE86 /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFC14F0C28EA520E00F6EE86 /* AboutView.swift */; };
DFC14F0F28EA55BD00F6EE86 /* AboutWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFC14F0E28EA55BD00F6EE86 /* AboutWindowController.swift */; };
DFC14F1028EA5D7C00F6EE86 /* Thanks.md in Resources */ = {isa = PBXBuildFile; fileRef = DF790D5F28E9769300455FC7 /* Thanks.md */; };
DFC14F1128EA5D7C00F6EE86 /* About.plist in Resources */ = {isa = PBXBuildFile; fileRef = DFFC4E7528E95F78006B82AF /* About.plist */; };
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 */; };
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 */; };
@@ -1591,6 +1599,10 @@
DD82AB09231003F6002269DF /* SharingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharingTests.swift; 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>"; };
DFC14F0C28EA520E00F6EE86 /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.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>"; };
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>"; };
@@ -1856,6 +1868,8 @@
511D43CE231FA51100FB1562 /* Resources */ = {
isa = PBXGroup;
children = (
DFFC4E7528E95F78006B82AF /* About.plist */,
DF790D5F28E9769300455FC7 /* Thanks.md */,
DFD6AACB27ADE80900463FAD /* NewsFax.nnwtheme */,
51DEE81126FB9233006DAA56 /* Appanoose.nnwtheme */,
51077C5727A86D16000C71DB /* Hyperlegible.nnwtheme */,
@@ -1990,7 +2004,6 @@
isa = PBXGroup;
children = (
DFFC4E7328E95C01006B82AF /* AboutView.swift */,
DF790D6128E990A900455FC7 /* AboutData.swift */,
51A16992235E10D600EB091F /* AddAccountViewController.swift */,
519ED455244828C3007F8E94 /* AddExtensionPointViewController.swift */,
5137C2E926F63AE6009EFEDB /* ArticleThemeImporter.swift */,
@@ -2259,6 +2272,7 @@
842E45E11ED8C681000A8B52 /* MainWindow */ = {
isa = PBXGroup;
children = (
DFC14F0928EA51AB00F6EE86 /* About */,
8483630C2262A3FE00DA1D35 /* MainWindow.storyboard */,
51927A0328E28D1C000AE856 /* MainWindow.swift */,
519279FD28E24CCA000AE856 /* MainWindowController.swift */,
@@ -2584,6 +2598,7 @@
84C9FC6822629C9A00D921D6 /* Shared */ = {
isa = PBXGroup;
children = (
DF790D6128E990A900455FC7 /* AboutData.swift */,
842E45CD1ED8C308000A8B52 /* AppNotifications.swift */,
51C4CFEF24D37D1F00AF9874 /* Secrets.swift */,
511B9805237DCAC90028BCAA /* UserInfoKey.swift */,
@@ -2730,8 +2745,6 @@
84C9FC9A2262A1A900D921D6 /* Resources */ = {
isa = PBXGroup;
children = (
DFFC4E7528E95F78006B82AF /* About.plist */,
DF790D5F28E9769300455FC7 /* Thanks.md */,
5103A9B324216A4200410853 /* blank.html */,
51BB7C302335ACDE008E8144 /* page.html */,
514219572353C28900E07E2C /* main_ios.js */,
@@ -2873,6 +2886,17 @@
path = Scriptability;
sourceTree = "<group>";
};
DFC14F0928EA51AB00F6EE86 /* About */ = {
isa = PBXGroup;
children = (
DFC14F0C28EA520E00F6EE86 /* AboutView.swift */,
DFC14F1428EB177000F6EE86 /* AboutNetNewsWireView.swift */,
DFC14F1628EB17A800F6EE86 /* CreditsNetNewsWireView.swift */,
DFC14F0E28EA55BD00F6EE86 /* AboutWindowController.swift */,
);
path = About;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -3477,6 +3501,7 @@
845479881FEB77C000AD8B59 /* TimelineKeyboardShortcuts.plist in Resources */,
848362FF2262A30E00DA1D35 /* template.html in Resources */,
848363082262A3DD00DA1D35 /* Main.storyboard in Resources */,
DFC14F1128EA5D7C00F6EE86 /* About.plist in Resources */,
84C9FC8F22629E8F00D921D6 /* NetNewsWire.sdef in Resources */,
84C9FC7D22629E1200D921D6 /* AccountsDetail.xib in Resources */,
5137C2E426F3F52D009EFEDB /* Sepia.nnwtheme in Resources */,
@@ -3504,6 +3529,7 @@
B528F81E23333C7E00E735DD /* page.html in Resources */,
8483630E2262A3FE00DA1D35 /* MainWindow.storyboard in Resources */,
55E15BCB229D65A900D6602A /* AccountsReaderAPI.xib in Resources */,
DFC14F1028EA5D7C00F6EE86 /* Thanks.md in Resources */,
49F40DF82335B71000552BF4 /* newsfoot.js in Resources */,
51333D3B2468615D00EB5C91 /* AddRedditFeedSheet.xib in Resources */,
BDCB516724282C8A00102A80 /* AccountsNewsBlur.xib in Resources */,
@@ -4297,6 +4323,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 */,
@@ -4316,6 +4343,7 @@
84DEE56522C32CA4005FC42C /* SmartFeedDelegate.swift in Sources */,
845213231FCA5B11003B6E93 /* ImageDownloader.swift in Sources */,
51FA73B72332D5F70090D516 /* LegacyArticleExtractorButton.swift in Sources */,
DFC14F0D28EA520E00F6EE86 /* AboutView.swift in Sources */,
849A97431ED9EAA9007D329B /* AddFolderWindowController.swift in Sources */,
8405DDA522168C62008CE1BF /* TimelineContainerViewController.swift in Sources */,
844B5B671FEA18E300C7C76A /* MainWIndowKeyboardHandler.swift in Sources */,
@@ -4324,12 +4352,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 */,
@@ -4338,6 +4369,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 */,

View File

@@ -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?
}
}

View File

@@ -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>
@@ -42,7 +50,7 @@
<key>name</key>
<string>Nate Weaver</string>
<key>role</key>
<string>Under-the-hood magic and CSS stylins</string>
<string>HTML and CSS</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>

View File

@@ -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.

View File

@@ -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,19 @@ 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(.callout)
.foregroundColor(.secondary)
}
if let _ = appCredit.url {
Image(systemName: "info.circle")
.foregroundColor(.secondary)
}
}
.onTapGesture {
guard let url = appCredit.url else { return }
@@ -82,18 +80,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 +88,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()
}
}
}