💄 Modernise About Panel

This commit is contained in:
Stuar Breckenridge
2025-06-26 17:37:51 +08:00
parent d86cb46b85
commit c6acc1036f
6 changed files with 262 additions and 37 deletions

View File

@@ -0,0 +1,79 @@
//
// AboutWindowController.swift
// NetNewsWire
//
// Created by Stuart Breckenridge on 26/06/2025.
// Copyright © 2025 Ranchero Software. All rights reserved.
//
import Cocoa
class AboutWindowController: NSWindowController {
@IBOutlet weak var appIconImageView: NSImageView!
@IBOutlet weak var appTitleLabel: NSTextField!
@IBOutlet weak var versionLabel: NSTextField!
@IBOutlet weak var copyrightLabel: NSTextField!
@IBOutlet weak var websiteLabel: LinkLabel!
@IBOutlet weak var creditsTextView: NSTextView!
override func windowDidLoad() {
super.windowDidLoad()
configureWindow()
updateUI()
}
func configureWindow() {
window?.isOpaque = false
window?.backgroundColor = .clear
window?.titlebarAppearsTransparent = true
window?.titleVisibility = .hidden
window?.styleMask.insert(.fullSizeContentView)
if let contentView = window?.contentView {
let visualEffectView = NSVisualEffectView(frame: contentView.bounds)
visualEffectView.autoresizingMask = [.width, .height]
visualEffectView.blendingMode = .behindWindow
visualEffectView.material = .titlebar
visualEffectView.state = .active
contentView.addSubview(visualEffectView, positioned: .below, relativeTo: nil)
}
//creditsScrollView.backgroundColor = .clear
//creditsTextView.backgroundColor = .clear
}
private func updateUI() {
let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown"
let build = Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "Unknown"
let versionString = "Version \(version) (Build \(build))"
versionLabel.stringValue = versionString
let copyright = Bundle.main.infoDictionary?["NSHumanReadableCopyright"] as? String ?? "Copyright © 2002-2025 Brent Simmons. All rights reserved."
copyrightLabel.stringValue = copyright
websiteLabel.stringValue = "inessential.com"
appIconImageView.image = NSImage(named: "AppIcon")
if let creditsURL = Bundle.main.url(forResource: "Credits", withExtension: "rtf"),
let creditsData = try? Data(contentsOf: creditsURL),
let attributedString = try? NSAttributedString(data: creditsData, options: [.documentType: NSAttributedString.DocumentType.rtf], documentAttributes: nil) {
creditsTextView.textStorage?.setAttributedString(attributedString)
} else {
creditsTextView.string = "Credits not available."
}
let fullRange = NSRange(location: 0, length: creditsTextView.string.utf16.count)
let centeredParagraphStyle = NSMutableParagraphStyle()
centeredParagraphStyle.alignment = .center
creditsTextView.textStorage?.addAttribute(.paragraphStyle, value: centeredParagraphStyle, range: fullRange)
let url = URL(string: "https://inessential.com")!
let attributedString = NSMutableAttributedString(string: "inessential.com")
attributedString.addAttribute(.link, value: url, range: NSRange(location: 0, length: attributedString.length))
attributedString.addAttribute(.foregroundColor, value: NSColor.systemBlue, range: NSRange(location: 0, length: attributedString.length))
attributedString.addAttribute(.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: NSRange(location: 0, length: attributedString.length))
websiteLabel.attributedStringValue = attributedString
}
}

View File

