2019-04-15 22:03:05 +02:00
|
|
|
//
|
|
|
|
// AppDefaults.swift
|
|
|
|
// NetNewsWire
|
|
|
|
//
|
|
|
|
// Created by Brent Simmons on 9/22/17.
|
|
|
|
// Copyright © 2017 Ranchero Software. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
import UIKit
|
2024-04-16 07:21:17 +02:00
|
|
|
import Images
|
2019-04-15 22:03:05 +02:00
|
|
|
|
2020-03-15 10:25:25 +01:00
|
|
|
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")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-07-02 12:36:23 +02:00
|
|
|
final class AppDefaults {
|
2019-04-15 22:03:05 +02:00
|
|
|
|
2021-09-07 23:58:06 +02:00
|
|
|
static let defaultThemeName = "Defaults"
|
|
|
|
|
2024-05-04 07:47:14 +02:00
|
|
|
@MainActor static let shared = AppDefaults()
|
2020-07-02 04:47:45 +02:00
|
|
|
private init() {}
|
|
|
|
|
2024-03-27 00:50:11 +01:00
|
|
|
static let store: UserDefaults = {
|
2019-10-25 19:56:28 +02:00
|
|
|
let appIdentifierPrefix = Bundle.main.object(forInfoDictionaryKey: "AppIdentifierPrefix") as! String
|
|
|
|
let suiteName = "\(appIdentifierPrefix)group.\(Bundle.main.bundleIdentifier!)"
|
2019-10-15 16:11:18 +02:00
|
|
|
return UserDefaults.init(suiteName: suiteName)!
|
2019-11-04 18:35:45 +01:00
|
|
|
}()
|
2019-10-15 16:11:18 +02:00
|
|
|
|
2019-04-15 22:03:05 +02:00
|
|
|
struct Key {
|
2020-03-15 10:25:25 +01:00
|
|
|
static let userInterfaceColorPalette = "userInterfaceColorPalette"
|
2019-09-17 00:09:49 +02:00
|
|
|
static let lastImageCacheFlushDate = "lastImageCacheFlushDate"
|
2019-04-15 22:03:05 +02:00
|
|
|
static let firstRunDate = "firstRunDate"
|
2019-09-09 00:41:00 +02:00
|
|
|
static let timelineGroupByFeed = "timelineGroupByFeed"
|
2020-01-11 02:14:21 +01:00
|
|
|
static let refreshClearsReadArticles = "refreshClearsReadArticles"
|
2019-09-09 00:41:00 +02:00
|
|
|
static let timelineNumberOfLines = "timelineNumberOfLines"
|
2020-07-03 08:24:35 +02:00
|
|
|
static let timelineIconDimension = "timelineIconSize"
|
2019-04-15 22:03:05 +02:00
|
|
|
static let timelineSortDirection = "timelineSortDirection"
|
2020-02-04 20:24:06 +01:00
|
|
|
static let articleFullscreenAvailable = "articleFullscreenAvailable"
|
2019-11-24 21:18:58 +01:00
|
|
|
static let articleFullscreenEnabled = "articleFullscreenEnabled"
|
2020-01-11 19:30:16 +01:00
|
|
|
static let confirmMarkAllAsRead = "confirmMarkAllAsRead"
|
2019-04-26 22:24:39 +02:00
|
|
|
static let lastRefresh = "lastRefresh"
|
2024-02-26 08:12:21 +01:00
|
|
|
static let addFeedAccountID = "addWebFeedAccountID"
|
|
|
|
static let addFeedFolderName = "addWebFeedFolderName"
|
2019-11-16 19:02:58 +01:00
|
|
|
static let addFolderAccountID = "addFolderAccountID"
|
2021-08-26 04:27:23 +02:00
|
|
|
static let useSystemBrowser = "useSystemBrowser"
|
2021-09-07 23:58:06 +02:00
|
|
|
static let currentThemeName = "currentThemeName"
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
|
|
|
|
2020-07-02 04:47:45 +02:00
|
|
|
let isDeveloperBuild: Bool = {
|
2020-03-28 22:51:41 +01:00
|
|
|
if let dev = Bundle.main.object(forInfoDictionaryKey: "DeveloperEntitlements") as? String, dev == "-dev" {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}()
|
|
|
|
|
2020-07-02 04:47:45 +02:00
|
|
|
let isFirstRun: Bool = {
|
|
|
|
if let _ = AppDefaults.store.object(forKey: Key.firstRunDate) as? Date {
|
2019-04-15 22:03:05 +02:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
firstRunDate = Date()
|
|
|
|
return true
|
|
|
|
}()
|
2020-03-15 10:25:25 +01:00
|
|
|
|
|
|
|
static var userInterfaceColorPalette: UserInterfaceColorPalette {
|
|
|
|
get {
|
|
|
|
if let result = UserInterfaceColorPalette(rawValue: int(for: Key.userInterfaceColorPalette)) {
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
return .automatic
|
|
|
|
}
|
|
|
|
set {
|
|
|
|
setInt(for: Key.userInterfaceColorPalette, newValue.rawValue)
|
|
|
|
}
|
|
|
|
}
|
2019-11-16 19:02:58 +01:00
|
|
|
|
2024-02-26 08:12:21 +01:00
|
|
|
var addFeedAccountID: String? {
|
2019-11-16 19:02:58 +01:00
|
|
|
get {
|
2024-02-26 08:12:21 +01:00
|
|
|
return AppDefaults.string(for: Key.addFeedAccountID)
|
2019-11-16 19:02:58 +01:00
|
|
|
}
|
|
|
|
set {
|
2024-02-26 08:12:21 +01:00
|
|
|
AppDefaults.setString(for: Key.addFeedAccountID, newValue)
|
2019-11-16 19:02:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-26 08:12:21 +01:00
|
|
|
var addFeedFolderName: String? {
|
2019-11-16 20:25:55 +01:00
|
|
|
get {
|
2024-02-26 08:12:21 +01:00
|
|
|
return AppDefaults.string(for: Key.addFeedFolderName)
|
2019-11-16 20:25:55 +01:00
|
|
|
}
|
|
|
|
set {
|
2024-02-26 08:12:21 +01:00
|
|
|
AppDefaults.setString(for: Key.addFeedFolderName, newValue)
|
2019-11-16 20:25:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-02 04:47:45 +02:00
|
|
|
var addFolderAccountID: String? {
|
2019-11-16 19:02:58 +01:00
|
|
|
get {
|
2020-07-02 04:47:45 +02:00
|
|
|
return AppDefaults.string(for: Key.addFolderAccountID)
|
2019-11-16 19:02:58 +01:00
|
|
|
}
|
|
|
|
set {
|
2020-07-02 04:47:45 +02:00
|
|
|
AppDefaults.setString(for: Key.addFolderAccountID, newValue)
|
2019-11-16 19:02:58 +01:00
|
|
|
}
|
|
|
|
}
|
2019-04-15 22:03:05 +02:00
|
|
|
|
2021-08-26 04:27:23 +02:00
|
|
|
var useSystemBrowser: Bool {
|
2021-08-22 03:42:06 +02:00
|
|
|
get {
|
2021-08-26 04:27:23 +02:00
|
|
|
return UserDefaults.standard.bool(forKey: Key.useSystemBrowser)
|
2021-08-22 03:42:06 +02:00
|
|
|
}
|
|
|
|
set {
|
2021-08-26 04:27:23 +02:00
|
|
|
UserDefaults.standard.setValue(newValue, forKey: Key.useSystemBrowser)
|
2021-08-22 03:42:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-02 04:47:45 +02:00
|
|
|
var lastImageCacheFlushDate: Date? {
|
2019-09-17 00:09:49 +02:00
|
|
|
get {
|
2020-07-02 04:47:45 +02:00
|
|
|
return AppDefaults.date(for: Key.lastImageCacheFlushDate)
|
2019-09-17 00:09:49 +02:00
|
|
|
}
|
|
|
|
set {
|
2020-07-02 04:47:45 +02:00
|
|
|
AppDefaults.setDate(for: Key.lastImageCacheFlushDate, newValue)
|
2019-09-17 00:09:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-02 04:47:45 +02:00
|
|
|
var timelineGroupByFeed: Bool {
|
2019-09-09 00:41:00 +02:00
|
|
|
get {
|
2020-07-02 04:47:45 +02:00
|
|
|
return AppDefaults.bool(for: Key.timelineGroupByFeed)
|
2019-09-09 00:41:00 +02:00
|
|
|
}
|
|
|
|
set {
|
2020-07-02 04:47:45 +02:00
|
|
|
AppDefaults.setBool(for: Key.timelineGroupByFeed, newValue)
|
2019-09-09 00:41:00 +02:00
|
|
|
}
|
|
|
|
}
|
2019-04-15 22:03:05 +02:00
|
|
|
|
2020-07-02 04:47:45 +02:00
|
|
|
var refreshClearsReadArticles: Bool {
|
2020-01-11 02:14:21 +01:00
|
|
|
get {
|
2020-07-02 04:47:45 +02:00
|
|
|
return AppDefaults.bool(for: Key.refreshClearsReadArticles)
|
2020-01-11 02:14:21 +01:00
|
|
|
}
|
|
|
|
set {
|
2020-07-02 04:47:45 +02:00
|
|
|
AppDefaults.setBool(for: Key.refreshClearsReadArticles, newValue)
|
2020-01-11 02:14:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-02 04:47:45 +02:00
|
|
|
var timelineSortDirection: ComparisonResult {
|
2019-04-15 22:03:05 +02:00
|
|
|
get {
|
2020-07-02 04:47:45 +02:00
|
|
|
return AppDefaults.sortDirection(for: Key.timelineSortDirection)
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
|
|
|
set {
|
2020-07-02 04:47:45 +02:00
|
|
|
AppDefaults.setSortDirection(for: Key.timelineSortDirection, newValue)
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-02 04:47:45 +02:00
|
|
|
var articleFullscreenAvailable: Bool {
|
2020-02-04 20:24:06 +01:00
|
|
|
get {
|
2020-07-02 04:47:45 +02:00
|
|
|
return AppDefaults.bool(for: Key.articleFullscreenAvailable)
|
2020-02-04 20:24:06 +01:00
|
|
|
}
|
|
|
|
set {
|
2020-07-02 04:47:45 +02:00
|
|
|
AppDefaults.setBool(for: Key.articleFullscreenAvailable, newValue)
|
2020-02-04 20:24:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-02 04:47:45 +02:00
|
|
|
var articleFullscreenEnabled: Bool {
|
2019-11-24 21:18:58 +01:00
|
|
|
get {
|
2020-07-02 04:47:45 +02:00
|
|
|
return AppDefaults.bool(for: Key.articleFullscreenEnabled)
|
2019-11-24 21:18:58 +01:00
|
|
|
}
|
|
|
|
set {
|
2020-07-02 04:47:45 +02:00
|
|
|
AppDefaults.setBool(for: Key.articleFullscreenEnabled, newValue)
|
2019-11-24 21:18:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-02 04:47:45 +02:00
|
|
|
var confirmMarkAllAsRead: Bool {
|
2019-10-08 02:48:58 +02:00
|
|
|
get {
|
2020-07-02 04:47:45 +02:00
|
|
|
return AppDefaults.bool(for: Key.confirmMarkAllAsRead)
|
2019-10-08 02:48:58 +02:00
|
|
|
}
|
|
|
|
set {
|
2020-07-02 04:47:45 +02:00
|
|
|
AppDefaults.setBool(for: Key.confirmMarkAllAsRead, newValue)
|
2019-10-08 02:48:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-02 04:47:45 +02:00
|
|
|
var lastRefresh: Date? {
|
2019-04-26 22:24:39 +02:00
|
|
|
get {
|
2020-07-02 04:47:45 +02:00
|
|
|
return AppDefaults.date(for: Key.lastRefresh)
|
2019-04-26 22:24:39 +02:00
|
|
|
}
|
|
|
|
set {
|
2020-07-02 04:47:45 +02:00
|
|
|
AppDefaults.setDate(for: Key.lastRefresh, newValue)
|
2019-04-26 22:24:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-02 04:47:45 +02:00
|
|
|
var timelineNumberOfLines: Int {
|
2019-04-29 22:29:00 +02:00
|
|
|
get {
|
2020-07-02 04:47:45 +02:00
|
|
|
return AppDefaults.int(for: Key.timelineNumberOfLines)
|
2019-04-29 22:29:00 +02:00
|
|
|
}
|
|
|
|
set {
|
2020-07-02 04:47:45 +02:00
|
|
|
AppDefaults.setInt(for: Key.timelineNumberOfLines, newValue)
|
2019-04-29 22:29:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-02 04:47:45 +02:00
|
|
|
var timelineIconSize: IconSize {
|
2019-11-09 00:16:09 +01:00
|
|
|
get {
|
2020-07-03 08:24:35 +02:00
|
|
|
let rawValue = AppDefaults.store.integer(forKey: Key.timelineIconDimension)
|
2019-11-17 02:44:01 +01:00
|
|
|
return IconSize(rawValue: rawValue) ?? IconSize.medium
|
2019-11-09 00:16:09 +01:00
|
|
|
}
|
|
|
|
set {
|
2020-07-03 08:24:35 +02:00
|
|
|
AppDefaults.store.set(newValue.rawValue, forKey: Key.timelineIconDimension)
|
2019-11-09 00:16:09 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-07 23:58:06 +02:00
|
|
|
var currentThemeName: String? {
|
|
|
|
get {
|
|
|
|
return AppDefaults.string(for: Key.currentThemeName)
|
|
|
|
}
|
|
|
|
set {
|
|
|
|
AppDefaults.setString(for: Key.currentThemeName, newValue)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-15 22:03:05 +02:00
|
|
|
static func registerDefaults() {
|
2020-03-15 10:25:25 +01:00
|
|
|
let defaults: [String : Any] = [Key.userInterfaceColorPalette: UserInterfaceColorPalette.automatic.rawValue,
|
|
|
|
Key.timelineGroupByFeed: false,
|
2020-01-11 02:14:21 +01:00
|
|
|
Key.refreshClearsReadArticles: false,
|
2019-10-23 20:33:22 +02:00
|
|
|
Key.timelineNumberOfLines: 2,
|
2020-07-03 08:24:35 +02:00
|
|
|
Key.timelineIconDimension: IconSize.medium.rawValue,
|
2019-10-08 02:48:58 +02:00
|
|
|
Key.timelineSortDirection: ComparisonResult.orderedDescending.rawValue,
|
2020-02-04 20:24:06 +01:00
|
|
|
Key.articleFullscreenAvailable: false,
|
2019-11-24 21:18:58 +01:00
|
|
|
Key.articleFullscreenEnabled: false,
|
2021-09-07 23:58:06 +02:00
|
|
|
Key.confirmMarkAllAsRead: true,
|
|
|
|
Key.currentThemeName: Self.defaultThemeName]
|
2020-07-02 04:47:45 +02:00
|
|
|
AppDefaults.store.register(defaults: defaults)
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private extension AppDefaults {
|
|
|
|
|
|
|
|
static var firstRunDate: Date? {
|
|
|
|
get {
|
|
|
|
return date(for: Key.firstRunDate)
|
|
|
|
}
|
|
|
|
set {
|
|
|
|
setDate(for: Key.firstRunDate, newValue)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-16 19:02:58 +01:00
|
|
|
static func string(for key: String) -> String? {
|
|
|
|
return UserDefaults.standard.string(forKey: key)
|
|
|
|
}
|
|
|
|
|
|
|
|
static func setString(for key: String, _ value: String?) {
|
|
|
|
UserDefaults.standard.set(value, forKey: key)
|
|
|
|
}
|
|
|
|
|
2019-04-15 22:03:05 +02:00
|
|
|
static func bool(for key: String) -> Bool {
|
2020-07-02 04:47:45 +02:00
|
|
|
return AppDefaults.store.bool(forKey: key)
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static func setBool(for key: String, _ flag: Bool) {
|
2020-07-02 04:47:45 +02:00
|
|
|
AppDefaults.store.set(flag, forKey: key)
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static func int(for key: String) -> Int {
|
2020-07-02 04:47:45 +02:00
|
|
|
return AppDefaults.store.integer(forKey: key)
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static func setInt(for key: String, _ x: Int) {
|
2020-07-02 04:47:45 +02:00
|
|
|
AppDefaults.store.set(x, forKey: key)
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static func date(for key: String) -> Date? {
|
2020-07-02 04:47:45 +02:00
|
|
|
return AppDefaults.store.object(forKey: key) as? Date
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static func setDate(for key: String, _ date: Date?) {
|
2020-07-02 04:47:45 +02:00
|
|
|
AppDefaults.store.set(date, forKey: key)
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static func sortDirection(for key:String) -> ComparisonResult {
|
|
|
|
let rawInt = int(for: key)
|
|
|
|
if rawInt == ComparisonResult.orderedAscending.rawValue {
|
|
|
|
return .orderedAscending
|
|
|
|
}
|
|
|
|
return .orderedDescending
|
|
|
|
}
|
|
|
|
|
|
|
|
static func setSortDirection(for key: String, _ value: ComparisonResult) {
|
|
|
|
if value == .orderedAscending {
|
|
|
|
setInt(for: key, ComparisonResult.orderedAscending.rawValue)
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
setInt(for: key, ComparisonResult.orderedDescending.rawValue)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|