Tusker/Tusker/Preferences/Preferences.swift

248 lines
11 KiB
Swift

//
// Preferences.swift
// Tusker
//
// Created by Shadowfacts on 8/28/18.
// Copyright © 2018 Shadowfacts. All rights reserved.
//
import UIKit
import Pachyderm
import Combine
class Preferences: Codable, ObservableObject {
static var shared: Preferences = load()
private static var documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
private static var archiveURL = Preferences.documentsDirectory.appendingPathComponent("preferences").appendingPathExtension("plist")
static func save() {
let encoder = PropertyListEncoder()
let data = try? encoder.encode(shared)
try? data?.write(to: archiveURL, options: .noFileProtection)
}
static func load() -> Preferences {
let decoder = PropertyListDecoder()
if let data = try? Data(contentsOf: archiveURL),
let preferences = try? decoder.decode(Preferences.self, from: data) {
return preferences
}
return Preferences()
}
private init() {}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.theme = try container.decode(UIUserInterfaceStyle.self, forKey: .theme)
self.avatarStyle = try container.decode(AvatarStyle.self, forKey: .avatarStyle)
self.hideCustomEmojiInUsernames = try container.decode(Bool.self, forKey: .hideCustomEmojiInUsernames)
self.showIsStatusReplyIcon = try container.decode(Bool.self, forKey: .showIsStatusReplyIcon)
self.alwaysShowStatusVisibilityIcon = try container.decode(Bool.self, forKey: .alwaysShowStatusVisibilityIcon)
self.hideActionsInTimeline = try container.decodeIfPresent(Bool.self, forKey: .hideActionsInTimeline) ?? false
self.defaultPostVisibility = try container.decode(Status.Visibility.self, forKey: .defaultPostVisibility)
self.defaultReplyVisibility = try container.decodeIfPresent(ReplyVisibility.self, forKey: .defaultReplyVisibility) ?? .sameAsPost
self.automaticallySaveDrafts = try container.decode(Bool.self, forKey: .automaticallySaveDrafts)
self.requireAttachmentDescriptions = try container.decode(Bool.self, forKey: .requireAttachmentDescriptions)
self.contentWarningCopyMode = try container.decode(ContentWarningCopyMode.self, forKey: .contentWarningCopyMode)
self.mentionReblogger = try container.decode(Bool.self, forKey: .mentionReblogger)
self.blurAllMedia = try container.decode(Bool.self, forKey: .blurAllMedia)
self.blurMediaBehindContentWarning = try container.decodeIfPresent(Bool.self, forKey: .blurMediaBehindContentWarning) ?? true
self.automaticallyPlayGifs = try container.decode(Bool.self, forKey: .automaticallyPlayGifs)
self.openLinksInApps = try container.decode(Bool.self, forKey: .openLinksInApps)
self.useInAppSafari = try container.decode(Bool.self, forKey: .useInAppSafari)
self.inAppSafariAutomaticReaderMode = try container.decode(Bool.self, forKey: .inAppSafariAutomaticReaderMode)
self.expandAllContentWarnings = try container.decodeIfPresent(Bool.self, forKey: .expandAllContentWarnings) ?? false
self.collapseLongPosts = try container.decodeIfPresent(Bool.self, forKey: .collapseLongPosts) ?? true
self.oppositeCollapseKeywords = try container.decodeIfPresent([String].self, forKey: .oppositeCollapseKeywords) ?? []
self.confirmBeforeReblog = try container.decodeIfPresent(Bool.self, forKey: .confirmBeforeReblog) ?? false
self.showFavoriteAndReblogCounts = try container.decode(Bool.self, forKey: .showFavoriteAndReblogCounts)
self.defaultNotificationsMode = try container.decode(NotificationsMode.self, forKey: .defaultNotificationsType)
self.grayscaleImages = try container.decodeIfPresent(Bool.self, forKey: .grayscaleImages) ?? false
self.disableInfiniteScrolling = try container.decodeIfPresent(Bool.self, forKey: .disableInfiniteScrolling) ?? false
self.hideDiscover = try container.decodeIfPresent(Bool.self, forKey: .hideDiscover) ?? false
self.statusContentType = try container.decode(StatusContentType.self, forKey: .statusContentType)
self.hasShownLocalTimelineDescription = try container.decodeIfPresent(Bool.self, forKey: .hasShownLocalTimelineDescription) ?? false
self.hasShownFederatedTimelineDescription = try container.decodeIfPresent(Bool.self, forKey: .hasShownFederatedTimelineDescription) ?? false
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(theme, forKey: .theme)
try container.encode(avatarStyle, forKey: .avatarStyle)
try container.encode(hideCustomEmojiInUsernames, forKey: .hideCustomEmojiInUsernames)
try container.encode(showIsStatusReplyIcon, forKey: .showIsStatusReplyIcon)
try container.encode(alwaysShowStatusVisibilityIcon, forKey: .alwaysShowStatusVisibilityIcon)
try container.encode(hideActionsInTimeline, forKey: .hideActionsInTimeline)
try container.encode(defaultPostVisibility, forKey: .defaultPostVisibility)
try container.encode(defaultReplyVisibility, forKey: .defaultReplyVisibility)
try container.encode(automaticallySaveDrafts, forKey: .automaticallySaveDrafts)
try container.encode(requireAttachmentDescriptions, forKey: .requireAttachmentDescriptions)
try container.encode(contentWarningCopyMode, forKey: .contentWarningCopyMode)
try container.encode(mentionReblogger, forKey: .mentionReblogger)
try container.encode(blurAllMedia, forKey: .blurAllMedia)
try container.encode(blurMediaBehindContentWarning, forKey: .blurMediaBehindContentWarning)
try container.encode(automaticallyPlayGifs, forKey: .automaticallyPlayGifs)
try container.encode(openLinksInApps, forKey: .openLinksInApps)
try container.encode(useInAppSafari, forKey: .useInAppSafari)
try container.encode(inAppSafariAutomaticReaderMode, forKey: .inAppSafariAutomaticReaderMode)
try container.encode(expandAllContentWarnings, forKey: .expandAllContentWarnings)
try container.encode(collapseLongPosts, forKey: .collapseLongPosts)
try container.encode(oppositeCollapseKeywords, forKey: .oppositeCollapseKeywords)
try container.encode(confirmBeforeReblog, forKey: .confirmBeforeReblog)
try container.encode(showFavoriteAndReblogCounts, forKey: .showFavoriteAndReblogCounts)
try container.encode(defaultNotificationsMode, forKey: .defaultNotificationsType)
try container.encode(grayscaleImages, forKey: .grayscaleImages)
try container.encode(disableInfiniteScrolling, forKey: .disableInfiniteScrolling)
try container.encode(hideDiscover, forKey: .hideDiscover)
try container.encode(statusContentType, forKey: .statusContentType)
try container.encode(hasShownLocalTimelineDescription, forKey: .hasShownLocalTimelineDescription)
try container.encode(hasShownFederatedTimelineDescription, forKey: .hasShownFederatedTimelineDescription)
}
// MARK: Appearance
@Published var theme = UIUserInterfaceStyle.unspecified
@Published var avatarStyle = AvatarStyle.roundRect
@Published var hideCustomEmojiInUsernames = false
@Published var showIsStatusReplyIcon = false
@Published var alwaysShowStatusVisibilityIcon = false
@Published var hideActionsInTimeline = false
// MARK: Composing
@Published var defaultPostVisibility = Status.Visibility.public
@Published var defaultReplyVisibility = ReplyVisibility.sameAsPost
@Published var automaticallySaveDrafts = true
@Published var requireAttachmentDescriptions = false
@Published var contentWarningCopyMode = ContentWarningCopyMode.asIs
@Published var mentionReblogger = false
// MARK: Media
@Published var blurAllMedia = false {
didSet {
if blurAllMedia {
blurMediaBehindContentWarning = true
}
}
}
@Published var blurMediaBehindContentWarning = true
@Published var automaticallyPlayGifs = true
// MARK: Behavior
@Published var openLinksInApps = true
@Published var useInAppSafari = true
@Published var inAppSafariAutomaticReaderMode = false
@Published var expandAllContentWarnings = false
@Published var collapseLongPosts = true
@Published var oppositeCollapseKeywords: [String] = []
@Published var confirmBeforeReblog = false
// MARK: Digital Wellness
@Published var showFavoriteAndReblogCounts = true
@Published var defaultNotificationsMode = NotificationsMode.allNotifications
@Published var grayscaleImages = false
@Published var disableInfiniteScrolling = false
@Published var hideDiscover = false
// MARK: Advanced
@Published var statusContentType: StatusContentType = .plain
@Published var reportErrorsAutomatically = true
// MARK:
@Published var hasShownLocalTimelineDescription = false
@Published var hasShownFederatedTimelineDescription = false
private enum CodingKeys: String, CodingKey {
case theme
case avatarStyle
case hideCustomEmojiInUsernames
case showIsStatusReplyIcon
case alwaysShowStatusVisibilityIcon
case hideActionsInTimeline
case defaultPostVisibility
case defaultReplyVisibility
case automaticallySaveDrafts
case requireAttachmentDescriptions
case contentWarningCopyMode
case mentionReblogger
case blurAllMedia
case blurMediaBehindContentWarning
case automaticallyPlayGifs
case openLinksInApps
case useInAppSafari
case inAppSafariAutomaticReaderMode
case expandAllContentWarnings
case collapseLongPosts
case oppositeCollapseKeywords
case confirmBeforeReblog
case showFavoriteAndReblogCounts
case defaultNotificationsType
case grayscaleImages
case disableInfiniteScrolling
case hideDiscover
case statusContentType
case hasShownLocalTimelineDescription
case hasShownFederatedTimelineDescription
}
}
extension Preferences {
enum ReplyVisibility: Codable, Hashable, CaseIterable {
case sameAsPost
case visibility(Status.Visibility)
static var allCases: [Preferences.ReplyVisibility] = [.sameAsPost] + Status.Visibility.allCases.map { .visibility($0) }
var resolved: Status.Visibility {
switch self {
case .sameAsPost:
return Preferences.shared.defaultPostVisibility
case .visibility(let vis):
return vis
}
}
var displayName: String {
switch self {
case .sameAsPost:
return "Same as Default"
case .visibility(let vis):
return vis.displayName
}
}
var imageName: String? {
switch self {
case .sameAsPost:
return nil
case .visibility(let vis):
return vis.imageName
}
}
}
}
extension UIUserInterfaceStyle: Codable {}