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 */; };
|
||||
D0091B7124DD68220040E8D2 /* 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 */; };
|
||||
D0159F8824DE742F00E78478 /* SecondaryNavigationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0159F8424DE742F00E78478 /* SecondaryNavigationViewModel.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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
|
@ -447,6 +450,14 @@
|
|||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
D009CCEE24F325AF00F410E7 /* Property Wrappers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D009CCEF24F3260300F410E7 /* DecodableDefault.swift */,
|
||||
);
|
||||
path = "Property Wrappers";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D0159F7F24DE739000E78478 /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -564,6 +575,7 @@
|
|||
D047FA8524C3E21000AF17C5 /* MetatextApp.swift */,
|
||||
D0666A3A24C6B56200F3F04B /* Model */,
|
||||
D0DB6EFA24C5730600D965FE /* Networking */,
|
||||
D009CCEE24F325AF00F410E7 /* Property Wrappers */,
|
||||
D019E6F224DF7C9E00697C7D /* Services */,
|
||||
D0DB6EFB24C658E400D965FE /* View Models */,
|
||||
D0DB6EF024C5224F00D965FE /* Views */,
|
||||
|
@ -1125,6 +1137,7 @@
|
|||
D074577A24D29366004758DB /* URLSessionConfiguration+Extensions.swift in Sources */,
|
||||
D0ED1BB724CE47F400B4899C /* WebAuthSession.swift in Sources */,
|
||||
D0A1CA7424DAC2F1003063E9 /* KingfisherOptionsInfo+Extensions.swift in Sources */,
|
||||
D009CCF024F3260300F410E7 /* DecodableDefault.swift in Sources */,
|
||||
D054951224EB1041008B00A5 /* StatusListService.swift in Sources */,
|
||||
D0159F9124DE743700E78478 /* TabNavigationView.swift in Sources */,
|
||||
D0ED1BC424CED54D00B4899C /* HTTPTarget.swift in Sources */,
|
||||
|
@ -1229,6 +1242,7 @@
|
|||
D0ED1BC524CED54D00B4899C /* HTTPTarget.swift in Sources */,
|
||||
D0C963FF24CC3812003BD330 /* Publisher+Extensions.swift in Sources */,
|
||||
D075817D24E6659A0081F6A3 /* NotificationTypesPreferencesView.swift in Sources */,
|
||||
D009CCF124F3260300F410E7 /* DecodableDefault.swift in Sources */,
|
||||
D019E6E824DF72E700697C7D /* AccessTokenEndpoint.swift in Sources */,
|
||||
D04FD73D24D4A83A007D572D /* InstanceEndpoint+Stubbing.swift in Sources */,
|
||||
D0DC175C24D0154F00A75C65 /* MastodonAPI.swift in Sources */,
|
||||
|
|
|
@ -135,10 +135,10 @@ private extension ContentDatabase {
|
|||
t.column("card", .blob)
|
||||
t.column("language", .text)
|
||||
t.column("text", .text)
|
||||
t.column("favourited", .boolean)
|
||||
t.column("reblogged", .boolean)
|
||||
t.column("muted", .boolean)
|
||||
t.column("bookmarked", .boolean)
|
||||
t.column("favourited", .boolean).notNull()
|
||||
t.column("reblogged", .boolean).notNull()
|
||||
t.column("muted", .boolean).notNull()
|
||||
t.column("bookmarked", .boolean).notNull()
|
||||
t.column("pinned", .boolean)
|
||||
}
|
||||
|
||||
|
@ -309,10 +309,10 @@ private struct StoredStatus: Codable, Hashable {
|
|||
let card: Card?
|
||||
let language: String?
|
||||
let text: String?
|
||||
let favourited: Bool?
|
||||
let reblogged: Bool?
|
||||
let muted: Bool?
|
||||
let bookmarked: Bool?
|
||||
let favourited: Bool
|
||||
let reblogged: Bool
|
||||
let muted: Bool
|
||||
let bookmarked: Bool
|
||||
let pinned: Bool?
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ struct Account: Codable, Hashable {
|
|||
let headerStatic: URL
|
||||
let fields: [Field]
|
||||
let emojis: [Emoji]
|
||||
let bot: Bool?
|
||||
let moved: Bool?
|
||||
let discoverable: Bool?
|
||||
@DecodableDefault.False private(set) var bot: Bool
|
||||
@DecodableDefault.False private(set) var moved: Bool
|
||||
@DecodableDefault.False private(set) var discoverable: Bool
|
||||
}
|
||||
|
|
|
@ -35,12 +35,12 @@ extension Identity {
|
|||
}
|
||||
|
||||
struct Preferences: Codable, Hashable {
|
||||
var useServerPostingReadingPreferences = true
|
||||
var postingDefaultVisibility = Status.Visibility.public
|
||||
var postingDefaultSensitive = false
|
||||
@DecodableDefault.True var useServerPostingReadingPreferences
|
||||
@DecodableDefault.StatusVisibilityPublic var postingDefaultVisibility: Status.Visibility
|
||||
@DecodableDefault.False var postingDefaultSensitive
|
||||
var postingDefaultLanguage: String?
|
||||
var readingExpandMedia = MastodonPreferences.ExpandMedia.default
|
||||
var readingExpandSpoilers = false
|
||||
@DecodableDefault.ExpandMediaDefault var readingExpandMedia: MastodonPreferences.ExpandMedia
|
||||
@DecodableDefault.False var readingExpandSpoilers
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,10 +19,10 @@ struct Instance: Codable, Hashable {
|
|||
let shortDescription: String?
|
||||
let email: String
|
||||
let version: String
|
||||
let languages: [String]
|
||||
let registrations: Bool?
|
||||
let approvalRequired: Bool?
|
||||
let invitesEnabled: Bool?
|
||||
@DecodableDefault.EmptyList private(set) var languages: [String]
|
||||
@DecodableDefault.False private(set) var registrations: Bool
|
||||
@DecodableDefault.False private(set) var approvalRequired: Bool
|
||||
@DecodableDefault.False private(set) var invitesEnabled: Bool
|
||||
let urls: URLs
|
||||
let stats: Stats
|
||||
let thumbnail: URL?
|
||||
|
|
|
@ -14,8 +14,8 @@ struct Poll: Codable, Hashable {
|
|||
let multiple: Bool
|
||||
let votesCount: Int
|
||||
let votersCount: Int?
|
||||
let voted: Bool?
|
||||
let ownVotes: [Int]?
|
||||
@DecodableDefault.False private(set) var voted: Bool
|
||||
@DecodableDefault.EmptyList private(set) var ownVotes: [Int]
|
||||
let options: [Option]
|
||||
let emojis: [Emoji]
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ struct PushSubscription: Codable {
|
|||
var favourite: Bool
|
||||
var reblog: Bool
|
||||
var mention: Bool
|
||||
var poll: Bool
|
||||
@DecodableDefault.True var poll: Bool
|
||||
}
|
||||
|
||||
let endpoint: URL
|
||||
|
@ -17,5 +17,10 @@ struct PushSubscription: Codable {
|
|||
}
|
||||
|
||||
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 reblogsCount: Int
|
||||
let favouritesCount: Int
|
||||
let repliesCount: Int
|
||||
@DecodableDefault.Zero private(set) var repliesCount: Int
|
||||
let application: Application?
|
||||
let url: URL?
|
||||
let inReplyToId: String?
|
||||
|
@ -37,10 +37,10 @@ class Status: Codable, Identifiable {
|
|||
let card: Card?
|
||||
let language: String?
|
||||
let text: String?
|
||||
let favourited: Bool?
|
||||
let reblogged: Bool?
|
||||
let muted: Bool?
|
||||
let bookmarked: Bool?
|
||||
@DecodableDefault.False private(set) var favourited: Bool
|
||||
@DecodableDefault.False private(set) var reblogged: Bool
|
||||
@DecodableDefault.False private(set) var muted: Bool
|
||||
@DecodableDefault.False private(set) var bookmarked: Bool
|
||||
let pinned: Bool?
|
||||
|
||||
// Xcode-generated memberwise initializer
|
||||
|
@ -69,10 +69,10 @@ class Status: Codable, Identifiable {
|
|||
card: Card?,
|
||||
language: String?,
|
||||
text: String?,
|
||||
favourited: Bool?,
|
||||
reblogged: Bool?,
|
||||
muted: Bool?,
|
||||
bookmarked: Bool?,
|
||||
favourited: Bool,
|
||||
reblogged: Bool,
|
||||
muted: Bool,
|
||||
bookmarked: Bool,
|
||||
pinned: Bool?) {
|
||||
self.id = id
|
||||
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