mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Create shared AppDefaults and delete platform-specific AppDefaults.
This commit is contained in:
662
Shared/Defaults/AppDefaults.swift
Normal file
662
Shared/Defaults/AppDefaults.swift
Normal file
@@ -0,0 +1,662 @@
|
||||
//
|
||||
// AppDefaults.swift
|
||||
// NetNewsWire
|
||||
//
|
||||
// Created by Brent Simmons on 1/25/25.
|
||||
// Copyright © 2025 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
#if os(macOS)
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
struct AppDefaults {
|
||||
|
||||
enum Key: String {
|
||||
case firstRunDate
|
||||
case lastImageCacheFlushDate
|
||||
case timelineGroupByFeed
|
||||
case timelineSortDirection
|
||||
case addFeedAccountID
|
||||
case addFeedFolderName
|
||||
case addFolderAccountID
|
||||
case currentThemeName
|
||||
case articleContentJavascriptEnabled
|
||||
|
||||
#if os(macOS)
|
||||
case windowState
|
||||
case sidebarFontSize
|
||||
case timelineFontSize
|
||||
case detailFontSize
|
||||
case openInBrowserInBackground
|
||||
case subscribeToFeedsInDefaultBrowser
|
||||
case articleTextSize
|
||||
case refreshInterval
|
||||
case importOPMLAccountID
|
||||
case exportOPMLAccountID
|
||||
case defaultBrowserID
|
||||
|
||||
case webInspectorEnabled = "WebInspectorEnabled"
|
||||
case webInspectorStartsAttached = "__WebInspectorPageGroupLevel1__.WebKit2InspectorStartsAttached"
|
||||
|
||||
// Hidden prefs
|
||||
case showDebugMenu
|
||||
case timelineShowsSeparators = "CorreiaSeparators"
|
||||
case showTitleOnMainWindow = "KafasisTitleMode"
|
||||
case feedDoubleClickMarkAsRead = "GruberFeedDoubleClickMarkAsRead"
|
||||
case suppressSyncOnLaunch = "DevroeSuppressSyncOnLaunch"
|
||||
|
||||
#elseif os(iOS)
|
||||
case userInterfaceColorPalette
|
||||
case refreshClearsReadArticles
|
||||
case timelineNumberOfLines
|
||||
case timelineIconDimension = "timelineIconSize"
|
||||
case articleFullscreenAvailable
|
||||
case articleFullscreenEnabled
|
||||
case confirmMarkAllAsRead
|
||||
case lastRefresh
|
||||
case useSystemBrowser
|
||||
#endif
|
||||
}
|
||||
|
||||
static let defaultThemeName = "Default"
|
||||
|
||||
static let isDeveloperBuild: Bool = {
|
||||
if let dev = Bundle.main.object(forInfoDictionaryKey: "DeveloperEntitlements") as? String, dev == "-dev" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}()
|
||||
|
||||
static let isFirstRun: Bool = {
|
||||
if firstRunDate == nil {
|
||||
firstRunDate = Date()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}()
|
||||
|
||||
#if os(macOS)
|
||||
static func registerDefaults() {
|
||||
|
||||
#if DEBUG
|
||||
let showDebugMenu = true
|
||||
#else
|
||||
let showDebugMenu = false
|
||||
#endif
|
||||
|
||||
let defaults: [String: Any] = [
|
||||
Key.sidebarFontSize.rawValue: FontSize.medium.rawValue,
|
||||
Key.timelineFontSize.rawValue: FontSize.medium.rawValue,
|
||||
Key.detailFontSize.rawValue: FontSize.medium.rawValue,
|
||||
Key.timelineSortDirection.rawValue: ComparisonResult.orderedDescending.rawValue,
|
||||
Key.timelineGroupByFeed.rawValue: false,
|
||||
Key.refreshInterval.rawValue: RefreshInterval.everyHour.rawValue,
|
||||
Key.showDebugMenu.rawValue: showDebugMenu,
|
||||
Key.currentThemeName.rawValue: Self.defaultThemeName,
|
||||
Key.articleContentJavascriptEnabled.rawValue: true,
|
||||
"NSScrollViewShouldScrollUnderTitlebar": false
|
||||
]
|
||||
UserDefaults.standard.register(defaults: defaults)
|
||||
}
|
||||
#elseif os(iOS)
|
||||
|
||||
static func registerDefaults() {
|
||||
|
||||
// TODO: migrate all (or as many as possible) out of shared
|
||||
let sharedDefaults: [String: Any] = [
|
||||
Key.userInterfaceColorPalette.rawValue: UserInterfaceColorPalette.automatic.rawValue,
|
||||
Key.timelineGroupByFeed.rawValue: false,
|
||||
Key.refreshClearsReadArticles.rawValue: false,
|
||||
Key.timelineNumberOfLines.rawValue: 2,
|
||||
Key.timelineIconDimension.rawValue: IconSize.medium.rawValue,
|
||||
Key.timelineSortDirection.rawValue: ComparisonResult.orderedDescending.rawValue,
|
||||
Key.articleFullscreenAvailable.rawValue: false,
|
||||
Key.articleFullscreenEnabled.rawValue: false,
|
||||
Key.confirmMarkAllAsRead.rawValue: true
|
||||
]
|
||||
appGroupStorage.register(defaults: sharedDefaults)
|
||||
|
||||
let defaults: [String: Any] = [
|
||||
Key.currentThemeName.rawValue: Self.defaultThemeName,
|
||||
Key.articleContentJavascriptEnabled.rawValue: true
|
||||
]
|
||||
UserDefaults.standard.register(defaults: defaults)
|
||||
}
|
||||
#endif
|
||||
|
||||
static var addFeedAccountID: String? {
|
||||
get {
|
||||
string(key: .addFeedAccountID)
|
||||
}
|
||||
set {
|
||||
setString(newValue, key: .addFeedAccountID)
|
||||
}
|
||||
}
|
||||
|
||||
static var addFeedFolderName: String? {
|
||||
get {
|
||||
string(key: .addFeedFolderName)
|
||||
}
|
||||
set {
|
||||
setString(newValue, key: .addFeedFolderName)
|
||||
}
|
||||
}
|
||||
|
||||
static var addFolderAccountID: String? {
|
||||
get {
|
||||
string(key: .addFolderAccountID)
|
||||
}
|
||||
set {
|
||||
setString(newValue, key: .addFolderAccountID)
|
||||
}
|
||||
}
|
||||
|
||||
static var currentThemeName: String? {
|
||||
get {
|
||||
string(key: .currentThemeName)
|
||||
}
|
||||
set {
|
||||
setString(newValue, key: .currentThemeName)
|
||||
}
|
||||
}
|
||||
|
||||
static var isArticleContentJavascriptEnabled: Bool {
|
||||
get {
|
||||
bool(key: .articleContentJavascriptEnabled)
|
||||
}
|
||||
set {
|
||||
setBool(newValue, key: .articleContentJavascriptEnabled)
|
||||
}
|
||||
}
|
||||
|
||||
#if os(macOS)
|
||||
static var timelineGroupByFeed: Bool {
|
||||
get {
|
||||
bool(key: .timelineGroupByFeed)
|
||||
}
|
||||
set {
|
||||
setBool(newValue, key: .timelineGroupByFeed)
|
||||
}
|
||||
}
|
||||
#elseif os(iOS)
|
||||
static var timelineGroupByFeed: Bool {
|
||||
// TODO: migrate to not shared
|
||||
get {
|
||||
sharedBool(key: .timelineGroupByFeed)
|
||||
}
|
||||
set {
|
||||
setSharedBool(newValue, key: .timelineGroupByFeed)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if os(macOS)
|
||||
static var timelineSortDirection: ComparisonResult {
|
||||
get {
|
||||
sortDirection(key: .timelineSortDirection)
|
||||
}
|
||||
set {
|
||||
setSortDirection(newValue, key: .timelineSortDirection)
|
||||
}
|
||||
}
|
||||
#else
|
||||
static var timelineSortDirection: ComparisonResult {
|
||||
// TODO: migrate to not shared
|
||||
get {
|
||||
sharedSortDirection(key: .timelineSortDirection)
|
||||
}
|
||||
set {
|
||||
setSharedSortDirection(newValue, key: .timelineSortDirection)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if os(macOS)
|
||||
static var lastImageCacheFlushDate: Date? {
|
||||
get {
|
||||
date(key: .lastImageCacheFlushDate)
|
||||
}
|
||||
set {
|
||||
setDate(newValue, key: .lastImageCacheFlushDate)
|
||||
}
|
||||
}
|
||||
#else
|
||||
static var lastImageCacheFlushDate: Date? {
|
||||
// TODO: migrate to not shared
|
||||
get {
|
||||
sharedDate(key: .lastImageCacheFlushDate)
|
||||
}
|
||||
set {
|
||||
setSharedDate(newValue, key: .lastImageCacheFlushDate)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// MARK: - Mac-only Defaults
|
||||
|
||||
#if os(macOS)
|
||||
|
||||
extension AppDefaults {
|
||||
|
||||
static var windowState: [AnyHashable: Any]? {
|
||||
get {
|
||||
UserDefaults.standard.object(forKey: Key.windowState.rawValue) as? [AnyHashable: Any]
|
||||
}
|
||||
set {
|
||||
UserDefaults.standard.set(newValue, forKey: Key.windowState.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
static var sidebarFontSize: FontSize {
|
||||
get {
|
||||
fontSize(key: .sidebarFontSize)
|
||||
}
|
||||
set {
|
||||
setFontSize(newValue, key: .sidebarFontSize)
|
||||
}
|
||||
}
|
||||
|
||||
static var timelineFontSize: FontSize {
|
||||
get {
|
||||
fontSize(key: .timelineFontSize)
|
||||
}
|
||||
set {
|
||||
setFontSize(newValue, key: .timelineFontSize)
|
||||
}
|
||||
}
|
||||
|
||||
static var detailFontSize: FontSize {
|
||||
get {
|
||||
fontSize(key: .detailFontSize)
|
||||
}
|
||||
set {
|
||||
setFontSize(newValue, key: .detailFontSize)
|
||||
}
|
||||
}
|
||||
|
||||
static var importOPMLAccountID: String? {
|
||||
get {
|
||||
string(key: .importOPMLAccountID)
|
||||
}
|
||||
set {
|
||||
setString(newValue, key: .importOPMLAccountID)
|
||||
}
|
||||
}
|
||||
|
||||
static var exportOPMLAccountID: String? {
|
||||
get {
|
||||
string(key: .exportOPMLAccountID)
|
||||
}
|
||||
set {
|
||||
setString(newValue, key: .exportOPMLAccountID)
|
||||
}
|
||||
}
|
||||
|
||||
static var defaultBrowserID: String? {
|
||||
get {
|
||||
string(key: .defaultBrowserID)
|
||||
}
|
||||
set {
|
||||
setString(newValue, key: .defaultBrowserID)
|
||||
}
|
||||
}
|
||||
|
||||
static var refreshInterval: RefreshInterval {
|
||||
get {
|
||||
let rawValue = int(key: .refreshInterval)
|
||||
return RefreshInterval(rawValue: rawValue) ?? RefreshInterval.everyHour
|
||||
}
|
||||
set {
|
||||
setInt(newValue.rawValue, key: .refreshInterval)
|
||||
}
|
||||
}
|
||||
|
||||
static var openInBrowserInBackground: Bool {
|
||||
get {
|
||||
bool(key: .openInBrowserInBackground)
|
||||
}
|
||||
set {
|
||||
setBool(newValue, key: .openInBrowserInBackground)
|
||||
}
|
||||
}
|
||||
|
||||
/// Shared with Subscribe to Feed Safari extension.
|
||||
static var subscribeToFeedsInDefaultBrowser: Bool {
|
||||
get {
|
||||
sharedBool(key: .subscribeToFeedsInDefaultBrowser)
|
||||
}
|
||||
set {
|
||||
setSharedBool(newValue, key: .subscribeToFeedsInDefaultBrowser)
|
||||
}
|
||||
}
|
||||
|
||||
static var articleTextSize: ArticleTextSize {
|
||||
get {
|
||||
let rawValue = int(key: .articleTextSize)
|
||||
return ArticleTextSize(rawValue: rawValue) ?? ArticleTextSize.large
|
||||
}
|
||||
set {
|
||||
setInt(newValue.rawValue, key: .articleTextSize)
|
||||
}
|
||||
}
|
||||
|
||||
static var webInspectorEnabled: Bool {
|
||||
get {
|
||||
bool(key: .webInspectorEnabled)
|
||||
}
|
||||
set {
|
||||
setBool(newValue, key: .webInspectorEnabled)
|
||||
}
|
||||
}
|
||||
|
||||
static var webInspectorStartsAttached: Bool {
|
||||
get {
|
||||
bool(key: .webInspectorStartsAttached)
|
||||
}
|
||||
set {
|
||||
setBool(newValue, key: .webInspectorStartsAttached)
|
||||
}
|
||||
}
|
||||
|
||||
private static let smallestFontSizeRawValue = FontSize.small.rawValue
|
||||
private static let largestFontSizeRawValue = FontSize.veryLarge.rawValue
|
||||
|
||||
static func fontSize(key: Key) -> FontSize {
|
||||
// Punted till after 1.0.
|
||||
return .medium
|
||||
|
||||
// var rawFontSize = int(for: key)
|
||||
// if rawFontSize < smallestFontSizeRawValue {
|
||||
// rawFontSize = smallestFontSizeRawValue
|
||||
// }
|
||||
// if rawFontSize > largestFontSizeRawValue {
|
||||
// rawFontSize = largestFontSizeRawValue
|
||||
// }
|
||||
// return FontSize(rawValue: rawFontSize)!
|
||||
}
|
||||
|
||||
static func setFontSize(_ fontSize: FontSize, key: Key) {
|
||||
setInt(fontSize.rawValue, key: key)
|
||||
}
|
||||
|
||||
static func actualFontSize(for fontSize: FontSize) -> CGFloat {
|
||||
switch fontSize {
|
||||
case .small:
|
||||
return NSFont.systemFontSize
|
||||
case .medium:
|
||||
return actualFontSize(for: .small) + 1.0
|
||||
case .large:
|
||||
return actualFontSize(for: .medium) + 4.0
|
||||
case .veryLarge:
|
||||
return actualFontSize(for: .large) + 8.0
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Hidden prefs
|
||||
|
||||
static var showTitleOnMainWindow: Bool {
|
||||
bool(key: .showTitleOnMainWindow)
|
||||
}
|
||||
|
||||
static var showDebugMenu: Bool {
|
||||
bool(key: .showDebugMenu)
|
||||
}
|
||||
|
||||
static var suppressSyncOnLaunch: Bool {
|
||||
bool(key: .suppressSyncOnLaunch)
|
||||
}
|
||||
|
||||
static var timelineShowsSeparators: Bool {
|
||||
bool(key: .timelineShowsSeparators)
|
||||
}
|
||||
|
||||
static var feedDoubleClickMarkAsRead: Bool {
|
||||
bool(key: .feedDoubleClickMarkAsRead)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// MARK: - iOS-only Defaults
|
||||
|
||||
#if os(iOS)
|
||||
|
||||
extension AppDefaults {
|
||||
|
||||
static var userInterfaceColorPalette: UserInterfaceColorPalette {
|
||||
// TODO: migrate to not shared
|
||||
get {
|
||||
if let result = UserInterfaceColorPalette(rawValue: sharedInt(key: .userInterfaceColorPalette)) {
|
||||
return result
|
||||
}
|
||||
return .automatic
|
||||
}
|
||||
set {
|
||||
setSharedInt(newValue.rawValue, key: .userInterfaceColorPalette)
|
||||
}
|
||||
}
|
||||
|
||||
static var refreshClearsReadArticles: Bool {
|
||||
// TODO: migrate to not shared
|
||||
get {
|
||||
sharedBool(key: .refreshClearsReadArticles)
|
||||
}
|
||||
set {
|
||||
setSharedBool(newValue, key: .refreshClearsReadArticles)
|
||||
}
|
||||
}
|
||||
|
||||
static var useSystemBrowser: Bool {
|
||||
get {
|
||||
bool(key: .useSystemBrowser)
|
||||
}
|
||||
set {
|
||||
setBool(newValue, key: .useSystemBrowser)
|
||||
}
|
||||
}
|
||||
|
||||
static var timelineIconSize: IconSize {
|
||||
// TODO: migrate to not shared
|
||||
get {
|
||||
let rawValue = sharedInt(key: .timelineIconDimension)
|
||||
return IconSize(rawValue: rawValue) ?? IconSize.medium
|
||||
}
|
||||
set {
|
||||
setSharedInt(newValue.rawValue, key: .timelineIconDimension)
|
||||
}
|
||||
}
|
||||
|
||||
static var articleFullscreenAvailable: Bool {
|
||||
// TODO: migrate to not shared
|
||||
get {
|
||||
sharedBool(key: .articleFullscreenAvailable)
|
||||
}
|
||||
set {
|
||||
setSharedBool(newValue, key: .articleFullscreenAvailable)
|
||||
}
|
||||
}
|
||||
|
||||
static var articleFullscreenEnabled: Bool {
|
||||
// TODO: migrate to not shared
|
||||
get {
|
||||
sharedBool(key: .articleFullscreenEnabled)
|
||||
}
|
||||
set {
|
||||
setSharedBool(newValue, key: .articleFullscreenEnabled)
|
||||
}
|
||||
}
|
||||
|
||||
static var logicalArticleFullscreenEnabled: Bool {
|
||||
articleFullscreenAvailable && articleFullscreenEnabled
|
||||
}
|
||||
|
||||
static var confirmMarkAllAsRead: Bool {
|
||||
// TODO: migrate to not shared
|
||||
get {
|
||||
sharedBool(key: .confirmMarkAllAsRead)
|
||||
}
|
||||
set {
|
||||
setSharedBool(newValue, key: .confirmMarkAllAsRead)
|
||||
}
|
||||
}
|
||||
|
||||
static var lastRefresh: Date? {
|
||||
// TODO: migrate to not shared
|
||||
get {
|
||||
sharedDate(key: .lastRefresh)
|
||||
}
|
||||
set {
|
||||
setSharedDate(newValue, key: .lastRefresh)
|
||||
}
|
||||
}
|
||||
|
||||
static var timelineNumberOfLines: Int {
|
||||
// TODO: migrate to not shared
|
||||
get {
|
||||
sharedInt(key: .timelineNumberOfLines)
|
||||
}
|
||||
set {
|
||||
setSharedInt(newValue, key: .timelineNumberOfLines)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private extension AppDefaults {
|
||||
|
||||
#if os(macOS)
|
||||
static var firstRunDate: Date? {
|
||||
get {
|
||||
date(key: .firstRunDate)
|
||||
}
|
||||
set {
|
||||
setDate(newValue, key: .firstRunDate)
|
||||
}
|
||||
}
|
||||
#elseif os(iOS)
|
||||
static var firstRunDate: Date? {
|
||||
get {
|
||||
sharedDate(key: .firstRunDate)
|
||||
}
|
||||
set {
|
||||
setSharedDate(newValue, key: .firstRunDate)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static func bool(key: Key) -> Bool {
|
||||
UserDefaults.standard.bool(forKey: key.rawValue)
|
||||
}
|
||||
|
||||
static func setBool(_ flag: Bool, key: Key) {
|
||||
UserDefaults.standard.set(flag, forKey: key.rawValue)
|
||||
}
|
||||
|
||||
static func int(key: Key) -> Int {
|
||||
UserDefaults.standard.integer(forKey: key.rawValue)
|
||||
}
|
||||
|
||||
static func setInt(_ x: Int, key: Key) {
|
||||
UserDefaults.standard.set(x, forKey: key.rawValue)
|
||||
}
|
||||
|
||||
static func date(key: Key) -> Date? {
|
||||
UserDefaults.standard.object(forKey: key.rawValue) as? Date
|
||||
}
|
||||
|
||||
static func setDate(_ date: Date?, key: Key) {
|
||||
UserDefaults.standard.set(date, forKey: key.rawValue)
|
||||
}
|
||||
|
||||
static func string(key: Key) -> String? {
|
||||
return UserDefaults.standard.string(forKey: key.rawValue)
|
||||
}
|
||||
|
||||
static func setString(_ value: String?, key: Key) {
|
||||
UserDefaults.standard.set(value, forKey: key.rawValue)
|
||||
}
|
||||
|
||||
static func sortDirection(key: Key) -> ComparisonResult {
|
||||
let rawInt = int(key: key)
|
||||
if rawInt == ComparisonResult.orderedAscending.rawValue {
|
||||
return .orderedAscending
|
||||
}
|
||||
return .orderedDescending
|
||||
}
|
||||
|
||||
static func setSortDirection(_ value: ComparisonResult, key: Key) {
|
||||
if value == .orderedAscending {
|
||||
setInt(ComparisonResult.orderedAscending.rawValue, key: key)
|
||||
} else {
|
||||
setInt(ComparisonResult.orderedDescending.rawValue, key: key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - App Group Storage
|
||||
|
||||
// These are for preferences that are shared between the app and extensions and widgets.
|
||||
// These are to be used *only* for preferences for that are actually shared, which should be rare.
|
||||
|
||||
private extension AppDefaults {
|
||||
|
||||
static var appGroupStorage: UserDefaults = {
|
||||
|
||||
#if os(macOS)
|
||||
let appGroupSuiteName = Bundle.main.object(forInfoDictionaryKey: "AppGroup") as! String
|
||||
#elseif os(iOS)
|
||||
let appIdentifierPrefix = Bundle.main.object(forInfoDictionaryKey: "AppIdentifierPrefix") as! String
|
||||
let appGroupSuiteName = "\(appIdentifierPrefix)group.\(Bundle.main.bundleIdentifier!)"
|
||||
#endif
|
||||
|
||||
return UserDefaults(suiteName: appGroupSuiteName)!
|
||||
}()
|
||||
|
||||
static func sharedBool(key: Key) -> Bool {
|
||||
appGroupStorage.bool(forKey: key.rawValue)
|
||||
}
|
||||
|
||||
static func setSharedBool(_ flag: Bool, key: Key) {
|
||||
appGroupStorage.set(flag, forKey: key.rawValue)
|
||||
}
|
||||
|
||||
#if os(iOS)
|
||||
static func sharedInt(key: Key) -> Int {
|
||||
appGroupStorage.integer(forKey: key.rawValue)
|
||||
}
|
||||
|
||||
static func setSharedInt(_ x: Int, key: Key) {
|
||||
appGroupStorage.set(x, forKey: key.rawValue)
|
||||
}
|
||||
|
||||
static func sharedDate(key: Key) -> Date? {
|
||||
appGroupStorage.object(forKey: key.rawValue) as? Date
|
||||
}
|
||||
|
||||
static func setSharedDate(_ date: Date?, key: Key) {
|
||||
appGroupStorage.set(date, forKey: key.rawValue)
|
||||
}
|
||||
|
||||
static func sharedSortDirection(key: Key) -> ComparisonResult {
|
||||
let rawInt = sharedInt(key: key)
|
||||
if rawInt == ComparisonResult.orderedAscending.rawValue {
|
||||
return .orderedAscending
|
||||
}
|
||||
return .orderedDescending
|
||||
}
|
||||
|
||||
static func setSharedSortDirection(_ value: ComparisonResult, key: Key) {
|
||||
if value == .orderedAscending {
|
||||
setSharedInt(ComparisonResult.orderedAscending.rawValue, key: key)
|
||||
} else {
|
||||
setSharedInt(ComparisonResult.orderedDescending.rawValue, key: key)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
49
Shared/Defaults/ArticleTextSize.swift
Normal file
49
Shared/Defaults/ArticleTextSize.swift
Normal file
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// ArticleTextSize.swift
|
||||
// NetNewsWire
|
||||
//
|
||||
// Created by Brent Simmons on 1/26/25.
|
||||
// Copyright © 2025 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum ArticleTextSize: Int, CaseIterable, Identifiable {
|
||||
case small = 1
|
||||
case medium = 2
|
||||
case large = 3
|
||||
case xlarge = 4
|
||||
case xxlarge = 5
|
||||
|
||||
var id: String { description() }
|
||||
|
||||
var cssClass: String {
|
||||
switch self {
|
||||
case .small:
|
||||
return "smallText"
|
||||
case .medium:
|
||||
return "mediumText"
|
||||
case .large:
|
||||
return "largeText"
|
||||
case .xlarge:
|
||||
return "xLargeText"
|
||||
case .xxlarge:
|
||||
return "xxLargeText"
|
||||
}
|
||||
}
|
||||
|
||||
func description() -> String {
|
||||
switch self {
|
||||
case .small:
|
||||
return NSLocalizedString("Small", comment: "Small")
|
||||
case .medium:
|
||||
return NSLocalizedString("Medium", comment: "Medium")
|
||||
case .large:
|
||||
return NSLocalizedString("Large", comment: "Large")
|
||||
case .xlarge:
|
||||
return NSLocalizedString("Extra Large", comment: "X-Large")
|
||||
case .xxlarge:
|
||||
return NSLocalizedString("Extra Extra Large", comment: "XX-Large")
|
||||
}
|
||||
}
|
||||
}
|
||||
16
Shared/Defaults/FontSize.swift
Normal file
16
Shared/Defaults/FontSize.swift
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// FontSize.swift
|
||||
// NetNewsWire
|
||||
//
|
||||
// Created by Brent Simmons on 1/26/25.
|
||||
// Copyright © 2025 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum FontSize: Int {
|
||||
case small = 0
|
||||
case medium = 1
|
||||
case large = 2
|
||||
case veryLarge = 3
|
||||
}
|
||||
59
Shared/Defaults/RefreshInterval.swift
Normal file
59
Shared/Defaults/RefreshInterval.swift
Normal file
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// RefreshInterval.swift
|
||||
// NetNewsWire-iOS
|
||||
//
|
||||
// Created by Maurice Parker on 4/23/19.
|
||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum RefreshInterval: Int, CaseIterable, Identifiable {
|
||||
case manually = 1
|
||||
case every10Minutes = 2
|
||||
case every30Minutes = 3
|
||||
case everyHour = 4
|
||||
case every2Hours = 5
|
||||
case every4Hours = 6
|
||||
case every8Hours = 7
|
||||
|
||||
func inSeconds() -> TimeInterval {
|
||||
switch self {
|
||||
case .manually:
|
||||
return 0
|
||||
case .every10Minutes:
|
||||
return 10 * 60
|
||||
case .every30Minutes:
|
||||
return 30 * 60
|
||||
case .everyHour:
|
||||
return 60 * 60
|
||||
case .every2Hours:
|
||||
return 2 * 60 * 60
|
||||
case .every4Hours:
|
||||
return 4 * 60 * 60
|
||||
case .every8Hours:
|
||||
return 8 * 60 * 60
|
||||
}
|
||||
}
|
||||
|
||||
var id: String { description() }
|
||||
|
||||
func description() -> String {
|
||||
switch self {
|
||||
case .manually:
|
||||
return NSLocalizedString("Manually", comment: "Manually")
|
||||
case .every10Minutes:
|
||||
return NSLocalizedString("Every 10 Minutes", comment: "Every 10 Minutes")
|
||||
case .every30Minutes:
|
||||
return NSLocalizedString("Every 30 Minutes", comment: "Every 30 Minutes")
|
||||
case .everyHour:
|
||||
return NSLocalizedString("Every Hour", comment: "Every Hour")
|
||||
case .every2Hours:
|
||||
return NSLocalizedString("Every 2 Hours", comment: "Every 2 Hours")
|
||||
case .every4Hours:
|
||||
return NSLocalizedString("Every 4 Hours", comment: "Every 4 Hours")
|
||||
case .every8Hours:
|
||||
return NSLocalizedString("Every 8 Hours", comment: "Every 8 Hours")
|
||||
}
|
||||
}
|
||||
}
|
||||
26
Shared/Defaults/UserInterfaceColorPalette.swift
Normal file
26
Shared/Defaults/UserInterfaceColorPalette.swift
Normal file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// UserInterfaceColorPalette.swift
|
||||
// NetNewsWire
|
||||
//
|
||||
// Created by Brent Simmons on 1/26/25.
|
||||
// Copyright © 2025 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum UserInterfaceColorPalette: Int, CustomStringConvertible, CaseIterable {
|
||||
case automatic = 0
|
||||
case light = 1
|
||||
case dark = 2
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
case .automatic:
|
||||
return NSLocalizedString("Automatic", comment: "Automatic")
|
||||
case .light:
|
||||
return NSLocalizedString("Light", comment: "Light")
|
||||
case .dark:
|
||||
return NSLocalizedString("Dark", comment: "Dark")
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user