diff --git a/Databases/ContentDatabase.swift b/Databases/ContentDatabase.swift index 58370cc..db35f50 100644 --- a/Databases/ContentDatabase.swift +++ b/Databases/ContentDatabase.swift @@ -3,12 +3,13 @@ import Foundation import Combine import GRDB +import Mastodon // swiftlint:disable file_length struct ContentDatabase { private let databaseQueue: DatabaseQueue - init(identityID: UUID, environment: AppEnvironment) throws { + init(identityID: UUID, inMemory: Bool) throws { guard let documentsDirectory = NSSearchPathForDirectoriesInDomains( .documentDirectory, @@ -16,7 +17,7 @@ struct ContentDatabase { .first else { throw DatabaseError.documentsDirectoryNotFound } - if environment.inMemoryContent { + if inMemory { databaseQueue = DatabaseQueue() } else { databaseQueue = try DatabaseQueue(path: "\(documentsDirectory)/\(identityID.uuidString).sqlite3") @@ -24,7 +25,6 @@ struct ContentDatabase { try Self.migrate(databaseQueue) try Self.createTemporaryTables(databaseQueue) - Self.attributedStringCache = environment.attributedStringCache } } @@ -131,8 +131,6 @@ extension ContentDatabase { } private extension ContentDatabase { - static var attributedStringCache: AttributedStringCache? - // swiftlint:disable function_body_length static func migrate(_ writer: DatabaseWriter) throws { var migrator = DatabaseMigrator() @@ -244,21 +242,11 @@ private extension ContentDatabase { } extension Account: TableRecord, FetchableRecord, PersistableRecord { - static var databaseDecodingUserInfo: [CodingUserInfoKey: Any] { - var userInfo = [CodingUserInfoKey: Any]() - - if let attributedStringCache = ContentDatabase.attributedStringCache { - userInfo[.attributedStringCache] = attributedStringCache - } - - return userInfo - } - - static func databaseJSONDecoder(for column: String) -> JSONDecoder { + public static func databaseJSONDecoder(for column: String) -> JSONDecoder { MastodonDecoder() } - static func databaseJSONEncoder(for column: String) -> JSONEncoder { + public static func databaseJSONEncoder(for column: String) -> JSONEncoder { MastodonEncoder() } } @@ -282,7 +270,7 @@ extension Timeline: StatusCollection { case id, listTitle } - init(row: Row) { + public init(row: Row) { switch (row[Columns.id] as String, row[Columns.listTitle] as String?) { case (Timeline.home.id, _): self = .home @@ -297,7 +285,7 @@ extension Timeline: StatusCollection { } } - func encode(to container: inout PersistenceContainer) { + public func encode(to container: inout PersistenceContainer) { container[Columns.id] = id if case let .list(list) = self { @@ -336,11 +324,11 @@ private extension Timeline { } extension Filter: TableRecord, FetchableRecord, PersistableRecord { - static func databaseJSONDecoder(for column: String) -> JSONDecoder { + public static func databaseJSONDecoder(for column: String) -> JSONDecoder { MastodonDecoder() } - static func databaseJSONEncoder(for column: String) -> JSONEncoder { + public static func databaseJSONEncoder(for column: String) -> JSONEncoder { MastodonEncoder() } } @@ -464,16 +452,6 @@ private extension StoredStatus { } extension StoredStatus: TableRecord, FetchableRecord, PersistableRecord { - static var databaseDecodingUserInfo: [CodingUserInfoKey: Any] { - var userInfo = [CodingUserInfoKey: Any]() - - if let attributedStringCache = ContentDatabase.attributedStringCache { - userInfo[.attributedStringCache] = attributedStringCache - } - - return userInfo - } - static func databaseJSONDecoder(for column: String) -> JSONDecoder { MastodonDecoder() } diff --git a/Databases/IdentityDatabase.swift b/Databases/IdentityDatabase.swift index 275f9da..e63591a 100644 --- a/Databases/IdentityDatabase.swift +++ b/Databases/IdentityDatabase.swift @@ -3,6 +3,7 @@ import Foundation import Combine import GRDB +import Mastodon enum IdentityDatabaseError: Error { case identityNotFound diff --git a/Development Assets/DevelopmentModels.swift b/Development Assets/DevelopmentModels.swift index 98e8e6e..f1c82d9 100644 --- a/Development Assets/DevelopmentModels.swift +++ b/Development Assets/DevelopmentModels.swift @@ -2,6 +2,7 @@ import Foundation import Combine +import Mastodon // swiftlint:disable force_try private let decoder = MastodonDecoder() @@ -119,7 +120,7 @@ extension FiltersViewModel { } extension EditFilterViewModel { - static let development = EditFilterViewModel(filter: .new, identityService: .development) + static let development = EditFilterViewModel(filter: Filter.new, identityService: .development) } extension StatusListViewModel { diff --git a/Development Assets/HTTPStubs.swift b/Development Assets/HTTPStubs.swift index b18aae3..6e7d48a 100644 --- a/Development Assets/HTTPStubs.swift +++ b/Development Assets/HTTPStubs.swift @@ -1,6 +1,7 @@ // Copyright © 2020 Metabolist. All rights reserved. import Foundation +import Mastodon struct HTTPStubs { static func stub( diff --git a/Development Assets/Mastodon API Stubs/AccessTokenEndpoint+Stubbing.swift b/Development Assets/Mastodon API Stubs/AccessTokenEndpoint+Stubbing.swift index ce5516c..1989ee8 100644 --- a/Development Assets/Mastodon API Stubs/AccessTokenEndpoint+Stubbing.swift +++ b/Development Assets/Mastodon API Stubs/AccessTokenEndpoint+Stubbing.swift @@ -1,6 +1,7 @@ // Copyright © 2020 Metabolist. All rights reserved. import Foundation +import Mastodon extension AccessTokenEndpoint: Stubbing { func dataString(url: URL) -> String? { diff --git a/Development Assets/Mastodon API Stubs/AccountEndpoint+Stubbing.swift b/Development Assets/Mastodon API Stubs/AccountEndpoint+Stubbing.swift index 09c4939..c5c64d2 100644 --- a/Development Assets/Mastodon API Stubs/AccountEndpoint+Stubbing.swift +++ b/Development Assets/Mastodon API Stubs/AccountEndpoint+Stubbing.swift @@ -1,6 +1,7 @@ // Copyright © 2020 Metabolist. All rights reserved. import Foundation +import Mastodon // swiftlint:disable line_length let officialAccountJSON = #""" diff --git a/Development Assets/Mastodon API Stubs/AppAuthorizationEndpoint+Stubbing.swift b/Development Assets/Mastodon API Stubs/AppAuthorizationEndpoint+Stubbing.swift index 9cb1d6e..9ef836e 100644 --- a/Development Assets/Mastodon API Stubs/AppAuthorizationEndpoint+Stubbing.swift +++ b/Development Assets/Mastodon API Stubs/AppAuthorizationEndpoint+Stubbing.swift @@ -1,6 +1,7 @@ // Copyright © 2020 Metabolist. All rights reserved. import Foundation +import Mastodon extension AppAuthorizationEndpoint: Stubbing { func dataString(url: URL) -> String? { diff --git a/Development Assets/Mastodon API Stubs/ContextEndpoint+Stubbing.swift b/Development Assets/Mastodon API Stubs/ContextEndpoint+Stubbing.swift index ff0a60a..d7afbca 100644 --- a/Development Assets/Mastodon API Stubs/ContextEndpoint+Stubbing.swift +++ b/Development Assets/Mastodon API Stubs/ContextEndpoint+Stubbing.swift @@ -1,6 +1,7 @@ // Copyright © 2020 Metabolist. All rights reserved. import Foundation +import Mastodon extension ContextEndpoint: Stubbing { func dataString(url: URL) -> String? { diff --git a/Development Assets/Mastodon API Stubs/InstanceEndpoint+Stubbing.swift b/Development Assets/Mastodon API Stubs/InstanceEndpoint+Stubbing.swift index 98ff2ec..d60cdd1 100644 --- a/Development Assets/Mastodon API Stubs/InstanceEndpoint+Stubbing.swift +++ b/Development Assets/Mastodon API Stubs/InstanceEndpoint+Stubbing.swift @@ -1,6 +1,7 @@ // Copyright © 2020 Metabolist. All rights reserved. import Foundation +import Mastodon // swiftlint:disable line_length let officialInstanceJSON = #""" diff --git a/Development Assets/Mastodon API Stubs/MastodonTarget+Stubbing.swift b/Development Assets/Mastodon API Stubs/MastodonTarget+Stubbing.swift index fee53ca..4238482 100644 --- a/Development Assets/Mastodon API Stubs/MastodonTarget+Stubbing.swift +++ b/Development Assets/Mastodon API Stubs/MastodonTarget+Stubbing.swift @@ -1,6 +1,7 @@ // Copyright © 2020 Metabolist. All rights reserved. import Foundation +import Mastodon extension MastodonTarget: Stubbing { func stub(url: URL) -> HTTPStub? { diff --git a/Development Assets/Mastodon API Stubs/PreferencesEndpoint+Stubbing.swift b/Development Assets/Mastodon API Stubs/PreferencesEndpoint+Stubbing.swift index 0286656..ca53be3 100644 --- a/Development Assets/Mastodon API Stubs/PreferencesEndpoint+Stubbing.swift +++ b/Development Assets/Mastodon API Stubs/PreferencesEndpoint+Stubbing.swift @@ -1,6 +1,7 @@ // Copyright © 2020 Metabolist. All rights reserved. import Foundation +import Mastodon extension PreferencesEndpoint: Stubbing { func dataString(url: URL) -> String? { diff --git a/Development Assets/Mastodon API Stubs/TimelinesEndpoint+Stubbing.swift b/Development Assets/Mastodon API Stubs/TimelinesEndpoint+Stubbing.swift index f633e61..64fcc30 100644 --- a/Development Assets/Mastodon API Stubs/TimelinesEndpoint+Stubbing.swift +++ b/Development Assets/Mastodon API Stubs/TimelinesEndpoint+Stubbing.swift @@ -2,6 +2,7 @@ import Foundation import UIKit +import Mastodon extension TimelinesEndpoint: Stubbing { func data(url: URL) -> Data? { diff --git a/Development Assets/StubbingURLProtocol.swift b/Development Assets/StubbingURLProtocol.swift index dbfab8d..f32e1e2 100644 --- a/Development Assets/StubbingURLProtocol.swift +++ b/Development Assets/StubbingURLProtocol.swift @@ -1,6 +1,7 @@ // Copyright © 2020 Metabolist. All rights reserved. import Foundation +import Mastodon class StubbingURLProtocol: URLProtocol { private static var targetsForURLs = [URL: HTTPTarget]() diff --git a/Extensions/CodingUserInfoKey+Extensions.swift b/Extensions/CodingUserInfoKey+Extensions.swift deleted file mode 100644 index ce3f707..0000000 --- a/Extensions/CodingUserInfoKey+Extensions.swift +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Foundation - -typealias AttributedStringCache = NSCache - -extension CodingUserInfoKey { - static let attributedStringCache = CodingUserInfoKey(rawValue: "com.metabolist.metatext.attributed-string-cache")! -} diff --git a/Extensions/NSMutableAttributedString+Extensions.swift b/Extensions/NSMutableAttributedString+Extensions.swift index 57d320e..89c134b 100644 --- a/Extensions/NSMutableAttributedString+Extensions.swift +++ b/Extensions/NSMutableAttributedString+Extensions.swift @@ -2,6 +2,7 @@ import UIKit import Kingfisher +import Mastodon extension NSMutableAttributedString { func insert(emoji: [Emoji], view: UIView) { diff --git a/Mastodon/.gitignore b/Mastodon/.gitignore new file mode 100644 index 0000000..95c4320 --- /dev/null +++ b/Mastodon/.gitignore @@ -0,0 +1,5 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ diff --git a/Mastodon/Package.swift b/Mastodon/Package.swift new file mode 100644 index 0000000..fb03bc2 --- /dev/null +++ b/Mastodon/Package.swift @@ -0,0 +1,29 @@ +// swift-tools-version:5.3 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "Mastodon", + platforms: [.iOS(.v14), .macOS(.v11)], + products: [ + // Products define the executables and libraries a package produces, and make them visible to other packages. + .library( + name: "Mastodon", + targets: ["Mastodon"]) + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + .package(url: "https://github.com/Alamofire/Alamofire.git", .upToNextMajor(from: "5.2.2")) + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages this package depends on. + .target( + name: "Mastodon", + dependencies: ["Alamofire"]), + .testTarget( + name: "MastodonTests", + dependencies: ["Mastodon"]) + ] +) diff --git a/Mastodon/README.md b/Mastodon/README.md new file mode 100644 index 0000000..cd977ae --- /dev/null +++ b/Mastodon/README.md @@ -0,0 +1,3 @@ +# Mastodon + +A description of this package. diff --git a/Mastodon/Sources/Mastodon/Constants.swift b/Mastodon/Sources/Mastodon/Constants.swift new file mode 100644 index 0000000..15d4594 --- /dev/null +++ b/Mastodon/Sources/Mastodon/Constants.swift @@ -0,0 +1,5 @@ +import Foundation + +public enum Constants { + public static let dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" +} diff --git a/Mastodon/Sources/Mastodon/Entities/AccessToken.swift b/Mastodon/Sources/Mastodon/Entities/AccessToken.swift new file mode 100644 index 0000000..608e3f4 --- /dev/null +++ b/Mastodon/Sources/Mastodon/Entities/AccessToken.swift @@ -0,0 +1,9 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import Foundation + +public struct AccessToken: Codable { + public let scope: String + public let tokenType: String + public let accessToken: String +} diff --git a/Mastodon/Sources/Mastodon/Entities/Account.swift b/Mastodon/Sources/Mastodon/Entities/Account.swift new file mode 100644 index 0000000..5a4153f --- /dev/null +++ b/Mastodon/Sources/Mastodon/Entities/Account.swift @@ -0,0 +1,32 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import Foundation + +public struct Account: Codable, Hashable { + public struct Field: Codable, Hashable { + public let name: String + public let value: HTML + public let verifiedAt: Date? + } + + public let id: String + public let username: String + public let acct: String + public let displayName: String + public let locked: Bool + public let createdAt: Date + public let followersCount: Int + public let followingCount: Int + public let statusesCount: Int + public let note: HTML + public let url: URL + public let avatar: URL + public let avatarStatic: URL + public let header: URL + public let headerStatic: URL + public let fields: [Field] + public let emojis: [Emoji] + @DecodableDefault.False public private(set) var bot: Bool + @DecodableDefault.False public private(set) var moved: Bool + @DecodableDefault.False public private(set) var discoverable: Bool +} diff --git a/Mastodon/Sources/Mastodon/Entities/AppAuthorization.swift b/Mastodon/Sources/Mastodon/Entities/AppAuthorization.swift new file mode 100644 index 0000000..9a79c62 --- /dev/null +++ b/Mastodon/Sources/Mastodon/Entities/AppAuthorization.swift @@ -0,0 +1,13 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import Foundation + +public struct AppAuthorization: Codable { + public let id: String + public let clientId: String + public let clientSecret: String + public let name: String + public let redirectUri: String + public let website: String? + public let vapidKey: String? +} diff --git a/Mastodon/Sources/Mastodon/Entities/Application.swift b/Mastodon/Sources/Mastodon/Entities/Application.swift new file mode 100644 index 0000000..44428ba --- /dev/null +++ b/Mastodon/Sources/Mastodon/Entities/Application.swift @@ -0,0 +1,8 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import Foundation + +public struct Application: Codable, Hashable { + public let name: String + public let website: String? +} diff --git a/Mastodon/Sources/Mastodon/Entities/Attachment.swift b/Mastodon/Sources/Mastodon/Entities/Attachment.swift new file mode 100644 index 0000000..eed505d --- /dev/null +++ b/Mastodon/Sources/Mastodon/Entities/Attachment.swift @@ -0,0 +1,43 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import Foundation + +public struct Attachment: Codable, Hashable { + public enum AttachmentType: String, Codable, Hashable, Unknowable { + case image, video, gifv, audio, unknown + + public static var unknownCase: Self { .unknown } + } + + // swiftlint:disable nesting + public struct Meta: Codable, Hashable { + public struct Info: Codable, Hashable { + public let width: Int? + public let height: Int? + public let size: String? + public let aspect: Double? + public let frameRate: String? + public let duration: Double? + public let bitrate: Int? + } + + public struct Focus: Codable, Hashable { + public let x: Double + public let y: Double + } + + public let original: Info? + public let small: Info? + public let focus: Focus? + } + // swiftlint:enable nesting + + public let id: String + public let type: AttachmentType + public let url: URL + public let remoteUrl: URL? + public let previewUrl: URL + public let textUrl: URL? + public let meta: Meta? + public let description: String? +} diff --git a/Mastodon/Sources/Mastodon/Entities/Card.swift b/Mastodon/Sources/Mastodon/Entities/Card.swift new file mode 100644 index 0000000..2c22dd2 --- /dev/null +++ b/Mastodon/Sources/Mastodon/Entities/Card.swift @@ -0,0 +1,25 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import Foundation + +public struct Card: Codable, Hashable { + public enum CardType: String, Codable, Hashable, Unknowable { + case link, photo, video, rich, unknown + + public static var unknownCase: Self { .unknown } + } + + public let url: URL + public let title: String + public let description: String + public let type: CardType + public let authorName: String? + public let authorUrl: String? + public let providerName: String? + public let providerUrl: String? + public let html: String? + public let width: Int? + public let height: Int? + public let image: URL? + public let embedUrl: String? +} diff --git a/Mastodon/Sources/Mastodon/Entities/Emoji.swift b/Mastodon/Sources/Mastodon/Entities/Emoji.swift new file mode 100644 index 0000000..df39dd3 --- /dev/null +++ b/Mastodon/Sources/Mastodon/Entities/Emoji.swift @@ -0,0 +1,10 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import Foundation + +public struct Emoji: Codable, Hashable { + public let shortcode: String + public let staticUrl: URL + public let url: URL + public let visibleInPicker: Bool +} diff --git a/Model/Filter.swift b/Mastodon/Sources/Mastodon/Entities/Filter.swift similarity index 57% rename from Model/Filter.swift rename to Mastodon/Sources/Mastodon/Entities/Filter.swift index 775e67a..78e2441 100644 --- a/Model/Filter.swift +++ b/Mastodon/Sources/Mastodon/Entities/Filter.swift @@ -2,8 +2,8 @@ import Foundation -struct Filter: Codable, Hashable, Identifiable { - enum Context: String, Codable, Unknowable { +public struct Filter: Codable, Hashable, Identifiable { + public enum Context: String, Codable, Unknowable { case home case notifications case `public` @@ -11,18 +11,18 @@ struct Filter: Codable, Hashable, Identifiable { case account case unknown - static var unknownCase: Self { .unknown } + public static var unknownCase: Self { .unknown } } - let id: String - var phrase: String - var context: [Context] - var expiresAt: Date? - var irreversible: Bool - var wholeWord: Bool + public let id: String + public var phrase: String + public var context: [Context] + public var expiresAt: Date? + public var irreversible: Bool + public var wholeWord: Bool } -extension Filter { +public extension Filter { static let newFilterID: String = "com.metabolist.metatext.new-filter-id" static let new = Self(id: newFilterID, phrase: "", @@ -36,7 +36,7 @@ extension Array where Element == Filter { // swiftlint:disable line_length // Adapted from https://github.com/tootsuite/mastodon/blob/bf477cee9f31036ebf3d164ddec1cebef5375513/app/javascript/mastodon/selectors/index.js#L43 // swiftlint:enable line_length - func regularExpression() -> String? { + public func regularExpression() -> String? { guard !isEmpty else { return nil } return map { @@ -59,24 +59,5 @@ extension Array where Element == Filter { } extension Filter.Context: Identifiable { - var id: Self { self } -} - -extension Filter.Context { - var localized: String { - switch self { - case .home: - return NSLocalizedString("filter.context.home", comment: "") - case .notifications: - return NSLocalizedString("filter.context.notifications", comment: "") - case .public: - return NSLocalizedString("filter.context.public", comment: "") - case .thread: - return NSLocalizedString("filter.context.thread", comment: "") - case .account: - return NSLocalizedString("filter.context.account", comment: "") - case .unknown: - return NSLocalizedString("filter.context.unknown", comment: "") - } - } + public var id: Self { self } } diff --git a/Model/HTML.swift b/Mastodon/Sources/Mastodon/Entities/HTML.swift similarity index 86% rename from Model/HTML.swift rename to Mastodon/Sources/Mastodon/Entities/HTML.swift index 5abbad6..01138c5 100644 --- a/Model/HTML.swift +++ b/Mastodon/Sources/Mastodon/Entities/HTML.swift @@ -1,30 +1,26 @@ // Copyright © 2020 Metabolist. All rights reserved. import Foundation +#if !os(macOS) +import UIKit +#else +import AppKit +#endif -struct HTML: Hashable { - let raw: String - let attributed: NSAttributedString +public struct HTML: Hashable { + public let raw: String + public let attributed: NSAttributedString } extension HTML: Codable { - init(from decoder: Decoder) throws { + public init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() - let attributedStringCache = decoder.userInfo[.attributedStringCache] as? AttributedStringCache raw = try container.decode(String.self) - - if let attributed = attributedStringCache?.object(forKey: raw as NSString) { - self.attributed = attributed - - return - } - attributed = HTMLParser(string: raw).parse() - attributedStringCache?.setObject(attributed, forKey: raw as NSString) } - func encode(to encoder: Encoder) throws { + public func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() try container.encode(raw) diff --git a/Mastodon/Sources/Mastodon/Entities/Instance.swift b/Mastodon/Sources/Mastodon/Entities/Instance.swift new file mode 100644 index 0000000..080df19 --- /dev/null +++ b/Mastodon/Sources/Mastodon/Entities/Instance.swift @@ -0,0 +1,30 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import Foundation + +public struct Instance: Codable, Hashable { + public struct URLs: Codable, Hashable { + public let streamingApi: URL + } + + public struct Stats: Codable, Hashable { + public let userCount: Int + public let statusCount: Int + public let domainCount: Int + } + + public let uri: String + public let title: String + public let description: String + public let shortDescription: String? + public let email: String + public let version: String + @DecodableDefault.EmptyList public private(set) var languages: [String] + @DecodableDefault.False public private(set) var registrations: Bool + @DecodableDefault.False public private(set) var approvalRequired: Bool + @DecodableDefault.False public private(set) var invitesEnabled: Bool + public let urls: URLs + public let stats: Stats + public let thumbnail: URL? + public let contactAccount: Account? +} diff --git a/Mastodon/Sources/Mastodon/Entities/List.swift b/Mastodon/Sources/Mastodon/Entities/List.swift new file mode 100644 index 0000000..6b76a00 --- /dev/null +++ b/Mastodon/Sources/Mastodon/Entities/List.swift @@ -0,0 +1,13 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import Foundation + +public struct MastodonList: Codable, Hashable, Identifiable { + public let id: String + public let title: String + + public init(id: String, title: String) { + self.id = id + self.title = title + } +} diff --git a/Mastodon/Sources/Mastodon/Entities/MastodonContext.swift b/Mastodon/Sources/Mastodon/Entities/MastodonContext.swift new file mode 100644 index 0000000..fcdd891 --- /dev/null +++ b/Mastodon/Sources/Mastodon/Entities/MastodonContext.swift @@ -0,0 +1,13 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import Foundation + +public struct MastodonContext: Codable, Hashable { + public let ancestors: [Status] + public let descendants: [Status] + + public init(ancestors: [Status], descendants: [Status]) { + self.ancestors = ancestors + self.descendants = descendants + } +} diff --git a/Mastodon/Sources/Mastodon/Entities/MastodonError.swift b/Mastodon/Sources/Mastodon/Entities/MastodonError.swift new file mode 100644 index 0000000..a32d802 --- /dev/null +++ b/Mastodon/Sources/Mastodon/Entities/MastodonError.swift @@ -0,0 +1,11 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import Foundation + +public struct MastodonError: Error, Codable { + public let error: String +} + +extension MastodonError: LocalizedError { + public var errorDescription: String? { error } +} diff --git a/Model/MastodonPreferences.swift b/Mastodon/Sources/Mastodon/Entities/MastodonPreferences.swift similarity index 60% rename from Model/MastodonPreferences.swift rename to Mastodon/Sources/Mastodon/Entities/MastodonPreferences.swift index 55250b3..05048b8 100644 --- a/Model/MastodonPreferences.swift +++ b/Mastodon/Sources/Mastodon/Entities/MastodonPreferences.swift @@ -2,7 +2,7 @@ import Foundation -struct MastodonPreferences: Codable { +public struct MastodonPreferences: Codable { enum CodingKeys: String, CodingKey { case postingDefaultVisibility = "posting:default:visibility" case postingDefaultSensitive = "posting:default:sensitive" @@ -11,20 +11,20 @@ struct MastodonPreferences: Codable { case readingExpandSpoilers = "reading:expand:spoilers" } - let postingDefaultVisibility: Status.Visibility - let postingDefaultSensitive: Bool - let postingDefaultLanguage: String? - let readingExpandMedia: ExpandMedia - let readingExpandSpoilers: Bool + public let postingDefaultVisibility: Status.Visibility + public let postingDefaultSensitive: Bool + public let postingDefaultLanguage: String? + public let readingExpandMedia: ExpandMedia + public let readingExpandSpoilers: Bool } -extension MastodonPreferences { +public extension MastodonPreferences { enum ExpandMedia: String, Codable, Unknowable { case `default` case showAll case hideAll case unknown - static var unknownCase: Self { .unknown } + public static var unknownCase: Self { .unknown } } } diff --git a/Mastodon/Sources/Mastodon/Entities/Mention.swift b/Mastodon/Sources/Mastodon/Entities/Mention.swift new file mode 100644 index 0000000..572fa69 --- /dev/null +++ b/Mastodon/Sources/Mastodon/Entities/Mention.swift @@ -0,0 +1,10 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import Foundation + +public struct Mention: Codable, Hashable { + public let url: URL + public let username: String + public let acct: String + public let id: String +} diff --git a/Mastodon/Sources/Mastodon/Entities/Poll.swift b/Mastodon/Sources/Mastodon/Entities/Poll.swift new file mode 100644 index 0000000..f42e079 --- /dev/null +++ b/Mastodon/Sources/Mastodon/Entities/Poll.swift @@ -0,0 +1,21 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import Foundation + +public struct Poll: Codable, Hashable { + public struct Option: Codable, Hashable { + public var title: String + public var votesCount: Int + } + + public let id: String + public let expiresAt: Date + public let expired: Bool + public let multiple: Bool + public let votesCount: Int + public let votersCount: Int? + @DecodableDefault.False public private(set) var voted: Bool + @DecodableDefault.EmptyList public private(set) var ownVotes: [Int] + public let options: [Option] + public let emojis: [Emoji] +} diff --git a/Mastodon/Sources/Mastodon/Entities/PushNotification.swift b/Mastodon/Sources/Mastodon/Entities/PushNotification.swift new file mode 100644 index 0000000..4d6e88d --- /dev/null +++ b/Mastodon/Sources/Mastodon/Entities/PushNotification.swift @@ -0,0 +1,23 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import Foundation + +public struct PushNotification: Codable { + public enum NotificationType: String, Codable, Unknowable { + case mention + case reblog + case favourite + case follow + case unknown + + public static var unknownCase: Self { .unknown } + } + + public let accessToken: String + public let body: String + public let title: String + public let icon: URL + public let notificationId: Int + public let notificationType: NotificationType + public let preferredLocale: String +} diff --git a/Mastodon/Sources/Mastodon/Entities/PushSubscription.swift b/Mastodon/Sources/Mastodon/Entities/PushSubscription.swift new file mode 100644 index 0000000..f2523c2 --- /dev/null +++ b/Mastodon/Sources/Mastodon/Entities/PushSubscription.swift @@ -0,0 +1,26 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import Foundation + +public struct PushSubscription: Codable { + public struct Alerts: Codable, Hashable { + public var follow: Bool + public var favourite: Bool + public var reblog: Bool + public var mention: Bool + @DecodableDefault.True public var poll: Bool + } + + public let endpoint: URL + public let alerts: Alerts + public let serverKey: String +} + +public extension PushSubscription.Alerts { + static let initial: Self = Self( + follow: true, + favourite: true, + reblog: true, + mention: true, + poll: DecodableDefault.True()) +} diff --git a/Model/Status.swift b/Mastodon/Sources/Mastodon/Entities/Status.swift similarity index 76% rename from Model/Status.swift rename to Mastodon/Sources/Mastodon/Entities/Status.swift index 3fcd543..cbfbc42 100644 --- a/Model/Status.swift +++ b/Mastodon/Sources/Mastodon/Entities/Status.swift @@ -2,49 +2,49 @@ import Foundation -class Status: Codable, Identifiable { - enum Visibility: String, Codable, Unknowable { +public class Status: Codable, Identifiable { + public enum Visibility: String, Codable, Unknowable { case `public` case unlisted case `private` case direct case unknown - static var unknownCase: Self { .unknown } + public static var unknownCase: Self { .unknown } } - let id: String - let uri: String - let createdAt: Date - let account: Account - let content: HTML - let visibility: Visibility - let sensitive: Bool - let spoilerText: String - let mediaAttachments: [Attachment] - let mentions: [Mention] - let tags: [Tag] - let emojis: [Emoji] - let reblogsCount: Int - let favouritesCount: Int - @DecodableDefault.Zero private(set) var repliesCount: Int - let application: Application? - let url: URL? - let inReplyToId: String? - let inReplyToAccountId: String? - let reblog: Status? - let poll: Poll? - let card: Card? - let language: String? - let text: String? - @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? + public let id: String + public let uri: String + public let createdAt: Date + public let account: Account + public let content: HTML + public let visibility: Visibility + public let sensitive: Bool + public let spoilerText: String + public let mediaAttachments: [Attachment] + public let mentions: [Mention] + public let tags: [Tag] + public let emojis: [Emoji] + public let reblogsCount: Int + public let favouritesCount: Int + @DecodableDefault.Zero public private(set) var repliesCount: Int + public let application: Application? + public let url: URL? + public let inReplyToId: String? + public let inReplyToAccountId: String? + public let reblog: Status? + public let poll: Poll? + public let card: Card? + public let language: String? + public let text: String? + @DecodableDefault.False public private(set) var favourited: Bool + @DecodableDefault.False public private(set) var reblogged: Bool + @DecodableDefault.False public private(set) var muted: Bool + @DecodableDefault.False public private(set) var bookmarked: Bool + public let pinned: Bool? // Xcode-generated memberwise initializer - init( + public init( id: String, uri: String, createdAt: Date, @@ -88,7 +88,6 @@ class Status: Codable, Identifiable { self.emojis = emojis self.reblogsCount = reblogsCount self.favouritesCount = favouritesCount - self.repliesCount = repliesCount self.application = application self.url = url self.inReplyToId = inReplyToId @@ -98,15 +97,16 @@ class Status: Codable, Identifiable { self.card = card self.language = language self.text = text + self.pinned = pinned + self.repliesCount = repliesCount self.favourited = favourited self.reblogged = reblogged self.muted = muted self.bookmarked = bookmarked - self.pinned = pinned } } -extension Status { +public extension Status { var displayStatus: Status { reblog ?? self } @@ -121,7 +121,7 @@ extension Status { } extension Status: Hashable { - static func == (lhs: Status, rhs: Status) -> Bool { + public static func == (lhs: Status, rhs: Status) -> Bool { lhs.id == rhs.id && lhs.uri == rhs.uri && lhs.createdAt == rhs.createdAt @@ -153,7 +153,7 @@ extension Status: Hashable { && lhs.pinned == rhs.pinned } - func hash(into hasher: inout Hasher) { + public func hash(into hasher: inout Hasher) { hasher.combine(id) hasher.combine(uri) hasher.combine(createdAt) diff --git a/Mastodon/Sources/Mastodon/Entities/Tag.swift b/Mastodon/Sources/Mastodon/Entities/Tag.swift new file mode 100644 index 0000000..d173fdb --- /dev/null +++ b/Mastodon/Sources/Mastodon/Entities/Tag.swift @@ -0,0 +1,8 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import Foundation + +public struct Tag: Codable, Hashable { + public let name: String + public let url: URL +} diff --git a/Model/Timeline.swift b/Mastodon/Sources/Mastodon/Entities/Timeline.swift similarity index 91% rename from Model/Timeline.swift rename to Mastodon/Sources/Mastodon/Entities/Timeline.swift index 1b2c9dc..8ea3a45 100644 --- a/Model/Timeline.swift +++ b/Mastodon/Sources/Mastodon/Entities/Timeline.swift @@ -2,7 +2,7 @@ import Foundation -enum Timeline: Hashable { +public enum Timeline: Hashable { case home case local case federated @@ -10,7 +10,7 @@ enum Timeline: Hashable { case tag(String) } -extension Timeline { +public extension Timeline { static let nonLists: [Timeline] = [.home, .local, .federated] var endpoint: TimelinesEndpoint { @@ -30,7 +30,7 @@ extension Timeline { } extension Timeline: Identifiable { - var id: String { + public var id: String { switch self { case .home: return "home" diff --git a/Networking/HTTPClient.swift b/Mastodon/Sources/Mastodon/Networking/HTTPClient.swift similarity index 68% rename from Networking/HTTPClient.swift rename to Mastodon/Sources/Mastodon/Networking/HTTPClient.swift index a1c85eb..2e85b1c 100644 --- a/Networking/HTTPClient.swift +++ b/Mastodon/Sources/Mastodon/Networking/HTTPClient.swift @@ -4,22 +4,22 @@ import Foundation import Combine import Alamofire -typealias Session = Alamofire.Session +public typealias Session = Alamofire.Session -class HTTPClient { +public class HTTPClient { private let session: Session private let decoder: DataDecoder - init(session: Session, decoder: DataDecoder) { + public init(session: Session, decoder: DataDecoder) { self.session = session self.decoder = decoder } - func request(_ target: T) -> AnyPublisher { + public func request(_ target: T) -> AnyPublisher { requestPublisher(target).value().mapError { $0 as Error }.eraseToAnyPublisher() } - func request( + public func request( _ target: T, decodeErrorsAs errorType: E.Type) -> AnyPublisher { let decoder = self.decoder @@ -43,12 +43,12 @@ class HTTPClient { } private extension HTTPClient { - private func requestPublisher(_ target: T) -> DataResponsePublisher { - #if DEBUG - if let url = try? target.asURLRequest().url { - StubbingURLProtocol.setTarget(target, forURL: url) - } - #endif + func requestPublisher(_ target: T) -> DataResponsePublisher { +// #if DEBUG +// if let url = try? target.asURLRequest().url { +// StubbingURLProtocol.setTarget(target, forURL: url) +// } +// #endif return session.request(target) .validate() diff --git a/Networking/HTTPTarget.swift b/Mastodon/Sources/Mastodon/Networking/HTTPTarget.swift similarity index 62% rename from Networking/HTTPTarget.swift rename to Mastodon/Sources/Mastodon/Networking/HTTPTarget.swift index 753b222..2cfde03 100644 --- a/Networking/HTTPTarget.swift +++ b/Mastodon/Sources/Mastodon/Networking/HTTPTarget.swift @@ -3,13 +3,13 @@ import Foundation import Alamofire -typealias HTTPMethod = Alamofire.HTTPMethod -typealias HTTPHeaders = Alamofire.HTTPHeaders -typealias ParameterEncoding = Alamofire.ParameterEncoding -typealias URLEncoding = Alamofire.URLEncoding -typealias JSONEncoding = Alamofire.JSONEncoding +public typealias HTTPMethod = Alamofire.HTTPMethod +public typealias HTTPHeaders = Alamofire.HTTPHeaders +public typealias ParameterEncoding = Alamofire.ParameterEncoding +public typealias URLEncoding = Alamofire.URLEncoding +public typealias JSONEncoding = Alamofire.JSONEncoding -protocol HTTPTarget: URLRequestConvertible { +public protocol HTTPTarget: URLRequestConvertible { var baseURL: URL { get } var pathComponents: [String] { get } var method: HTTPMethod { get } @@ -18,7 +18,7 @@ protocol HTTPTarget: URLRequestConvertible { var headers: HTTPHeaders? { get } } -extension HTTPTarget { +public extension HTTPTarget { func asURLRequest() throws -> URLRequest { var url = baseURL @@ -30,6 +30,6 @@ extension HTTPTarget { } } -protocol DecodableTarget: HTTPTarget { +public protocol DecodableTarget: HTTPTarget { associatedtype ResultType: Decodable } diff --git a/Networking/Mastodon API/Endpoints/AccessTokenEndpoint.swift b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/AccessTokenEndpoint.swift similarity index 76% rename from Networking/Mastodon API/Endpoints/AccessTokenEndpoint.swift rename to Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/AccessTokenEndpoint.swift index 0ab60b5..0816028 100644 --- a/Networking/Mastodon API/Endpoints/AccessTokenEndpoint.swift +++ b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/AccessTokenEndpoint.swift @@ -2,7 +2,7 @@ import Foundation -enum AccessTokenEndpoint { +public enum AccessTokenEndpoint { case oauthToken( clientID: String, clientSecret: String, @@ -14,21 +14,21 @@ enum AccessTokenEndpoint { } extension AccessTokenEndpoint: MastodonEndpoint { - typealias ResultType = AccessToken + public typealias ResultType = AccessToken - var context: [String] { [] } + public var context: [String] { [] } - var pathComponentsInContext: [String] { + public var pathComponentsInContext: [String] { ["oauth", "token"] } - var method: HTTPMethod { + public var method: HTTPMethod { switch self { case .oauthToken: return .post } } - var parameters: [String: Any]? { + public var parameters: [String: Any]? { switch self { case let .oauthToken(clientID, clientSecret, code, grantType, scopes, redirectURI): return [ diff --git a/Networking/Mastodon API/Endpoints/AccountEndpoint.swift b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/AccountEndpoint.swift similarity index 66% rename from Networking/Mastodon API/Endpoints/AccountEndpoint.swift rename to Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/AccountEndpoint.swift index ac7e666..a3143e3 100644 --- a/Networking/Mastodon API/Endpoints/AccountEndpoint.swift +++ b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/AccountEndpoint.swift @@ -2,24 +2,24 @@ import Foundation -enum AccountEndpoint { +public enum AccountEndpoint { case verifyCredentials } extension AccountEndpoint: MastodonEndpoint { - typealias ResultType = Account + public typealias ResultType = Account - var context: [String] { + public var context: [String] { defaultContext + ["accounts"] } - var pathComponentsInContext: [String] { + public var pathComponentsInContext: [String] { switch self { case .verifyCredentials: return ["verify_credentials"] } } - var method: HTTPMethod { + public var method: HTTPMethod { switch self { case .verifyCredentials: return .get } diff --git a/Networking/Mastodon API/Endpoints/AppAuthorizationEndpoint.swift b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/AppAuthorizationEndpoint.swift similarity index 76% rename from Networking/Mastodon API/Endpoints/AppAuthorizationEndpoint.swift rename to Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/AppAuthorizationEndpoint.swift index a431f23..b887841 100644 --- a/Networking/Mastodon API/Endpoints/AppAuthorizationEndpoint.swift +++ b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/AppAuthorizationEndpoint.swift @@ -2,26 +2,26 @@ import Foundation -enum AppAuthorizationEndpoint { +public enum AppAuthorizationEndpoint { case apps(clientName: String, redirectURI: String, scopes: String, website: URL?) } extension AppAuthorizationEndpoint: MastodonEndpoint { - typealias ResultType = AppAuthorization + public typealias ResultType = AppAuthorization - var pathComponentsInContext: [String] { + public var pathComponentsInContext: [String] { switch self { case .apps: return ["apps"] } } - var method: HTTPMethod { + public var method: HTTPMethod { switch self { case .apps: return .post } } - var parameters: [String: Any]? { + public var parameters: [String: Any]? { switch self { case let .apps(clientName, redirectURI, scopes, website): var params = [ diff --git a/Networking/Mastodon API/Endpoints/ContextEndpoint.swift b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/ContextEndpoint.swift similarity index 59% rename from Networking/Mastodon API/Endpoints/ContextEndpoint.swift rename to Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/ContextEndpoint.swift index 8f91063..1ec70d3 100644 --- a/Networking/Mastodon API/Endpoints/ContextEndpoint.swift +++ b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/ContextEndpoint.swift @@ -2,23 +2,23 @@ import Foundation -enum ContextEndpoint { +public enum ContextEndpoint { case context(id: String) } extension ContextEndpoint: MastodonEndpoint { - typealias ResultType = MastodonContext + public typealias ResultType = MastodonContext - var context: [String] { + public var context: [String] { defaultContext + ["statuses"] } - var pathComponentsInContext: [String] { + public var pathComponentsInContext: [String] { switch self { case let .context(id): return [id, "context"] } } - var method: HTTPMethod { .get } + public var method: HTTPMethod { .get } } diff --git a/Networking/Mastodon API/Endpoints/DeletionEndpoint.swift b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/DeletionEndpoint.swift similarity index 80% rename from Networking/Mastodon API/Endpoints/DeletionEndpoint.swift rename to Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/DeletionEndpoint.swift index 38c669d..6316ccd 100644 --- a/Networking/Mastodon API/Endpoints/DeletionEndpoint.swift +++ b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/DeletionEndpoint.swift @@ -2,16 +2,16 @@ import Foundation -enum DeletionEndpoint { +public enum DeletionEndpoint { case oauthRevoke(token: String, clientID: String, clientSecret: String) case list(id: String) case filter(id: String) } extension DeletionEndpoint: MastodonEndpoint { - typealias ResultType = [String: String] + public typealias ResultType = [String: String] - var context: [String] { + public var context: [String] { switch self { case .oauthRevoke: return ["oauth"] @@ -22,7 +22,7 @@ extension DeletionEndpoint: MastodonEndpoint { } } - var pathComponentsInContext: [String] { + public var pathComponentsInContext: [String] { switch self { case .oauthRevoke: return ["revoke"] @@ -31,7 +31,7 @@ extension DeletionEndpoint: MastodonEndpoint { } } - var method: HTTPMethod { + public var method: HTTPMethod { switch self { case .oauthRevoke: return .post @@ -40,7 +40,7 @@ extension DeletionEndpoint: MastodonEndpoint { } } - var parameters: [String: Any]? { + public var parameters: [String: Any]? { switch self { case let .oauthRevoke(token, clientID, clientSecret): return ["token": token, "client_id": clientID, "client_secret": clientSecret] diff --git a/Networking/Mastodon API/Endpoints/FilterEndpoint.swift b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/FilterEndpoint.swift similarity index 90% rename from Networking/Mastodon API/Endpoints/FilterEndpoint.swift rename to Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/FilterEndpoint.swift index fe79f5d..0674276 100644 --- a/Networking/Mastodon API/Endpoints/FilterEndpoint.swift +++ b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/FilterEndpoint.swift @@ -2,7 +2,7 @@ import Foundation -enum FilterEndpoint { +public enum FilterEndpoint { case create( phrase: String, context: [Filter.Context], @@ -19,13 +19,13 @@ enum FilterEndpoint { } extension FilterEndpoint: MastodonEndpoint { - typealias ResultType = Filter + public typealias ResultType = Filter - var context: [String] { + public var context: [String] { defaultContext + ["filters"] } - var pathComponentsInContext: [String] { + public var pathComponentsInContext: [String] { switch self { case .create: return [] @@ -34,7 +34,7 @@ extension FilterEndpoint: MastodonEndpoint { } } - var parameters: [String: Any]? { + public var parameters: [String: Any]? { switch self { case let .create(phrase, context, irreversible, wholeWord, expiresIn): return params(phrase: phrase, @@ -55,7 +55,7 @@ extension FilterEndpoint: MastodonEndpoint { } } - var method: HTTPMethod { + public var method: HTTPMethod { switch self { case .create: return .post diff --git a/Networking/Mastodon API/Endpoints/FiltersEndpoint.swift b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/FiltersEndpoint.swift similarity index 64% rename from Networking/Mastodon API/Endpoints/FiltersEndpoint.swift rename to Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/FiltersEndpoint.swift index d2adb1e..2d31377 100644 --- a/Networking/Mastodon API/Endpoints/FiltersEndpoint.swift +++ b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/FiltersEndpoint.swift @@ -2,25 +2,25 @@ import Foundation -enum FiltersEndpoint { +public enum FiltersEndpoint { case filters } extension FiltersEndpoint: MastodonEndpoint { - typealias ResultType = [Filter] + public typealias ResultType = [Filter] - var context: [String] { + public var context: [String] { defaultContext + ["filters"] } - var pathComponentsInContext: [String] { + public var pathComponentsInContext: [String] { switch self { case .filters: return [] } } - var method: HTTPMethod { + public var method: HTTPMethod { switch self { case .filters: return .get diff --git a/Networking/Mastodon API/Endpoints/InstanceEndpoint.swift b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/InstanceEndpoint.swift similarity index 65% rename from Networking/Mastodon API/Endpoints/InstanceEndpoint.swift rename to Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/InstanceEndpoint.swift index 8483774..afae7ad 100644 --- a/Networking/Mastodon API/Endpoints/InstanceEndpoint.swift +++ b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/InstanceEndpoint.swift @@ -2,20 +2,20 @@ import Foundation -enum InstanceEndpoint { +public enum InstanceEndpoint { case instance } extension InstanceEndpoint: MastodonEndpoint { - typealias ResultType = Instance + public typealias ResultType = Instance - var pathComponentsInContext: [String] { + public var pathComponentsInContext: [String] { switch self { case .instance: return ["instance"] } } - var method: HTTPMethod { + public var method: HTTPMethod { switch self { case .instance: return .get } diff --git a/Networking/Mastodon API/Endpoints/ListEndpoint.swift b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/ListEndpoint.swift similarity index 66% rename from Networking/Mastodon API/Endpoints/ListEndpoint.swift rename to Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/ListEndpoint.swift index 053129c..281c0a6 100644 --- a/Networking/Mastodon API/Endpoints/ListEndpoint.swift +++ b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/ListEndpoint.swift @@ -2,32 +2,32 @@ import Foundation -enum ListEndpoint { +public enum ListEndpoint { case create(title: String) } extension ListEndpoint: MastodonEndpoint { - typealias ResultType = MastodonList + public typealias ResultType = MastodonList - var context: [String] { + public var context: [String] { defaultContext + ["lists"] } - var pathComponentsInContext: [String] { + public var pathComponentsInContext: [String] { switch self { case .create: return [] } } - var parameters: [String: Any]? { + public var parameters: [String: Any]? { switch self { case let .create(title): return ["title": title] } } - var method: HTTPMethod { + public var method: HTTPMethod { switch self { case .create: return .post diff --git a/Networking/Mastodon API/Endpoints/ListsEndpoint.swift b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/ListsEndpoint.swift similarity index 52% rename from Networking/Mastodon API/Endpoints/ListsEndpoint.swift rename to Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/ListsEndpoint.swift index ee3afaa..ab0ace8 100644 --- a/Networking/Mastodon API/Endpoints/ListsEndpoint.swift +++ b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/ListsEndpoint.swift @@ -2,18 +2,18 @@ import Foundation -enum ListsEndpoint { +public enum ListsEndpoint { case lists } extension ListsEndpoint: MastodonEndpoint { - typealias ResultType = [MastodonList] + public typealias ResultType = [MastodonList] - var pathComponentsInContext: [String] { + public var pathComponentsInContext: [String] { ["lists"] } - var method: HTTPMethod { + public var method: HTTPMethod { .get } } diff --git a/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/Paged.swift b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/Paged.swift new file mode 100644 index 0000000..b7add26 --- /dev/null +++ b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/Paged.swift @@ -0,0 +1,46 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import Foundation + +public struct Paged { + public let endpoint: T + public let maxID: String? + public let minID: String? + public let sinceID: String? + public let limit: Int? + + public init(_ endpoint: T, maxID: String? = nil, minID: String? = nil, sinceID: String? = nil, limit: Int? = nil) { + self.endpoint = endpoint + self.maxID = maxID + self.minID = minID + self.sinceID = sinceID + self.limit = limit + } +} + +extension Paged: MastodonEndpoint { + public typealias ResultType = T.ResultType + + public var APIVersion: String { endpoint.APIVersion } + + public var context: [String] { endpoint.context } + + public var pathComponentsInContext: [String] { endpoint.pathComponentsInContext } + + public var method: HTTPMethod { endpoint.method } + + public var encoding: ParameterEncoding { endpoint.encoding } + + public var parameters: [String: Any]? { + var parameters = endpoint.parameters ?? [String: Any]() + + parameters["max_id"] = maxID + parameters["min_id"] = minID + parameters["since_id"] = sinceID + parameters["limit"] = limit + + return parameters + } + + public var headers: HTTPHeaders? { endpoint.headers } +} diff --git a/Networking/Mastodon API/Endpoints/PreferencesEndpoint.swift b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/PreferencesEndpoint.swift similarity index 64% rename from Networking/Mastodon API/Endpoints/PreferencesEndpoint.swift rename to Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/PreferencesEndpoint.swift index 7b1f8a3..6b1046b 100644 --- a/Networking/Mastodon API/Endpoints/PreferencesEndpoint.swift +++ b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/PreferencesEndpoint.swift @@ -2,20 +2,20 @@ import Foundation -enum PreferencesEndpoint { +public enum PreferencesEndpoint { case preferences } extension PreferencesEndpoint: MastodonEndpoint { - typealias ResultType = MastodonPreferences + public typealias ResultType = MastodonPreferences - var pathComponentsInContext: [String] { + public var pathComponentsInContext: [String] { switch self { case .preferences: return ["preferences"] } } - var method: HTTPMethod { + public var method: HTTPMethod { switch self { case .preferences: return .get } diff --git a/Networking/Mastodon API/Endpoints/PushSubscriptionEndpoint.swift b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/PushSubscriptionEndpoint.swift similarity index 86% rename from Networking/Mastodon API/Endpoints/PushSubscriptionEndpoint.swift rename to Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/PushSubscriptionEndpoint.swift index 069efac..4b17260 100644 --- a/Networking/Mastodon API/Endpoints/PushSubscriptionEndpoint.swift +++ b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/PushSubscriptionEndpoint.swift @@ -2,7 +2,7 @@ import Foundation -enum PushSubscriptionEndpoint { +public enum PushSubscriptionEndpoint { case create( endpoint: URL, publicKey: String, @@ -14,15 +14,15 @@ enum PushSubscriptionEndpoint { } extension PushSubscriptionEndpoint: MastodonEndpoint { - typealias ResultType = PushSubscription + public typealias ResultType = PushSubscription - var context: [String] { + public var context: [String] { defaultContext + ["push", "subscription"] } - var pathComponentsInContext: [String] { [] } + public var pathComponentsInContext: [String] { [] } - var method: HTTPMethod { + public var method: HTTPMethod { switch self { case .create: return .post case .read: return .get @@ -31,7 +31,7 @@ extension PushSubscriptionEndpoint: MastodonEndpoint { } } - var parameters: [String: Any]? { + public var parameters: [String: Any]? { switch self { case let .create(endpoint, publicKey, auth, alerts): return ["subscription": diff --git a/Networking/Mastodon API/Endpoints/StatusEndpoint.swift b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/StatusEndpoint.swift similarity index 77% rename from Networking/Mastodon API/Endpoints/StatusEndpoint.swift rename to Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/StatusEndpoint.swift index 6133beb..a935efe 100644 --- a/Networking/Mastodon API/Endpoints/StatusEndpoint.swift +++ b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/StatusEndpoint.swift @@ -2,20 +2,20 @@ import Foundation -enum StatusEndpoint { +public enum StatusEndpoint { case status(id: String) case favourite(id: String) case unfavourite(id: String) } extension StatusEndpoint: MastodonEndpoint { - typealias ResultType = Status + public typealias ResultType = Status - var context: [String] { + public var context: [String] { defaultContext + ["statuses"] } - var pathComponentsInContext: [String] { + public var pathComponentsInContext: [String] { switch self { case let .status(id): return [id] @@ -26,7 +26,7 @@ extension StatusEndpoint: MastodonEndpoint { } } - var method: HTTPMethod { + public var method: HTTPMethod { switch self { case .status: return .get diff --git a/Networking/Mastodon API/Endpoints/TimelinesEndpoint.swift b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/TimelinesEndpoint.swift similarity index 73% rename from Networking/Mastodon API/Endpoints/TimelinesEndpoint.swift rename to Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/TimelinesEndpoint.swift index 324e849..5668d55 100644 --- a/Networking/Mastodon API/Endpoints/TimelinesEndpoint.swift +++ b/Mastodon/Sources/Mastodon/Networking/Mastodon API/Endpoints/TimelinesEndpoint.swift @@ -2,7 +2,7 @@ import Foundation -enum TimelinesEndpoint { +public enum TimelinesEndpoint { case `public`(local: Bool) case tag(String) case home @@ -10,13 +10,13 @@ enum TimelinesEndpoint { } extension TimelinesEndpoint: MastodonEndpoint { - typealias ResultType = [Status] + public typealias ResultType = [Status] - var context: [String] { + public var context: [String] { defaultContext + ["timelines"] } - var pathComponentsInContext: [String] { + public var pathComponentsInContext: [String] { switch self { case .public: return ["public"] @@ -29,7 +29,7 @@ extension TimelinesEndpoint: MastodonEndpoint { } } - var parameters: [String: Any]? { + public var parameters: [String: Any]? { switch self { case let .public(local): return ["local": local] @@ -38,5 +38,5 @@ extension TimelinesEndpoint: MastodonEndpoint { } } - var method: HTTPMethod { .get } + public var method: HTTPMethod { .get } } diff --git a/Mastodon/Sources/Mastodon/Networking/Mastodon API/MastodonClient.swift b/Mastodon/Sources/Mastodon/Networking/Mastodon API/MastodonClient.swift new file mode 100644 index 0000000..7b91a3b --- /dev/null +++ b/Mastodon/Sources/Mastodon/Networking/Mastodon API/MastodonClient.swift @@ -0,0 +1,29 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import Foundation +import Combine + +public class MastodonClient: HTTPClient { + public var instanceURL: URL? + public var accessToken: String? + + public required init(session: Session) { + super.init(session: session, decoder: MastodonDecoder()) + } + + public override func request(_ target: T) -> AnyPublisher { + super.request(target, decodeErrorsAs: MastodonError.self) + } +} + +extension MastodonClient { + public func request(_ endpoint: E) -> AnyPublisher { + guard let instanceURL = instanceURL else { + return Fail(error: URLError(.badURL)).eraseToAnyPublisher() + } + + return super.request( + MastodonTarget(baseURL: instanceURL, endpoint: endpoint, accessToken: accessToken), + decodeErrorsAs: MastodonError.self) + } +} diff --git a/Networking/Mastodon API/MastodonDecoder.swift b/Mastodon/Sources/Mastodon/Networking/Mastodon API/MastodonDecoder.swift similarity index 66% rename from Networking/Mastodon API/MastodonDecoder.swift rename to Mastodon/Sources/Mastodon/Networking/Mastodon API/MastodonDecoder.swift index fd1fbaa..9d2f44e 100644 --- a/Networking/Mastodon API/MastodonDecoder.swift +++ b/Mastodon/Sources/Mastodon/Networking/Mastodon API/MastodonDecoder.swift @@ -2,13 +2,13 @@ import Foundation -class MastodonDecoder: JSONDecoder { - override init() { +public class MastodonDecoder: JSONDecoder { + public override init() { super.init() let dateFormatter = DateFormatter() - dateFormatter.dateFormat = MastodonAPI.dateFormat + dateFormatter.dateFormat = Constants.dateFormat dateDecodingStrategy = .formatted(dateFormatter) keyDecodingStrategy = .convertFromSnakeCase } diff --git a/Networking/Mastodon API/MastodonEncoder.swift b/Mastodon/Sources/Mastodon/Networking/Mastodon API/MastodonEncoder.swift similarity index 69% rename from Networking/Mastodon API/MastodonEncoder.swift rename to Mastodon/Sources/Mastodon/Networking/Mastodon API/MastodonEncoder.swift index c07f0e6..f683b12 100644 --- a/Networking/Mastodon API/MastodonEncoder.swift +++ b/Mastodon/Sources/Mastodon/Networking/Mastodon API/MastodonEncoder.swift @@ -2,13 +2,13 @@ import Foundation -class MastodonEncoder: JSONEncoder { - override init() { +public class MastodonEncoder: JSONEncoder { + public override init() { super.init() let dateFormatter = DateFormatter() - dateFormatter.dateFormat = MastodonAPI.dateFormat + dateFormatter.dateFormat = Constants.dateFormat dateEncodingStrategy = .formatted(dateFormatter) keyEncodingStrategy = .convertToSnakeCase outputFormatting = .sortedKeys diff --git a/Networking/Mastodon API/MastodonEndpoint.swift b/Mastodon/Sources/Mastodon/Networking/Mastodon API/MastodonEndpoint.swift similarity index 92% rename from Networking/Mastodon API/MastodonEndpoint.swift rename to Mastodon/Sources/Mastodon/Networking/Mastodon API/MastodonEndpoint.swift index a4bea7c..a8ee81c 100644 --- a/Networking/Mastodon API/MastodonEndpoint.swift +++ b/Mastodon/Sources/Mastodon/Networking/Mastodon API/MastodonEndpoint.swift @@ -2,7 +2,7 @@ import Foundation -protocol MastodonEndpoint { +public protocol MastodonEndpoint { associatedtype ResultType: Decodable var APIVersion: String { get } var context: [String] { get } @@ -13,7 +13,7 @@ protocol MastodonEndpoint { var headers: HTTPHeaders? { get } } -extension MastodonEndpoint { +public extension MastodonEndpoint { var defaultContext: [String] { ["api", APIVersion] } diff --git a/Mastodon/Sources/Mastodon/Networking/Mastodon API/MastodonTarget.swift b/Mastodon/Sources/Mastodon/Networking/Mastodon API/MastodonTarget.swift new file mode 100644 index 0000000..4f8fb55 --- /dev/null +++ b/Mastodon/Sources/Mastodon/Networking/Mastodon API/MastodonTarget.swift @@ -0,0 +1,41 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import Foundation + +public struct MastodonTarget { + public let baseURL: URL + public let endpoint: E + public let accessToken: String? + + public init(baseURL: URL, endpoint: E, accessToken: String?) { + self.baseURL = baseURL + self.endpoint = endpoint + self.accessToken = accessToken + } +} + +extension MastodonTarget: DecodableTarget { + public typealias ResultType = E.ResultType + + public var pathComponents: [String] { endpoint.pathComponents } + + public var method: HTTPMethod { endpoint.method } + + public var encoding: ParameterEncoding { endpoint.encoding } + + public var parameters: [String: Any]? { endpoint.parameters } + + public var headers: HTTPHeaders? { + var headers = endpoint.headers + + if let accessToken = accessToken { + if headers == nil { + headers = HTTPHeaders() + } + + headers?.add(.authorization(bearerToken: accessToken)) + } + + return headers + } +} diff --git a/Property Wrappers/DecodableDefault.swift b/Mastodon/Sources/Mastodon/Property Wrappers/DecodableDefault.swift similarity index 57% rename from Property Wrappers/DecodableDefault.swift rename to Mastodon/Sources/Mastodon/Property Wrappers/DecodableDefault.swift index e807ee1..44e3fda 100644 --- a/Property Wrappers/DecodableDefault.swift +++ b/Mastodon/Sources/Mastodon/Property Wrappers/DecodableDefault.swift @@ -4,64 +4,66 @@ import Foundation // Thank you https://www.swiftbysundell.com/tips/default-decoding-values/ -protocol DecodableDefaultSource { +public protocol DecodableDefaultSource { associatedtype Value: Decodable static var defaultValue: Value { get } } -enum DecodableDefault {} +public enum DecodableDefault {} // swiftlint:disable nesting extension DecodableDefault { @propertyWrapper - struct Wrapper { - typealias Value = Source.Value - var wrappedValue = Source.defaultValue + public struct Wrapper { + public typealias Value = Source.Value + public var wrappedValue = Source.defaultValue + + public init() {} } } -extension DecodableDefault { +public extension DecodableDefault { typealias Source = DecodableDefaultSource typealias List = Decodable & ExpressibleByArrayLiteral typealias Map = Decodable & ExpressibleByDictionaryLiteral enum Sources { - enum True: Source { - static var defaultValue: Bool { true } + public enum True: Source { + public static var defaultValue: Bool { true } } - enum False: Source { - static var defaultValue: Bool { false } + public enum False: Source { + public static var defaultValue: Bool { false } } - enum EmptyString: Source { - static var defaultValue: String { "" } + public enum EmptyString: Source { + public static var defaultValue: String { "" } } - enum EmptyList: Source { - static var defaultValue: T { [] } + public enum EmptyList: Source { + public static var defaultValue: T { [] } } - enum EmptyMap: Source { - static var defaultValue: T { [:] } + public enum EmptyMap: Source { + public static var defaultValue: T { [:] } } - enum Zero: Source { - static var defaultValue: Int { 0 } + public enum Zero: Source { + public static var defaultValue: Int { 0 } } - enum StatusVisibilityPublic: Source { - static var defaultValue: Status.Visibility { .public } + public enum StatusVisibilityPublic: Source { + public static var defaultValue: Status.Visibility { .public } } - enum ExpandMediaDefault: Source { - static var defaultValue: MastodonPreferences.ExpandMedia { .default } + public enum ExpandMediaDefault: Source { + public static var defaultValue: MastodonPreferences.ExpandMedia { .default } } } } // swiftlint:enable nesting -extension DecodableDefault { +public extension DecodableDefault { typealias True = Wrapper typealias False = Wrapper typealias EmptyString = Wrapper @@ -73,7 +75,7 @@ extension DecodableDefault { } extension DecodableDefault.Wrapper: Decodable { - init(from decoder: Decoder) throws { + public init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() wrappedValue = try container.decode(Value.self) } @@ -83,13 +85,13 @@ 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 { + public func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() try container.encode(wrappedValue) } } -extension KeyedDecodingContainer { +public extension KeyedDecodingContainer { func decode(_ type: DecodableDefault.Wrapper.Type, forKey key: Key) throws -> DecodableDefault.Wrapper { try decodeIfPresent(type, forKey: key) ?? .init() diff --git a/Model/Unknowable.swift b/Mastodon/Sources/Mastodon/Protocols/Unknowable.swift similarity index 71% rename from Model/Unknowable.swift rename to Mastodon/Sources/Mastodon/Protocols/Unknowable.swift index 54ba0c5..b9d4e09 100644 --- a/Model/Unknowable.swift +++ b/Mastodon/Sources/Mastodon/Protocols/Unknowable.swift @@ -2,16 +2,14 @@ import Foundation -protocol Unknowable: RawRepresentable, CaseIterable where RawValue: Equatable { +public protocol Unknowable: RawRepresentable, CaseIterable where RawValue: Equatable { static var unknownCase: Self { get } } -extension Unknowable { +public extension Unknowable { init(rawValue: RawValue) { self = Self.allCases.first { $0.rawValue == rawValue } ?? Self.unknownCase } -} -extension Unknowable { static var allCasesExceptUnknown: [Self] { allCases.filter { $0 != unknownCase } } } diff --git a/Mastodon/Tests/LinuxMain.swift b/Mastodon/Tests/LinuxMain.swift new file mode 100644 index 0000000..cd710a3 --- /dev/null +++ b/Mastodon/Tests/LinuxMain.swift @@ -0,0 +1,7 @@ +import XCTest + +import MastodonTests + +var tests = [XCTestCaseEntry]() +tests += MastodonTests.allTests() +XCTMain(tests) diff --git a/Mastodon/Tests/MastodonTests/MastodonTests.swift b/Mastodon/Tests/MastodonTests/MastodonTests.swift new file mode 100644 index 0000000..714b3d2 --- /dev/null +++ b/Mastodon/Tests/MastodonTests/MastodonTests.swift @@ -0,0 +1,15 @@ +import XCTest +@testable import Mastodon + +final class MastodonTests: XCTestCase { + func testExample() { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct + // results. + XCTAssertEqual(Mastodon().text, "Hello, World!") + } + + static var allTests = [ + ("testExample", testExample) + ] +} diff --git a/Mastodon/Tests/MastodonTests/XCTestManifests.swift b/Mastodon/Tests/MastodonTests/XCTestManifests.swift new file mode 100644 index 0000000..49c001d --- /dev/null +++ b/Mastodon/Tests/MastodonTests/XCTestManifests.swift @@ -0,0 +1,9 @@ +import XCTest + +#if !canImport(ObjectiveC) +public func allTests() -> [XCTestCaseEntry] { + return [ + testCase(MastodonTests.allTests) + ] +} +#endif diff --git a/Metatext.xcodeproj/project.pbxproj b/Metatext.xcodeproj/project.pbxproj index cfabdb2..2bd6bdb 100644 --- a/Metatext.xcodeproj/project.pbxproj +++ b/Metatext.xcodeproj/project.pbxproj @@ -27,17 +27,11 @@ D074577A24D29366004758DB /* URLSessionConfiguration+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D074577924D29366004758DB /* URLSessionConfiguration+Extensions.swift */; }; D0A652AD24DE3EB6002EA33F /* PreferencesEndpoint+Stubbing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A652AC24DE3EB6002EA33F /* PreferencesEndpoint+Stubbing.swift */; }; D0BEB1F324F8EE8C001B0F04 /* AttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1F224F8EE8C001B0F04 /* AttachmentView.swift */; }; - D0BEB1F524F9A216001B0F04 /* Paged.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1F424F9A216001B0F04 /* Paged.swift */; }; D0BEB1F724F9A84B001B0F04 /* LoadingTableFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1F624F9A84B001B0F04 /* LoadingTableFooterView.swift */; }; - D0BEB1F924F9D627001B0F04 /* ListsEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1F824F9D627001B0F04 /* ListsEndpoint.swift */; }; D0BEB1FD24F9E4E5001B0F04 /* ListsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1FC24F9E4E5001B0F04 /* ListsViewModel.swift */; }; D0BEB1FF24F9E5BB001B0F04 /* ListsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1FE24F9E5BB001B0F04 /* ListsView.swift */; }; - D0BEB20124FA0220001B0F04 /* ListEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB20024FA0220001B0F04 /* ListEndpoint.swift */; }; D0BEB20524FA1107001B0F04 /* FiltersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB20424FA1107001B0F04 /* FiltersView.swift */; }; D0BEB20724FA1121001B0F04 /* FiltersViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB20624FA1121001B0F04 /* FiltersViewModel.swift */; }; - D0BEB20924FA1136001B0F04 /* Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB20824FA1136001B0F04 /* Filter.swift */; }; - D0BEB20B24FA12D8001B0F04 /* FiltersEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB20A24FA12D8001B0F04 /* FiltersEndpoint.swift */; }; - D0BEB20D24FA193A001B0F04 /* FilterEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB20C24FA193A001B0F04 /* FilterEndpoint.swift */; }; D0BEB21124FA2A91001B0F04 /* EditFilterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB21024FA2A90001B0F04 /* EditFilterView.swift */; }; D0BEB21324FA2C0A001B0F04 /* EditFilterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB21224FA2C0A001B0F04 /* EditFilterViewModel.swift */; }; D0C7D49724F7616A001EBDBB /* IdentitiesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D42224F76169001EBDBB /* IdentitiesView.swift */; }; @@ -51,32 +45,10 @@ D0C7D4A224F7616A001EBDBB /* NotificationTypesPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D42D24F76169001EBDBB /* NotificationTypesPreferencesView.swift */; }; D0C7D4A324F7616A001EBDBB /* TabNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D42E24F76169001EBDBB /* TabNavigationView.swift */; }; D0C7D4A524F7616A001EBDBB /* StatusListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D43124F76169001EBDBB /* StatusListViewController.swift */; }; - D0C7D4A624F7616A001EBDBB /* DecodableDefault.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D43324F76169001EBDBB /* DecodableDefault.swift */; }; - D0C7D4A924F7616A001EBDBB /* Mention.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D43924F76169001EBDBB /* Mention.swift */; }; - D0C7D4AA24F7616A001EBDBB /* Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D43A24F76169001EBDBB /* Attachment.swift */; }; D0C7D4AB24F7616A001EBDBB /* Identity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D43B24F76169001EBDBB /* Identity.swift */; }; - D0C7D4AC24F7616A001EBDBB /* Poll.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D43C24F76169001EBDBB /* Poll.swift */; }; - D0C7D4AD24F7616A001EBDBB /* AccessToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D43D24F76169001EBDBB /* AccessToken.swift */; }; - D0C7D4AE24F7616A001EBDBB /* Timeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D43E24F76169001EBDBB /* Timeline.swift */; }; - D0C7D4AF24F7616A001EBDBB /* PushNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D43F24F76169001EBDBB /* PushNotification.swift */; }; - D0C7D4B024F7616A001EBDBB /* PushSubscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D44024F76169001EBDBB /* PushSubscription.swift */; }; - D0C7D4B124F7616A001EBDBB /* Card.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D44124F76169001EBDBB /* Card.swift */; }; - D0C7D4B224F7616A001EBDBB /* HTML.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D44224F76169001EBDBB /* HTML.swift */; }; - D0C7D4B324F7616A001EBDBB /* MastodonError.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D44324F76169001EBDBB /* MastodonError.swift */; }; - D0C7D4B424F7616A001EBDBB /* MastodonContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D44424F76169001EBDBB /* MastodonContext.swift */; }; - D0C7D4B524F7616A001EBDBB /* Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D44524F76169001EBDBB /* Instance.swift */; }; - D0C7D4B624F7616A001EBDBB /* ListTimeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D44624F76169001EBDBB /* ListTimeline.swift */; }; D0C7D4B724F7616A001EBDBB /* TransientStatusCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D44724F76169001EBDBB /* TransientStatusCollection.swift */; }; - D0C7D4B824F7616A001EBDBB /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D44824F76169001EBDBB /* Application.swift */; }; - D0C7D4B924F7616A001EBDBB /* Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D44924F76169001EBDBB /* Status.swift */; }; - D0C7D4BA24F7616A001EBDBB /* AppAuthorization.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D44A24F76169001EBDBB /* AppAuthorization.swift */; }; - D0C7D4BB24F7616A001EBDBB /* Emoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D44B24F76169001EBDBB /* Emoji.swift */; }; - D0C7D4BC24F7616A001EBDBB /* Tag.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D44C24F76169001EBDBB /* Tag.swift */; }; - D0C7D4BD24F7616A001EBDBB /* Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D44D24F76169001EBDBB /* Account.swift */; }; - D0C7D4BE24F7616A001EBDBB /* Unknowable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D44E24F76169001EBDBB /* Unknowable.swift */; }; D0C7D4BF24F7616A001EBDBB /* AppEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D44F24F76169001EBDBB /* AppEnvironment.swift */; }; D0C7D4C024F7616A001EBDBB /* AlertItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D45024F76169001EBDBB /* AlertItem.swift */; }; - D0C7D4C124F7616A001EBDBB /* MastodonPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D45124F76169001EBDBB /* MastodonPreferences.swift */; }; D0C7D4C224F7616A001EBDBB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D0C7D45224F76169001EBDBB /* Assets.xcassets */; }; D0C7D4C324F7616A001EBDBB /* MetatextApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D45424F76169001EBDBB /* MetatextApp.swift */; }; D0C7D4C424F7616A001EBDBB /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D45524F76169001EBDBB /* AppDelegate.swift */; }; @@ -104,26 +76,7 @@ D0C7D4DA24F7616A001EBDBB /* View+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D46F24F76169001EBDBB /* View+Extensions.swift */; }; D0C7D4DB24F7616A001EBDBB /* Date+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D47024F76169001EBDBB /* Date+Extensions.swift */; }; D0C7D4DC24F7616A001EBDBB /* Data+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D47124F76169001EBDBB /* Data+Extensions.swift */; }; - D0C7D4DD24F7616A001EBDBB /* CodingUserInfoKey+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D47224F76169001EBDBB /* CodingUserInfoKey+Extensions.swift */; }; - D0C7D4DE24F7616A001EBDBB /* HTTPTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D47424F76169001EBDBB /* HTTPTarget.swift */; }; - D0C7D4DF24F7616A001EBDBB /* HTTPClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D47524F76169001EBDBB /* HTTPClient.swift */; }; D0C7D4E024F7616A001EBDBB /* WebAuthSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D47624F76169001EBDBB /* WebAuthSession.swift */; }; - D0C7D4E124F7616A001EBDBB /* MastodonDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D47824F76169001EBDBB /* MastodonDecoder.swift */; }; - D0C7D4E224F7616A001EBDBB /* MastodonEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D47924F76169001EBDBB /* MastodonEndpoint.swift */; }; - D0C7D4E324F7616A001EBDBB /* PushSubscriptionEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D47B24F76169001EBDBB /* PushSubscriptionEndpoint.swift */; }; - D0C7D4E424F7616A001EBDBB /* PreferencesEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D47C24F76169001EBDBB /* PreferencesEndpoint.swift */; }; - D0C7D4E524F7616A001EBDBB /* InstanceEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D47D24F76169001EBDBB /* InstanceEndpoint.swift */; }; - D0C7D4E624F7616A001EBDBB /* TimelinesEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D47E24F76169001EBDBB /* TimelinesEndpoint.swift */; }; - D0C7D4E724F7616A001EBDBB /* AppAuthorizationEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D47F24F76169001EBDBB /* AppAuthorizationEndpoint.swift */; }; - D0C7D4E824F7616A001EBDBB /* AccountEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D48024F76169001EBDBB /* AccountEndpoint.swift */; }; - D0C7D4E924F7616A001EBDBB /* AccessTokenEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D48124F76169001EBDBB /* AccessTokenEndpoint.swift */; }; - D0C7D4EA24F7616A001EBDBB /* DeletionEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D48224F76169001EBDBB /* DeletionEndpoint.swift */; }; - D0C7D4EB24F7616A001EBDBB /* ContextEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D48324F76169001EBDBB /* ContextEndpoint.swift */; }; - D0C7D4EC24F7616A001EBDBB /* StatusEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D48424F76169001EBDBB /* StatusEndpoint.swift */; }; - D0C7D4ED24F7616A001EBDBB /* MastodonAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D48524F76169001EBDBB /* MastodonAPI.swift */; }; - D0C7D4EE24F7616A001EBDBB /* MastodonEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D48624F76169001EBDBB /* MastodonEncoder.swift */; }; - D0C7D4EF24F7616A001EBDBB /* MastodonClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D48724F76169001EBDBB /* MastodonClient.swift */; }; - D0C7D4F024F7616A001EBDBB /* MastodonTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D48824F76169001EBDBB /* MastodonTarget.swift */; }; D0C7D4F124F7616A001EBDBB /* IdentityService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D48A24F76169001EBDBB /* IdentityService.swift */; }; D0C7D4F224F7616A001EBDBB /* TimelineService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D48C24F76169001EBDBB /* TimelineService.swift */; }; D0C7D4F324F7616A001EBDBB /* ContextService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D48D24F76169001EBDBB /* ContextService.swift */; }; @@ -134,13 +87,9 @@ D0C7D4F824F7616A001EBDBB /* SecretsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D49224F7616A001EBDBB /* SecretsService.swift */; }; D0C7D4F924F7616A001EBDBB /* UserNotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D49324F7616A001EBDBB /* UserNotificationService.swift */; }; D0C7D4FA24F7616A001EBDBB /* AllIdentitiesService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D49424F7616A001EBDBB /* AllIdentitiesService.swift */; }; - D0C7D4FB24F7619F001EBDBB /* PushNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D43F24F76169001EBDBB /* PushNotification.swift */; }; - D0C7D4FC24F761A8001EBDBB /* Unknowable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D44E24F76169001EBDBB /* Unknowable.swift */; }; - D0C7D4FD24F761C1001EBDBB /* MastodonDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D47824F76169001EBDBB /* MastodonDecoder.swift */; }; D0C7D4FE24F761C9001EBDBB /* SecretsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D49224F7616A001EBDBB /* SecretsService.swift */; }; D0C7D4FF24F761D0001EBDBB /* KeychainService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D49024F7616A001EBDBB /* KeychainService.swift */; }; D0C7D50024F761E0001EBDBB /* NSError+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D46924F76169001EBDBB /* NSError+Extensions.swift */; }; - D0C7D50124F761EC001EBDBB /* MastodonAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D48524F76169001EBDBB /* MastodonAPI.swift */; }; D0DC174624CFEC2000A75C65 /* StubbingURLProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC174524CFEC2000A75C65 /* StubbingURLProtocol.swift */; }; D0DC174A24CFF15F00A75C65 /* AppAuthorizationEndpoint+Stubbing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC174924CFF15F00A75C65 /* AppAuthorizationEndpoint+Stubbing.swift */; }; D0DC174D24CFF1F100A75C65 /* Stubbing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC174C24CFF1F100A75C65 /* Stubbing.swift */; }; @@ -149,6 +98,8 @@ D0DC175824D0130800A75C65 /* HTTPStubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC175724D0130800A75C65 /* HTTPStubs.swift */; }; D0DC175F24D016EA00A75C65 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = D0DC175E24D016EA00A75C65 /* Alamofire */; }; D0DC177724D0CF2600A75C65 /* MockKeychainService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC177624D0CF2600A75C65 /* MockKeychainService.swift */; }; + D0E0F1E624FC4B76002C04BF /* Mastodon in Frameworks */ = {isa = PBXBuildFile; productRef = D0E0F1E524FC4B76002C04BF /* Mastodon */; }; + D0E0F1E824FC5A61002C04BF /* Mastodon in Frameworks */ = {isa = PBXBuildFile; productRef = D0E0F1E724FC5A61002C04BF /* Mastodon */; }; D0E5361C24E3EB4D00FB1CE1 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E5361B24E3EB4D00FB1CE1 /* NotificationService.swift */; }; D0E5362024E3EB4D00FB1CE1 /* Notification Service Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = D0E5361924E3EB4D00FB1CE1 /* Notification Service Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; D0EC8DD424DFE38900A08489 /* AuthenticationServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EC8DD324DFE38900A08489 /* AuthenticationServiceTests.swift */; }; @@ -207,17 +158,11 @@ D074577924D29366004758DB /* URLSessionConfiguration+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLSessionConfiguration+Extensions.swift"; sourceTree = ""; }; D0A652AC24DE3EB6002EA33F /* PreferencesEndpoint+Stubbing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreferencesEndpoint+Stubbing.swift"; sourceTree = ""; }; D0BEB1F224F8EE8C001B0F04 /* AttachmentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentView.swift; sourceTree = ""; }; - D0BEB1F424F9A216001B0F04 /* Paged.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Paged.swift; sourceTree = ""; }; D0BEB1F624F9A84B001B0F04 /* LoadingTableFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingTableFooterView.swift; sourceTree = ""; }; - D0BEB1F824F9D627001B0F04 /* ListsEndpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListsEndpoint.swift; sourceTree = ""; }; D0BEB1FC24F9E4E5001B0F04 /* ListsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListsViewModel.swift; sourceTree = ""; }; D0BEB1FE24F9E5BB001B0F04 /* ListsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListsView.swift; sourceTree = ""; }; - D0BEB20024FA0220001B0F04 /* ListEndpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListEndpoint.swift; sourceTree = ""; }; D0BEB20424FA1107001B0F04 /* FiltersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FiltersView.swift; sourceTree = ""; }; D0BEB20624FA1121001B0F04 /* FiltersViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FiltersViewModel.swift; sourceTree = ""; }; - D0BEB20824FA1136001B0F04 /* Filter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Filter.swift; sourceTree = ""; }; - D0BEB20A24FA12D8001B0F04 /* FiltersEndpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FiltersEndpoint.swift; sourceTree = ""; }; - D0BEB20C24FA193A001B0F04 /* FilterEndpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterEndpoint.swift; sourceTree = ""; }; D0BEB21024FA2A90001B0F04 /* EditFilterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditFilterView.swift; sourceTree = ""; }; D0BEB21224FA2C0A001B0F04 /* EditFilterViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditFilterViewModel.swift; sourceTree = ""; }; D0C7D41E24F76169001EBDBB /* Metatext.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Metatext.entitlements; sourceTree = ""; }; @@ -233,32 +178,10 @@ D0C7D42D24F76169001EBDBB /* NotificationTypesPreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationTypesPreferencesView.swift; sourceTree = ""; }; D0C7D42E24F76169001EBDBB /* TabNavigationView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabNavigationView.swift; sourceTree = ""; }; D0C7D43124F76169001EBDBB /* StatusListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusListViewController.swift; sourceTree = ""; }; - D0C7D43324F76169001EBDBB /* DecodableDefault.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DecodableDefault.swift; sourceTree = ""; }; - D0C7D43924F76169001EBDBB /* Mention.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Mention.swift; sourceTree = ""; }; - D0C7D43A24F76169001EBDBB /* Attachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Attachment.swift; sourceTree = ""; }; D0C7D43B24F76169001EBDBB /* Identity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Identity.swift; sourceTree = ""; }; - D0C7D43C24F76169001EBDBB /* Poll.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Poll.swift; sourceTree = ""; }; - D0C7D43D24F76169001EBDBB /* AccessToken.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccessToken.swift; sourceTree = ""; }; - D0C7D43E24F76169001EBDBB /* Timeline.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Timeline.swift; sourceTree = ""; }; - D0C7D43F24F76169001EBDBB /* PushNotification.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushNotification.swift; sourceTree = ""; }; - D0C7D44024F76169001EBDBB /* PushSubscription.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushSubscription.swift; sourceTree = ""; }; - D0C7D44124F76169001EBDBB /* Card.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Card.swift; sourceTree = ""; }; - D0C7D44224F76169001EBDBB /* HTML.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTML.swift; sourceTree = ""; }; - D0C7D44324F76169001EBDBB /* MastodonError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonError.swift; sourceTree = ""; }; - D0C7D44424F76169001EBDBB /* MastodonContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonContext.swift; sourceTree = ""; }; - D0C7D44524F76169001EBDBB /* Instance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Instance.swift; sourceTree = ""; }; - D0C7D44624F76169001EBDBB /* ListTimeline.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListTimeline.swift; sourceTree = ""; }; D0C7D44724F76169001EBDBB /* TransientStatusCollection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransientStatusCollection.swift; sourceTree = ""; }; - D0C7D44824F76169001EBDBB /* Application.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = ""; }; - D0C7D44924F76169001EBDBB /* Status.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Status.swift; sourceTree = ""; }; - D0C7D44A24F76169001EBDBB /* AppAuthorization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppAuthorization.swift; sourceTree = ""; }; - D0C7D44B24F76169001EBDBB /* Emoji.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Emoji.swift; sourceTree = ""; }; - D0C7D44C24F76169001EBDBB /* Tag.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Tag.swift; sourceTree = ""; }; - D0C7D44D24F76169001EBDBB /* Account.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Account.swift; sourceTree = ""; }; - D0C7D44E24F76169001EBDBB /* Unknowable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Unknowable.swift; sourceTree = ""; }; D0C7D44F24F76169001EBDBB /* AppEnvironment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppEnvironment.swift; sourceTree = ""; }; D0C7D45024F76169001EBDBB /* AlertItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertItem.swift; sourceTree = ""; }; - D0C7D45124F76169001EBDBB /* MastodonPreferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonPreferences.swift; sourceTree = ""; }; D0C7D45224F76169001EBDBB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; D0C7D45424F76169001EBDBB /* MetatextApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MetatextApp.swift; sourceTree = ""; }; D0C7D45524F76169001EBDBB /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -286,26 +209,7 @@ D0C7D46F24F76169001EBDBB /* View+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View+Extensions.swift"; sourceTree = ""; }; D0C7D47024F76169001EBDBB /* Date+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Date+Extensions.swift"; sourceTree = ""; }; D0C7D47124F76169001EBDBB /* Data+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Data+Extensions.swift"; sourceTree = ""; }; - D0C7D47224F76169001EBDBB /* CodingUserInfoKey+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CodingUserInfoKey+Extensions.swift"; sourceTree = ""; }; - D0C7D47424F76169001EBDBB /* HTTPTarget.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPTarget.swift; sourceTree = ""; }; - D0C7D47524F76169001EBDBB /* HTTPClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPClient.swift; sourceTree = ""; }; D0C7D47624F76169001EBDBB /* WebAuthSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebAuthSession.swift; sourceTree = ""; }; - D0C7D47824F76169001EBDBB /* MastodonDecoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonDecoder.swift; sourceTree = ""; }; - D0C7D47924F76169001EBDBB /* MastodonEndpoint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonEndpoint.swift; sourceTree = ""; }; - D0C7D47B24F76169001EBDBB /* PushSubscriptionEndpoint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushSubscriptionEndpoint.swift; sourceTree = ""; }; - D0C7D47C24F76169001EBDBB /* PreferencesEndpoint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesEndpoint.swift; sourceTree = ""; }; - D0C7D47D24F76169001EBDBB /* InstanceEndpoint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InstanceEndpoint.swift; sourceTree = ""; }; - D0C7D47E24F76169001EBDBB /* TimelinesEndpoint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimelinesEndpoint.swift; sourceTree = ""; }; - D0C7D47F24F76169001EBDBB /* AppAuthorizationEndpoint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppAuthorizationEndpoint.swift; sourceTree = ""; }; - D0C7D48024F76169001EBDBB /* AccountEndpoint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountEndpoint.swift; sourceTree = ""; }; - D0C7D48124F76169001EBDBB /* AccessTokenEndpoint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccessTokenEndpoint.swift; sourceTree = ""; }; - D0C7D48224F76169001EBDBB /* DeletionEndpoint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeletionEndpoint.swift; sourceTree = ""; }; - D0C7D48324F76169001EBDBB /* ContextEndpoint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContextEndpoint.swift; sourceTree = ""; }; - D0C7D48424F76169001EBDBB /* StatusEndpoint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusEndpoint.swift; sourceTree = ""; }; - D0C7D48524F76169001EBDBB /* MastodonAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonAPI.swift; sourceTree = ""; }; - D0C7D48624F76169001EBDBB /* MastodonEncoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonEncoder.swift; sourceTree = ""; }; - D0C7D48724F76169001EBDBB /* MastodonClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonClient.swift; sourceTree = ""; }; - D0C7D48824F76169001EBDBB /* MastodonTarget.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonTarget.swift; sourceTree = ""; }; D0C7D48A24F76169001EBDBB /* IdentityService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IdentityService.swift; sourceTree = ""; }; D0C7D48C24F76169001EBDBB /* TimelineService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimelineService.swift; sourceTree = ""; }; D0C7D48D24F76169001EBDBB /* ContextService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContextService.swift; sourceTree = ""; }; @@ -323,6 +227,7 @@ D0DC175424D00F0A00A75C65 /* AccessTokenEndpoint+Stubbing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AccessTokenEndpoint+Stubbing.swift"; sourceTree = ""; }; D0DC175724D0130800A75C65 /* HTTPStubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPStubs.swift; sourceTree = ""; }; D0DC177624D0CF2600A75C65 /* MockKeychainService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockKeychainService.swift; sourceTree = ""; }; + D0E0F1E424FC49FC002C04BF /* Mastodon */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Mastodon; sourceTree = ""; }; D0E5361924E3EB4D00FB1CE1 /* Notification Service Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Notification Service Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; D0E5361B24E3EB4D00FB1CE1 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; D0E5361D24E3EB4D00FB1CE1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -337,6 +242,7 @@ buildActionMask = 2147483647; files = ( D06B492324D4611300642749 /* KingfisherSwiftUI in Frameworks */, + D0E0F1E624FC4B76002C04BF /* Mastodon in Frameworks */, D0666A4924C6C1A300F3F04B /* GRDB in Frameworks */, D0DC175F24D016EA00A75C65 /* Alamofire in Frameworks */, ); @@ -354,6 +260,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D0E0F1E824FC5A61002C04BF /* Mastodon in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -382,6 +289,7 @@ D047FA7F24C3E21000AF17C5 = { isa = PBXGroup; children = ( + D0E0F1E424FC49FC002C04BF /* Mastodon */, D0C7D45224F76169001EBDBB /* Assets.xcassets */, D0C7D46424F76169001EBDBB /* Databases */, D0ED1BB224CE3A1600B4899C /* Development Assets */, @@ -392,7 +300,6 @@ D0C7D47324F76169001EBDBB /* Networking */, D0E5361A24E3EB4D00FB1CE1 /* Notification Service Extension */, D047FA8D24C3E21200AF17C5 /* Products */, - D0C7D43224F76169001EBDBB /* Property Wrappers */, D0C7D48924F76169001EBDBB /* Services */, D0C7D41D24F76169001EBDBB /* Supporting Files */, D0C7D45324F76169001EBDBB /* System */, @@ -470,43 +377,13 @@ path = "View Controllers"; sourceTree = ""; }; - D0C7D43224F76169001EBDBB /* Property Wrappers */ = { - isa = PBXGroup; - children = ( - D0C7D43324F76169001EBDBB /* DecodableDefault.swift */, - ); - path = "Property Wrappers"; - sourceTree = ""; - }; D0C7D43824F76169001EBDBB /* Model */ = { isa = PBXGroup; children = ( - D0C7D43D24F76169001EBDBB /* AccessToken.swift */, - D0C7D44D24F76169001EBDBB /* Account.swift */, D0C7D45024F76169001EBDBB /* AlertItem.swift */, - D0C7D44A24F76169001EBDBB /* AppAuthorization.swift */, D0C7D44F24F76169001EBDBB /* AppEnvironment.swift */, - D0C7D44824F76169001EBDBB /* Application.swift */, - D0C7D43A24F76169001EBDBB /* Attachment.swift */, - D0C7D44124F76169001EBDBB /* Card.swift */, - D0C7D44B24F76169001EBDBB /* Emoji.swift */, - D0BEB20824FA1136001B0F04 /* Filter.swift */, - D0C7D44224F76169001EBDBB /* HTML.swift */, D0C7D43B24F76169001EBDBB /* Identity.swift */, - D0C7D44524F76169001EBDBB /* Instance.swift */, - D0C7D44624F76169001EBDBB /* ListTimeline.swift */, - D0C7D44424F76169001EBDBB /* MastodonContext.swift */, - D0C7D44324F76169001EBDBB /* MastodonError.swift */, - D0C7D45124F76169001EBDBB /* MastodonPreferences.swift */, - D0C7D43924F76169001EBDBB /* Mention.swift */, - D0C7D43C24F76169001EBDBB /* Poll.swift */, - D0C7D43F24F76169001EBDBB /* PushNotification.swift */, - D0C7D44024F76169001EBDBB /* PushSubscription.swift */, - D0C7D44924F76169001EBDBB /* Status.swift */, - D0C7D44C24F76169001EBDBB /* Tag.swift */, - D0C7D43E24F76169001EBDBB /* Timeline.swift */, D0C7D44724F76169001EBDBB /* TransientStatusCollection.swift */, - D0C7D44E24F76169001EBDBB /* Unknowable.swift */, ); path = Model; sourceTree = ""; @@ -563,7 +440,6 @@ D0C7D46824F76169001EBDBB /* Extensions */ = { isa = PBXGroup; children = ( - D0C7D47224F76169001EBDBB /* CodingUserInfoKey+Extensions.swift */, D0C7D47124F76169001EBDBB /* Data+Extensions.swift */, D0C7D47024F76169001EBDBB /* Date+Extensions.swift */, D0C7D46E24F76169001EBDBB /* KingfisherOptionsInfo+Extensions.swift */, @@ -580,50 +456,11 @@ D0C7D47324F76169001EBDBB /* Networking */ = { isa = PBXGroup; children = ( - D0C7D47524F76169001EBDBB /* HTTPClient.swift */, - D0C7D47424F76169001EBDBB /* HTTPTarget.swift */, - D0C7D47724F76169001EBDBB /* Mastodon API */, D0C7D47624F76169001EBDBB /* WebAuthSession.swift */, ); path = Networking; sourceTree = ""; }; - D0C7D47724F76169001EBDBB /* Mastodon API */ = { - isa = PBXGroup; - children = ( - D0C7D47A24F76169001EBDBB /* Endpoints */, - D0C7D48524F76169001EBDBB /* MastodonAPI.swift */, - D0C7D48724F76169001EBDBB /* MastodonClient.swift */, - D0C7D47824F76169001EBDBB /* MastodonDecoder.swift */, - D0C7D48624F76169001EBDBB /* MastodonEncoder.swift */, - D0C7D47924F76169001EBDBB /* MastodonEndpoint.swift */, - D0C7D48824F76169001EBDBB /* MastodonTarget.swift */, - ); - path = "Mastodon API"; - sourceTree = ""; - }; - D0C7D47A24F76169001EBDBB /* Endpoints */ = { - isa = PBXGroup; - children = ( - D0C7D48124F76169001EBDBB /* AccessTokenEndpoint.swift */, - D0C7D48024F76169001EBDBB /* AccountEndpoint.swift */, - D0C7D47F24F76169001EBDBB /* AppAuthorizationEndpoint.swift */, - D0C7D48324F76169001EBDBB /* ContextEndpoint.swift */, - D0C7D48224F76169001EBDBB /* DeletionEndpoint.swift */, - D0BEB20C24FA193A001B0F04 /* FilterEndpoint.swift */, - D0BEB20A24FA12D8001B0F04 /* FiltersEndpoint.swift */, - D0C7D47D24F76169001EBDBB /* InstanceEndpoint.swift */, - D0BEB20024FA0220001B0F04 /* ListEndpoint.swift */, - D0BEB1F824F9D627001B0F04 /* ListsEndpoint.swift */, - D0BEB1F424F9A216001B0F04 /* Paged.swift */, - D0C7D47C24F76169001EBDBB /* PreferencesEndpoint.swift */, - D0C7D47B24F76169001EBDBB /* PushSubscriptionEndpoint.swift */, - D0C7D48424F76169001EBDBB /* StatusEndpoint.swift */, - D0C7D47E24F76169001EBDBB /* TimelinesEndpoint.swift */, - ); - path = Endpoints; - sourceTree = ""; - }; D0C7D48924F76169001EBDBB /* Services */ = { isa = PBXGroup; children = ( @@ -731,6 +568,7 @@ D0666A4824C6C1A300F3F04B /* GRDB */, D0DC175E24D016EA00A75C65 /* Alamofire */, D06B492224D4611300642749 /* KingfisherSwiftUI */, + D0E0F1E524FC4B76002C04BF /* Mastodon */, ); productName = "Metatext (iOS)"; productReference = D047FA8C24C3E21200AF17C5 /* Metatext.app */; @@ -771,6 +609,7 @@ ); name = "Notification Service Extension"; packageProductDependencies = ( + D0E0F1E724FC5A61002C04BF /* Mastodon */, ); productName = "Notification Service Extension"; productReference = D0E5361924E3EB4D00FB1CE1 /* Notification Service Extension.appex */; @@ -880,16 +719,9 @@ buildActionMask = 2147483647; files = ( D0C7D4CA24F7616A001EBDBB /* NotificationTypesPreferencesViewModel.swift in Sources */, - D0C7D4EE24F7616A001EBDBB /* MastodonEncoder.swift in Sources */, - D0C7D4E624F7616A001EBDBB /* TimelinesEndpoint.swift in Sources */, - D0C7D4B924F7616A001EBDBB /* Status.swift in Sources */, D0C7D4F424F7616A001EBDBB /* StatusListService.swift in Sources */, - D0C7D4B824F7616A001EBDBB /* Application.swift in Sources */, - D0C7D4E724F7616A001EBDBB /* AppAuthorizationEndpoint.swift in Sources */, - D0C7D4EA24F7616A001EBDBB /* DeletionEndpoint.swift in Sources */, D0C7D4B724F7616A001EBDBB /* TransientStatusCollection.swift in Sources */, D01F41DF24F8868800D55A2D /* AttachmentViewModel.swift in Sources */, - D0C7D4E824F7616A001EBDBB /* AccountEndpoint.swift in Sources */, D0C7D4A324F7616A001EBDBB /* TabNavigationView.swift in Sources */, D0C7D49C24F7616A001EBDBB /* RootView.swift in Sources */, D0C7D4D224F7616A001EBDBB /* ContentDatabase.swift in Sources */, @@ -900,55 +732,33 @@ D0C7D4CD24F7616A001EBDBB /* AddIdentityViewModel.swift in Sources */, D03658D124EDD80900AC17EC /* ContextEndpoint+Stubbing.swift in Sources */, D0BEB1F324F8EE8C001B0F04 /* AttachmentView.swift in Sources */, - D0BEB1F524F9A216001B0F04 /* Paged.swift in Sources */, D0DC174A24CFF15F00A75C65 /* AppAuthorizationEndpoint+Stubbing.swift in Sources */, - D0BEB20D24FA193A001B0F04 /* FilterEndpoint.swift in Sources */, D0C7D49A24F7616A001EBDBB /* StatusListView.swift in Sources */, D01F41D924F880C400D55A2D /* TouchFallthroughTextView.swift in Sources */, - D0BEB20924FA1136001B0F04 /* Filter.swift in Sources */, D0C7D4A524F7616A001EBDBB /* StatusListViewController.swift in Sources */, D0C7D4CC24F7616A001EBDBB /* IdentitiesViewModel.swift in Sources */, D0C7D4E024F7616A001EBDBB /* WebAuthSession.swift in Sources */, - D0C7D4F024F7616A001EBDBB /* MastodonTarget.swift in Sources */, - D0C7D4A624F7616A001EBDBB /* DecodableDefault.swift in Sources */, D0C7D4CB24F7616A001EBDBB /* RootViewModel.swift in Sources */, - D0C7D4BC24F7616A001EBDBB /* Tag.swift in Sources */, - D0C7D4E324F7616A001EBDBB /* PushSubscriptionEndpoint.swift in Sources */, D0C7D4CE24F7616A001EBDBB /* PreferencesViewModel.swift in Sources */, D0C7D4D124F7616A001EBDBB /* IdentityDatabase.swift in Sources */, - D0C7D4ED24F7616A001EBDBB /* MastodonAPI.swift in Sources */, D0C7D4D624F7616A001EBDBB /* NSMutableAttributedString+Extensions.swift in Sources */, D05494FA24EA4E5E008B00A5 /* TimelinesEndpoint+Stubbing.swift in Sources */, D0A652AD24DE3EB6002EA33F /* PreferencesEndpoint+Stubbing.swift in Sources */, - D0C7D4A924F7616A001EBDBB /* Mention.swift in Sources */, D0DC175524D00F0A00A75C65 /* AccessTokenEndpoint+Stubbing.swift in Sources */, - D0C7D4B524F7616A001EBDBB /* Instance.swift in Sources */, D0C7D4D324F7616A001EBDBB /* DatabaseError.swift in Sources */, - D0C7D4E224F7616A001EBDBB /* MastodonEndpoint.swift in Sources */, D0C7D4F224F7616A001EBDBB /* TimelineService.swift in Sources */, D0C7D4BF24F7616A001EBDBB /* AppEnvironment.swift in Sources */, D0C7D49D24F7616A001EBDBB /* PostingReadingPreferencesView.swift in Sources */, D0C7D4D024F7616A001EBDBB /* StatusListViewModel.swift in Sources */, - D0C7D4AC24F7616A001EBDBB /* Poll.swift in Sources */, - D0C7D4BD24F7616A001EBDBB /* Account.swift in Sources */, - D0C7D4EB24F7616A001EBDBB /* ContextEndpoint.swift in Sources */, D0C7D49E24F7616A001EBDBB /* SecondaryNavigationView.swift in Sources */, - D0C7D4DF24F7616A001EBDBB /* HTTPClient.swift in Sources */, D0C7D4D424F7616A001EBDBB /* NSError+Extensions.swift in Sources */, D052BBCA24D74C9200A80A7A /* MockUserDefaults.swift in Sources */, D0C7D4DB24F7616A001EBDBB /* Date+Extensions.swift in Sources */, D0C7D4DA24F7616A001EBDBB /* View+Extensions.swift in Sources */, D0C7D4C824F7616A001EBDBB /* SecondaryNavigationViewModel.swift in Sources */, - D0C7D4EF24F7616A001EBDBB /* MastodonClient.swift in Sources */, - D0C7D4B224F7616A001EBDBB /* HTML.swift in Sources */, - D0C7D4B324F7616A001EBDBB /* MastodonError.swift in Sources */, - D0C7D4E924F7616A001EBDBB /* AccessTokenEndpoint.swift in Sources */, D0C7D4D524F7616A001EBDBB /* String+Extensions.swift in Sources */, - D0BEB20124FA0220001B0F04 /* ListEndpoint.swift in Sources */, - D0C7D4BA24F7616A001EBDBB /* AppAuthorization.swift in Sources */, D0C7D4AB24F7616A001EBDBB /* Identity.swift in Sources */, D0C7D4C024F7616A001EBDBB /* AlertItem.swift in Sources */, - D0C7D4B424F7616A001EBDBB /* MastodonContext.swift in Sources */, D0C7D4A224F7616A001EBDBB /* NotificationTypesPreferencesView.swift in Sources */, D0C7D4CF24F7616A001EBDBB /* StatusViewModel.swift in Sources */, D0C7D4C724F7616A001EBDBB /* PostingReadingPreferencesViewModel.swift in Sources */, @@ -964,46 +774,28 @@ D0DC174624CFEC2000A75C65 /* StubbingURLProtocol.swift in Sources */, D0BEB1FF24F9E5BB001B0F04 /* ListsView.swift in Sources */, D0C7D4F824F7616A001EBDBB /* SecretsService.swift in Sources */, - D0C7D4DE24F7616A001EBDBB /* HTTPTarget.swift in Sources */, D0C7D4F624F7616A001EBDBB /* KeychainService.swift in Sources */, - D0C7D4C124F7616A001EBDBB /* MastodonPreferences.swift in Sources */, D0DC174D24CFF1F100A75C65 /* Stubbing.swift in Sources */, - D0C7D4E524F7616A001EBDBB /* InstanceEndpoint.swift in Sources */, D0C7D49724F7616A001EBDBB /* IdentitiesView.swift in Sources */, D074577724D29006004758DB /* MockWebAuthSession.swift in Sources */, D0C7D4F924F7616A001EBDBB /* UserNotificationService.swift in Sources */, D0C7D49824F7616A001EBDBB /* CustomEmojiText.swift in Sources */, D01F41E424F8889700D55A2D /* AttachmentsView.swift in Sources */, - D0C7D4AA24F7616A001EBDBB /* Attachment.swift in Sources */, - D0C7D4AF24F7616A001EBDBB /* PushNotification.swift in Sources */, D0BEB20724FA1121001B0F04 /* FiltersViewModel.swift in Sources */, D0C7D4C924F7616A001EBDBB /* TabNavigationViewModel.swift in Sources */, D0BEB21124FA2A91001B0F04 /* EditFilterView.swift in Sources */, - D0C7D4B624F7616A001EBDBB /* ListTimeline.swift in Sources */, - D0C7D4E124F7616A001EBDBB /* MastodonDecoder.swift in Sources */, - D0C7D4B024F7616A001EBDBB /* PushSubscription.swift in Sources */, - D0BEB20B24FA12D8001B0F04 /* FiltersEndpoint.swift in Sources */, D0C7D4C424F7616A001EBDBB /* AppDelegate.swift in Sources */, D074577A24D29366004758DB /* URLSessionConfiguration+Extensions.swift in Sources */, - D0C7D4E424F7616A001EBDBB /* PreferencesEndpoint.swift in Sources */, D0C7D49924F7616A001EBDBB /* AddIdentityView.swift in Sources */, D0BEB1FD24F9E4E5001B0F04 /* ListsViewModel.swift in Sources */, D0C7D4C324F7616A001EBDBB /* MetatextApp.swift in Sources */, - D0C7D4B124F7616A001EBDBB /* Card.swift in Sources */, D0C7D4F324F7616A001EBDBB /* ContextService.swift in Sources */, - D0C7D4DD24F7616A001EBDBB /* CodingUserInfoKey+Extensions.swift in Sources */, D0C7D4D824F7616A001EBDBB /* Publisher+Extensions.swift in Sources */, D0BEB20524FA1107001B0F04 /* FiltersView.swift in Sources */, D01F41D824F880C400D55A2D /* StatusTableViewCell.swift in Sources */, D04FD73C24D4A83A007D572D /* InstanceEndpoint+Stubbing.swift in Sources */, - D0C7D4BE24F7616A001EBDBB /* Unknowable.swift in Sources */, - D0C7D4AE24F7616A001EBDBB /* Timeline.swift in Sources */, D0C7D49B24F7616A001EBDBB /* PreferencesView.swift in Sources */, - D0C7D4EC24F7616A001EBDBB /* StatusEndpoint.swift in Sources */, D0C7D4D724F7616A001EBDBB /* UIColor+Extensions.swift in Sources */, - D0C7D4BB24F7616A001EBDBB /* Emoji.swift in Sources */, - D0BEB1F924F9D627001B0F04 /* ListsEndpoint.swift in Sources */, - D0C7D4AD24F7616A001EBDBB /* AccessToken.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1021,12 +813,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - D0C7D4FC24F761A8001EBDBB /* Unknowable.swift in Sources */, - D0C7D4FB24F7619F001EBDBB /* PushNotification.swift in Sources */, D0C7D4FE24F761C9001EBDBB /* SecretsService.swift in Sources */, - D0C7D50124F761EC001EBDBB /* MastodonAPI.swift in Sources */, D0E5361C24E3EB4D00FB1CE1 /* NotificationService.swift in Sources */, - D0C7D4FD24F761C1001EBDBB /* MastodonDecoder.swift in Sources */, D0C7D50024F761E0001EBDBB /* NSError+Extensions.swift in Sources */, D0C7D4FF24F761D0001EBDBB /* KeychainService.swift in Sources */, ); @@ -1404,6 +1192,14 @@ package = D0DC175D24D016EA00A75C65 /* XCRemoteSwiftPackageReference "Alamofire" */; productName = Alamofire; }; + D0E0F1E524FC4B76002C04BF /* Mastodon */ = { + isa = XCSwiftPackageProductDependency; + productName = Mastodon; + }; + D0E0F1E724FC5A61002C04BF /* Mastodon */ = { + isa = XCSwiftPackageProductDependency; + productName = Mastodon; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = D047FA8024C3E21000AF17C5 /* Project object */; diff --git a/Model/AccessToken.swift b/Model/AccessToken.swift deleted file mode 100644 index 4d0feec..0000000 --- a/Model/AccessToken.swift +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Foundation - -struct AccessToken: Codable { - let scope: String - let tokenType: String - let accessToken: String -} diff --git a/Model/Account.swift b/Model/Account.swift deleted file mode 100644 index 2f80188..0000000 --- a/Model/Account.swift +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Foundation - -struct Account: Codable, Hashable { - struct Field: Codable, Hashable { - let name: String - let value: HTML - let verifiedAt: Date? - } - - let id: String - let username: String - let acct: String - let displayName: String - let locked: Bool - let createdAt: Date - let followersCount: Int - let followingCount: Int - let statusesCount: Int - let note: HTML - let url: URL - let avatar: URL - let avatarStatic: URL - let header: URL - let headerStatic: URL - let fields: [Field] - let emojis: [Emoji] - @DecodableDefault.False private(set) var bot: Bool - @DecodableDefault.False private(set) var moved: Bool - @DecodableDefault.False private(set) var discoverable: Bool -} diff --git a/Model/AppAuthorization.swift b/Model/AppAuthorization.swift deleted file mode 100644 index 82f34cd..0000000 --- a/Model/AppAuthorization.swift +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Foundation - -struct AppAuthorization: Codable { - let id: String - let clientId: String - let clientSecret: String - let name: String - let redirectUri: String - let website: String? - let vapidKey: String? -} diff --git a/Model/AppEnvironment.swift b/Model/AppEnvironment.swift index be07c9e..384b301 100644 --- a/Model/AppEnvironment.swift +++ b/Model/AppEnvironment.swift @@ -1,6 +1,7 @@ // Copyright © 2020 Metabolist. All rights reserved. import Foundation +import Mastodon struct AppEnvironment { let session: Session @@ -8,7 +9,6 @@ struct AppEnvironment { let keychainServiceType: KeychainService.Type let userDefaults: UserDefaults let inMemoryContent: Bool - let attributedStringCache = AttributedStringCache() } extension AppEnvironment { diff --git a/Model/Application.swift b/Model/Application.swift deleted file mode 100644 index 4416c8a..0000000 --- a/Model/Application.swift +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Foundation - -struct Application: Codable, Hashable { - let name: String - let website: String? -} diff --git a/Model/Attachment.swift b/Model/Attachment.swift deleted file mode 100644 index 30bf0b2..0000000 --- a/Model/Attachment.swift +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Foundation - -struct Attachment: Codable, Hashable { - enum AttachmentType: String, Codable, Hashable, Unknowable { - case image, video, gifv, audio, unknown - - static var unknownCase: Self { .unknown } - } - - // swiftlint:disable nesting - struct Meta: Codable, Hashable { - struct Info: Codable, Hashable { - let width: Int? - let height: Int? - let size: String? - let aspect: Double? - let frameRate: String? - let duration: Double? - let bitrate: Int? - } - - struct Focus: Codable, Hashable { - let x: Double - let y: Double - } - - let original: Info? - let small: Info? - let focus: Focus? - } - // swiftlint:enable nesting - - let id: String - let type: AttachmentType - let url: URL - let remoteUrl: URL? - let previewUrl: URL - let textUrl: URL? - let meta: Meta? - let description: String? -} diff --git a/Model/Card.swift b/Model/Card.swift deleted file mode 100644 index b2539e8..0000000 --- a/Model/Card.swift +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Foundation - -struct Card: Codable, Hashable { - enum CardType: String, Codable, Hashable, Unknowable { - case link, photo, video, rich, unknown - - static var unknownCase: Self { .unknown } - } - - let url: URL - let title: String - let description: String - let type: CardType - let authorName: String? - let authorUrl: String? - let providerName: String? - let providerUrl: String? - let html: String? - let width: Int? - let height: Int? - let image: URL? - let embedUrl: String? -} diff --git a/Model/Emoji.swift b/Model/Emoji.swift deleted file mode 100644 index 65fe288..0000000 --- a/Model/Emoji.swift +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Foundation - -struct Emoji: Codable, Hashable { - let shortcode: String - let staticUrl: URL - let url: URL - let visibleInPicker: Bool -} diff --git a/Model/Identity.swift b/Model/Identity.swift index f0d63ab..8ba6d68 100644 --- a/Model/Identity.swift +++ b/Model/Identity.swift @@ -1,6 +1,7 @@ // Copyright © 2020 Metabolist. All rights reserved. import Foundation +import Mastodon struct Identity: Codable, Hashable, Identifiable { let id: UUID diff --git a/Model/Instance.swift b/Model/Instance.swift deleted file mode 100644 index f914007..0000000 --- a/Model/Instance.swift +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Foundation - -struct Instance: Codable, Hashable { - struct URLs: Codable, Hashable { - let streamingApi: URL - } - - struct Stats: Codable, Hashable { - let userCount: Int - let statusCount: Int - let domainCount: Int - } - - let uri: String - let title: String - let description: String - let shortDescription: String? - let email: String - let version: String - @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? - let contactAccount: Account? -} diff --git a/Model/ListTimeline.swift b/Model/ListTimeline.swift deleted file mode 100644 index 99c4e2f..0000000 --- a/Model/ListTimeline.swift +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Foundation - -struct MastodonList: Codable, Hashable, Identifiable { - let id: String - let title: String -} diff --git a/Model/MastodonContext.swift b/Model/MastodonContext.swift deleted file mode 100644 index a7b9228..0000000 --- a/Model/MastodonContext.swift +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Foundation - -struct MastodonContext: Codable, Hashable { - let ancestors: [Status] - let descendants: [Status] -} diff --git a/Model/MastodonError.swift b/Model/MastodonError.swift deleted file mode 100644 index 5db85b0..0000000 --- a/Model/MastodonError.swift +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Foundation - -struct MastodonError: Error, Codable { - let error: String -} - -extension MastodonError: LocalizedError { - var errorDescription: String? { error } -} diff --git a/Model/Mention.swift b/Model/Mention.swift deleted file mode 100644 index 52720ea..0000000 --- a/Model/Mention.swift +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Foundation - -struct Mention: Codable, Hashable { - let url: URL - let username: String - let acct: String - let id: String -} diff --git a/Model/Poll.swift b/Model/Poll.swift deleted file mode 100644 index ad97f65..0000000 --- a/Model/Poll.swift +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Foundation - -struct Poll: Codable, Hashable { - struct Option: Codable, Hashable { - var title: String - var votesCount: Int - } - - let id: String - let expiresAt: Date - let expired: Bool - let multiple: Bool - let votesCount: Int - let votersCount: Int? - @DecodableDefault.False private(set) var voted: Bool - @DecodableDefault.EmptyList private(set) var ownVotes: [Int] - let options: [Option] - let emojis: [Emoji] -} diff --git a/Model/PushNotification.swift b/Model/PushNotification.swift deleted file mode 100644 index 924dfcd..0000000 --- a/Model/PushNotification.swift +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Foundation - -struct PushNotification: Codable { - enum NotificationType: String, Codable, Unknowable { - case mention - case reblog - case favourite - case follow - case unknown - - static var unknownCase: Self { .unknown } - } - - let accessToken: String - let body: String - let title: String - let icon: URL - let notificationId: Int - let notificationType: NotificationType - let preferredLocale: String -} diff --git a/Model/PushSubscription.swift b/Model/PushSubscription.swift deleted file mode 100644 index 88b15bd..0000000 --- a/Model/PushSubscription.swift +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Foundation - -struct PushSubscription: Codable { - struct Alerts: Codable, Hashable { - var follow: Bool - var favourite: Bool - var reblog: Bool - var mention: Bool - @DecodableDefault.True var poll: Bool - } - - let endpoint: URL - let alerts: Alerts - let serverKey: String -} - -extension PushSubscription.Alerts { - static let initial: Self = Self( - follow: true, - favourite: true, - reblog: true, - mention: true, - poll: DecodableDefault.True()) -} diff --git a/Model/Tag.swift b/Model/Tag.swift deleted file mode 100644 index f15b5b0..0000000 --- a/Model/Tag.swift +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Foundation - -struct Tag: Codable, Hashable { - let name: String - let url: URL -} diff --git a/Networking/Mastodon API/Endpoints/Paged.swift b/Networking/Mastodon API/Endpoints/Paged.swift deleted file mode 100644 index dd9eb99..0000000 --- a/Networking/Mastodon API/Endpoints/Paged.swift +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Foundation - -struct Paged { - let endpoint: T - let maxID: String? - let minID: String? - let sinceID: String? - let limit: Int? - - init(_ endpoint: T, maxID: String? = nil, minID: String? = nil, sinceID: String? = nil, limit: Int? = nil) { - self.endpoint = endpoint - self.maxID = maxID - self.minID = minID - self.sinceID = sinceID - self.limit = limit - } -} - -extension Paged: MastodonEndpoint { - typealias ResultType = T.ResultType - - var APIVersion: String { endpoint.APIVersion } - - var context: [String] { endpoint.context } - - var pathComponentsInContext: [String] { endpoint.pathComponentsInContext } - - var method: HTTPMethod { endpoint.method } - - var encoding: ParameterEncoding { endpoint.encoding } - - var parameters: [String: Any]? { - var parameters = endpoint.parameters ?? [String: Any]() - - parameters["max_id"] = maxID - parameters["min_id"] = minID - parameters["since_id"] = sinceID - parameters["limit"] = limit - - return parameters - } - - var headers: HTTPHeaders? { endpoint.headers } -} diff --git a/Networking/Mastodon API/MastodonAPI.swift b/Networking/Mastodon API/MastodonAPI.swift deleted file mode 100644 index 28cbba9..0000000 --- a/Networking/Mastodon API/MastodonAPI.swift +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Foundation - -struct MastodonAPI { - static let dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" -} diff --git a/Networking/Mastodon API/MastodonClient.swift b/Networking/Mastodon API/MastodonClient.swift deleted file mode 100644 index 14f3d05..0000000 --- a/Networking/Mastodon API/MastodonClient.swift +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Foundation -import Combine - -class MastodonClient: HTTPClient { - var instanceURL: URL? - var accessToken: String? - - required init(environment: AppEnvironment) { - let decoder = MastodonDecoder() - - decoder.userInfo[.attributedStringCache] = environment.attributedStringCache - - super.init(session: environment.session, decoder: decoder) - } - - override func request(_ target: T) -> AnyPublisher { - super.request(target, decodeErrorsAs: MastodonError.self) - } -} - -extension MastodonClient { - func request(_ endpoint: E) -> AnyPublisher { - guard let instanceURL = instanceURL else { - return Fail(error: URLError(.badURL)).eraseToAnyPublisher() - } - - return super.request( - MastodonTarget(baseURL: instanceURL, endpoint: endpoint, accessToken: accessToken), - decodeErrorsAs: MastodonError.self) - } -} diff --git a/Networking/Mastodon API/MastodonTarget.swift b/Networking/Mastodon API/MastodonTarget.swift deleted file mode 100644 index 9cbf9eb..0000000 --- a/Networking/Mastodon API/MastodonTarget.swift +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Foundation - -struct MastodonTarget { - let baseURL: URL - let endpoint: E - let accessToken: String? -} - -extension MastodonTarget: DecodableTarget { - typealias ResultType = E.ResultType - - var pathComponents: [String] { endpoint.pathComponents } - - var method: HTTPMethod { endpoint.method } - - var encoding: ParameterEncoding { endpoint.encoding } - - var parameters: [String: Any]? { endpoint.parameters } - - var headers: HTTPHeaders? { - var headers = endpoint.headers - - if let accessToken = accessToken { - if headers == nil { - headers = HTTPHeaders() - } - - headers?.add(.authorization(bearerToken: accessToken)) - } - - return headers - } -} diff --git a/Notification Service Extension/NotificationService.swift b/Notification Service Extension/NotificationService.swift index 5632edc..64f2b67 100644 --- a/Notification Service Extension/NotificationService.swift +++ b/Notification Service Extension/NotificationService.swift @@ -2,6 +2,7 @@ import UserNotifications import CryptoKit +import Mastodon class NotificationService: UNNotificationServiceExtension { diff --git a/Services/AllIdentitiesService.swift b/Services/AllIdentitiesService.swift index 1640d00..3848bb8 100644 --- a/Services/AllIdentitiesService.swift +++ b/Services/AllIdentitiesService.swift @@ -2,6 +2,7 @@ import Foundation import Combine +import Mastodon struct AllIdentitiesService { let mostRecentlyUsedIdentityID: AnyPublisher @@ -49,7 +50,7 @@ extension AllIdentitiesService { func deleteIdentity(_ identity: Identity) -> AnyPublisher { let secretsService = SecretsService(identityID: identity.id, keychainService: environment.keychainServiceType) - let networkClient = MastodonClient(environment: environment) + let networkClient = MastodonClient(session: environment.session) networkClient.instanceURL = identity.url diff --git a/Services/AuthenticationService.swift b/Services/AuthenticationService.swift index a102595..9fd80c8 100644 --- a/Services/AuthenticationService.swift +++ b/Services/AuthenticationService.swift @@ -2,6 +2,7 @@ import Foundation import Combine +import Mastodon struct AuthenticationService { private let networkClient: MastodonClient @@ -9,7 +10,7 @@ struct AuthenticationService { private let webAuthSessionContextProvider = WebAuthSessionContextProvider() init(environment: AppEnvironment) { - networkClient = MastodonClient(environment: environment) + networkClient = MastodonClient(session: environment.session) webAuthSessionType = environment.webAuthSessionType } } diff --git a/Services/IdentityService.swift b/Services/IdentityService.swift index a0e40e1..9d4c5e5 100644 --- a/Services/IdentityService.swift +++ b/Services/IdentityService.swift @@ -2,6 +2,7 @@ import Foundation import Combine +import Mastodon class IdentityService { @Published private(set) var identity: Identity @@ -34,11 +35,11 @@ class IdentityService { secretsService = SecretsService( identityID: identityID, keychainService: environment.keychainServiceType) - networkClient = MastodonClient(environment: environment) + networkClient = MastodonClient(session: environment.session) networkClient.instanceURL = identity.url networkClient.accessToken = try? secretsService.item(.accessToken) - contentDatabase = try ContentDatabase(identityID: identityID, environment: environment) + contentDatabase = try ContentDatabase(identityID: identityID, inMemory: environment.inMemoryContent) observation.catch { [weak self] error -> Empty in self?.observationErrorsInput.send(error) diff --git a/Services/Status List Services/ContextService.swift b/Services/Status List Services/ContextService.swift index 3815705..9ee16d9 100644 --- a/Services/Status List Services/ContextService.swift +++ b/Services/Status List Services/ContextService.swift @@ -2,6 +2,7 @@ import Foundation import Combine +import Mastodon struct ContextService { let statusSections: AnyPublisher<[[Status]], Error> diff --git a/Services/Status List Services/StatusListService.swift b/Services/Status List Services/StatusListService.swift index 1a8a7f9..1310575 100644 --- a/Services/Status List Services/StatusListService.swift +++ b/Services/Status List Services/StatusListService.swift @@ -2,6 +2,7 @@ import Foundation import Combine +import Mastodon protocol StatusListService { var statusSections: AnyPublisher<[[Status]], Error> { get } diff --git a/Services/Status List Services/TimelineService.swift b/Services/Status List Services/TimelineService.swift index 593281f..91ee21a 100644 --- a/Services/Status List Services/TimelineService.swift +++ b/Services/Status List Services/TimelineService.swift @@ -2,6 +2,7 @@ import Foundation import Combine +import Mastodon struct TimelineService { let statusSections: AnyPublisher<[[Status]], Error> diff --git a/Services/StatusService.swift b/Services/StatusService.swift index 139117b..fc84557 100644 --- a/Services/StatusService.swift +++ b/Services/StatusService.swift @@ -2,6 +2,7 @@ import Foundation import Combine +import Mastodon struct StatusService { let status: Status diff --git a/View Models/AttachmentViewModel.swift b/View Models/AttachmentViewModel.swift index 8c5f958..0761fe3 100644 --- a/View Models/AttachmentViewModel.swift +++ b/View Models/AttachmentViewModel.swift @@ -1,6 +1,7 @@ // Copyright © 2020 Metabolist. All rights reserved. import Foundation +import Mastodon struct AttachmentViewModel { let attachment: Attachment diff --git a/View Models/EditFilterViewModel.swift b/View Models/EditFilterViewModel.swift index 543ac2a..cbffc26 100644 --- a/View Models/EditFilterViewModel.swift +++ b/View Models/EditFilterViewModel.swift @@ -2,6 +2,7 @@ import Foundation import Combine +import Mastodon class EditFilterViewModel: ObservableObject { @Published var filter: Filter @@ -56,3 +57,22 @@ extension EditFilterViewModel { .store(in: &cancellables) } } + +extension Filter.Context { + var localized: String { + switch self { + case .home: + return NSLocalizedString("filter.context.home", comment: "") + case .notifications: + return NSLocalizedString("filter.context.notifications", comment: "") + case .public: + return NSLocalizedString("filter.context.public", comment: "") + case .thread: + return NSLocalizedString("filter.context.thread", comment: "") + case .account: + return NSLocalizedString("filter.context.account", comment: "") + case .unknown: + return NSLocalizedString("filter.context.unknown", comment: "") + } + } +} diff --git a/View Models/FiltersViewModel.swift b/View Models/FiltersViewModel.swift index f46cb5f..2e39c8d 100644 --- a/View Models/FiltersViewModel.swift +++ b/View Models/FiltersViewModel.swift @@ -2,6 +2,7 @@ import Foundation import Combine +import Mastodon class FiltersViewModel: ObservableObject { @Published var activeFilters = [Filter]() diff --git a/View Models/ListsViewModel.swift b/View Models/ListsViewModel.swift index 5f89482..33f8b22 100644 --- a/View Models/ListsViewModel.swift +++ b/View Models/ListsViewModel.swift @@ -2,6 +2,7 @@ import Foundation import Combine +import Mastodon class ListsViewModel: ObservableObject { @Published private(set) var lists = [MastodonList]() diff --git a/View Models/NotificationTypesPreferencesViewModel.swift b/View Models/NotificationTypesPreferencesViewModel.swift index 6dc2da4..ce8f8b9 100644 --- a/View Models/NotificationTypesPreferencesViewModel.swift +++ b/View Models/NotificationTypesPreferencesViewModel.swift @@ -2,6 +2,7 @@ import Foundation import Combine +import Mastodon class NotificationTypesPreferencesViewModel: ObservableObject { @Published var pushSubscriptionAlerts: PushSubscription.Alerts diff --git a/View Models/StatusListViewModel.swift b/View Models/StatusListViewModel.swift index b4273bc..39e1561 100644 --- a/View Models/StatusListViewModel.swift +++ b/View Models/StatusListViewModel.swift @@ -2,6 +2,7 @@ import Foundation import Combine +import Mastodon class StatusListViewModel: ObservableObject { @Published private(set) var statusIDs = [[String]]() diff --git a/View Models/StatusViewModel.swift b/View Models/StatusViewModel.swift index ffc1b90..0865133 100644 --- a/View Models/StatusViewModel.swift +++ b/View Models/StatusViewModel.swift @@ -2,6 +2,7 @@ import Foundation import Combine +import Mastodon struct StatusViewModel { let content: NSAttributedString diff --git a/View Models/TabNavigationViewModel.swift b/View Models/TabNavigationViewModel.swift index 4c99910..9f493b8 100644 --- a/View Models/TabNavigationViewModel.swift +++ b/View Models/TabNavigationViewModel.swift @@ -2,6 +2,7 @@ import Foundation import Combine +import Mastodon class TabNavigationViewModel: ObservableObject { @Published private(set) var identity: Identity diff --git a/Views/CustomEmojiText.swift b/Views/CustomEmojiText.swift index 370aa66..549f7eb 100644 --- a/Views/CustomEmojiText.swift +++ b/Views/CustomEmojiText.swift @@ -1,6 +1,7 @@ // Copyright © 2020 Metabolist. All rights reserved. import SwiftUI +import struct Mastodon.Emoji struct CustomEmojiText: UIViewRepresentable { private let attributedText: NSMutableAttributedString diff --git a/Views/EditFilterView.swift b/Views/EditFilterView.swift index d48f936..60f6b3e 100644 --- a/Views/EditFilterView.swift +++ b/Views/EditFilterView.swift @@ -1,6 +1,7 @@ // Copyright © 2020 Metabolist. All rights reserved. import SwiftUI +import struct Mastodon.Filter struct EditFilterView: View { @StateObject var viewModel: EditFilterViewModel diff --git a/Views/FiltersView.swift b/Views/FiltersView.swift index badf90f..040c5ec 100644 --- a/Views/FiltersView.swift +++ b/Views/FiltersView.swift @@ -1,6 +1,7 @@ // Copyright © 2020 Metabolist. All rights reserved. import SwiftUI +import struct Mastodon.Filter struct FiltersView: View { @StateObject var viewModel: FiltersViewModel diff --git a/Views/PostingReadingPreferencesView.swift b/Views/PostingReadingPreferencesView.swift index 2d83b37..543c5b5 100644 --- a/Views/PostingReadingPreferencesView.swift +++ b/Views/PostingReadingPreferencesView.swift @@ -1,6 +1,8 @@ // Copyright © 2020 Metabolist. All rights reserved. import SwiftUI +import class Mastodon.Status +import struct Mastodon.MastodonPreferences struct PostingReadingPreferencesView: View { @StateObject var viewModel: PostingReadingPreferencesViewModel