@@ -0,0 +1,116 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="24093.8" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="24093.8"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="AboutWindowController" customModule="NetNewsWire" customModuleProvider="target">
<connections>
<outlet property="appIconImageView" destination="kFw-rc-wEJ" id="Cgj-qd-V1E"/>
<outlet property="appTitleLabel" destination="zSW-nT-ANt" id="lFq-Kv-hqz"/>
<outlet property="copyrightLabel" destination="aNw-sB-24m" id="dBq-XD-2fE"/>
<outlet property="creditsTextView" destination="hXV-nv-VJf" id="Glp-al-KJm"/>
<outlet property="versionLabel" destination="xLI-yT-116" id="bSA-Ip-EIj"/>
<outlet property="websiteLabel" destination="quK-3X-Mnw" id="796-rs-sUS"/>
<outlet property="window" destination="F0z-JX-Cv5" id="gIp-Ho-8D9"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Window" separatorStyle="none" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" titlebarAppearsTransparent="YES" titleVisibility="hidden" id="F0z-JX-Cv5">
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
<rect key="contentRect" x="196" y="120" width="490" height="274"/>
<rect key="screenRect" x="0.0" y="0.0" width="1728" height="1083"/>
<view key="contentView" id="se5-gp-TjO">
<rect key="frame" x="0.0" y="0.0" width="490" height="274"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="kFw-rc-wEJ">
<rect key="frame" x="66" y="141" width="85" height="85"/>
<constraints>
<constraint firstAttribute="height" constant="85" id="36U-FK-YAn"/>
<constraint firstAttribute="width" constant="85" id="GX8-xO-f4C"/>
</constraints>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="icon" id="G5J-V9-bZN"/>
</imageView>
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zSW-nT-ANt">
<rect key="frame" x="56" y="114" width="105" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="NetNewsWire" id="gJ9-0j-Zg6">
<font key="font" size="16" name="SFProDisplay-Semibold"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="aNw-sB-24m">
<rect key="frame" x="18" y="56" width="181" height="28"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" alignment="center" title="© 2002 - 2025 Brent Simmons. All rights reserved." id="1hS-Cw-3kX">
<font key="font" textStyle="subheadline" name=".SFNS-Regular"/>
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<scrollView fixedFrame="YES" borderType="none" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HQS-xi-g6z">
<rect key="frame" x="214" y="20" width="256" height="206"/>
<autoresizingMask key="autoresizingMask"/>
<clipView key="contentView" drawsBackground="NO" id="aNl-9n-tcX">
<rect key="frame" x="0.0" y="0.0" width="256" height="206"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textView wantsLayer="YES" editable="NO" drawsBackground="NO" importsGraphics="NO" verticallyResizable="YES" allowsCharacterPickerTouchBarItem="NO" textCompletion="NO" spellingCorrection="YES" smartInsertDelete="YES" id="hXV-nv-VJf">
<rect key="frame" x="0.0" y="0.0" width="256" height="206"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<size key="minSize" width="256" height="206"/>
<size key="maxSize" width="256" height="10000000"/>
</textView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</clipView>
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="ZAE-ok-OL5">
<rect key="frame" x="-100" y="-100" width="240" height="17"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="y4e-dI-wGV">
<rect key="frame" x="239" y="0.0" width="17" height="206"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" contentType="url" translatesAutoresizingMaskIntoConstraints="NO" id="quK-3X-Mnw" customClass="LinkLabel" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="64" y="34" width="90" height="14"/>
<textFieldCell key="cell" alignment="center" title="inessential.com" id="TYf-Hx-QuA">
<font key="font" textStyle="subheadline" name=".SFNS-Regular"/>
<color key="textColor" name="linkColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="xLI-yT-116">
<rect key="frame" x="74" y="92" width="69" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Version Text" id="G9F-XS-Hb5">
<font key="font" textStyle="subheadline" name=".SFNS-Regular"/>
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstAttribute="bottom" secondItem="quK-3X-Mnw" secondAttribute="bottom" constant="34" id="0Vv-qV-Blm"/>
<constraint firstItem="kFw-rc-wEJ" firstAttribute="leading" secondItem="se5-gp-TjO" secondAttribute="leading" constant="66" id="4zV-p0-XWQ"/>
<constraint firstItem="kFw-rc-wEJ" firstAttribute="top" secondItem="se5-gp-TjO" secondAttribute="top" constant="48" id="dvK-Oy-KgA"/>
<constraint firstItem="quK-3X-Mnw" firstAttribute="centerX" secondItem="kFw-rc-wEJ" secondAttribute="centerX" id="zuU-IM-WmK"/>
</constraints>
</view>
<connections>
<outlet property="delegate" destination="-2" id="0bl-1N-AYu"/>
</connections>
<point key="canvasLocation" x="144" y="132"/>
</window>
</objects>
<resources>
<image name="icon" width="128" height="128"/>
</resources>
</document>

16
Mac/About/LinkLabel.swift Normal file
View File

@@ -0,0 +1,16 @@
//
// LinkLabel.swift
// NetNewsWire
//
// Created by Stuart Breckenridge on 26/06/2025.
// Copyright © 2025 Ranchero Software. All rights reserved.
//
class LinkLabel: NSTextField {
/// pièces de résistance -- keeping it a mac-assed mac app.
override func resetCursorRects() {
addCursorRect(bounds, cursor: .pointingHand)
}
}

View File

