Default decoding values
This commit is contained in:
parent
cabbe30c2f
commit
8ca6f43610
|
@ -15,6 +15,8 @@
|
||||||
D0091B6F24DD68090040E8D2 /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0091B6D24DD68090040E8D2 /* PreferencesView.swift */; };
|
D0091B6F24DD68090040E8D2 /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0091B6D24DD68090040E8D2 /* PreferencesView.swift */; };
|
||||||
D0091B7124DD68220040E8D2 /* PreferencesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0091B7024DD68220040E8D2 /* PreferencesViewModel.swift */; };
|
D0091B7124DD68220040E8D2 /* PreferencesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0091B7024DD68220040E8D2 /* PreferencesViewModel.swift */; };
|
||||||
D0091B7224DD68220040E8D2 /* PreferencesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0091B7024DD68220040E8D2 /* PreferencesViewModel.swift */; };
|
D0091B7224DD68220040E8D2 /* PreferencesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0091B7024DD68220040E8D2 /* PreferencesViewModel.swift */; };
|
||||||
|
D009CCF024F3260300F410E7 /* DecodableDefault.swift in Sources */ = {isa = PBXBuildFile; fileRef = D009CCEF24F3260300F410E7 /* DecodableDefault.swift */; };
|
||||||
|
D009CCF124F3260300F410E7 /* DecodableDefault.swift in Sources */ = {isa = PBXBuildFile; fileRef = D009CCEF24F3260300F410E7 /* DecodableDefault.swift */; };
|
||||||
D0159F8624DE742F00E78478 /* TabNavigationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0159F8324DE742F00E78478 /* TabNavigationViewModel.swift */; };
|
D0159F8624DE742F00E78478 /* TabNavigationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0159F8324DE742F00E78478 /* TabNavigationViewModel.swift */; };
|
||||||
D0159F8824DE742F00E78478 /* SecondaryNavigationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0159F8424DE742F00E78478 /* SecondaryNavigationViewModel.swift */; };
|
D0159F8824DE742F00E78478 /* SecondaryNavigationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0159F8424DE742F00E78478 /* SecondaryNavigationViewModel.swift */; };
|
||||||
D0159F8A24DE742F00E78478 /* IdentitiesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0159F8524DE742F00E78478 /* IdentitiesViewModel.swift */; };
|
D0159F8A24DE742F00E78478 /* IdentitiesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0159F8524DE742F00E78478 /* IdentitiesViewModel.swift */; };
|
||||||
|
@ -279,6 +281,7 @@
|
||||||
D0091B6A24DC10CE0040E8D2 /* PostingReadingPreferencesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostingReadingPreferencesViewModel.swift; sourceTree = "<group>"; };
|
D0091B6A24DC10CE0040E8D2 /* PostingReadingPreferencesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostingReadingPreferencesViewModel.swift; sourceTree = "<group>"; };
|
||||||
D0091B6D24DD68090040E8D2 /* PreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesView.swift; sourceTree = "<group>"; };
|
D0091B6D24DD68090040E8D2 /* PreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesView.swift; sourceTree = "<group>"; };
|
||||||
D0091B7024DD68220040E8D2 /* PreferencesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesViewModel.swift; sourceTree = "<group>"; };
|
D0091B7024DD68220040E8D2 /* PreferencesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesViewModel.swift; sourceTree = "<group>"; };
|
||||||
|
D009CCEF24F3260300F410E7 /* DecodableDefault.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecodableDefault.swift; sourceTree = "<group>"; };
|
||||||
D0159F8324DE742F00E78478 /* TabNavigationViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabNavigationViewModel.swift; sourceTree = "<group>"; };
|
D0159F8324DE742F00E78478 /* TabNavigationViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabNavigationViewModel.swift; sourceTree = "<group>"; };
|
||||||
D0159F8424DE742F00E78478 /* SecondaryNavigationViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecondaryNavigationViewModel.swift; sourceTree = "<group>"; };
|
D0159F8424DE742F00E78478 /* SecondaryNavigationViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecondaryNavigationViewModel.swift; sourceTree = "<group>"; };
|
||||||
D0159F8524DE742F00E78478 /* IdentitiesViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IdentitiesViewModel.swift; sourceTree = "<group>"; };
|
D0159F8524DE742F00E78478 /* IdentitiesViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IdentitiesViewModel.swift; sourceTree = "<group>"; };
|
||||||
|
@ -447,6 +450,14 @@
|
||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
|
D009CCEE24F325AF00F410E7 /* Property Wrappers */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
D009CCEF24F3260300F410E7 /* DecodableDefault.swift */,
|
||||||
|
);
|
||||||
|
path = "Property Wrappers";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
D0159F7F24DE739000E78478 /* Views */ = {
|
D0159F7F24DE739000E78478 /* Views */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -564,6 +575,7 @@
|
||||||
D047FA8524C3E21000AF17C5 /* MetatextApp.swift */,
|
D047FA8524C3E21000AF17C5 /* MetatextApp.swift */,
|
||||||
D0666A3A24C6B56200F3F04B /* Model */,
|
D0666A3A24C6B56200F3F04B /* Model */,
|
||||||
D0DB6EFA24C5730600D965FE /* Networking */,
|
D0DB6EFA24C5730600D965FE /* Networking */,
|
||||||
|
D009CCEE24F325AF00F410E7 /* Property Wrappers */,
|
||||||
D019E6F224DF7C9E00697C7D /* Services */,
|
D019E6F224DF7C9E00697C7D /* Services */,
|
||||||
D0DB6EFB24C658E400D965FE /* View Models */,
|
D0DB6EFB24C658E400D965FE /* View Models */,
|
||||||
D0DB6EF024C5224F00D965FE /* Views */,
|
D0DB6EF024C5224F00D965FE /* Views */,
|
||||||
|
@ -1125,6 +1137,7 @@
|
||||||
D074577A24D29366004758DB /* URLSessionConfiguration+Extensions.swift in Sources */,
|
D074577A24D29366004758DB /* URLSessionConfiguration+Extensions.swift in Sources */,
|
||||||
D0ED1BB724CE47F400B4899C /* WebAuthSession.swift in Sources */,
|
D0ED1BB724CE47F400B4899C /* WebAuthSession.swift in Sources */,
|
||||||
D0A1CA7424DAC2F1003063E9 /* KingfisherOptionsInfo+Extensions.swift in Sources */,
|
D0A1CA7424DAC2F1003063E9 /* KingfisherOptionsInfo+Extensions.swift in Sources */,
|
||||||
|
D009CCF024F3260300F410E7 /* DecodableDefault.swift in Sources */,
|
||||||
D054951224EB1041008B00A5 /* StatusListService.swift in Sources */,
|
D054951224EB1041008B00A5 /* StatusListService.swift in Sources */,
|
||||||
D0159F9124DE743700E78478 /* TabNavigationView.swift in Sources */,
|
D0159F9124DE743700E78478 /* TabNavigationView.swift in Sources */,
|
||||||
D0ED1BC424CED54D00B4899C /* HTTPTarget.swift in Sources */,
|
D0ED1BC424CED54D00B4899C /* HTTPTarget.swift in Sources */,
|
||||||
|
@ -1229,6 +1242,7 @@
|
||||||
D0ED1BC524CED54D00B4899C /* HTTPTarget.swift in Sources */,
|
D0ED1BC524CED54D00B4899C /* HTTPTarget.swift in Sources */,
|
||||||
D0C963FF24CC3812003BD330 /* Publisher+Extensions.swift in Sources */,
|
D0C963FF24CC3812003BD330 /* Publisher+Extensions.swift in Sources */,
|
||||||
D075817D24E6659A0081F6A3 /* NotificationTypesPreferencesView.swift in Sources */,
|
D075817D24E6659A0081F6A3 /* NotificationTypesPreferencesView.swift in Sources */,
|
||||||
|
D009CCF124F3260300F410E7 /* DecodableDefault.swift in Sources */,
|
||||||
D019E6E824DF72E700697C7D /* AccessTokenEndpoint.swift in Sources */,
|
D019E6E824DF72E700697C7D /* AccessTokenEndpoint.swift in Sources */,
|
||||||
D04FD73D24D4A83A007D572D /* InstanceEndpoint+Stubbing.swift in Sources */,
|
D04FD73D24D4A83A007D572D /* InstanceEndpoint+Stubbing.swift in Sources */,
|
||||||
D0DC175C24D0154F00A75C65 /* MastodonAPI.swift in Sources */,
|
D0DC175C24D0154F00A75C65 /* MastodonAPI.swift in Sources */,
|
||||||
|
|
|
@ -135,10 +135,10 @@ private extension ContentDatabase {
|
||||||
t.column("card", .blob)
|
t.column("card", .blob)
|
||||||
t.column("language", .text)
|
t.column("language", .text)
|
||||||
t.column("text", .text)
|
t.column("text", .text)
|
||||||
t.column("favourited", .boolean)
|
t.column("favourited", .boolean).notNull()
|
||||||
t.column("reblogged", .boolean)
|
t.column("reblogged", .boolean).notNull()
|
||||||
t.column("muted", .boolean)
|
t.column("muted", .boolean).notNull()
|
||||||
t.column("bookmarked", .boolean)
|
t.column("bookmarked", .boolean).notNull()
|
||||||
t.column("pinned", .boolean)
|
t.column("pinned", .boolean)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,10 +309,10 @@ private struct StoredStatus: Codable, Hashable {
|
||||||
let card: Card?
|
let card: Card?
|
||||||
let language: String?
|
let language: String?
|
||||||
let text: String?
|
let text: String?
|
||||||
let favourited: Bool?
|
let favourited: Bool
|
||||||
let reblogged: Bool?
|
let reblogged: Bool
|
||||||
let muted: Bool?
|
let muted: Bool
|
||||||
let bookmarked: Bool?
|
let bookmarked: Bool
|
||||||
let pinned: Bool?
|
let pinned: Bool?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ struct Account: Codable, Hashable {
|
||||||
let headerStatic: URL
|
let headerStatic: URL
|
||||||
let fields: [Field]
|
let fields: [Field]
|
||||||
let emojis: [Emoji]
|
let emojis: [Emoji]
|
||||||
let bot: Bool?
|
@DecodableDefault.False private(set) var bot: Bool
|
||||||
let moved: Bool?
|
@DecodableDefault.False private(set) var moved: Bool
|
||||||
let discoverable: Bool?
|
@DecodableDefault.False private(set) var discoverable: Bool
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,12 +35,12 @@ extension Identity {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Preferences: Codable, Hashable {
|
struct Preferences: Codable, Hashable {
|
||||||
var useServerPostingReadingPreferences = true
|
@DecodableDefault.True var useServerPostingReadingPreferences
|
||||||
var postingDefaultVisibility = Status.Visibility.public
|
@DecodableDefault.StatusVisibilityPublic var postingDefaultVisibility: Status.Visibility
|
||||||
var postingDefaultSensitive = false
|
@DecodableDefault.False var postingDefaultSensitive
|
||||||
var postingDefaultLanguage: String?
|
var postingDefaultLanguage: String?
|
||||||
var readingExpandMedia = MastodonPreferences.ExpandMedia.default
|
@DecodableDefault.ExpandMediaDefault var readingExpandMedia: MastodonPreferences.ExpandMedia
|
||||||
var readingExpandSpoilers = false
|
@DecodableDefault.False var readingExpandSpoilers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,10 +19,10 @@ struct Instance: Codable, Hashable {
|
||||||
let shortDescription: String?
|
let shortDescription: String?
|
||||||
let email: String
|
let email: String
|
||||||
let version: String
|
let version: String
|
||||||
let languages: [String]
|
@DecodableDefault.EmptyList private(set) var languages: [String]
|
||||||
let registrations: Bool?
|
@DecodableDefault.False private(set) var registrations: Bool
|
||||||
let approvalRequired: Bool?
|
@DecodableDefault.False private(set) var approvalRequired: Bool
|
||||||
let invitesEnabled: Bool?
|
@DecodableDefault.False private(set) var invitesEnabled: Bool
|
||||||
let urls: URLs
|
let urls: URLs
|
||||||
let stats: Stats
|
let stats: Stats
|
||||||
let thumbnail: URL?
|
let thumbnail: URL?
|
||||||
|
|
|
@ -14,8 +14,8 @@ struct Poll: Codable, Hashable {
|
||||||
let multiple: Bool
|
let multiple: Bool
|
||||||
let votesCount: Int
|
let votesCount: Int
|
||||||
let votersCount: Int?
|
let votersCount: Int?
|
||||||
let voted: Bool?
|
@DecodableDefault.False private(set) var voted: Bool
|
||||||
let ownVotes: [Int]?
|
@DecodableDefault.EmptyList private(set) var ownVotes: [Int]
|
||||||
let options: [Option]
|
let options: [Option]
|
||||||
let emojis: [Emoji]
|
let emojis: [Emoji]
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ struct PushSubscription: Codable {
|
||||||
var favourite: Bool
|
var favourite: Bool
|
||||||
var reblog: Bool
|
var reblog: Bool
|
||||||
var mention: Bool
|
var mention: Bool
|
||||||
var poll: Bool
|
@DecodableDefault.True var poll: Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
let endpoint: URL
|
let endpoint: URL
|
||||||
|
@ -17,5 +17,10 @@ struct PushSubscription: Codable {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension PushSubscription.Alerts {
|
extension PushSubscription.Alerts {
|
||||||
static let initial: Self = Self(follow: true, favourite: true, reblog: true, mention: true, poll: true)
|
static let initial: Self = Self(
|
||||||
|
follow: true,
|
||||||
|
favourite: true,
|
||||||
|
reblog: true,
|
||||||
|
mention: true,
|
||||||
|
poll: DecodableDefault.True())
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ class Status: Codable, Identifiable {
|
||||||
let emojis: [Emoji]
|
let emojis: [Emoji]
|
||||||
let reblogsCount: Int
|
let reblogsCount: Int
|
||||||
let favouritesCount: Int
|
let favouritesCount: Int
|
||||||
let repliesCount: Int
|
@DecodableDefault.Zero private(set) var repliesCount: Int
|
||||||
let application: Application?
|
let application: Application?
|
||||||
let url: URL?
|
let url: URL?
|
||||||
let inReplyToId: String?
|
let inReplyToId: String?
|
||||||
|
@ -37,10 +37,10 @@ class Status: Codable, Identifiable {
|
||||||
let card: Card?
|
let card: Card?
|
||||||
let language: String?
|
let language: String?
|
||||||
let text: String?
|
let text: String?
|
||||||
let favourited: Bool?
|
@DecodableDefault.False private(set) var favourited: Bool
|
||||||
let reblogged: Bool?
|
@DecodableDefault.False private(set) var reblogged: Bool
|
||||||
let muted: Bool?
|
@DecodableDefault.False private(set) var muted: Bool
|
||||||
let bookmarked: Bool?
|
@DecodableDefault.False private(set) var bookmarked: Bool
|
||||||
let pinned: Bool?
|
let pinned: Bool?
|
||||||
|
|
||||||
// Xcode-generated memberwise initializer
|
// Xcode-generated memberwise initializer
|
||||||
|
@ -69,10 +69,10 @@ class Status: Codable, Identifiable {
|
||||||
card: Card?,
|
card: Card?,
|
||||||
language: String?,
|
language: String?,
|
||||||
text: String?,
|
text: String?,
|
||||||
favourited: Bool?,
|
favourited: Bool,
|
||||||
reblogged: Bool?,
|
reblogged: Bool,
|
||||||
muted: Bool?,
|
muted: Bool,
|
||||||
bookmarked: Bool?,
|
bookmarked: Bool,
|
||||||
pinned: Bool?) {
|
pinned: Bool?) {
|
||||||
self.id = id
|
self.id = id
|
||||||
self.uri = uri
|
self.uri = uri
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
// Copyright © 2020 Metabolist. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
// Thank you https://www.swiftbysundell.com/tips/default-decoding-values/
|
||||||
|
|
||||||
|
protocol DecodableDefaultSource {
|
||||||
|
associatedtype Value: Decodable
|
||||||
|
static var defaultValue: Value { get }
|
||||||
|
}
|
||||||
|
|
||||||
|
enum DecodableDefault {}
|
||||||
|
|
||||||
|
// swiftlint:disable nesting
|
||||||
|
extension DecodableDefault {
|
||||||
|
@propertyWrapper
|
||||||
|
struct Wrapper<Source: DecodableDefaultSource> {
|
||||||
|
typealias Value = Source.Value
|
||||||
|
var wrappedValue = Source.defaultValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DecodableDefault {
|
||||||
|
typealias Source = DecodableDefaultSource
|
||||||
|
typealias List = Decodable & ExpressibleByArrayLiteral
|
||||||
|
typealias Map = Decodable & ExpressibleByDictionaryLiteral
|
||||||
|
|
||||||
|
enum Sources {
|
||||||
|
enum True: Source {
|
||||||
|
static var defaultValue: Bool { true }
|
||||||
|
}
|
||||||
|
|
||||||
|
enum False: Source {
|
||||||
|
static var defaultValue: Bool { false }
|
||||||
|
}
|
||||||
|
|
||||||
|
enum EmptyString: Source {
|
||||||
|
static var defaultValue: String { "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
enum EmptyList<T: List>: Source {
|
||||||
|
static var defaultValue: T { [] }
|
||||||
|
}
|
||||||
|
|
||||||
|
enum EmptyMap<T: Map>: Source {
|
||||||
|
static var defaultValue: T { [:] }
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Zero: Source {
|
||||||
|
static var defaultValue: Int { 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
enum StatusVisibilityPublic: Source {
|
||||||
|
static var defaultValue: Status.Visibility { .public }
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ExpandMediaDefault: Source {
|
||||||
|
static var defaultValue: MastodonPreferences.ExpandMedia { .default }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// swiftlint:enable nesting
|
||||||
|
|
||||||
|
extension DecodableDefault {
|
||||||
|
typealias True = Wrapper<Sources.True>
|
||||||
|
typealias False = Wrapper<Sources.False>
|
||||||
|
typealias EmptyString = Wrapper<Sources.EmptyString>
|
||||||
|
typealias EmptyList<T: List> = Wrapper<Sources.EmptyList<T>>
|
||||||
|
typealias EmptyMap<T: Map> = Wrapper<Sources.EmptyMap<T>>
|
||||||
|
typealias Zero = Wrapper<Sources.Zero>
|
||||||
|
typealias StatusVisibilityPublic = Wrapper<Sources.StatusVisibilityPublic>
|
||||||
|
typealias ExpandMediaDefault = Wrapper<Sources.ExpandMediaDefault>
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DecodableDefault.Wrapper: Decodable {
|
||||||
|
init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.singleValueContainer()
|
||||||
|
wrappedValue = try container.decode(Value.self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DecodableDefault.Wrapper: Equatable where Value: Equatable {}
|
||||||
|
extension DecodableDefault.Wrapper: Hashable where Value: Hashable {}
|
||||||
|
|
||||||
|
extension DecodableDefault.Wrapper: Encodable where Value: Encodable {
|
||||||
|
func encode(to encoder: Encoder) throws {
|
||||||
|
var container = encoder.singleValueContainer()
|
||||||
|
try container.encode(wrappedValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension KeyedDecodingContainer {
|
||||||
|
func decode<T>(_ type: DecodableDefault.Wrapper<T>.Type,
|
||||||
|
forKey key: Key) throws -> DecodableDefault.Wrapper<T> {
|
||||||
|
try decodeIfPresent(type, forKey: key) ?? .init()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue