mirror of
https://github.com/metabolist/metatext.git
synced 2024-11-25 09:41:00 +00:00
wip
This commit is contained in:
parent
71c8861600
commit
5f96f59ac3
69 changed files with 393 additions and 564 deletions
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
{
|
|
||||||
"data" : [
|
|
||||||
{
|
|
||||||
"filename" : "timeline.json",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"universal-type-identifier" : "public.json"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,6 +4,8 @@ import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
import HTTP
|
import HTTP
|
||||||
import Mastodon
|
import Mastodon
|
||||||
|
import Services
|
||||||
|
import ServiceMocks
|
||||||
|
|
||||||
// swiftlint:disable force_try
|
// swiftlint:disable force_try
|
||||||
private let decoder = APIDecoder()
|
private let decoder = APIDecoder()
|
||||||
|
@ -20,31 +22,6 @@ extension Instance {
|
||||||
static let development = try! decoder.decode(Instance.self, from: Data(officialInstanceJSON.utf8))
|
static let development = try! decoder.decode(Instance.self, from: Data(officialInstanceJSON.utf8))
|
||||||
}
|
}
|
||||||
|
|
||||||
extension IdentityDatabase {
|
|
||||||
static func fresh() -> IdentityDatabase { try! IdentityDatabase(inMemory: true) }
|
|
||||||
|
|
||||||
static var development: IdentityDatabase = {
|
|
||||||
let db = IdentityDatabase.fresh()
|
|
||||||
|
|
||||||
db.createIdentity(id: devIdentityID, url: devInstanceURL)
|
|
||||||
.receive(on: ImmediateScheduler.shared)
|
|
||||||
.sink(receiveCompletion: { _ in }, receiveValue: { _ in })
|
|
||||||
.store(in: &cancellables)
|
|
||||||
|
|
||||||
db.updateAccount(.development, forIdentityID: devIdentityID)
|
|
||||||
.receive(on: ImmediateScheduler.shared)
|
|
||||||
.sink(receiveCompletion: { _ in }, receiveValue: { _ in })
|
|
||||||
.store(in: &cancellables)
|
|
||||||
|
|
||||||
db.updateInstance(.development, forIdentityID: devIdentityID)
|
|
||||||
.receive(on: ImmediateScheduler.shared)
|
|
||||||
.sink(receiveCompletion: { _ in }, receiveValue: { _ in })
|
|
||||||
.store(in: &cancellables)
|
|
||||||
|
|
||||||
return db
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
extension AppEnvironment {
|
extension AppEnvironment {
|
||||||
static let development = AppEnvironment(
|
static let development = AppEnvironment(
|
||||||
session: Session(configuration: .stubbing),
|
session: Session(configuration: .stubbing),
|
||||||
|
@ -55,18 +32,30 @@ extension AppEnvironment {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AllIdentitiesService {
|
extension AllIdentitiesService {
|
||||||
static func fresh(
|
static let fresh = try! AllIdentitiesService(environment: .development)
|
||||||
identityDatabase: IdentityDatabase = .fresh(),
|
|
||||||
keychainService: KeychainService = MockKeychainService(),
|
|
||||||
environment: AppEnvironment = .development) -> AllIdentitiesService {
|
|
||||||
AllIdentitiesService(
|
|
||||||
identityDatabase: identityDatabase,
|
|
||||||
environment: environment)
|
|
||||||
}
|
|
||||||
|
|
||||||
static let development = AllIdentitiesService(
|
static var development: Self = {
|
||||||
identityDatabase: .development,
|
let allIdentitiesService = try! AllIdentitiesService(environment: .development)
|
||||||
environment: .development)
|
|
||||||
|
allIdentitiesService.authorizeIdentity(id: devIdentityID, instanceURL: devInstanceURL)
|
||||||
|
.receive(on: ImmediateScheduler.shared)
|
||||||
|
.sink { _ in } receiveValue: { _ in }
|
||||||
|
.store(in: &cancellables)
|
||||||
|
|
||||||
|
// let identityService = try! allIdentitiesService.identityService(id: devIdentityID)
|
||||||
|
//
|
||||||
|
// identityService.verifyCredentials()
|
||||||
|
// .receive(on: ImmediateScheduler.shared)
|
||||||
|
// .sink { _ in } receiveValue: { _ in }
|
||||||
|
// .store(in: &cancellables)
|
||||||
|
//
|
||||||
|
// identityService.refreshInstance()
|
||||||
|
// .receive(on: ImmediateScheduler.shared)
|
||||||
|
// .sink { _ in } receiveValue: { _ in }
|
||||||
|
// .store(in: &cancellables)
|
||||||
|
|
||||||
|
return allIdentitiesService
|
||||||
|
} ()
|
||||||
}
|
}
|
||||||
|
|
||||||
extension IdentityService {
|
extension IdentityService {
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
// Copyright © 2020 Metabolist. All rights reserved.
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
class MockKeychainService {
|
|
||||||
private var guts = [String: Data]()
|
|
||||||
}
|
|
||||||
|
|
||||||
extension MockKeychainService: KeychainServiceType {
|
|
||||||
func set(data: Data, forKey key: String) throws {
|
|
||||||
guts[key] = data
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteData(key: String) throws {
|
|
||||||
guts[key] = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getData(key: String) throws -> Data? {
|
|
||||||
guts[key]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
// Copyright © 2020 Metabolist. All rights reserved.
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import HTTP
|
|
||||||
|
|
||||||
struct HTTPStubs {
|
|
||||||
static func stub(
|
|
||||||
request: URLRequest,
|
|
||||||
target: Target? = nil,
|
|
||||||
userInfo: [String: Any] = [:]) -> HTTPStub? {
|
|
||||||
guard let url = request.url else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return (target as? Stubbing)?.stub(url: url)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
// Copyright © 2020 Metabolist. All rights reserved.
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import UIKit
|
|
||||||
import Mastodon
|
|
||||||
|
|
||||||
extension TimelinesEndpoint: Stubbing {
|
|
||||||
func data(url: URL) -> Data? {
|
|
||||||
NSDataAsset(name: "timelineJSON")!.data
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,7 +11,10 @@ let package = Package(
|
||||||
products: [
|
products: [
|
||||||
.library(
|
.library(
|
||||||
name: "HTTP",
|
name: "HTTP",
|
||||||
targets: ["HTTP"])
|
targets: ["HTTP"]),
|
||||||
|
.library(
|
||||||
|
name: "Stubbing",
|
||||||
|
targets: ["Stubbing"])
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(url: "https://github.com/Alamofire/Alamofire.git", .upToNextMajor(from: "5.2.2"))
|
.package(url: "https://github.com/Alamofire/Alamofire.git", .upToNextMajor(from: "5.2.2"))
|
||||||
|
@ -20,6 +23,9 @@ let package = Package(
|
||||||
.target(
|
.target(
|
||||||
name: "HTTP",
|
name: "HTTP",
|
||||||
dependencies: ["Alamofire"]),
|
dependencies: ["Alamofire"]),
|
||||||
|
.target(
|
||||||
|
name: "Stubbing",
|
||||||
|
dependencies: ["HTTP"]),
|
||||||
.testTarget(
|
.testTarget(
|
||||||
name: "HTTPTests",
|
name: "HTTPTests",
|
||||||
dependencies: ["HTTP"])
|
dependencies: ["HTTP"])
|
||||||
|
|
|
@ -2,16 +2,16 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
typealias HTTPStub = Result<(URLResponse, Data), Error>
|
public typealias HTTPStub = Result<(URLResponse, Data), Error>
|
||||||
|
|
||||||
protocol Stubbing {
|
public protocol Stubbing {
|
||||||
func stub(url: URL) -> HTTPStub?
|
func stub(url: URL) -> HTTPStub?
|
||||||
func data(url: URL) -> Data?
|
func data(url: URL) -> Data?
|
||||||
func dataString(url: URL) -> String?
|
func dataString(url: URL) -> String?
|
||||||
func statusCode(url: URL) -> Int?
|
func statusCode(url: URL) -> Int?
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Stubbing {
|
public extension Stubbing {
|
||||||
func stub(url: URL) -> HTTPStub? {
|
func stub(url: URL) -> HTTPStub? {
|
||||||
if let data = data(url: url),
|
if let data = data(url: url),
|
||||||
let statusCode = statusCode(url: url),
|
let statusCode = statusCode(url: url),
|
|
@ -3,25 +3,25 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import HTTP
|
import HTTP
|
||||||
|
|
||||||
class StubbingURLProtocol: URLProtocol {
|
public class StubbingURLProtocol: URLProtocol {
|
||||||
private static var targetsForURLs = [URL: Target]()
|
private static var targetsForURLs = [URL: Target]()
|
||||||
|
|
||||||
override class func canInit(with task: URLSessionTask) -> Bool {
|
override public class func canInit(with task: URLSessionTask) -> Bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
override class func canInit(with request: URLRequest) -> Bool {
|
override public class func canInit(with request: URLRequest) -> Bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
override class func canonicalRequest(for request: URLRequest) -> URLRequest {
|
override public class func canonicalRequest(for request: URLRequest) -> URLRequest {
|
||||||
request
|
request
|
||||||
}
|
}
|
||||||
|
|
||||||
override func startLoading() {
|
override public func startLoading() {
|
||||||
guard
|
guard
|
||||||
let url = request.url,
|
let url = request.url,
|
||||||
let stub = HTTPStubs.stub(request: request, target: Self.targetsForURLs[url]) else {
|
let stub = Self.stub(request: request, target: Self.targetsForURLs[url]) else {
|
||||||
preconditionFailure("Stub for request not found")
|
preconditionFailure("Stub for request not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,11 +35,24 @@ class StubbingURLProtocol: URLProtocol {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func stopLoading() {}
|
override public func stopLoading() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension StubbingURLProtocol {
|
||||||
|
class func stub(
|
||||||
|
request: URLRequest,
|
||||||
|
target: Target? = nil,
|
||||||
|
userInfo: [String: Any] = [:]) -> HTTPStub? {
|
||||||
|
guard let url = request.url else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return (target as? Stubbing)?.stub(url: url)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension StubbingURLProtocol: TargetProcessing {
|
extension StubbingURLProtocol: TargetProcessing {
|
||||||
static func process(target: Target) {
|
public static func process(target: Target) {
|
||||||
if let url = try? target.asURLRequest().url {
|
if let url = try? target.asURLRequest().url {
|
||||||
targetsForURLs[url] = target
|
targetsForURLs[url] = target
|
||||||
}
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
extension URLSessionConfiguration {
|
public extension URLSessionConfiguration {
|
||||||
static var stubbing: URLSessionConfiguration {
|
static var stubbing: URLSessionConfiguration {
|
||||||
let configuration = Self.default
|
let configuration = Self.default
|
||||||
|
|
|
@ -11,7 +11,10 @@ let package = Package(
|
||||||
products: [
|
products: [
|
||||||
.library(
|
.library(
|
||||||
name: "Mastodon",
|
name: "Mastodon",
|
||||||
targets: ["Mastodon"])
|
targets: ["Mastodon"]),
|
||||||
|
.library(
|
||||||
|
name: "MastodonStubs",
|
||||||
|
targets: ["MastodonStubs"])
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(path: "HTTP")
|
.package(path: "HTTP")
|
||||||
|
@ -20,8 +23,12 @@ let package = Package(
|
||||||
.target(
|
.target(
|
||||||
name: "Mastodon",
|
name: "Mastodon",
|
||||||
dependencies: ["HTTP"]),
|
dependencies: ["HTTP"]),
|
||||||
|
.target(
|
||||||
|
name: "MastodonStubs",
|
||||||
|
dependencies: ["Mastodon", .product(name: "Stubbing", package: "HTTP")],
|
||||||
|
resources: [.process("Resources")]),
|
||||||
.testTarget(
|
.testTarget(
|
||||||
name: "MastodonTests",
|
name: "MastodonTests",
|
||||||
dependencies: ["Mastodon"])
|
dependencies: ["MastodonStubs"])
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,9 +2,10 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import Mastodon
|
import Mastodon
|
||||||
|
import Stubbing
|
||||||
|
|
||||||
extension AccessTokenEndpoint: Stubbing {
|
extension AccessTokenEndpoint: Stubbing {
|
||||||
func dataString(url: URL) -> String? {
|
public func dataString(url: URL) -> String? {
|
||||||
switch self {
|
switch self {
|
||||||
case let .oauthToken(_, _, _, _, scopes, _):
|
case let .oauthToken(_, _, _, _, scopes, _):
|
||||||
return """
|
return """
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright © 2020 Metabolist. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Mastodon
|
||||||
|
import Stubbing
|
||||||
|
|
||||||
|
extension AccountEndpoint: Stubbing {
|
||||||
|
public func data(url: URL) -> Data? {
|
||||||
|
switch self {
|
||||||
|
case .verifyCredentials: return try? Data(contentsOf: Bundle.module.url(forResource: "account", withExtension: "json")!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,9 +2,10 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import Mastodon
|
import Mastodon
|
||||||
|
import Stubbing
|
||||||
|
|
||||||
extension AppAuthorizationEndpoint: Stubbing {
|
extension AppAuthorizationEndpoint: Stubbing {
|
||||||
func dataString(url: URL) -> String? {
|
public func dataString(url: URL) -> String? {
|
||||||
switch self {
|
switch self {
|
||||||
case let .apps(clientName, redirectURI, _, _):
|
case let .apps(clientName, redirectURI, _, _):
|
||||||
return """
|
return """
|
|
@ -2,9 +2,10 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import Mastodon
|
import Mastodon
|
||||||
|
import Stubbing
|
||||||
|
|
||||||
extension ContextEndpoint: Stubbing {
|
extension ContextEndpoint: Stubbing {
|
||||||
func dataString(url: URL) -> String? {
|
public func dataString(url: URL) -> String? {
|
||||||
switch self {
|
switch self {
|
||||||
case .context:
|
case .context:
|
||||||
return """
|
return """
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright © 2020 Metabolist. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Mastodon
|
||||||
|
import Stubbing
|
||||||
|
|
||||||
|
extension InstanceEndpoint: Stubbing {
|
||||||
|
public func data(url: URL) -> Data? {
|
||||||
|
switch self {
|
||||||
|
case .instance: return try? Data(contentsOf: Bundle.module.url(forResource: "instance", withExtension: "json")!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,21 +2,22 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import Mastodon
|
import Mastodon
|
||||||
|
import Stubbing
|
||||||
|
|
||||||
extension APITarget: Stubbing {
|
extension APITarget: Stubbing {
|
||||||
func stub(url: URL) -> HTTPStub? {
|
public func stub(url: URL) -> HTTPStub? {
|
||||||
(endpoint as? Stubbing)?.stub(url: url)
|
(endpoint as? Stubbing)?.stub(url: url)
|
||||||
}
|
}
|
||||||
|
|
||||||
func data(url: URL) -> Data? {
|
public func data(url: URL) -> Data? {
|
||||||
(endpoint as? Stubbing)?.data(url: url)
|
(endpoint as? Stubbing)?.data(url: url)
|
||||||
}
|
}
|
||||||
|
|
||||||
func dataString(url: URL) -> String? {
|
public func dataString(url: URL) -> String? {
|
||||||
(endpoint as? Stubbing)?.dataString(url: url)
|
(endpoint as? Stubbing)?.dataString(url: url)
|
||||||
}
|
}
|
||||||
|
|
||||||
func statusCode(url: URL) -> Int? {
|
public func statusCode(url: URL) -> Int? {
|
||||||
(endpoint as? Stubbing)?.statusCode(url: url)
|
(endpoint as? Stubbing)?.statusCode(url: url)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,9 +2,10 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import Mastodon
|
import Mastodon
|
||||||
|
import Stubbing
|
||||||
|
|
||||||
extension PreferencesEndpoint: Stubbing {
|
extension PreferencesEndpoint: Stubbing {
|
||||||
func dataString(url: URL) -> String? {
|
public func dataString(url: URL) -> String? {
|
||||||
switch self {
|
switch self {
|
||||||
case .preferences:
|
case .preferences:
|
||||||
return """
|
return """
|
|
@ -1,10 +1,3 @@
|
||||||
// Copyright © 2020 Metabolist. All rights reserved.
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import Mastodon
|
|
||||||
|
|
||||||
// swiftlint:disable line_length
|
|
||||||
let officialAccountJSON = #"""
|
|
||||||
{
|
{
|
||||||
"id": "13179",
|
"id": "13179",
|
||||||
"username": "Mastodon",
|
"username": "Mastodon",
|
||||||
|
@ -39,13 +32,3 @@ let officialAccountJSON = #"""
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
"""#
|
|
||||||
|
|
||||||
extension AccountEndpoint: Stubbing {
|
|
||||||
func dataString(url: URL) -> String? {
|
|
||||||
switch self {
|
|
||||||
case .verifyCredentials: return officialAccountJSON
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// swiftlint:enable line_length
|
|
|
@ -1,10 +1,3 @@
|
||||||
// Copyright © 2020 Metabolist. All rights reserved.
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import Mastodon
|
|
||||||
|
|
||||||
// swiftlint:disable line_length
|
|
||||||
let officialInstanceJSON = #"""
|
|
||||||
{
|
{
|
||||||
"uri": "mastodon.social",
|
"uri": "mastodon.social",
|
||||||
"title": "Mastodon",
|
"title": "Mastodon",
|
||||||
|
@ -62,14 +55,3 @@ let officialInstanceJSON = #"""
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"""#
|
|
||||||
|
|
||||||
extension InstanceEndpoint: Stubbing {
|
|
||||||
|
|
||||||
func dataString(url: URL) -> String? {
|
|
||||||
switch self {
|
|
||||||
case .instance: return officialInstanceJSON
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// swiftlint:enable line_length
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
// Copyright © 2020 Metabolist. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Mastodon
|
||||||
|
import Stubbing
|
||||||
|
|
||||||
|
extension TimelinesEndpoint: Stubbing {
|
||||||
|
public func data(url: URL) -> Data? {
|
||||||
|
try? Data(contentsOf: Bundle.module.url(forResource: "timeline", withExtension: "json")!)
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,20 +12,13 @@
|
||||||
D01F41D924F880C400D55A2D /* TouchFallthroughTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F41D624F880C400D55A2D /* TouchFallthroughTextView.swift */; };
|
D01F41D924F880C400D55A2D /* TouchFallthroughTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F41D624F880C400D55A2D /* TouchFallthroughTextView.swift */; };
|
||||||
D01F41DF24F8868800D55A2D /* AttachmentViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F41DE24F8868800D55A2D /* AttachmentViewModel.swift */; };
|
D01F41DF24F8868800D55A2D /* AttachmentViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F41DE24F8868800D55A2D /* AttachmentViewModel.swift */; };
|
||||||
D01F41E424F8889700D55A2D /* AttachmentsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F41E224F8889700D55A2D /* AttachmentsView.swift */; };
|
D01F41E424F8889700D55A2D /* AttachmentsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F41E224F8889700D55A2D /* AttachmentsView.swift */; };
|
||||||
D03658D124EDD80900AC17EC /* ContextEndpoint+Stubbing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03658D024EDD80900AC17EC /* ContextEndpoint+Stubbing.swift */; };
|
|
||||||
D04FD73924D4A7B4007D572D /* AccountEndpoint+Stubbing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04FD73824D4A7B4007D572D /* AccountEndpoint+Stubbing.swift */; };
|
|
||||||
D04FD73C24D4A83A007D572D /* InstanceEndpoint+Stubbing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04FD73B24D4A83A007D572D /* InstanceEndpoint+Stubbing.swift */; };
|
|
||||||
D04FD74224D4AA34007D572D /* DevelopmentModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04FD74124D4AA34007D572D /* DevelopmentModels.swift */; };
|
D04FD74224D4AA34007D572D /* DevelopmentModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04FD74124D4AA34007D572D /* DevelopmentModels.swift */; };
|
||||||
D052BBC724D749C800A80A7A /* RootViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D052BBC624D749C800A80A7A /* RootViewModelTests.swift */; };
|
D052BBC724D749C800A80A7A /* RootViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D052BBC624D749C800A80A7A /* RootViewModelTests.swift */; };
|
||||||
D052BBCA24D74C9200A80A7A /* MockUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = D052BBC824D74B6400A80A7A /* MockUserDefaults.swift */; };
|
|
||||||
D05494FA24EA4E5E008B00A5 /* TimelinesEndpoint+Stubbing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05494F924EA4E5E008B00A5 /* TimelinesEndpoint+Stubbing.swift */; };
|
|
||||||
D054950124EA4FFE008B00A5 /* DevelopmentAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D054950024EA4FFE008B00A5 /* DevelopmentAssets.xcassets */; };
|
|
||||||
D065F53924D37E5100741304 /* CombineExpectations in Frameworks */ = {isa = PBXBuildFile; productRef = D065F53824D37E5100741304 /* CombineExpectations */; };
|
D065F53924D37E5100741304 /* CombineExpectations in Frameworks */ = {isa = PBXBuildFile; productRef = D065F53824D37E5100741304 /* CombineExpectations */; };
|
||||||
D0666A4924C6C1A300F3F04B /* GRDB in Frameworks */ = {isa = PBXBuildFile; productRef = D0666A4824C6C1A300F3F04B /* GRDB */; };
|
|
||||||
D06B492324D4611300642749 /* KingfisherSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = D06B492224D4611300642749 /* KingfisherSwiftUI */; };
|
D06B492324D4611300642749 /* KingfisherSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = D06B492224D4611300642749 /* KingfisherSwiftUI */; };
|
||||||
D074577724D29006004758DB /* MockWebAuthSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D074577624D29006004758DB /* MockWebAuthSession.swift */; };
|
D075C28524FCD41D00D35112 /* Services in Frameworks */ = {isa = PBXBuildFile; productRef = D075C28424FCD41D00D35112 /* Services */; };
|
||||||
D074577A24D29366004758DB /* URLSessionConfiguration+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D074577924D29366004758DB /* URLSessionConfiguration+Extensions.swift */; };
|
D075C28724FCD92400D35112 /* Services in Frameworks */ = {isa = PBXBuildFile; productRef = D075C28624FCD92400D35112 /* Services */; };
|
||||||
D0A652AD24DE3EB6002EA33F /* PreferencesEndpoint+Stubbing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A652AC24DE3EB6002EA33F /* PreferencesEndpoint+Stubbing.swift */; };
|
D0ADCBF124FD05510062ACCE /* ServiceMocks in Frameworks */ = {isa = PBXBuildFile; productRef = D0ADCBF024FD05510062ACCE /* ServiceMocks */; };
|
||||||
D0BEB1F324F8EE8C001B0F04 /* AttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1F224F8EE8C001B0F04 /* AttachmentView.swift */; };
|
D0BEB1F324F8EE8C001B0F04 /* AttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1F224F8EE8C001B0F04 /* AttachmentView.swift */; };
|
||||||
D0BEB1F724F9A84B001B0F04 /* LoadingTableFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1F624F9A84B001B0F04 /* LoadingTableFooterView.swift */; };
|
D0BEB1F724F9A84B001B0F04 /* LoadingTableFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1F624F9A84B001B0F04 /* LoadingTableFooterView.swift */; };
|
||||||
D0BEB1FD24F9E4E5001B0F04 /* ListsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1FC24F9E4E5001B0F04 /* ListsViewModel.swift */; };
|
D0BEB1FD24F9E4E5001B0F04 /* ListsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1FC24F9E4E5001B0F04 /* ListsViewModel.swift */; };
|
||||||
|
@ -45,9 +38,6 @@
|
||||||
D0C7D4A224F7616A001EBDBB /* NotificationTypesPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D42D24F76169001EBDBB /* NotificationTypesPreferencesView.swift */; };
|
D0C7D4A224F7616A001EBDBB /* NotificationTypesPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D42D24F76169001EBDBB /* NotificationTypesPreferencesView.swift */; };
|
||||||
D0C7D4A324F7616A001EBDBB /* TabNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D42E24F76169001EBDBB /* TabNavigationView.swift */; };
|
D0C7D4A324F7616A001EBDBB /* TabNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D42E24F76169001EBDBB /* TabNavigationView.swift */; };
|
||||||
D0C7D4A524F7616A001EBDBB /* StatusListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D43124F76169001EBDBB /* StatusListViewController.swift */; };
|
D0C7D4A524F7616A001EBDBB /* StatusListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D43124F76169001EBDBB /* StatusListViewController.swift */; };
|
||||||
D0C7D4AB24F7616A001EBDBB /* Identity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D43B24F76169001EBDBB /* Identity.swift */; };
|
|
||||||
D0C7D4B724F7616A001EBDBB /* TransientStatusCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D44724F76169001EBDBB /* TransientStatusCollection.swift */; };
|
|
||||||
D0C7D4BF24F7616A001EBDBB /* AppEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D44F24F76169001EBDBB /* AppEnvironment.swift */; };
|
|
||||||
D0C7D4C024F7616A001EBDBB /* AlertItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D45024F76169001EBDBB /* AlertItem.swift */; };
|
D0C7D4C024F7616A001EBDBB /* AlertItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D45024F76169001EBDBB /* AlertItem.swift */; };
|
||||||
D0C7D4C224F7616A001EBDBB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D0C7D45224F76169001EBDBB /* Assets.xcassets */; };
|
D0C7D4C224F7616A001EBDBB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D0C7D45224F76169001EBDBB /* Assets.xcassets */; };
|
||||||
D0C7D4C324F7616A001EBDBB /* MetatextApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D45424F76169001EBDBB /* MetatextApp.swift */; };
|
D0C7D4C324F7616A001EBDBB /* MetatextApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D45424F76169001EBDBB /* MetatextApp.swift */; };
|
||||||
|
@ -64,10 +54,6 @@
|
||||||
D0C7D4CE24F7616A001EBDBB /* PreferencesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D46124F76169001EBDBB /* PreferencesViewModel.swift */; };
|
D0C7D4CE24F7616A001EBDBB /* PreferencesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D46124F76169001EBDBB /* PreferencesViewModel.swift */; };
|
||||||
D0C7D4CF24F7616A001EBDBB /* StatusViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D46224F76169001EBDBB /* StatusViewModel.swift */; };
|
D0C7D4CF24F7616A001EBDBB /* StatusViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D46224F76169001EBDBB /* StatusViewModel.swift */; };
|
||||||
D0C7D4D024F7616A001EBDBB /* StatusListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D46324F76169001EBDBB /* StatusListViewModel.swift */; };
|
D0C7D4D024F7616A001EBDBB /* StatusListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D46324F76169001EBDBB /* StatusListViewModel.swift */; };
|
||||||
D0C7D4D124F7616A001EBDBB /* IdentityDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D46524F76169001EBDBB /* IdentityDatabase.swift */; };
|
|
||||||
D0C7D4D224F7616A001EBDBB /* ContentDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D46624F76169001EBDBB /* ContentDatabase.swift */; };
|
|
||||||
D0C7D4D324F7616A001EBDBB /* DatabaseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D46724F76169001EBDBB /* DatabaseError.swift */; };
|
|
||||||
D0C7D4D424F7616A001EBDBB /* NSError+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D46924F76169001EBDBB /* NSError+Extensions.swift */; };
|
|
||||||
D0C7D4D524F7616A001EBDBB /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D46A24F76169001EBDBB /* String+Extensions.swift */; };
|
D0C7D4D524F7616A001EBDBB /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D46A24F76169001EBDBB /* String+Extensions.swift */; };
|
||||||
D0C7D4D624F7616A001EBDBB /* NSMutableAttributedString+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D46B24F76169001EBDBB /* NSMutableAttributedString+Extensions.swift */; };
|
D0C7D4D624F7616A001EBDBB /* NSMutableAttributedString+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D46B24F76169001EBDBB /* NSMutableAttributedString+Extensions.swift */; };
|
||||||
D0C7D4D724F7616A001EBDBB /* UIColor+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D46C24F76169001EBDBB /* UIColor+Extensions.swift */; };
|
D0C7D4D724F7616A001EBDBB /* UIColor+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D46C24F76169001EBDBB /* UIColor+Extensions.swift */; };
|
||||||
|
@ -76,32 +62,8 @@
|
||||||
D0C7D4DA24F7616A001EBDBB /* View+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D46F24F76169001EBDBB /* View+Extensions.swift */; };
|
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 */; };
|
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 */; };
|
D0C7D4DC24F7616A001EBDBB /* Data+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D47124F76169001EBDBB /* Data+Extensions.swift */; };
|
||||||
D0C7D4E024F7616A001EBDBB /* WebAuthSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D47624F76169001EBDBB /* WebAuthSession.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 */; };
|
|
||||||
D0C7D4F424F7616A001EBDBB /* StatusListService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D48E24F7616A001EBDBB /* StatusListService.swift */; };
|
|
||||||
D0C7D4F524F7616A001EBDBB /* AuthenticationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D48F24F7616A001EBDBB /* AuthenticationService.swift */; };
|
|
||||||
D0C7D4F624F7616A001EBDBB /* KeychainService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D49024F7616A001EBDBB /* KeychainService.swift */; };
|
|
||||||
D0C7D4F724F7616A001EBDBB /* StatusService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D49124F7616A001EBDBB /* StatusService.swift */; };
|
|
||||||
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 */; };
|
|
||||||
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 */; };
|
|
||||||
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 */; };
|
|
||||||
D0DC175224D008E300A75C65 /* MastodonTarget+Stubbing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC175124D008E300A75C65 /* MastodonTarget+Stubbing.swift */; };
|
|
||||||
D0DC175524D00F0A00A75C65 /* AccessTokenEndpoint+Stubbing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC175424D00F0A00A75C65 /* AccessTokenEndpoint+Stubbing.swift */; };
|
|
||||||
D0DC175824D0130800A75C65 /* HTTPStubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC175724D0130800A75C65 /* HTTPStubs.swift */; };
|
|
||||||
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 */; };
|
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, ); }; };
|
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 */; };
|
|
||||||
D0ED1B6E24CE100C00B4899C /* AddIdentityViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ED1B6D24CE100C00B4899C /* AddIdentityViewModelTests.swift */; };
|
D0ED1B6E24CE100C00B4899C /* AddIdentityViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ED1B6D24CE100C00B4899C /* AddIdentityViewModelTests.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
@ -142,20 +104,12 @@
|
||||||
D01F41D624F880C400D55A2D /* TouchFallthroughTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TouchFallthroughTextView.swift; sourceTree = "<group>"; };
|
D01F41D624F880C400D55A2D /* TouchFallthroughTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TouchFallthroughTextView.swift; sourceTree = "<group>"; };
|
||||||
D01F41DE24F8868800D55A2D /* AttachmentViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentViewModel.swift; sourceTree = "<group>"; };
|
D01F41DE24F8868800D55A2D /* AttachmentViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentViewModel.swift; sourceTree = "<group>"; };
|
||||||
D01F41E224F8889700D55A2D /* AttachmentsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttachmentsView.swift; sourceTree = "<group>"; };
|
D01F41E224F8889700D55A2D /* AttachmentsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttachmentsView.swift; sourceTree = "<group>"; };
|
||||||
D03658D024EDD80900AC17EC /* ContextEndpoint+Stubbing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContextEndpoint+Stubbing.swift"; sourceTree = "<group>"; };
|
|
||||||
D047FA8C24C3E21200AF17C5 /* Metatext.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Metatext.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
D047FA8C24C3E21200AF17C5 /* Metatext.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Metatext.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
D04FD73824D4A7B4007D572D /* AccountEndpoint+Stubbing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AccountEndpoint+Stubbing.swift"; sourceTree = "<group>"; };
|
|
||||||
D04FD73B24D4A83A007D572D /* InstanceEndpoint+Stubbing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "InstanceEndpoint+Stubbing.swift"; sourceTree = "<group>"; };
|
|
||||||
D04FD74124D4AA34007D572D /* DevelopmentModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DevelopmentModels.swift; sourceTree = "<group>"; };
|
D04FD74124D4AA34007D572D /* DevelopmentModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DevelopmentModels.swift; sourceTree = "<group>"; };
|
||||||
D052BBC624D749C800A80A7A /* RootViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootViewModelTests.swift; sourceTree = "<group>"; };
|
D052BBC624D749C800A80A7A /* RootViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootViewModelTests.swift; sourceTree = "<group>"; };
|
||||||
D052BBC824D74B6400A80A7A /* MockUserDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockUserDefaults.swift; sourceTree = "<group>"; };
|
|
||||||
D05494F924EA4E5E008B00A5 /* TimelinesEndpoint+Stubbing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TimelinesEndpoint+Stubbing.swift"; sourceTree = "<group>"; };
|
|
||||||
D054950024EA4FFE008B00A5 /* DevelopmentAssets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = DevelopmentAssets.xcassets; sourceTree = "<group>"; };
|
|
||||||
D0666A2124C677B400F3F04B /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
D0666A2124C677B400F3F04B /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
D0666A2524C677B400F3F04B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
D0666A2524C677B400F3F04B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
D074577624D29006004758DB /* MockWebAuthSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockWebAuthSession.swift; sourceTree = "<group>"; };
|
D075C28324FCD27300D35112 /* Services */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Services; sourceTree = "<group>"; };
|
||||||
D074577924D29366004758DB /* URLSessionConfiguration+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLSessionConfiguration+Extensions.swift"; sourceTree = "<group>"; };
|
|
||||||
D0A652AC24DE3EB6002EA33F /* PreferencesEndpoint+Stubbing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreferencesEndpoint+Stubbing.swift"; sourceTree = "<group>"; };
|
|
||||||
D0BEB1F224F8EE8C001B0F04 /* AttachmentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentView.swift; sourceTree = "<group>"; };
|
D0BEB1F224F8EE8C001B0F04 /* AttachmentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentView.swift; sourceTree = "<group>"; };
|
||||||
D0BEB1F624F9A84B001B0F04 /* LoadingTableFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingTableFooterView.swift; sourceTree = "<group>"; };
|
D0BEB1F624F9A84B001B0F04 /* LoadingTableFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingTableFooterView.swift; sourceTree = "<group>"; };
|
||||||
D0BEB1FC24F9E4E5001B0F04 /* ListsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListsViewModel.swift; sourceTree = "<group>"; };
|
D0BEB1FC24F9E4E5001B0F04 /* ListsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListsViewModel.swift; sourceTree = "<group>"; };
|
||||||
|
@ -178,9 +132,6 @@
|
||||||
D0C7D42D24F76169001EBDBB /* NotificationTypesPreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationTypesPreferencesView.swift; sourceTree = "<group>"; };
|
D0C7D42D24F76169001EBDBB /* NotificationTypesPreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationTypesPreferencesView.swift; sourceTree = "<group>"; };
|
||||||
D0C7D42E24F76169001EBDBB /* TabNavigationView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabNavigationView.swift; sourceTree = "<group>"; };
|
D0C7D42E24F76169001EBDBB /* TabNavigationView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabNavigationView.swift; sourceTree = "<group>"; };
|
||||||
D0C7D43124F76169001EBDBB /* StatusListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusListViewController.swift; sourceTree = "<group>"; };
|
D0C7D43124F76169001EBDBB /* StatusListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusListViewController.swift; sourceTree = "<group>"; };
|
||||||
D0C7D43B24F76169001EBDBB /* Identity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Identity.swift; sourceTree = "<group>"; };
|
|
||||||
D0C7D44724F76169001EBDBB /* TransientStatusCollection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransientStatusCollection.swift; sourceTree = "<group>"; };
|
|
||||||
D0C7D44F24F76169001EBDBB /* AppEnvironment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppEnvironment.swift; sourceTree = "<group>"; };
|
|
||||||
D0C7D45024F76169001EBDBB /* AlertItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertItem.swift; sourceTree = "<group>"; };
|
D0C7D45024F76169001EBDBB /* AlertItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertItem.swift; sourceTree = "<group>"; };
|
||||||
D0C7D45224F76169001EBDBB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
D0C7D45224F76169001EBDBB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
D0C7D45424F76169001EBDBB /* MetatextApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MetatextApp.swift; sourceTree = "<group>"; };
|
D0C7D45424F76169001EBDBB /* MetatextApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MetatextApp.swift; sourceTree = "<group>"; };
|
||||||
|
@ -197,10 +148,6 @@
|
||||||
D0C7D46124F76169001EBDBB /* PreferencesViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesViewModel.swift; sourceTree = "<group>"; };
|
D0C7D46124F76169001EBDBB /* PreferencesViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesViewModel.swift; sourceTree = "<group>"; };
|
||||||
D0C7D46224F76169001EBDBB /* StatusViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusViewModel.swift; sourceTree = "<group>"; };
|
D0C7D46224F76169001EBDBB /* StatusViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusViewModel.swift; sourceTree = "<group>"; };
|
||||||
D0C7D46324F76169001EBDBB /* StatusListViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusListViewModel.swift; sourceTree = "<group>"; };
|
D0C7D46324F76169001EBDBB /* StatusListViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusListViewModel.swift; sourceTree = "<group>"; };
|
||||||
D0C7D46524F76169001EBDBB /* IdentityDatabase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IdentityDatabase.swift; sourceTree = "<group>"; };
|
|
||||||
D0C7D46624F76169001EBDBB /* ContentDatabase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentDatabase.swift; sourceTree = "<group>"; };
|
|
||||||
D0C7D46724F76169001EBDBB /* DatabaseError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseError.swift; sourceTree = "<group>"; };
|
|
||||||
D0C7D46924F76169001EBDBB /* NSError+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSError+Extensions.swift"; sourceTree = "<group>"; };
|
|
||||||
D0C7D46A24F76169001EBDBB /* String+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Extensions.swift"; sourceTree = "<group>"; };
|
D0C7D46A24F76169001EBDBB /* String+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Extensions.swift"; sourceTree = "<group>"; };
|
||||||
D0C7D46B24F76169001EBDBB /* NSMutableAttributedString+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSMutableAttributedString+Extensions.swift"; sourceTree = "<group>"; };
|
D0C7D46B24F76169001EBDBB /* NSMutableAttributedString+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSMutableAttributedString+Extensions.swift"; sourceTree = "<group>"; };
|
||||||
D0C7D46C24F76169001EBDBB /* UIColor+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Extensions.swift"; sourceTree = "<group>"; };
|
D0C7D46C24F76169001EBDBB /* UIColor+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Extensions.swift"; sourceTree = "<group>"; };
|
||||||
|
@ -209,30 +156,11 @@
|
||||||
D0C7D46F24F76169001EBDBB /* View+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View+Extensions.swift"; sourceTree = "<group>"; };
|
D0C7D46F24F76169001EBDBB /* View+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View+Extensions.swift"; sourceTree = "<group>"; };
|
||||||
D0C7D47024F76169001EBDBB /* Date+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Date+Extensions.swift"; sourceTree = "<group>"; };
|
D0C7D47024F76169001EBDBB /* Date+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Date+Extensions.swift"; sourceTree = "<group>"; };
|
||||||
D0C7D47124F76169001EBDBB /* Data+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Data+Extensions.swift"; sourceTree = "<group>"; };
|
D0C7D47124F76169001EBDBB /* Data+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Data+Extensions.swift"; sourceTree = "<group>"; };
|
||||||
D0C7D47624F76169001EBDBB /* WebAuthSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebAuthSession.swift; sourceTree = "<group>"; };
|
|
||||||
D0C7D48A24F76169001EBDBB /* IdentityService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IdentityService.swift; sourceTree = "<group>"; };
|
|
||||||
D0C7D48C24F76169001EBDBB /* TimelineService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimelineService.swift; sourceTree = "<group>"; };
|
|
||||||
D0C7D48D24F76169001EBDBB /* ContextService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContextService.swift; sourceTree = "<group>"; };
|
|
||||||
D0C7D48E24F7616A001EBDBB /* StatusListService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusListService.swift; sourceTree = "<group>"; };
|
|
||||||
D0C7D48F24F7616A001EBDBB /* AuthenticationService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticationService.swift; sourceTree = "<group>"; };
|
|
||||||
D0C7D49024F7616A001EBDBB /* KeychainService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeychainService.swift; sourceTree = "<group>"; };
|
|
||||||
D0C7D49124F7616A001EBDBB /* StatusService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusService.swift; sourceTree = "<group>"; };
|
|
||||||
D0C7D49224F7616A001EBDBB /* SecretsService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsService.swift; sourceTree = "<group>"; };
|
|
||||||
D0C7D49324F7616A001EBDBB /* UserNotificationService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserNotificationService.swift; sourceTree = "<group>"; };
|
|
||||||
D0C7D49424F7616A001EBDBB /* AllIdentitiesService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AllIdentitiesService.swift; sourceTree = "<group>"; };
|
|
||||||
D0DC174524CFEC2000A75C65 /* StubbingURLProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubbingURLProtocol.swift; sourceTree = "<group>"; };
|
|
||||||
D0DC174924CFF15F00A75C65 /* AppAuthorizationEndpoint+Stubbing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppAuthorizationEndpoint+Stubbing.swift"; sourceTree = "<group>"; };
|
|
||||||
D0DC174C24CFF1F100A75C65 /* Stubbing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stubbing.swift; sourceTree = "<group>"; };
|
|
||||||
D0DC175124D008E300A75C65 /* MastodonTarget+Stubbing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MastodonTarget+Stubbing.swift"; sourceTree = "<group>"; };
|
|
||||||
D0DC175424D00F0A00A75C65 /* AccessTokenEndpoint+Stubbing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AccessTokenEndpoint+Stubbing.swift"; sourceTree = "<group>"; };
|
|
||||||
D0DC175724D0130800A75C65 /* HTTPStubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPStubs.swift; sourceTree = "<group>"; };
|
|
||||||
D0DC177624D0CF2600A75C65 /* MockKeychainService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockKeychainService.swift; sourceTree = "<group>"; };
|
|
||||||
D0E0F1E424FC49FC002C04BF /* Mastodon */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Mastodon; sourceTree = "<group>"; };
|
D0E0F1E424FC49FC002C04BF /* Mastodon */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Mastodon; sourceTree = "<group>"; };
|
||||||
D0E5361924E3EB4D00FB1CE1 /* Notification Service Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Notification Service Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
|
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 = "<group>"; };
|
D0E5361B24E3EB4D00FB1CE1 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
|
||||||
D0E5361D24E3EB4D00FB1CE1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
D0E5361D24E3EB4D00FB1CE1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
D0E5362824E4A06B00FB1CE1 /* Notification Service Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Notification Service Extension.entitlements"; sourceTree = "<group>"; };
|
D0E5362824E4A06B00FB1CE1 /* Notification Service Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Notification Service Extension.entitlements"; sourceTree = "<group>"; };
|
||||||
D0EC8DD324DFE38900A08489 /* AuthenticationServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationServiceTests.swift; sourceTree = "<group>"; };
|
|
||||||
D0ED1B6D24CE100C00B4899C /* AddIdentityViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddIdentityViewModelTests.swift; sourceTree = "<group>"; };
|
D0ED1B6D24CE100C00B4899C /* AddIdentityViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddIdentityViewModelTests.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
@ -241,9 +169,9 @@
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
D075C28524FCD41D00D35112 /* Services in Frameworks */,
|
||||||
|
D0ADCBF124FD05510062ACCE /* ServiceMocks in Frameworks */,
|
||||||
D06B492324D4611300642749 /* KingfisherSwiftUI in Frameworks */,
|
D06B492324D4611300642749 /* KingfisherSwiftUI in Frameworks */,
|
||||||
D0E0F1E624FC4B76002C04BF /* Mastodon in Frameworks */,
|
|
||||||
D0666A4924C6C1A300F3F04B /* GRDB in Frameworks */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -259,7 +187,7 @@
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
D0E0F1E824FC5A61002C04BF /* Mastodon in Frameworks */,
|
D075C28724FCD92400D35112 /* Services in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -289,7 +217,6 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
D0C7D45224F76169001EBDBB /* Assets.xcassets */,
|
D0C7D45224F76169001EBDBB /* Assets.xcassets */,
|
||||||
D0C7D46424F76169001EBDBB /* Databases */,
|
|
||||||
D0ED1BB224CE3A1600B4899C /* Development Assets */,
|
D0ED1BB224CE3A1600B4899C /* Development Assets */,
|
||||||
D0C7D46824F76169001EBDBB /* Extensions */,
|
D0C7D46824F76169001EBDBB /* Extensions */,
|
||||||
D0666A7924C7745A00F3F04B /* Frameworks */,
|
D0666A7924C7745A00F3F04B /* Frameworks */,
|
||||||
|
@ -297,10 +224,9 @@
|
||||||
D0C7D45624F76169001EBDBB /* Localizations */,
|
D0C7D45624F76169001EBDBB /* Localizations */,
|
||||||
D0E0F1E424FC49FC002C04BF /* Mastodon */,
|
D0E0F1E424FC49FC002C04BF /* Mastodon */,
|
||||||
D0C7D43824F76169001EBDBB /* Model */,
|
D0C7D43824F76169001EBDBB /* Model */,
|
||||||
D0C7D47324F76169001EBDBB /* Networking */,
|
|
||||||
D0E5361A24E3EB4D00FB1CE1 /* Notification Service Extension */,
|
D0E5361A24E3EB4D00FB1CE1 /* Notification Service Extension */,
|
||||||
D047FA8D24C3E21200AF17C5 /* Products */,
|
D047FA8D24C3E21200AF17C5 /* Products */,
|
||||||
D0C7D48924F76169001EBDBB /* Services */,
|
D075C28324FCD27300D35112 /* Services */,
|
||||||
D0C7D41D24F76169001EBDBB /* Supporting Files */,
|
D0C7D41D24F76169001EBDBB /* Supporting Files */,
|
||||||
D0C7D45324F76169001EBDBB /* System */,
|
D0C7D45324F76169001EBDBB /* System */,
|
||||||
D0666A2224C677B400F3F04B /* Tests */,
|
D0666A2224C677B400F3F04B /* Tests */,
|
||||||
|
@ -324,7 +250,6 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
D0666A2524C677B400F3F04B /* Info.plist */,
|
D0666A2524C677B400F3F04B /* Info.plist */,
|
||||||
D0EC8DD024DFE34F00A08489 /* Services */,
|
|
||||||
D0ED1B6C24CE0EED00B4899C /* View Models */,
|
D0ED1B6C24CE0EED00B4899C /* View Models */,
|
||||||
);
|
);
|
||||||
path = Tests;
|
path = Tests;
|
||||||
|
@ -381,9 +306,6 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
D0C7D45024F76169001EBDBB /* AlertItem.swift */,
|
D0C7D45024F76169001EBDBB /* AlertItem.swift */,
|
||||||
D0C7D44F24F76169001EBDBB /* AppEnvironment.swift */,
|
|
||||||
D0C7D43B24F76169001EBDBB /* Identity.swift */,
|
|
||||||
D0C7D44724F76169001EBDBB /* TransientStatusCollection.swift */,
|
|
||||||
);
|
);
|
||||||
path = Model;
|
path = Model;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -427,23 +349,12 @@
|
||||||
path = "View Models";
|
path = "View Models";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
D0C7D46424F76169001EBDBB /* Databases */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
D0C7D46624F76169001EBDBB /* ContentDatabase.swift */,
|
|
||||||
D0C7D46724F76169001EBDBB /* DatabaseError.swift */,
|
|
||||||
D0C7D46524F76169001EBDBB /* IdentityDatabase.swift */,
|
|
||||||
);
|
|
||||||
path = Databases;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
D0C7D46824F76169001EBDBB /* Extensions */ = {
|
D0C7D46824F76169001EBDBB /* Extensions */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
D0C7D47124F76169001EBDBB /* Data+Extensions.swift */,
|
D0C7D47124F76169001EBDBB /* Data+Extensions.swift */,
|
||||||
D0C7D47024F76169001EBDBB /* Date+Extensions.swift */,
|
D0C7D47024F76169001EBDBB /* Date+Extensions.swift */,
|
||||||
D0C7D46E24F76169001EBDBB /* KingfisherOptionsInfo+Extensions.swift */,
|
D0C7D46E24F76169001EBDBB /* KingfisherOptionsInfo+Extensions.swift */,
|
||||||
D0C7D46924F76169001EBDBB /* NSError+Extensions.swift */,
|
|
||||||
D0C7D46B24F76169001EBDBB /* NSMutableAttributedString+Extensions.swift */,
|
D0C7D46B24F76169001EBDBB /* NSMutableAttributedString+Extensions.swift */,
|
||||||
D0C7D46D24F76169001EBDBB /* Publisher+Extensions.swift */,
|
D0C7D46D24F76169001EBDBB /* Publisher+Extensions.swift */,
|
||||||
D0C7D46A24F76169001EBDBB /* String+Extensions.swift */,
|
D0C7D46A24F76169001EBDBB /* String+Extensions.swift */,
|
||||||
|
@ -453,54 +364,6 @@
|
||||||
path = Extensions;
|
path = Extensions;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
D0C7D47324F76169001EBDBB /* Networking */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
D0C7D47624F76169001EBDBB /* WebAuthSession.swift */,
|
|
||||||
);
|
|
||||||
path = Networking;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
D0C7D48924F76169001EBDBB /* Services */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
D0C7D49424F7616A001EBDBB /* AllIdentitiesService.swift */,
|
|
||||||
D0C7D48F24F7616A001EBDBB /* AuthenticationService.swift */,
|
|
||||||
D0C7D48A24F76169001EBDBB /* IdentityService.swift */,
|
|
||||||
D0C7D49024F7616A001EBDBB /* KeychainService.swift */,
|
|
||||||
D0C7D49224F7616A001EBDBB /* SecretsService.swift */,
|
|
||||||
D0C7D48B24F76169001EBDBB /* Status List Services */,
|
|
||||||
D0C7D49124F7616A001EBDBB /* StatusService.swift */,
|
|
||||||
D0C7D49324F7616A001EBDBB /* UserNotificationService.swift */,
|
|
||||||
);
|
|
||||||
path = Services;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
D0C7D48B24F76169001EBDBB /* Status List Services */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
D0C7D48D24F76169001EBDBB /* ContextService.swift */,
|
|
||||||
D0C7D48E24F7616A001EBDBB /* StatusListService.swift */,
|
|
||||||
D0C7D48C24F76169001EBDBB /* TimelineService.swift */,
|
|
||||||
);
|
|
||||||
path = "Status List Services";
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
D0DC174824CFF13700A75C65 /* Mastodon API Stubs */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
D0DC175424D00F0A00A75C65 /* AccessTokenEndpoint+Stubbing.swift */,
|
|
||||||
D04FD73824D4A7B4007D572D /* AccountEndpoint+Stubbing.swift */,
|
|
||||||
D0DC174924CFF15F00A75C65 /* AppAuthorizationEndpoint+Stubbing.swift */,
|
|
||||||
D03658D024EDD80900AC17EC /* ContextEndpoint+Stubbing.swift */,
|
|
||||||
D04FD73B24D4A83A007D572D /* InstanceEndpoint+Stubbing.swift */,
|
|
||||||
D0DC175124D008E300A75C65 /* MastodonTarget+Stubbing.swift */,
|
|
||||||
D0A652AC24DE3EB6002EA33F /* PreferencesEndpoint+Stubbing.swift */,
|
|
||||||
D05494F924EA4E5E008B00A5 /* TimelinesEndpoint+Stubbing.swift */,
|
|
||||||
);
|
|
||||||
path = "Mastodon API Stubs";
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
D0E5361A24E3EB4D00FB1CE1 /* Notification Service Extension */ = {
|
D0E5361A24E3EB4D00FB1CE1 /* Notification Service Extension */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -511,14 +374,6 @@
|
||||||
path = "Notification Service Extension";
|
path = "Notification Service Extension";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
D0EC8DD024DFE34F00A08489 /* Services */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
D0EC8DD324DFE38900A08489 /* AuthenticationServiceTests.swift */,
|
|
||||||
);
|
|
||||||
path = Services;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
D0ED1B6C24CE0EED00B4899C /* View Models */ = {
|
D0ED1B6C24CE0EED00B4899C /* View Models */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -531,16 +386,7 @@
|
||||||
D0ED1BB224CE3A1600B4899C /* Development Assets */ = {
|
D0ED1BB224CE3A1600B4899C /* Development Assets */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
D054950024EA4FFE008B00A5 /* DevelopmentAssets.xcassets */,
|
|
||||||
D04FD74124D4AA34007D572D /* DevelopmentModels.swift */,
|
D04FD74124D4AA34007D572D /* DevelopmentModels.swift */,
|
||||||
D0DC175724D0130800A75C65 /* HTTPStubs.swift */,
|
|
||||||
D0DC174824CFF13700A75C65 /* Mastodon API Stubs */,
|
|
||||||
D0DC177624D0CF2600A75C65 /* MockKeychainService.swift */,
|
|
||||||
D052BBC824D74B6400A80A7A /* MockUserDefaults.swift */,
|
|
||||||
D074577624D29006004758DB /* MockWebAuthSession.swift */,
|
|
||||||
D0DC174C24CFF1F100A75C65 /* Stubbing.swift */,
|
|
||||||
D0DC174524CFEC2000A75C65 /* StubbingURLProtocol.swift */,
|
|
||||||
D074577924D29366004758DB /* URLSessionConfiguration+Extensions.swift */,
|
|
||||||
);
|
);
|
||||||
path = "Development Assets";
|
path = "Development Assets";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -565,9 +411,9 @@
|
||||||
);
|
);
|
||||||
name = Metatext;
|
name = Metatext;
|
||||||
packageProductDependencies = (
|
packageProductDependencies = (
|
||||||
D0666A4824C6C1A300F3F04B /* GRDB */,
|
|
||||||
D06B492224D4611300642749 /* KingfisherSwiftUI */,
|
D06B492224D4611300642749 /* KingfisherSwiftUI */,
|
||||||
D0E0F1E524FC4B76002C04BF /* Mastodon */,
|
D075C28424FCD41D00D35112 /* Services */,
|
||||||
|
D0ADCBF024FD05510062ACCE /* ServiceMocks */,
|
||||||
);
|
);
|
||||||
productName = "Metatext (iOS)";
|
productName = "Metatext (iOS)";
|
||||||
productReference = D047FA8C24C3E21200AF17C5 /* Metatext.app */;
|
productReference = D047FA8C24C3E21200AF17C5 /* Metatext.app */;
|
||||||
|
@ -608,7 +454,7 @@
|
||||||
);
|
);
|
||||||
name = "Notification Service Extension";
|
name = "Notification Service Extension";
|
||||||
packageProductDependencies = (
|
packageProductDependencies = (
|
||||||
D0E0F1E724FC5A61002C04BF /* Mastodon */,
|
D075C28624FCD92400D35112 /* Services */,
|
||||||
);
|
);
|
||||||
productName = "Notification Service Extension";
|
productName = "Notification Service Extension";
|
||||||
productReference = D0E5361924E3EB4D00FB1CE1 /* Notification Service Extension.appex */;
|
productReference = D0E5361924E3EB4D00FB1CE1 /* Notification Service Extension.appex */;
|
||||||
|
@ -647,7 +493,6 @@
|
||||||
);
|
);
|
||||||
mainGroup = D047FA7F24C3E21000AF17C5;
|
mainGroup = D047FA7F24C3E21000AF17C5;
|
||||||
packageReferences = (
|
packageReferences = (
|
||||||
D0666A4724C6C1A300F3F04B /* XCRemoteSwiftPackageReference "GRDB" */,
|
|
||||||
D065F53724D37E5100741304 /* XCRemoteSwiftPackageReference "CombineExpectations" */,
|
D065F53724D37E5100741304 /* XCRemoteSwiftPackageReference "CombineExpectations" */,
|
||||||
D06B492124D4611300642749 /* XCRemoteSwiftPackageReference "Kingfisher" */,
|
D06B492124D4611300642749 /* XCRemoteSwiftPackageReference "Kingfisher" */,
|
||||||
);
|
);
|
||||||
|
@ -669,7 +514,6 @@
|
||||||
files = (
|
files = (
|
||||||
D0C7D4C524F7616A001EBDBB /* Localizable.strings in Resources */,
|
D0C7D4C524F7616A001EBDBB /* Localizable.strings in Resources */,
|
||||||
D01F41D724F880C400D55A2D /* StatusTableViewCell.xib in Resources */,
|
D01F41D724F880C400D55A2D /* StatusTableViewCell.xib in Resources */,
|
||||||
D054950124EA4FFE008B00A5 /* DevelopmentAssets.xcassets in Resources */,
|
|
||||||
D0C7D4C224F7616A001EBDBB /* Assets.xcassets in Resources */,
|
D0C7D4C224F7616A001EBDBB /* Assets.xcassets in Resources */,
|
||||||
D0C7D4C624F7616A001EBDBB /* Localizable.stringsdict in Resources */,
|
D0C7D4C624F7616A001EBDBB /* Localizable.stringsdict in Resources */,
|
||||||
);
|
);
|
||||||
|
@ -717,81 +561,48 @@
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
D0C7D4CA24F7616A001EBDBB /* NotificationTypesPreferencesViewModel.swift in Sources */,
|
D0C7D4CA24F7616A001EBDBB /* NotificationTypesPreferencesViewModel.swift in Sources */,
|
||||||
D0C7D4F424F7616A001EBDBB /* StatusListService.swift in Sources */,
|
|
||||||
D0C7D4B724F7616A001EBDBB /* TransientStatusCollection.swift in Sources */,
|
|
||||||
D01F41DF24F8868800D55A2D /* AttachmentViewModel.swift in Sources */,
|
D01F41DF24F8868800D55A2D /* AttachmentViewModel.swift in Sources */,
|
||||||
D0C7D4A324F7616A001EBDBB /* TabNavigationView.swift in Sources */,
|
D0C7D4A324F7616A001EBDBB /* TabNavigationView.swift in Sources */,
|
||||||
D0C7D49C24F7616A001EBDBB /* RootView.swift in Sources */,
|
D0C7D49C24F7616A001EBDBB /* RootView.swift in Sources */,
|
||||||
D0C7D4D224F7616A001EBDBB /* ContentDatabase.swift in Sources */,
|
|
||||||
D0C7D4F724F7616A001EBDBB /* StatusService.swift in Sources */,
|
|
||||||
D04FD73924D4A7B4007D572D /* AccountEndpoint+Stubbing.swift in Sources */,
|
|
||||||
D0BEB21324FA2C0A001B0F04 /* EditFilterViewModel.swift in Sources */,
|
D0BEB21324FA2C0A001B0F04 /* EditFilterViewModel.swift in Sources */,
|
||||||
D0C7D4FA24F7616A001EBDBB /* AllIdentitiesService.swift in Sources */,
|
|
||||||
D0C7D4CD24F7616A001EBDBB /* AddIdentityViewModel.swift in Sources */,
|
D0C7D4CD24F7616A001EBDBB /* AddIdentityViewModel.swift in Sources */,
|
||||||
D03658D124EDD80900AC17EC /* ContextEndpoint+Stubbing.swift in Sources */,
|
|
||||||
D0BEB1F324F8EE8C001B0F04 /* AttachmentView.swift in Sources */,
|
D0BEB1F324F8EE8C001B0F04 /* AttachmentView.swift in Sources */,
|
||||||
D0DC174A24CFF15F00A75C65 /* AppAuthorizationEndpoint+Stubbing.swift in Sources */,
|
|
||||||
D0C7D49A24F7616A001EBDBB /* StatusListView.swift in Sources */,
|
D0C7D49A24F7616A001EBDBB /* StatusListView.swift in Sources */,
|
||||||
D01F41D924F880C400D55A2D /* TouchFallthroughTextView.swift in Sources */,
|
D01F41D924F880C400D55A2D /* TouchFallthroughTextView.swift in Sources */,
|
||||||
D0C7D4A524F7616A001EBDBB /* StatusListViewController.swift in Sources */,
|
D0C7D4A524F7616A001EBDBB /* StatusListViewController.swift in Sources */,
|
||||||
D0C7D4CC24F7616A001EBDBB /* IdentitiesViewModel.swift in Sources */,
|
D0C7D4CC24F7616A001EBDBB /* IdentitiesViewModel.swift in Sources */,
|
||||||
D0C7D4E024F7616A001EBDBB /* WebAuthSession.swift in Sources */,
|
|
||||||
D0C7D4CB24F7616A001EBDBB /* RootViewModel.swift in Sources */,
|
D0C7D4CB24F7616A001EBDBB /* RootViewModel.swift in Sources */,
|
||||||
D0C7D4CE24F7616A001EBDBB /* PreferencesViewModel.swift in Sources */,
|
D0C7D4CE24F7616A001EBDBB /* PreferencesViewModel.swift in Sources */,
|
||||||
D0C7D4D124F7616A001EBDBB /* IdentityDatabase.swift in Sources */,
|
|
||||||
D0C7D4D624F7616A001EBDBB /* NSMutableAttributedString+Extensions.swift in Sources */,
|
D0C7D4D624F7616A001EBDBB /* NSMutableAttributedString+Extensions.swift in Sources */,
|
||||||
D05494FA24EA4E5E008B00A5 /* TimelinesEndpoint+Stubbing.swift in Sources */,
|
|
||||||
D0A652AD24DE3EB6002EA33F /* PreferencesEndpoint+Stubbing.swift in Sources */,
|
|
||||||
D0DC175524D00F0A00A75C65 /* AccessTokenEndpoint+Stubbing.swift in Sources */,
|
|
||||||
D0C7D4D324F7616A001EBDBB /* DatabaseError.swift in Sources */,
|
|
||||||
D0C7D4F224F7616A001EBDBB /* TimelineService.swift in Sources */,
|
|
||||||
D0C7D4BF24F7616A001EBDBB /* AppEnvironment.swift in Sources */,
|
|
||||||
D0C7D49D24F7616A001EBDBB /* PostingReadingPreferencesView.swift in Sources */,
|
D0C7D49D24F7616A001EBDBB /* PostingReadingPreferencesView.swift in Sources */,
|
||||||
D0C7D4D024F7616A001EBDBB /* StatusListViewModel.swift in Sources */,
|
D0C7D4D024F7616A001EBDBB /* StatusListViewModel.swift in Sources */,
|
||||||
D0C7D49E24F7616A001EBDBB /* SecondaryNavigationView.swift in Sources */,
|
D0C7D49E24F7616A001EBDBB /* SecondaryNavigationView.swift in Sources */,
|
||||||
D0C7D4D424F7616A001EBDBB /* NSError+Extensions.swift in Sources */,
|
|
||||||
D052BBCA24D74C9200A80A7A /* MockUserDefaults.swift in Sources */,
|
|
||||||
D0C7D4DB24F7616A001EBDBB /* Date+Extensions.swift in Sources */,
|
D0C7D4DB24F7616A001EBDBB /* Date+Extensions.swift in Sources */,
|
||||||
D0C7D4DA24F7616A001EBDBB /* View+Extensions.swift in Sources */,
|
D0C7D4DA24F7616A001EBDBB /* View+Extensions.swift in Sources */,
|
||||||
D0C7D4C824F7616A001EBDBB /* SecondaryNavigationViewModel.swift in Sources */,
|
D0C7D4C824F7616A001EBDBB /* SecondaryNavigationViewModel.swift in Sources */,
|
||||||
D0C7D4D524F7616A001EBDBB /* String+Extensions.swift in Sources */,
|
D0C7D4D524F7616A001EBDBB /* String+Extensions.swift in Sources */,
|
||||||
D0C7D4AB24F7616A001EBDBB /* Identity.swift in Sources */,
|
|
||||||
D0C7D4C024F7616A001EBDBB /* AlertItem.swift in Sources */,
|
D0C7D4C024F7616A001EBDBB /* AlertItem.swift in Sources */,
|
||||||
D0C7D4A224F7616A001EBDBB /* NotificationTypesPreferencesView.swift in Sources */,
|
D0C7D4A224F7616A001EBDBB /* NotificationTypesPreferencesView.swift in Sources */,
|
||||||
D0C7D4CF24F7616A001EBDBB /* StatusViewModel.swift in Sources */,
|
D0C7D4CF24F7616A001EBDBB /* StatusViewModel.swift in Sources */,
|
||||||
D0C7D4C724F7616A001EBDBB /* PostingReadingPreferencesViewModel.swift in Sources */,
|
D0C7D4C724F7616A001EBDBB /* PostingReadingPreferencesViewModel.swift in Sources */,
|
||||||
D0BEB1F724F9A84B001B0F04 /* LoadingTableFooterView.swift in Sources */,
|
D0BEB1F724F9A84B001B0F04 /* LoadingTableFooterView.swift in Sources */,
|
||||||
D0DC175224D008E300A75C65 /* MastodonTarget+Stubbing.swift in Sources */,
|
|
||||||
D0C7D4F124F7616A001EBDBB /* IdentityService.swift in Sources */,
|
|
||||||
D04FD74224D4AA34007D572D /* DevelopmentModels.swift in Sources */,
|
D04FD74224D4AA34007D572D /* DevelopmentModels.swift in Sources */,
|
||||||
D0C7D4F524F7616A001EBDBB /* AuthenticationService.swift in Sources */,
|
|
||||||
D0DC175824D0130800A75C65 /* HTTPStubs.swift in Sources */,
|
|
||||||
D0C7D4D924F7616A001EBDBB /* KingfisherOptionsInfo+Extensions.swift in Sources */,
|
D0C7D4D924F7616A001EBDBB /* KingfisherOptionsInfo+Extensions.swift in Sources */,
|
||||||
D0C7D4DC24F7616A001EBDBB /* Data+Extensions.swift in Sources */,
|
D0C7D4DC24F7616A001EBDBB /* Data+Extensions.swift in Sources */,
|
||||||
D0DC177724D0CF2600A75C65 /* MockKeychainService.swift in Sources */,
|
|
||||||
D0DC174624CFEC2000A75C65 /* StubbingURLProtocol.swift in Sources */,
|
|
||||||
D0BEB1FF24F9E5BB001B0F04 /* ListsView.swift in Sources */,
|
D0BEB1FF24F9E5BB001B0F04 /* ListsView.swift in Sources */,
|
||||||
D0C7D4F824F7616A001EBDBB /* SecretsService.swift in Sources */,
|
|
||||||
D0C7D4F624F7616A001EBDBB /* KeychainService.swift in Sources */,
|
|
||||||
D0DC174D24CFF1F100A75C65 /* Stubbing.swift in Sources */,
|
|
||||||
D0C7D49724F7616A001EBDBB /* IdentitiesView.swift in Sources */,
|
D0C7D49724F7616A001EBDBB /* IdentitiesView.swift in Sources */,
|
||||||
D074577724D29006004758DB /* MockWebAuthSession.swift in Sources */,
|
|
||||||
D0C7D4F924F7616A001EBDBB /* UserNotificationService.swift in Sources */,
|
|
||||||
D0C7D49824F7616A001EBDBB /* CustomEmojiText.swift in Sources */,
|
D0C7D49824F7616A001EBDBB /* CustomEmojiText.swift in Sources */,
|
||||||
D01F41E424F8889700D55A2D /* AttachmentsView.swift in Sources */,
|
D01F41E424F8889700D55A2D /* AttachmentsView.swift in Sources */,
|
||||||
D0BEB20724FA1121001B0F04 /* FiltersViewModel.swift in Sources */,
|
D0BEB20724FA1121001B0F04 /* FiltersViewModel.swift in Sources */,
|
||||||
D0C7D4C924F7616A001EBDBB /* TabNavigationViewModel.swift in Sources */,
|
D0C7D4C924F7616A001EBDBB /* TabNavigationViewModel.swift in Sources */,
|
||||||
D0BEB21124FA2A91001B0F04 /* EditFilterView.swift in Sources */,
|
D0BEB21124FA2A91001B0F04 /* EditFilterView.swift in Sources */,
|
||||||
D0C7D4C424F7616A001EBDBB /* AppDelegate.swift in Sources */,
|
D0C7D4C424F7616A001EBDBB /* AppDelegate.swift in Sources */,
|
||||||
D074577A24D29366004758DB /* URLSessionConfiguration+Extensions.swift in Sources */,
|
|
||||||
D0C7D49924F7616A001EBDBB /* AddIdentityView.swift in Sources */,
|
D0C7D49924F7616A001EBDBB /* AddIdentityView.swift in Sources */,
|
||||||
D0BEB1FD24F9E4E5001B0F04 /* ListsViewModel.swift in Sources */,
|
D0BEB1FD24F9E4E5001B0F04 /* ListsViewModel.swift in Sources */,
|
||||||
D0C7D4C324F7616A001EBDBB /* MetatextApp.swift in Sources */,
|
D0C7D4C324F7616A001EBDBB /* MetatextApp.swift in Sources */,
|
||||||
D0C7D4F324F7616A001EBDBB /* ContextService.swift in Sources */,
|
|
||||||
D0C7D4D824F7616A001EBDBB /* Publisher+Extensions.swift in Sources */,
|
D0C7D4D824F7616A001EBDBB /* Publisher+Extensions.swift in Sources */,
|
||||||
D0BEB20524FA1107001B0F04 /* FiltersView.swift in Sources */,
|
D0BEB20524FA1107001B0F04 /* FiltersView.swift in Sources */,
|
||||||
D01F41D824F880C400D55A2D /* StatusTableViewCell.swift in Sources */,
|
D01F41D824F880C400D55A2D /* StatusTableViewCell.swift in Sources */,
|
||||||
D04FD73C24D4A83A007D572D /* InstanceEndpoint+Stubbing.swift in Sources */,
|
|
||||||
D0C7D49B24F7616A001EBDBB /* PreferencesView.swift in Sources */,
|
D0C7D49B24F7616A001EBDBB /* PreferencesView.swift in Sources */,
|
||||||
D0C7D4D724F7616A001EBDBB /* UIColor+Extensions.swift in Sources */,
|
D0C7D4D724F7616A001EBDBB /* UIColor+Extensions.swift in Sources */,
|
||||||
);
|
);
|
||||||
|
@ -801,7 +612,6 @@
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
D0EC8DD424DFE38900A08489 /* AuthenticationServiceTests.swift in Sources */,
|
|
||||||
D0ED1B6E24CE100C00B4899C /* AddIdentityViewModelTests.swift in Sources */,
|
D0ED1B6E24CE100C00B4899C /* AddIdentityViewModelTests.swift in Sources */,
|
||||||
D052BBC724D749C800A80A7A /* RootViewModelTests.swift in Sources */,
|
D052BBC724D749C800A80A7A /* RootViewModelTests.swift in Sources */,
|
||||||
);
|
);
|
||||||
|
@ -811,10 +621,7 @@
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
D0C7D4FE24F761C9001EBDBB /* SecretsService.swift in Sources */,
|
|
||||||
D0E5361C24E3EB4D00FB1CE1 /* NotificationService.swift in Sources */,
|
D0E5361C24E3EB4D00FB1CE1 /* NotificationService.swift in Sources */,
|
||||||
D0C7D50024F761E0001EBDBB /* NSError+Extensions.swift in Sources */,
|
|
||||||
D0C7D4FF24F761D0001EBDBB /* KeychainService.swift in Sources */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -953,7 +760,7 @@
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_ENTITLEMENTS = "Supporting Files/Metatext.entitlements";
|
CODE_SIGN_ENTITLEMENTS = "Supporting Files/Metatext.entitlements";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
DEVELOPMENT_ASSET_PATHS = "Development\\ Assets Development\\ Assets/Mastodon\\ API\\ Stubs";
|
DEVELOPMENT_ASSET_PATHS = "Development\\ Assets";
|
||||||
DEVELOPMENT_TEAM = 82HL67AXQ2;
|
DEVELOPMENT_TEAM = 82HL67AXQ2;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
INFOPLIST_FILE = "Supporting Files/Info.plist";
|
INFOPLIST_FILE = "Supporting Files/Info.plist";
|
||||||
|
@ -979,7 +786,7 @@
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_ENTITLEMENTS = "Supporting Files/Metatext.entitlements";
|
CODE_SIGN_ENTITLEMENTS = "Supporting Files/Metatext.entitlements";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
DEVELOPMENT_ASSET_PATHS = "Development\\ Assets Development\\ Assets/Mastodon\\ API\\ Stubs";
|
DEVELOPMENT_ASSET_PATHS = "Development\\ Assets";
|
||||||
DEVELOPMENT_TEAM = 82HL67AXQ2;
|
DEVELOPMENT_TEAM = 82HL67AXQ2;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
INFOPLIST_FILE = "Supporting Files/Info.plist";
|
INFOPLIST_FILE = "Supporting Files/Info.plist";
|
||||||
|
@ -1143,14 +950,6 @@
|
||||||
minimumVersion = 0.5.0;
|
minimumVersion = 0.5.0;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
D0666A4724C6C1A300F3F04B /* XCRemoteSwiftPackageReference "GRDB" */ = {
|
|
||||||
isa = XCRemoteSwiftPackageReference;
|
|
||||||
repositoryURL = "https://github.com/groue/GRDB.swift";
|
|
||||||
requirement = {
|
|
||||||
kind = upToNextMajorVersion;
|
|
||||||
minimumVersion = "5.0.0-beta.10";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
D06B492124D4611300642749 /* XCRemoteSwiftPackageReference "Kingfisher" */ = {
|
D06B492124D4611300642749 /* XCRemoteSwiftPackageReference "Kingfisher" */ = {
|
||||||
isa = XCRemoteSwiftPackageReference;
|
isa = XCRemoteSwiftPackageReference;
|
||||||
repositoryURL = "https://github.com/onevcat/Kingfisher";
|
repositoryURL = "https://github.com/onevcat/Kingfisher";
|
||||||
|
@ -1167,23 +966,22 @@
|
||||||
package = D065F53724D37E5100741304 /* XCRemoteSwiftPackageReference "CombineExpectations" */;
|
package = D065F53724D37E5100741304 /* XCRemoteSwiftPackageReference "CombineExpectations" */;
|
||||||
productName = CombineExpectations;
|
productName = CombineExpectations;
|
||||||
};
|
};
|
||||||
D0666A4824C6C1A300F3F04B /* GRDB */ = {
|
|
||||||
isa = XCSwiftPackageProductDependency;
|
|
||||||
package = D0666A4724C6C1A300F3F04B /* XCRemoteSwiftPackageReference "GRDB" */;
|
|
||||||
productName = GRDB;
|
|
||||||
};
|
|
||||||
D06B492224D4611300642749 /* KingfisherSwiftUI */ = {
|
D06B492224D4611300642749 /* KingfisherSwiftUI */ = {
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
package = D06B492124D4611300642749 /* XCRemoteSwiftPackageReference "Kingfisher" */;
|
package = D06B492124D4611300642749 /* XCRemoteSwiftPackageReference "Kingfisher" */;
|
||||||
productName = KingfisherSwiftUI;
|
productName = KingfisherSwiftUI;
|
||||||
};
|
};
|
||||||
D0E0F1E524FC4B76002C04BF /* Mastodon */ = {
|
D075C28424FCD41D00D35112 /* Services */ = {
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
productName = Mastodon;
|
productName = Services;
|
||||||
};
|
};
|
||||||
D0E0F1E724FC5A61002C04BF /* Mastodon */ = {
|
D075C28624FCD92400D35112 /* Services */ = {
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
productName = Mastodon;
|
productName = Services;
|
||||||
|
};
|
||||||
|
D0ADCBF024FD05510062ACCE /* ServiceMocks */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
productName = ServiceMocks;
|
||||||
};
|
};
|
||||||
/* End XCSwiftPackageProductDependency section */
|
/* End XCSwiftPackageProductDependency section */
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"package": "GRDB",
|
"package": "GRDB",
|
||||||
"repositoryURL": "https://github.com/groue/GRDB.swift",
|
"repositoryURL": "https://github.com/groue/GRDB.swift.git",
|
||||||
"state": {
|
"state": {
|
||||||
"branch": null,
|
"branch": null,
|
||||||
"revision": "ededd8668abd5a3c4c43cc9ebcfd611082b47f65",
|
"revision": "ededd8668abd5a3c4c43cc9ebcfd611082b47f65",
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
// Copyright © 2020 Metabolist. All rights reserved.
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import Mastodon
|
|
||||||
|
|
||||||
struct Identity: Codable, Hashable, Identifiable {
|
|
||||||
let id: UUID
|
|
||||||
let url: URL
|
|
||||||
let lastUsedAt: Date
|
|
||||||
let preferences: Identity.Preferences
|
|
||||||
let instance: Identity.Instance?
|
|
||||||
let account: Identity.Account?
|
|
||||||
let lastRegisteredDeviceToken: String?
|
|
||||||
let pushSubscriptionAlerts: PushSubscription.Alerts
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Identity {
|
|
||||||
struct Instance: Codable, Hashable {
|
|
||||||
let uri: String
|
|
||||||
let streamingAPI: URL
|
|
||||||
let title: String
|
|
||||||
let thumbnail: URL?
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Account: Codable, Hashable {
|
|
||||||
let id: String
|
|
||||||
let identityID: UUID
|
|
||||||
let username: String
|
|
||||||
let displayName: String
|
|
||||||
let url: URL
|
|
||||||
let avatar: URL
|
|
||||||
let avatarStatic: URL
|
|
||||||
let header: URL
|
|
||||||
let headerStatic: URL
|
|
||||||
let emojis: [Emoji]
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Preferences: Codable, Hashable {
|
|
||||||
@DecodableDefault.True var useServerPostingReadingPreferences
|
|
||||||
@DecodableDefault.StatusVisibilityPublic var postingDefaultVisibility: Status.Visibility
|
|
||||||
@DecodableDefault.False var postingDefaultSensitive
|
|
||||||
var postingDefaultLanguage: String?
|
|
||||||
@DecodableDefault.ExpandMediaDefault var readingExpandMedia: Mastodon.Preferences.ExpandMedia
|
|
||||||
@DecodableDefault.False var readingExpandSpoilers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Identity {
|
|
||||||
var handle: String {
|
|
||||||
if let account = account, let host = account.url.host {
|
|
||||||
return account.url.lastPathComponent + "@" + host
|
|
||||||
}
|
|
||||||
|
|
||||||
return instance?.title ?? url.host ?? url.absoluteString
|
|
||||||
}
|
|
||||||
|
|
||||||
var image: URL? { account?.avatar ?? instance?.thumbnail }
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Identity.Preferences {
|
|
||||||
func updated(from serverPreferences: Preferences) -> Self {
|
|
||||||
var mutable = self
|
|
||||||
|
|
||||||
if useServerPostingReadingPreferences {
|
|
||||||
mutable.postingDefaultVisibility = serverPreferences.postingDefaultVisibility
|
|
||||||
mutable.postingDefaultSensitive = serverPreferences.postingDefaultSensitive
|
|
||||||
mutable.readingExpandMedia = serverPreferences.readingExpandMedia
|
|
||||||
mutable.readingExpandSpoilers = serverPreferences.readingExpandSpoilers
|
|
||||||
}
|
|
||||||
|
|
||||||
return mutable
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
// Copyright © 2020 Metabolist. All rights reserved.
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
struct TransientStatusCollection: Codable {
|
|
||||||
let id: String
|
|
||||||
}
|
|
|
@ -3,6 +3,7 @@
|
||||||
import UserNotifications
|
import UserNotifications
|
||||||
import CryptoKit
|
import CryptoKit
|
||||||
import Mastodon
|
import Mastodon
|
||||||
|
import Services
|
||||||
|
|
||||||
class NotificationService: UNNotificationServiceExtension {
|
class NotificationService: UNNotificationServiceExtension {
|
||||||
|
|
||||||
|
|
5
Services/.gitignore
vendored
Normal file
5
Services/.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
.DS_Store
|
||||||
|
/.build
|
||||||
|
/Packages
|
||||||
|
/*.xcodeproj
|
||||||
|
xcuserdata/
|
35
Services/Package.swift
Normal file
35
Services/Package.swift
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
// swift-tools-version:5.3
|
||||||
|
|
||||||
|
import PackageDescription
|
||||||
|
|
||||||
|
let package = Package(
|
||||||
|
name: "Services",
|
||||||
|
platforms: [
|
||||||
|
.iOS(.v14),
|
||||||
|
.macOS(.v11)
|
||||||
|
],
|
||||||
|
products: [
|
||||||
|
.library(
|
||||||
|
name: "Services",
|
||||||
|
targets: ["Services"]),
|
||||||
|
.library(
|
||||||
|
name: "ServiceMocks",
|
||||||
|
targets: ["ServiceMocks"])
|
||||||
|
],
|
||||||
|
dependencies: [
|
||||||
|
.package(url: "https://github.com/groue/CombineExpectations.git", .upToNextMajor(from: "0.5.0")),
|
||||||
|
.package(name: "GRDB", url: "https://github.com/groue/GRDB.swift.git", .upToNextMajor(from: "5.0.0-beta.10")),
|
||||||
|
.package(path: "Mastodon")
|
||||||
|
],
|
||||||
|
targets: [
|
||||||
|
.target(
|
||||||
|
name: "Services",
|
||||||
|
dependencies: ["GRDB", "Mastodon"]),
|
||||||
|
.target(
|
||||||
|
name: "ServiceMocks",
|
||||||
|
dependencies: ["Services", .product(name: "MastodonStubs", package: "Mastodon")]),
|
||||||
|
.testTarget(
|
||||||
|
name: "ServicesTests",
|
||||||
|
dependencies: ["ServiceMocks", "CombineExpectations"])
|
||||||
|
]
|
||||||
|
)
|
13
Services/Sources/ServiceMocks/MockAppEnvironment.swift
Normal file
13
Services/Sources/ServiceMocks/MockAppEnvironment.swift
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import Foundation
|
||||||
|
import HTTP
|
||||||
|
import Services
|
||||||
|
import Stubbing
|
||||||
|
|
||||||
|
extension AppEnvironment {
|
||||||
|
static let mock = AppEnvironment(
|
||||||
|
session: Session(configuration: .stubbing),
|
||||||
|
webAuthSessionType: SuccessfulMockWebAuthSession.self,
|
||||||
|
keychainServiceType: MockKeychainService.self,
|
||||||
|
userDefaults: MockUserDefaults(),
|
||||||
|
inMemoryContent: true)
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright © 2020 Metabolist. All rights reserved.
|
// Copyright © 2020 Metabolist. All rights reserved.
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import Services
|
||||||
|
|
||||||
struct MockKeychainService {}
|
struct MockKeychainService {}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright © 2020 Metabolist. All rights reserved.
|
// Copyright © 2020 Metabolist. All rights reserved.
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import Services
|
||||||
|
|
||||||
class MockWebAuthSession: WebAuthSession {
|
class MockWebAuthSession: WebAuthSession {
|
||||||
let completionHandler: WebAuthSessionCompletionHandler
|
let completionHandler: WebAuthSessionCompletionHandler
|
|
@ -4,14 +4,14 @@ import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
import Mastodon
|
import Mastodon
|
||||||
|
|
||||||
struct AllIdentitiesService {
|
public struct AllIdentitiesService {
|
||||||
let mostRecentlyUsedIdentityID: AnyPublisher<UUID?, Never>
|
public let mostRecentlyUsedIdentityID: AnyPublisher<UUID?, Never>
|
||||||
|
|
||||||
private let identityDatabase: IdentityDatabase
|
private let identityDatabase: IdentityDatabase
|
||||||
private let environment: AppEnvironment
|
private let environment: AppEnvironment
|
||||||
|
|
||||||
init(identityDatabase: IdentityDatabase, environment: AppEnvironment) {
|
public init(environment: AppEnvironment) throws {
|
||||||
self.identityDatabase = identityDatabase
|
self.identityDatabase = try IdentityDatabase(inMemory: environment.inMemoryContent)
|
||||||
self.environment = environment
|
self.environment = environment
|
||||||
|
|
||||||
mostRecentlyUsedIdentityID = identityDatabase.mostRecentlyUsedIdentityIDObservation()
|
mostRecentlyUsedIdentityID = identityDatabase.mostRecentlyUsedIdentityIDObservation()
|
||||||
|
@ -20,7 +20,7 @@ struct AllIdentitiesService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AllIdentitiesService {
|
public extension AllIdentitiesService {
|
||||||
func identityService(id: UUID) throws -> IdentityService {
|
func identityService(id: UUID) throws -> IdentityService {
|
||||||
try IdentityService(identityID: id,
|
try IdentityService(identityID: id,
|
||||||
identityDatabase: identityDatabase,
|
identityDatabase: identityDatabase,
|
|
@ -4,18 +4,18 @@ import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
import Mastodon
|
import Mastodon
|
||||||
|
|
||||||
struct AuthenticationService {
|
public struct AuthenticationService {
|
||||||
private let networkClient: APIClient
|
private let networkClient: APIClient
|
||||||
private let webAuthSessionType: WebAuthSession.Type
|
private let webAuthSessionType: WebAuthSession.Type
|
||||||
private let webAuthSessionContextProvider = WebAuthSessionContextProvider()
|
private let webAuthSessionContextProvider = WebAuthSessionContextProvider()
|
||||||
|
|
||||||
init(environment: AppEnvironment) {
|
public init(environment: AppEnvironment) {
|
||||||
networkClient = APIClient(session: environment.session)
|
networkClient = APIClient(session: environment.session)
|
||||||
webAuthSessionType = environment.webAuthSessionType
|
webAuthSessionType = environment.webAuthSessionType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AuthenticationService {
|
public extension AuthenticationService {
|
||||||
func authorizeApp(instanceURL: URL) -> AnyPublisher<AppAuthorization, Error> {
|
func authorizeApp(instanceURL: URL) -> AnyPublisher<AppAuthorization, Error> {
|
||||||
let endpoint = AppAuthorizationEndpoint.apps(
|
let endpoint = AppAuthorizationEndpoint.apps(
|
||||||
clientName: OAuth.clientName,
|
clientName: OAuth.clientName,
|
|
@ -241,7 +241,7 @@ private extension ContentDatabase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Account: TableRecord, FetchableRecord, PersistableRecord {
|
extension Account: FetchableRecord, PersistableRecord {
|
||||||
public static func databaseJSONDecoder(for column: String) -> JSONDecoder {
|
public static func databaseJSONDecoder(for column: String) -> JSONDecoder {
|
||||||
APIDecoder()
|
APIDecoder()
|
||||||
}
|
}
|
||||||
|
@ -251,14 +251,14 @@ extension Account: TableRecord, FetchableRecord, PersistableRecord {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol StatusCollection: FetchableRecord, PersistableRecord {
|
public protocol StatusCollection: FetchableRecord, PersistableRecord {
|
||||||
var id: String { get }
|
var id: String { get }
|
||||||
var fetch: (Database) throws -> [StatusResult] { get }
|
var fetch: (Database) throws -> [StatusResult] { get }
|
||||||
|
|
||||||
func joinRecord(status: Status) -> PersistableRecord
|
func joinRecord(status: Status) -> PersistableRecord
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct TimelineStatusJoin: Codable, TableRecord, FetchableRecord, PersistableRecord {
|
private struct TimelineStatusJoin: Codable, FetchableRecord, PersistableRecord {
|
||||||
let timelineId: String
|
let timelineId: String
|
||||||
let statusId: String
|
let statusId: String
|
||||||
|
|
||||||
|
@ -293,7 +293,7 @@ extension Timeline: StatusCollection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var fetch: (Database) throws -> [StatusResult] {
|
public var fetch: (Database) throws -> [StatusResult] {
|
||||||
statuses
|
statuses
|
||||||
.including(required: StoredStatus.account)
|
.including(required: StoredStatus.account)
|
||||||
.including(optional: StoredStatus.reblogAccount)
|
.including(optional: StoredStatus.reblogAccount)
|
||||||
|
@ -302,7 +302,7 @@ extension Timeline: StatusCollection {
|
||||||
.fetchAll
|
.fetchAll
|
||||||
}
|
}
|
||||||
|
|
||||||
func joinRecord(status: Status) -> PersistableRecord {
|
public func joinRecord(status: Status) -> PersistableRecord {
|
||||||
TimelineStatusJoin(timelineId: id, statusId: status.id)
|
TimelineStatusJoin(timelineId: id, statusId: status.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -323,7 +323,7 @@ private extension Timeline {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Filter: TableRecord, FetchableRecord, PersistableRecord {
|
extension Filter: FetchableRecord, PersistableRecord {
|
||||||
public static func databaseJSONDecoder(for column: String) -> JSONDecoder {
|
public static func databaseJSONDecoder(for column: String) -> JSONDecoder {
|
||||||
APIDecoder()
|
APIDecoder()
|
||||||
}
|
}
|
||||||
|
@ -333,7 +333,7 @@ extension Filter: TableRecord, FetchableRecord, PersistableRecord {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct TransientStatusCollectionElement: Codable, TableRecord, FetchableRecord, PersistableRecord {
|
private struct TransientStatusCollectionElement: Codable, FetchableRecord, PersistableRecord {
|
||||||
let transientStatusCollectionId: String
|
let transientStatusCollectionId: String
|
||||||
let statusId: String
|
let statusId: String
|
||||||
|
|
||||||
|
@ -341,7 +341,7 @@ private struct TransientStatusCollectionElement: Codable, TableRecord, Fetchable
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TransientStatusCollection: StatusCollection {
|
extension TransientStatusCollection: StatusCollection {
|
||||||
var fetch: (Database) throws -> [StatusResult] {
|
public var fetch: (Database) throws -> [StatusResult] {
|
||||||
{
|
{
|
||||||
try StatusResult.fetchAll(
|
try StatusResult.fetchAll(
|
||||||
$0,
|
$0,
|
||||||
|
@ -356,7 +356,7 @@ extension TransientStatusCollection: StatusCollection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func joinRecord(status: Status) -> PersistableRecord {
|
public func joinRecord(status: Status) -> PersistableRecord {
|
||||||
TransientStatusCollectionElement(transientStatusCollectionId: id, statusId: status.id)
|
TransientStatusCollectionElement(transientStatusCollectionId: id, statusId: status.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -451,7 +451,7 @@ private extension StoredStatus {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension StoredStatus: TableRecord, FetchableRecord, PersistableRecord {
|
extension StoredStatus: FetchableRecord, PersistableRecord {
|
||||||
static func databaseJSONDecoder(for column: String) -> JSONDecoder {
|
static func databaseJSONDecoder(for column: String) -> JSONDecoder {
|
||||||
APIDecoder()
|
APIDecoder()
|
||||||
}
|
}
|
||||||
|
@ -461,7 +461,7 @@ extension StoredStatus: TableRecord, FetchableRecord, PersistableRecord {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StatusResult: Codable, Hashable, FetchableRecord {
|
public struct StatusResult: Codable, Hashable, FetchableRecord {
|
||||||
let account: Account
|
let account: Account
|
||||||
fileprivate let status: StoredStatus
|
fileprivate let status: StoredStatus
|
||||||
let reblogAccount: Account?
|
let reblogAccount: Account?
|
|
@ -2,6 +2,6 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum DatabaseError: Error {
|
public enum DatabaseError: Error {
|
||||||
case documentsDirectoryNotFound
|
case documentsDirectoryNotFound
|
||||||
}
|
}
|
|
@ -237,7 +237,7 @@ private extension IdentityDatabase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct StoredIdentity: Codable, Hashable, TableRecord, FetchableRecord, PersistableRecord {
|
private struct StoredIdentity: Codable, Hashable, FetchableRecord, PersistableRecord {
|
||||||
let id: UUID
|
let id: UUID
|
||||||
let url: URL
|
let url: URL
|
||||||
let lastUsedAt: Date
|
let lastUsedAt: Date
|
||||||
|
@ -281,6 +281,6 @@ private extension Identity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Identity.Instance: TableRecord, FetchableRecord, PersistableRecord {}
|
extension Identity.Instance: FetchableRecord, PersistableRecord {}
|
||||||
|
|
||||||
extension Identity.Account: TableRecord, FetchableRecord, PersistableRecord {}
|
extension Identity.Account: FetchableRecord, PersistableRecord {}
|
|
@ -4,15 +4,27 @@ import Foundation
|
||||||
import HTTP
|
import HTTP
|
||||||
import Mastodon
|
import Mastodon
|
||||||
|
|
||||||
struct AppEnvironment {
|
public struct AppEnvironment {
|
||||||
let session: Session
|
let session: Session
|
||||||
let webAuthSessionType: WebAuthSession.Type
|
let webAuthSessionType: WebAuthSession.Type
|
||||||
let keychainServiceType: KeychainService.Type
|
let keychainServiceType: KeychainService.Type
|
||||||
let userDefaults: UserDefaults
|
let userDefaults: UserDefaults
|
||||||
let inMemoryContent: Bool
|
let inMemoryContent: Bool
|
||||||
|
|
||||||
|
public init(session: Session,
|
||||||
|
webAuthSessionType: WebAuthSession.Type,
|
||||||
|
keychainServiceType: KeychainService.Type,
|
||||||
|
userDefaults: UserDefaults,
|
||||||
|
inMemoryContent: Bool) {
|
||||||
|
self.session = session
|
||||||
|
self.webAuthSessionType = webAuthSessionType
|
||||||
|
self.keychainServiceType = keychainServiceType
|
||||||
|
self.userDefaults = userDefaults
|
||||||
|
self.inMemoryContent = inMemoryContent
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AppEnvironment {
|
public extension AppEnvironment {
|
||||||
static let live: Self = Self(
|
static let live: Self = Self(
|
||||||
session: Session(configuration: .default),
|
session: Session(configuration: .default),
|
||||||
webAuthSessionType: LiveWebAuthSession.self,
|
webAuthSessionType: LiveWebAuthSession.self,
|
71
Services/Sources/Services/Entities/Identity.swift
Normal file
71
Services/Sources/Services/Entities/Identity.swift
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
// Copyright © 2020 Metabolist. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Mastodon
|
||||||
|
|
||||||
|
public struct Identity: Codable, Hashable, Identifiable {
|
||||||
|
public let id: UUID
|
||||||
|
public let url: URL
|
||||||
|
public let lastUsedAt: Date
|
||||||
|
public let preferences: Identity.Preferences
|
||||||
|
public let instance: Identity.Instance?
|
||||||
|
public let account: Identity.Account?
|
||||||
|
public let lastRegisteredDeviceToken: String?
|
||||||
|
public let pushSubscriptionAlerts: PushSubscription.Alerts
|
||||||
|
}
|
||||||
|
|
||||||
|
public extension Identity {
|
||||||
|
struct Instance: Codable, Hashable {
|
||||||
|
public let uri: String
|
||||||
|
public let streamingAPI: URL
|
||||||
|
public let title: String
|
||||||
|
public let thumbnail: URL?
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Account: Codable, Hashable {
|
||||||
|
public let id: String
|
||||||
|
public let identityID: UUID
|
||||||
|
public let username: String
|
||||||
|
public let displayName: String
|
||||||
|
public let url: URL
|
||||||
|
public let avatar: URL
|
||||||
|
public let avatarStatic: URL
|
||||||
|
public let header: URL
|
||||||
|
public let headerStatic: URL
|
||||||
|
public let emojis: [Emoji]
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Preferences: Codable, Hashable {
|
||||||
|
@DecodableDefault.True public var useServerPostingReadingPreferences
|
||||||
|
@DecodableDefault.StatusVisibilityPublic public var postingDefaultVisibility: Status.Visibility
|
||||||
|
@DecodableDefault.False public var postingDefaultSensitive
|
||||||
|
public var postingDefaultLanguage: String?
|
||||||
|
@DecodableDefault.ExpandMediaDefault public var readingExpandMedia: Mastodon.Preferences.ExpandMedia
|
||||||
|
@DecodableDefault.False public var readingExpandSpoilers
|
||||||
|
}
|
||||||
|
|
||||||
|
var handle: String {
|
||||||
|
if let account = account, let host = account.url.host {
|
||||||
|
return account.url.lastPathComponent + "@" + host
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance?.title ?? url.host ?? url.absoluteString
|
||||||
|
}
|
||||||
|
|
||||||
|
var image: URL? { account?.avatar ?? instance?.thumbnail }
|
||||||
|
}
|
||||||
|
|
||||||
|
public extension Identity.Preferences {
|
||||||
|
func updated(from serverPreferences: Preferences) -> Self {
|
||||||
|
var mutable = self
|
||||||
|
|
||||||
|
if useServerPostingReadingPreferences {
|
||||||
|
mutable.postingDefaultVisibility = serverPreferences.postingDefaultVisibility
|
||||||
|
mutable.postingDefaultSensitive = serverPreferences.postingDefaultSensitive
|
||||||
|
mutable.readingExpandMedia = serverPreferences.readingExpandMedia
|
||||||
|
mutable.readingExpandSpoilers = serverPreferences.readingExpandSpoilers
|
||||||
|
}
|
||||||
|
|
||||||
|
return mutable
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
// Copyright © 2020 Metabolist. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
public struct TransientStatusCollection: Codable {
|
||||||
|
public let id: String
|
||||||
|
|
||||||
|
public init(id: String) {
|
||||||
|
self.id = id
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ import Foundation
|
||||||
import AuthenticationServices
|
import AuthenticationServices
|
||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
protocol WebAuthSession: AnyObject {
|
public protocol WebAuthSession: AnyObject {
|
||||||
init(url URL: URL,
|
init(url URL: URL,
|
||||||
callbackURLScheme: String?,
|
callbackURLScheme: String?,
|
||||||
completionHandler: @escaping WebAuthSessionCompletionHandler)
|
completionHandler: @escaping WebAuthSessionCompletionHandler)
|
||||||
|
@ -41,9 +41,9 @@ class WebAuthSessionContextProvider: NSObject, ASWebAuthenticationPresentationCo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typealias WebAuthSessionCompletionHandler = ASWebAuthenticationSession.CompletionHandler
|
public typealias WebAuthSessionCompletionHandler = ASWebAuthenticationSession.CompletionHandler
|
||||||
typealias WebAuthSessionError = ASWebAuthenticationSessionError
|
public typealias WebAuthSessionError = ASWebAuthenticationSessionError
|
||||||
typealias WebAuthPresentationContextProviding = ASWebAuthenticationPresentationContextProviding
|
public typealias WebAuthPresentationContextProviding = ASWebAuthenticationPresentationContextProviding
|
||||||
typealias LiveWebAuthSession = ASWebAuthenticationSession
|
public typealias LiveWebAuthSession = ASWebAuthenticationSession
|
||||||
|
|
||||||
extension LiveWebAuthSession: WebAuthSession {}
|
extension LiveWebAuthSession: WebAuthSession {}
|
|
@ -4,9 +4,9 @@ import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
import Mastodon
|
import Mastodon
|
||||||
|
|
||||||
class IdentityService {
|
public class IdentityService {
|
||||||
@Published private(set) var identity: Identity
|
@Published public private(set) var identity: Identity
|
||||||
let observationErrors: AnyPublisher<Error, Never>
|
public let observationErrors: AnyPublisher<Error, Never>
|
||||||
|
|
||||||
private let identityDatabase: IdentityDatabase
|
private let identityDatabase: IdentityDatabase
|
||||||
private let contentDatabase: ContentDatabase
|
private let contentDatabase: ContentDatabase
|
||||||
|
@ -50,7 +50,7 @@ class IdentityService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension IdentityService {
|
public extension IdentityService {
|
||||||
var isAuthorized: Bool { networkClient.accessToken != nil }
|
var isAuthorized: Bool { networkClient.accessToken != nil }
|
||||||
|
|
||||||
func updateLastUse() -> AnyPublisher<Never, Error> {
|
func updateLastUse() -> AnyPublisher<Never, Error> {
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
protocol KeychainService {
|
public protocol KeychainService {
|
||||||
static func setGenericPassword(data: Data, forAccount key: String, service: String) throws
|
static func setGenericPassword(data: Data, forAccount key: String, service: String) throws
|
||||||
static func deleteGenericPassword(account: String, service: String) throws
|
static func deleteGenericPassword(account: String, service: String) throws
|
||||||
static func getGenericPassword(account: String, service: String) throws -> Data?
|
static func getGenericPassword(account: String, service: String) throws -> Data?
|
||||||
|
@ -11,10 +11,10 @@ protocol KeychainService {
|
||||||
static func deleteKey(applicationTag: String) throws
|
static func deleteKey(applicationTag: String) throws
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LiveKeychainService {}
|
public struct LiveKeychainService {}
|
||||||
|
|
||||||
extension LiveKeychainService: KeychainService {
|
extension LiveKeychainService: KeychainService {
|
||||||
static func setGenericPassword(data: Data, forAccount account: String, service: String) throws {
|
public static func setGenericPassword(data: Data, forAccount account: String, service: String) throws {
|
||||||
var query = genericPasswordQueryDictionary(account: account, service: service)
|
var query = genericPasswordQueryDictionary(account: account, service: service)
|
||||||
|
|
||||||
query[kSecValueData as String] = data
|
query[kSecValueData as String] = data
|
||||||
|
@ -26,7 +26,7 @@ extension LiveKeychainService: KeychainService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func deleteGenericPassword(account: String, service: String) throws {
|
public static func deleteGenericPassword(account: String, service: String) throws {
|
||||||
let status = SecItemDelete(genericPasswordQueryDictionary(account: account, service: service) as CFDictionary)
|
let status = SecItemDelete(genericPasswordQueryDictionary(account: account, service: service) as CFDictionary)
|
||||||
|
|
||||||
if status != errSecSuccess {
|
if status != errSecSuccess {
|
||||||
|
@ -34,7 +34,7 @@ extension LiveKeychainService: KeychainService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getGenericPassword(account: String, service: String) throws -> Data? {
|
public static func getGenericPassword(account: String, service: String) throws -> Data? {
|
||||||
var result: AnyObject?
|
var result: AnyObject?
|
||||||
var query = genericPasswordQueryDictionary(account: account, service: service)
|
var query = genericPasswordQueryDictionary(account: account, service: service)
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ extension LiveKeychainService: KeychainService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func generateKeyAndReturnPublicKey(applicationTag: String, attributes: [String: Any]) throws -> Data {
|
public static func generateKeyAndReturnPublicKey(applicationTag: String, attributes: [String: Any]) throws -> Data {
|
||||||
var attributes = attributes
|
var attributes = attributes
|
||||||
var error: Unmanaged<CFError>?
|
var error: Unmanaged<CFError>?
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ extension LiveKeychainService: KeychainService {
|
||||||
return publicKeyData
|
return publicKeyData
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getPrivateKey(applicationTag: String, attributes: [String: Any]) throws -> Data? {
|
public static func getPrivateKey(applicationTag: String, attributes: [String: Any]) throws -> Data? {
|
||||||
var result: AnyObject?
|
var result: AnyObject?
|
||||||
var error: Unmanaged<CFError>?
|
var error: Unmanaged<CFError>?
|
||||||
var query = keyQueryDictionary(applicationTag: applicationTag)
|
var query = keyQueryDictionary(applicationTag: applicationTag)
|
||||||
|
@ -106,7 +106,7 @@ extension LiveKeychainService: KeychainService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func deleteKey(applicationTag: String) throws {
|
public static func deleteKey(applicationTag: String) throws {
|
||||||
let status = SecItemDelete(keyQueryDictionary(applicationTag: applicationTag) as CFDictionary)
|
let status = SecItemDelete(keyQueryDictionary(applicationTag: applicationTag) as CFDictionary)
|
||||||
|
|
||||||
if status != errSecSuccess {
|
if status != errSecSuccess {
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
protocol SecretsStorable {
|
public protocol SecretsStorable {
|
||||||
var dataStoredInSecrets: Data { get }
|
var dataStoredInSecrets: Data { get }
|
||||||
static func fromDataStoredInSecrets(_ data: Data) throws -> Self
|
static func fromDataStoredInSecrets(_ data: Data) throws -> Self
|
||||||
}
|
}
|
||||||
|
@ -11,17 +11,17 @@ enum SecretsStorableError: Error {
|
||||||
case conversionFromDataStoredInSecrets(Data)
|
case conversionFromDataStoredInSecrets(Data)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SecretsService {
|
public struct SecretsService {
|
||||||
let identityID: UUID
|
public let identityID: UUID
|
||||||
private let keychainService: KeychainService.Type
|
private let keychainService: KeychainService.Type
|
||||||
|
|
||||||
init(identityID: UUID, keychainService: KeychainService.Type) {
|
public init(identityID: UUID, keychainService: KeychainService.Type) {
|
||||||
self.identityID = identityID
|
self.identityID = identityID
|
||||||
self.keychainService = keychainService
|
self.keychainService = keychainService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SecretsService {
|
public extension SecretsService {
|
||||||
enum Item: String, CaseIterable {
|
enum Item: String, CaseIterable {
|
||||||
case clientID
|
case clientID
|
||||||
case clientSecret
|
case clientSecret
|
||||||
|
@ -49,7 +49,7 @@ extension SecretsService.Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SecretsService {
|
public extension SecretsService {
|
||||||
func set(_ data: SecretsStorable, forItem item: Item) throws {
|
func set(_ data: SecretsStorable, forItem item: Item) throws {
|
||||||
try keychainService.setGenericPassword(
|
try keychainService.setGenericPassword(
|
||||||
data: data.dataStoredInSecrets,
|
data: data.dataStoredInSecrets,
|
||||||
|
@ -118,17 +118,17 @@ private extension SecretsService {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Data: SecretsStorable {
|
extension Data: SecretsStorable {
|
||||||
var dataStoredInSecrets: Data { self }
|
public var dataStoredInSecrets: Data { self }
|
||||||
|
|
||||||
static func fromDataStoredInSecrets(_ data: Data) throws -> Data {
|
public static func fromDataStoredInSecrets(_ data: Data) throws -> Data {
|
||||||
data
|
data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension String: SecretsStorable {
|
extension String: SecretsStorable {
|
||||||
var dataStoredInSecrets: Data { Data(utf8) }
|
public var dataStoredInSecrets: Data { Data(utf8) }
|
||||||
|
|
||||||
static func fromDataStoredInSecrets(_ data: Data) throws -> String {
|
public static func fromDataStoredInSecrets(_ data: Data) throws -> String {
|
||||||
guard let string = String(data: data, encoding: .utf8) else {
|
guard let string = String(data: data, encoding: .utf8) else {
|
||||||
throw SecretsStorableError.conversionFromDataStoredInSecrets(data)
|
throw SecretsStorableError.conversionFromDataStoredInSecrets(data)
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,7 @@ extension String: SecretsStorable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PushKey {
|
private struct PushKey {
|
||||||
static let authLength = 16
|
static let authLength = 16
|
||||||
static let sizeInBits = 256
|
static let sizeInBits = 256
|
||||||
static let attributes: [String: Any] = [
|
static let attributes: [String: Any] = [
|
|
@ -4,9 +4,9 @@ import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
import Mastodon
|
import Mastodon
|
||||||
|
|
||||||
struct ContextService {
|
public struct ContextService {
|
||||||
let statusSections: AnyPublisher<[[Status]], Error>
|
public let statusSections: AnyPublisher<[[Status]], Error>
|
||||||
let paginates = false
|
public let paginates = false
|
||||||
|
|
||||||
private let status: Status
|
private let status: Status
|
||||||
private let context = CurrentValueSubject<Context, Never>(Context(ancestors: [], descendants: []))
|
private let context = CurrentValueSubject<Context, Never>(Context(ancestors: [], descendants: []))
|
||||||
|
@ -34,13 +34,13 @@ struct ContextService {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ContextService: StatusListService {
|
extension ContextService: StatusListService {
|
||||||
var filters: AnyPublisher<[Filter], Error> {
|
public var filters: AnyPublisher<[Filter], Error> {
|
||||||
contentDatabase.activeFiltersObservation(date: Date(), context: .thread)
|
contentDatabase.activeFiltersObservation(date: Date(), context: .thread)
|
||||||
}
|
}
|
||||||
|
|
||||||
var contextParentID: String? { status.id }
|
public var contextParentID: String? { status.id }
|
||||||
|
|
||||||
func isReplyInContext(status: Status) -> Bool {
|
public func isReplyInContext(status: Status) -> Bool {
|
||||||
let flatContext = flattenedContext()
|
let flatContext = flattenedContext()
|
||||||
|
|
||||||
guard
|
guard
|
||||||
|
@ -53,7 +53,7 @@ extension ContextService: StatusListService {
|
||||||
return previousStatus.id != contextParentID && status.inReplyToId == previousStatus.id
|
return previousStatus.id != contextParentID && status.inReplyToId == previousStatus.id
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasReplyFollowing(status: Status) -> Bool {
|
public func hasReplyFollowing(status: Status) -> Bool {
|
||||||
let flatContext = flattenedContext()
|
let flatContext = flattenedContext()
|
||||||
|
|
||||||
guard
|
guard
|
||||||
|
@ -66,7 +66,7 @@ extension ContextService: StatusListService {
|
||||||
return status.id != contextParentID && nextStatus.inReplyToId == status.id
|
return status.id != contextParentID && nextStatus.inReplyToId == status.id
|
||||||
}
|
}
|
||||||
|
|
||||||
func request(maxID: String?, minID: String?) -> AnyPublisher<Never, Error> {
|
public func request(maxID: String?, minID: String?) -> AnyPublisher<Never, Error> {
|
||||||
Publishers.Merge(
|
Publishers.Merge(
|
||||||
networkClient.request(StatusEndpoint.status(id: status.id))
|
networkClient.request(StatusEndpoint.status(id: status.id))
|
||||||
.map { ([$0], collection) }
|
.map { ([$0], collection) }
|
||||||
|
@ -78,11 +78,11 @@ extension ContextService: StatusListService {
|
||||||
.eraseToAnyPublisher()
|
.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
func statusService(status: Status) -> StatusService {
|
public func statusService(status: Status) -> StatusService {
|
||||||
StatusService(status: status, networkClient: networkClient, contentDatabase: contentDatabase)
|
StatusService(status: status, networkClient: networkClient, contentDatabase: contentDatabase)
|
||||||
}
|
}
|
||||||
|
|
||||||
func contextService(status: Status) -> ContextService {
|
public func contextService(status: Status) -> ContextService {
|
||||||
ContextService(status: status.displayStatus, networkClient: networkClient, contentDatabase: contentDatabase)
|
ContextService(status: status.displayStatus, networkClient: networkClient, contentDatabase: contentDatabase)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,7 +4,7 @@ import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
import Mastodon
|
import Mastodon
|
||||||
|
|
||||||
protocol StatusListService {
|
public protocol StatusListService {
|
||||||
var statusSections: AnyPublisher<[[Status]], Error> { get }
|
var statusSections: AnyPublisher<[[Status]], Error> { get }
|
||||||
var filters: AnyPublisher<[Filter], Error> { get }
|
var filters: AnyPublisher<[Filter], Error> { get }
|
||||||
var paginates: Bool { get }
|
var paginates: Bool { get }
|
||||||
|
@ -17,7 +17,7 @@ protocol StatusListService {
|
||||||
func contextService(status: Status) -> ContextService
|
func contextService(status: Status) -> ContextService
|
||||||
}
|
}
|
||||||
|
|
||||||
extension StatusListService {
|
public extension StatusListService {
|
||||||
var paginates: Bool { true }
|
var paginates: Bool { true }
|
||||||
|
|
||||||
var contextParentID: String? { nil }
|
var contextParentID: String? { nil }
|
|
@ -4,8 +4,8 @@ import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
import Mastodon
|
import Mastodon
|
||||||
|
|
||||||
struct StatusService {
|
public struct StatusService {
|
||||||
let status: Status
|
public let status: Status
|
||||||
private let networkClient: APIClient
|
private let networkClient: APIClient
|
||||||
private let contentDatabase: ContentDatabase
|
private let contentDatabase: ContentDatabase
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ struct StatusService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension StatusService {
|
public extension StatusService {
|
||||||
func toggleFavorited() -> AnyPublisher<Never, Error> {
|
func toggleFavorited() -> AnyPublisher<Never, Error> {
|
||||||
networkClient.request(status.favourited
|
networkClient.request(status.favourited
|
||||||
? StatusEndpoint.unfavourite(id: status.id)
|
? StatusEndpoint.unfavourite(id: status.id)
|
|
@ -4,10 +4,10 @@ import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
import UserNotifications
|
import UserNotifications
|
||||||
|
|
||||||
class UserNotificationService: NSObject {
|
public class UserNotificationService: NSObject {
|
||||||
private let userNotificationCenter: UNUserNotificationCenter
|
private let userNotificationCenter: UNUserNotificationCenter
|
||||||
|
|
||||||
init(userNotificationCenter: UNUserNotificationCenter = .current()) {
|
public init(userNotificationCenter: UNUserNotificationCenter = .current()) {
|
||||||
self.userNotificationCenter = userNotificationCenter
|
self.userNotificationCenter = userNotificationCenter
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
@ -16,7 +16,7 @@ class UserNotificationService: NSObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension UserNotificationService {
|
public extension UserNotificationService {
|
||||||
func isAuthorized() -> AnyPublisher<Bool, Error> {
|
func isAuthorized() -> AnyPublisher<Bool, Error> {
|
||||||
getNotificationSettings()
|
getNotificationSettings()
|
||||||
.map(\.authorizationStatus)
|
.map(\.authorizationStatus)
|
||||||
|
@ -59,7 +59,7 @@ private extension UserNotificationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension UserNotificationService: UNUserNotificationCenterDelegate {
|
extension UserNotificationService: UNUserNotificationCenterDelegate {
|
||||||
func userNotificationCenter(
|
public func userNotificationCenter(
|
||||||
_ center: UNUserNotificationCenter,
|
_ center: UNUserNotificationCenter,
|
||||||
willPresent notification: UNNotification,
|
willPresent notification: UNNotification,
|
||||||
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
|
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
|
|
@ -3,11 +3,12 @@
|
||||||
import XCTest
|
import XCTest
|
||||||
import Combine
|
import Combine
|
||||||
import CombineExpectations
|
import CombineExpectations
|
||||||
@testable import Metatext
|
@testable import Services
|
||||||
|
@testable import ServiceMocks
|
||||||
|
|
||||||
class AuthenticationServiceTests: XCTestCase {
|
class AuthenticationServiceTests: XCTestCase {
|
||||||
func testAuthentication() throws {
|
func testAuthentication() throws {
|
||||||
let sut = AuthenticationService(environment: .development)
|
let sut = AuthenticationService(environment: .mock)
|
||||||
let instanceURL = URL(string: "https://mastodon.social")!
|
let instanceURL = URL(string: "https://mastodon.social")!
|
||||||
let appAuthorizationRecorder = sut.authorizeApp(instanceURL: instanceURL).record()
|
let appAuthorizationRecorder = sut.authorizeApp(instanceURL: instanceURL).record()
|
||||||
let appAuthorization = try wait(for: appAuthorizationRecorder.next(), timeout: 1)
|
let appAuthorization = try wait(for: appAuthorizationRecorder.next(), timeout: 1)
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright © 2020 Metabolist. All rights reserved.
|
// Copyright © 2020 Metabolist. All rights reserved.
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import Services
|
||||||
|
|
||||||
@main
|
@main
|
||||||
struct MetatextApp: App {
|
struct MetatextApp: App {
|
||||||
|
@ -8,23 +9,13 @@ struct MetatextApp: App {
|
||||||
@UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
|
@UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
|
||||||
// swiftlint:enable weak_delegate
|
// swiftlint:enable weak_delegate
|
||||||
|
|
||||||
private let allIdentitiesService: AllIdentitiesService = {
|
|
||||||
let identityDatabase: IdentityDatabase
|
|
||||||
|
|
||||||
do {
|
|
||||||
try identityDatabase = IdentityDatabase()
|
|
||||||
} catch {
|
|
||||||
fatalError("Failed to initialize identity database")
|
|
||||||
}
|
|
||||||
|
|
||||||
return AllIdentitiesService(identityDatabase: identityDatabase, environment: .live)
|
|
||||||
}()
|
|
||||||
|
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
WindowGroup {
|
WindowGroup {
|
||||||
RootView(
|
RootView(
|
||||||
viewModel: RootViewModel(appDelegate: appDelegate,
|
viewModel: RootViewModel(appDelegate: appDelegate,
|
||||||
allIdentitiesService: allIdentitiesService,
|
// swiftlint:disable force_try
|
||||||
|
allIdentitiesService: try! AllIdentitiesService(environment: .live),
|
||||||
|
// swiftlint:enable force_try
|
||||||
userNotificationService: UserNotificationService()))
|
userNotificationService: UserNotificationService()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,11 @@ import HTTP
|
||||||
import Mastodon
|
import Mastodon
|
||||||
@testable import Metatext
|
@testable import Metatext
|
||||||
|
|
||||||
|
import Services
|
||||||
|
|
||||||
class AddIdentityViewModelTests: XCTestCase {
|
class AddIdentityViewModelTests: XCTestCase {
|
||||||
func testAddIdentity() throws {
|
func testAddIdentity() throws {
|
||||||
let identityDatabase = IdentityDatabase.fresh()
|
let sut = AddIdentityViewModel(allIdentitiesService: .fresh)
|
||||||
let sut = AddIdentityViewModel(allIdentitiesService: .fresh(identityDatabase: identityDatabase))
|
|
||||||
let addedIDRecorder = sut.addedIdentityID.record()
|
let addedIDRecorder = sut.addedIdentityID.record()
|
||||||
|
|
||||||
sut.urlFieldText = "https://mastodon.social"
|
sut.urlFieldText = "https://mastodon.social"
|
||||||
|
@ -20,8 +21,7 @@ class AddIdentityViewModelTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAddIdentityWithoutScheme() throws {
|
func testAddIdentityWithoutScheme() throws {
|
||||||
let identityDatabase = IdentityDatabase.fresh()
|
let sut = AddIdentityViewModel(allIdentitiesService: .fresh)
|
||||||
let sut = AddIdentityViewModel(allIdentitiesService: .fresh(identityDatabase: identityDatabase))
|
|
||||||
let addedIDRecorder = sut.addedIdentityID.record()
|
let addedIDRecorder = sut.addedIdentityID.record()
|
||||||
|
|
||||||
sut.urlFieldText = "mastodon.social"
|
sut.urlFieldText = "mastodon.social"
|
||||||
|
@ -31,7 +31,7 @@ class AddIdentityViewModelTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testInvalidURL() throws {
|
func testInvalidURL() throws {
|
||||||
let sut = AddIdentityViewModel(allIdentitiesService: .fresh())
|
let sut = AddIdentityViewModel(allIdentitiesService: .fresh)
|
||||||
let recorder = sut.$alertItem.record()
|
let recorder = sut.$alertItem.record()
|
||||||
|
|
||||||
XCTAssertNil(try wait(for: recorder.next(), timeout: 1))
|
XCTAssertNil(try wait(for: recorder.next(), timeout: 1))
|
||||||
|
@ -51,9 +51,7 @@ class AddIdentityViewModelTests: XCTestCase {
|
||||||
keychainServiceType: MockKeychainService.self,
|
keychainServiceType: MockKeychainService.self,
|
||||||
userDefaults: MockUserDefaults(),
|
userDefaults: MockUserDefaults(),
|
||||||
inMemoryContent: true)
|
inMemoryContent: true)
|
||||||
let allIdentitiesService = AllIdentitiesService(
|
let allIdentitiesService = try AllIdentitiesService(environment: environment)
|
||||||
identityDatabase: .fresh(),
|
|
||||||
environment: environment)
|
|
||||||
let sut = AddIdentityViewModel(allIdentitiesService: allIdentitiesService)
|
let sut = AddIdentityViewModel(allIdentitiesService: allIdentitiesService)
|
||||||
let recorder = sut.$alertItem.record()
|
let recorder = sut.$alertItem.record()
|
||||||
|
|
||||||
|
@ -64,4 +62,8 @@ class AddIdentityViewModelTests: XCTestCase {
|
||||||
|
|
||||||
try wait(for: recorder.next().inverted, timeout: 1)
|
try wait(for: recorder.next().inverted, timeout: 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testFuck() {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import XCTest
|
import XCTest
|
||||||
import Combine
|
import Combine
|
||||||
import CombineExpectations
|
import CombineExpectations
|
||||||
|
import Services
|
||||||
@testable import Metatext
|
@testable import Metatext
|
||||||
|
|
||||||
class RootViewModelTests: XCTestCase {
|
class RootViewModelTests: XCTestCase {
|
||||||
|
@ -10,9 +11,7 @@ class RootViewModelTests: XCTestCase {
|
||||||
|
|
||||||
func testAddIdentity() throws {
|
func testAddIdentity() throws {
|
||||||
let sut = RootViewModel(appDelegate: AppDelegate(),
|
let sut = RootViewModel(appDelegate: AppDelegate(),
|
||||||
allIdentitiesService: AllIdentitiesService(
|
allIdentitiesService: .fresh,
|
||||||
identityDatabase: .fresh(),
|
|
||||||
environment: .development),
|
|
||||||
userNotificationService: UserNotificationService())
|
userNotificationService: UserNotificationService())
|
||||||
let recorder = sut.$tabNavigationViewModel.record()
|
let recorder = sut.$tabNavigationViewModel.record()
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
|
import Services
|
||||||
|
|
||||||
class AddIdentityViewModel: ObservableObject {
|
class AddIdentityViewModel: ObservableObject {
|
||||||
@Published var urlFieldText = ""
|
@Published var urlFieldText = ""
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
import Mastodon
|
import Mastodon
|
||||||
|
import Services
|
||||||
|
|
||||||
class EditFilterViewModel: ObservableObject {
|
class EditFilterViewModel: ObservableObject {
|
||||||
@Published var filter: Filter
|
@Published var filter: Filter
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
import Mastodon
|
import Mastodon
|
||||||
|
import Services
|
||||||
|
|
||||||
class FiltersViewModel: ObservableObject {
|
class FiltersViewModel: ObservableObject {
|
||||||
@Published var activeFilters = [Filter]()
|
@Published var activeFilters = [Filter]()
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import Combine
|
import Combine
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import Services
|
||||||
|
|
||||||
class IdentitiesViewModel: ObservableObject {
|
class IdentitiesViewModel: ObservableObject {
|
||||||
@Published private(set) var identity: Identity
|
@Published private(set) var identity: Identity
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
import Mastodon
|
import Mastodon
|
||||||
|
import Services
|
||||||
|
|
||||||
class ListsViewModel: ObservableObject {
|
class ListsViewModel: ObservableObject {
|
||||||
@Published private(set) var lists = [MastodonList]()
|
@Published private(set) var lists = [MastodonList]()
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
import Mastodon
|
import Mastodon
|
||||||
|
import Services
|
||||||
|
|
||||||
class NotificationTypesPreferencesViewModel: ObservableObject {
|
class NotificationTypesPreferencesViewModel: ObservableObject {
|
||||||
@Published var pushSubscriptionAlerts: PushSubscription.Alerts
|
@Published var pushSubscriptionAlerts: PushSubscription.Alerts
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
|
import Services
|
||||||
|
|
||||||
class PostingReadingPreferencesViewModel: ObservableObject {
|
class PostingReadingPreferencesViewModel: ObservableObject {
|
||||||
@Published var preferences: Identity.Preferences
|
@Published var preferences: Identity.Preferences
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright © 2020 Metabolist. All rights reserved.
|
// Copyright © 2020 Metabolist. All rights reserved.
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import Services
|
||||||
|
|
||||||
class PreferencesViewModel: ObservableObject {
|
class PreferencesViewModel: ObservableObject {
|
||||||
let handle: String
|
let handle: String
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
|
import Services
|
||||||
|
|
||||||
class RootViewModel: ObservableObject {
|
class RootViewModel: ObservableObject {
|
||||||
@Published private(set) var tabNavigationViewModel: TabNavigationViewModel?
|
@Published private(set) var tabNavigationViewModel: TabNavigationViewModel?
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright © 2020 Metabolist. All rights reserved.
|
// Copyright © 2020 Metabolist. All rights reserved.
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import Services
|
||||||
|
|
||||||
class SecondaryNavigationViewModel: ObservableObject {
|
class SecondaryNavigationViewModel: ObservableObject {
|
||||||
@Published private(set) var identity: Identity
|
@Published private(set) var identity: Identity
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
import Mastodon
|
import Mastodon
|
||||||
|
import Services
|
||||||
|
|
||||||
class StatusListViewModel: ObservableObject {
|
class StatusListViewModel: ObservableObject {
|
||||||
@Published private(set) var statusIDs = [[String]]()
|
@Published private(set) var statusIDs = [[String]]()
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
import Mastodon
|
import Mastodon
|
||||||
|
import Services
|
||||||
|
|
||||||
struct StatusViewModel {
|
struct StatusViewModel {
|
||||||
let content: NSAttributedString
|
let content: NSAttributedString
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
import Mastodon
|
import Mastodon
|
||||||
|
import Services
|
||||||
|
|
||||||
class TabNavigationViewModel: ObservableObject {
|
class TabNavigationViewModel: ObservableObject {
|
||||||
@Published private(set) var identity: Identity
|
@Published private(set) var identity: Identity
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import KingfisherSwiftUI
|
import KingfisherSwiftUI
|
||||||
|
import struct Services.Identity
|
||||||
|
|
||||||
struct IdentitiesView: View {
|
struct IdentitiesView: View {
|
||||||
@StateObject var viewModel: IdentitiesViewModel
|
@StateObject var viewModel: IdentitiesViewModel
|
||||||
|
|
Loading…
Reference in a new issue