@@ -277,7 +277,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
CrashReporter.check(crashReporter: self.crashReporter)
}
#endif
}
func application(_ application: NSApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([NSUserActivityRestoring]) -> Void) -> Bool {
@@ -675,6 +674,13 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
createAndShowMainWindowIfNecessary()
mainWindowController!.gotoStarred(sender)
}
@IBAction func showCustomAboutPanel(_ sender: Any?) {
let aboutWC = AboutWindowController(windowNibName: "AboutWindowController")
aboutWC.showWindow(nil)
aboutWC.window?.center()
aboutWC.window?.makeKeyAndOrderFront(nil)
}
@IBAction func sortByOldestArticleOnTop(_ sender: Any?) {

View File

@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="23504" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="24093.8" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="23504"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="24093.8"/>
</dependencies>
<scenes>
<!--Application-->
@@ -18,7 +17,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="showCustomAboutPanel:" target="Voe-Tx-rLC" id="ZQV-QH-KmS"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>

View File

@@ -3,50 +3,59 @@
{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
{\*\expandedcolortbl;;\cssrgb\c0\c0\c0\cname textColor;}
\vieww14060\viewh15660\viewkind0
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\sl360\slmult1\pardirnatural\partightenfactor0
{\field{\*\fldinst{HYPERLINK "https://ranchero.com/netnewswire/"}}{\fldrslt
\f0\b\fs22 \cf2 NetNewsWire}}
\f0\b\fs22 \cf2 \
By Brent Simmons\
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\sl360\slmult1\pardirnatural\partightenfactor0
{\field{\*\fldinst{HYPERLINK "http://inessential.com/"}}{\fldrslt \cf2 inessential.com}}
\deftab720
\pard\pardeftab720\sa60\partightenfactor0
\f0\b\fs22 \cf2 Credits
\f1\b0 \
\
\pard\pardeftab720\sl120\slmult1\sa60\partightenfactor0
\cf2 Contributing Developers \
{\field{\*\fldinst{HYPERLINK "https://github.com/vincode-io"}}{\fldrslt Maurice Parker}}, {\field{\*\fldinst{HYPERLINK "https://stuartbreckenridge.net/"}}{\fldrslt Stuart Breckenridge}}\
\
App Icon\
{\field{\*\fldinst{HYPERLINK "https://twitter.com/BradEllis"}}{\fldrslt Brad Ellis}}\
\
Feedly Syncing\
{\field{\*\fldinst{HYPERLINK "https://twitter.com/kielgillard"}}{\fldrslt Kiel Gillard}}\
\
NewsBlur Syncing\
{\field{\*\fldinst{HYPERLINK "https://twitter.com/quanganhdo"}}{\fldrslt Anh Do}}\
\
Under-the-Hood Magic and CSS Stylin's\
{\field{\*\fldinst{HYPERLINK "https://github.com/wevah"}}{\fldrslt Nate Weaver}}\
\
Newsfoot (JS footnote displayer)\
{\field{\*\fldinst{HYPERLINK "https://github.com/brehaut/"}}{\fldrslt Andrew Brehaut}}\
\
Help Book\
{\field{\*\fldinst{HYPERLINK "https://nostodnayr.net/"}}{\fldrslt Ryan Dotson}}\
\
And featuring contributions from\
{\field{\*\fldinst{HYPERLINK "https://github.com/danielpunkass"}}{\fldrslt Daniel Jalkut}}, {\field{\*\fldinst{HYPERLINK "https://rhonabwy.com/"}}{\fldrslt Joe Heck}}, {\field{\*\fldinst{HYPERLINK "https://github.com/olofhellman"}}{\fldrslt Olof Hellman}}, {\field{\*\fldinst{HYPERLINK "https://blog.rizwan.dev/"}}{\fldrslt Rizwan Mohamed Ibrahim}}, {\field{\*\fldinst{HYPERLINK "https://twitter.com/philviso"}}{\fldrslt Phil Viso}}, and {\field{\*\fldinst{HYPERLINK "https://github.com/Ranchero-Software/NetNewsWire/graphs/contributors"}}{\fldrslt many more}}!\
\pard\pardeftab720\li360\sa60\partightenfactor0
\cf2 \
\pard\pardeftab720\sa60\partightenfactor0
\f0\b \cf2 Credits:
\f0\b \cf2 Acknowledgments\
\f1\b0 \
{\field{\*\fldinst{HYPERLINK "https://github.com/ccgus/fmdb"}}{\fldrslt FMDB}} (greatest SQLite wrapper ever in history) is by {\field{\*\fldinst{HYPERLINK "http://flyingmeat.com/"}}{\fldrslt Flying Meat Software}}.\
{\field{\*\fldinst{HYPERLINK "https://sparkle-project.org/"}}{\fldrslt Sparkle}} is by Sparkle Project.\
\pard\pardeftab720\li360\sa60\partightenfactor0
\cf2 Contributing developers: {\field{\*\fldinst{HYPERLINK "https://github.com/vincode-io"}}{\fldrslt Maurice Parker}}, {\field{\*\fldinst{HYPERLINK "https://stuartbreckenridge.net/"}}{\fldrslt Stuart Breckenridge}}\
App icon: {\field{\*\fldinst{HYPERLINK "https://twitter.com/BradEllis"}}{\fldrslt Brad Ellis}}\
Feedly syncing: {\field{\*\fldinst{HYPERLINK "https://twitter.com/kielgillard"}}{\fldrslt Kiel Gillard}}\
NewsBlur syncing: {\field{\*\fldinst{HYPERLINK "https://twitter.com/quanganhdo"}}{\fldrslt Anh Do}}\
Under-the-hood magic and CSS stylin\'92s: {\field{\*\fldinst{HYPERLINK "https://github.com/wevah"}}{\fldrslt Nate Weaver}}\
Newsfoot (JS footnote displayer): {\field{\*\fldinst{HYPERLINK "https://github.com/brehaut/"}}{\fldrslt Andrew Brehaut}}\
Help book: {\field{\*\fldinst{HYPERLINK "https://nostodnayr.net/"}}{\fldrslt Ryan Dotson}}\
And featuring contributions from {\field{\*\fldinst{HYPERLINK "https://github.com/danielpunkass"}}{\fldrslt Daniel Jalkut}}, {\field{\*\fldinst{HYPERLINK "https://rhonabwy.com/"}}{\fldrslt Joe Heck}}, {\field{\*\fldinst{HYPERLINK "https://github.com/olofhellman"}}{\fldrslt Olof Hellman}}, {\field{\*\fldinst{HYPERLINK "https://blog.rizwan.dev/"}}{\fldrslt Rizwan Mohamed Ibrahim}}, {\field{\*\fldinst{HYPERLINK "https://twitter.com/philviso"}}{\fldrslt Phil Viso}}, and {\field{\*\fldinst{HYPERLINK "https://github.com/Ranchero-Software/NetNewsWire/graphs/contributors"}}{\fldrslt many more}}!\
\
\cf2 \
\pard\pardeftab720\sa60\partightenfactor0
\f0\b \cf2 Acknowledgments:
\f1\b0 \
\pard\pardeftab720\li360\sa60\partightenfactor0
{\field{\*\fldinst{HYPERLINK "https://github.com/ccgus/fmdb"}}{\fldrslt \cf2 FMDB}} (greatest SQLite wrapper ever in history) is by {\field{\*\fldinst{HYPERLINK "http://flyingmeat.com/"}}{\fldrslt Flying Meat Software}}.\
\pard\pardeftab720\li360\sa60\partightenfactor0
{\field{\*\fldinst{HYPERLINK "https://sparkle-project.org/"}}{\fldrslt \cf2 Sparkle}} is by Sparkle Project.\
\f0\b \cf2 Thanks\
\
\f1\b0 Thanks to Sheila and my family; thanks to my friends in Seattle and around the globe; thanks to the ever-patient and ever-awesome NetNewsWire beta testers. Thanks to {\field{\*\fldinst{HYPERLINK "https://github.com/"}}{\fldrslt GitHub}} and {\field{\*\fldinst{HYPERLINK "https://slack.com/"}}{\fldrslt Slack}} for making open source collaboration easy and fun.\
\pard\pardeftab720\li360\sa60\partightenfactor0
\cf2 \
\pard\pardeftab720\sa60\partightenfactor0
\f0\b \cf2 Thanks:\
\pard\pardeftab720\li360\sa60\partightenfactor0
\f1\b0 \cf2 Thanks to Sheila and my family; thanks to my friends in Seattle and around the globe; thanks to the ever-patient and ever-awesome NetNewsWire beta testers. Thanks to {\field{\*\fldinst{HYPERLINK "https://github.com/"}}{\fldrslt GitHub}} and {\field{\*\fldinst{HYPERLINK "https://slack.com/"}}{\fldrslt Slack}} for making open source collaboration easy and fun.\
\f0\b \cf2 Dedication\
\
\pard\pardeftab720\sa60\partightenfactor0
\f0\b \cf2 Dedication:\
\pard\pardeftab720\li360\sa60\partightenfactor0
\f1\b0 \cf2 NetNewsWire 6 is dedicated to everyone working to save democracy around the world.\
\f1\b0 NetNewsWire 6 is dedicated to everyone working to save democracy around the world.\
}