mirror of
https://github.com/metabolist/metatext.git
synced 2024-11-21 15:50:59 +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 HTTP
|
||||
import Mastodon
|
||||
import Services
|
||||
import ServiceMocks
|
||||
|
||||
// swiftlint:disable force_try
|
||||
private let decoder = APIDecoder()
|
||||
|
@ -20,31 +22,6 @@ extension Instance {
|
|||
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 {
|
||||
static let development = AppEnvironment(
|
||||
session: Session(configuration: .stubbing),
|
||||
|
@ -55,18 +32,30 @@ extension AppEnvironment {
|
|||
}
|
||||
|
||||
extension AllIdentitiesService {
|
||||
static func fresh(
|
||||
identityDatabase: IdentityDatabase = .fresh(),
|
||||
keychainService: KeychainService = MockKeychainService(),
|
||||
environment: AppEnvironment = .development) -> AllIdentitiesService {
|
||||
AllIdentitiesService(
|
||||
identityDatabase: identityDatabase,
|
||||
environment: environment)
|
||||
}
|
||||
static let fresh = try! AllIdentitiesService(environment: .development)
|
||||
|
||||
static let development = AllIdentitiesService(
|
||||
identityDatabase: .development,
|
||||
environment: .development)
|
||||
static var development: Self = {
|
||||
let allIdentitiesService = try! AllIdentitiesService(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 {
|
||||
|
|
|
@ -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: [
|
||||
.library(
|
||||
name: "HTTP",
|
||||
targets: ["HTTP"])
|
||||
targets: ["HTTP"]),
|
||||
.library(
|
||||
name: "Stubbing",
|
||||
targets: ["Stubbing"])
|
||||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/Alamofire/Alamofire.git", .upToNextMajor(from: "5.2.2"))
|
||||
|
@ -20,6 +23,9 @@ let package = Package(
|
|||
.target(
|
||||
name: "HTTP",
|
||||
dependencies: ["Alamofire"]),
|
||||
.target(
|
||||
name: "Stubbing",
|
||||
dependencies: ["HTTP"]),
|
||||
.testTarget(
|
||||
name: "HTTPTests",
|
||||
dependencies: ["HTTP"])
|
||||
|
|
|
@ -2,16 +2,16 @@
|
|||
|
||||
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 data(url: URL) -> Data?
|
||||
func dataString(url: URL) -> String?
|
||||
func statusCode(url: URL) -> Int?
|
||||
}
|
||||
|
||||
extension Stubbing {
|
||||
public extension Stubbing {
|
||||
func stub(url: URL) -> HTTPStub? {
|
||||
if let data = data(url: url),
|
||||
let statusCode = statusCode(url: url),
|
|
@ -3,25 +3,25 @@
|
|||
import Foundation
|
||||
import HTTP
|
||||
|
||||
class StubbingURLProtocol: URLProtocol {
|
||||
public class StubbingURLProtocol: URLProtocol {
|
||||
private static var targetsForURLs = [URL: Target]()
|
||||
|
||||
override class func canInit(with task: URLSessionTask) -> Bool {
|
||||
override public class func canInit(with task: URLSessionTask) -> Bool {
|
||||
true
|
||||
}
|
||||
|
||||
override class func canInit(with request: URLRequest) -> Bool {
|
||||
override public class func canInit(with request: URLRequest) -> Bool {
|
||||
true
|
||||
}
|
||||
|
||||
override class func canonicalRequest(for request: URLRequest) -> URLRequest {
|
||||
override public class func canonicalRequest(for request: URLRequest) -> URLRequest {
|
||||
request
|
||||
}
|
||||
|
||||
override func startLoading() {
|
||||
override public func startLoading() {
|
||||
guard
|
||||
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")
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
static func process(target: Target) {
|
||||
public static func process(target: Target) {
|
||||
if let url = try? target.asURLRequest().url {
|
||||
targetsForURLs[url] = target
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
extension URLSessionConfiguration {
|
||||
public extension URLSessionConfiguration {
|
||||
static var stubbing: URLSessionConfiguration {
|
||||
let configuration = Self.default
|
||||
|
|
@ -11,7 +11,10 @@ let package = Package(
|
|||
products: [
|
||||
.library(
|
||||
name: "Mastodon",
|
||||
targets: ["Mastodon"])
|
||||
targets: ["Mastodon"]),
|
||||
.library(
|
||||
name: "MastodonStubs",
|
||||
targets: ["MastodonStubs"])
|
||||
],
|
||||
dependencies: [
|
||||
.package(path: "HTTP")
|
||||
|
@ -20,8 +23,12 @@ let package = Package(
|
|||
.target(
|
||||
name: "Mastodon",
|
||||
dependencies: ["HTTP"]),
|
||||
.target(
|
||||
name: "MastodonStubs",
|
||||
dependencies: ["Mastodon", .product(name: "Stubbing", package: "HTTP")],
|
||||
resources: [.process("Resources")]),
|
||||
.testTarget(
|
||||
name: "MastodonTests",
|
||||
dependencies: ["Mastodon"])
|
||||
dependencies: ["MastodonStubs"])
|
||||
]
|
||||
)
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
|
||||
import Foundation
|
||||
import Mastodon
|
||||
import Stubbing
|
||||
|
||||
extension AccessTokenEndpoint: Stubbing {
|
||||
func dataString(url: URL) -> String? {
|
||||
public func dataString(url: URL) -> String? {
|
||||
switch self {
|
||||
case let .oauthToken(_, _, _, _, scopes, _):
|
||||
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 Mastodon
|
||||
import Stubbing
|
||||
|
||||
extension AppAuthorizationEndpoint: Stubbing {
|
||||
func dataString(url: URL) -> String? {
|
||||
public func dataString(url: URL) -> String? {
|
||||
switch self {
|
||||
case let .apps(clientName, redirectURI, _, _):
|
||||
return """
|
|
@ -2,9 +2,10 @@
|
|||
|
||||
import Foundation
|
||||
import Mastodon
|
||||
import Stubbing
|
||||
|
||||
extension ContextEndpoint: Stubbing {
|
||||
func dataString(url: URL) -> String? {
|
||||
public func dataString(url: URL) -> String? {
|
||||
switch self {
|
||||
case .context:
|
||||
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 Mastodon
|
||||
import Stubbing
|
||||
|
||||
extension APITarget: Stubbing {
|
||||
func stub(url: URL) -> HTTPStub? {
|
||||
public func stub(url: URL) -> HTTPStub? {
|
||||
(endpoint as? Stubbing)?.stub(url: url)
|
||||
}
|
||||
|
||||
func data(url: URL) -> Data? {
|
||||
public func data(url: URL) -> Data? {
|
||||
(endpoint as? Stubbing)?.data(url: url)
|
||||
}
|
||||
|
||||
func dataString(url: URL) -> String? {
|
||||
public func dataString(url: URL) -> String? {
|
||||
(endpoint as? Stubbing)?.dataString(url: url)
|
||||
}
|
||||
|
||||
func statusCode(url: URL) -> Int? {
|
||||
public func statusCode(url: URL) -> Int? {
|
||||
(endpoint as? Stubbing)?.statusCode(url: url)
|
||||
}
|
||||
}
|
|
@ -2,9 +2,10 @@
|
|||
|
||||
import Foundation
|
||||
import Mastodon
|
||||
import Stubbing
|
||||
|
||||
extension PreferencesEndpoint: Stubbing {
|
||||
func dataString(url: URL) -> String? {
|
||||
public func dataString(url: URL) -> String? {
|
||||
switch self {
|
||||
case .preferences:
|
||||
return """
|
|
@ -1,10 +1,3 @@
|
|||
// Copyright © 2020 Metabolist. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import Mastodon
|
||||
|
||||
// swiftlint:disable line_length
|
||||
let officialAccountJSON = #"""
|
||||
{
|
||||
"id": "13179",
|
||||
"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",
|
||||
"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 */; };
|
||||
D01F41DF24F8868800D55A2D /* AttachmentViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F41DE24F8868800D55A2D /* AttachmentViewModel.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 */; };
|
||||
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 */; };
|
||||
D0666A4924C6C1A300F3F04B /* GRDB in Frameworks */ = {isa = PBXBuildFile; productRef = D0666A4824C6C1A300F3F04B /* GRDB */; };
|
||||
D06B492324D4611300642749 /* KingfisherSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = D06B492224D4611300642749 /* KingfisherSwiftUI */; };
|
||||
D074577724D29006004758DB /* MockWebAuthSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D074577624D29006004758DB /* MockWebAuthSession.swift */; };
|
||||
D074577A24D29366004758DB /* URLSessionConfiguration+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D074577924D29366004758DB /* URLSessionConfiguration+Extensions.swift */; };
|
||||
D0A652AD24DE3EB6002EA33F /* PreferencesEndpoint+Stubbing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A652AC24DE3EB6002EA33F /* PreferencesEndpoint+Stubbing.swift */; };
|
||||
D075C28524FCD41D00D35112 /* Services in Frameworks */ = {isa = PBXBuildFile; productRef = D075C28424FCD41D00D35112 /* Services */; };
|
||||
D075C28724FCD92400D35112 /* Services in Frameworks */ = {isa = PBXBuildFile; productRef = D075C28624FCD92400D35112 /* Services */; };
|
||||
D0ADCBF124FD05510062ACCE /* ServiceMocks in Frameworks */ = {isa = PBXBuildFile; productRef = D0ADCBF024FD05510062ACCE /* ServiceMocks */; };
|
||||
D0BEB1F324F8EE8C001B0F04 /* AttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1F224F8EE8C001B0F04 /* AttachmentView.swift */; };
|
||||
D0BEB1F724F9A84B001B0F04 /* LoadingTableFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1F624F9A84B001B0F04 /* LoadingTableFooterView.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 */; };
|
||||
D0C7D4A324F7616A001EBDBB /* TabNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D42E24F76169001EBDBB /* TabNavigationView.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 */; };
|
||||
D0C7D4C224F7616A001EBDBB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D0C7D45224F76169001EBDBB /* Assets.xcassets */; };
|
||||
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 */; };
|
||||
D0C7D4CF24F7616A001EBDBB /* StatusViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D46224F76169001EBDBB /* StatusViewModel.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 */; };
|
||||
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 */; };
|
||||
|
@ -76,32 +62,8 @@
|
|||
D0C7D4DA24F7616A001EBDBB /* View+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D46F24F76169001EBDBB /* View+Extensions.swift */; };
|
||||
D0C7D4DB24F7616A001EBDBB /* Date+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D47024F76169001EBDBB /* Date+Extensions.swift */; };
|
||||
D0C7D4DC24F7616A001EBDBB /* Data+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D47124F76169001EBDBB /* Data+Extensions.swift */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
|
@ -142,20 +104,12 @@
|
|||
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>"; };
|
||||
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; };
|
||||
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>"; };
|
||||
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; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
D075C28324FCD27300D35112 /* Services */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Services; 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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
|
@ -197,10 +148,6 @@
|
|||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
|
@ -209,30 +156,11 @@
|
|||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
|
@ -241,9 +169,9 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D075C28524FCD41D00D35112 /* Services in Frameworks */,
|
||||
D0ADCBF124FD05510062ACCE /* ServiceMocks in Frameworks */,
|
||||
D06B492324D4611300642749 /* KingfisherSwiftUI in Frameworks */,
|
||||
D0E0F1E624FC4B76002C04BF /* Mastodon in Frameworks */,
|
||||
D0666A4924C6C1A300F3F04B /* GRDB in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -259,7 +187,7 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D0E0F1E824FC5A61002C04BF /* Mastodon in Frameworks */,
|
||||
D075C28724FCD92400D35112 /* Services in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -289,7 +217,6 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
D0C7D45224F76169001EBDBB /* Assets.xcassets */,
|
||||
D0C7D46424F76169001EBDBB /* Databases */,
|
||||
D0ED1BB224CE3A1600B4899C /* Development Assets */,
|
||||
D0C7D46824F76169001EBDBB /* Extensions */,
|
||||
D0666A7924C7745A00F3F04B /* Frameworks */,
|
||||
|
@ -297,10 +224,9 @@
|
|||
D0C7D45624F76169001EBDBB /* Localizations */,
|
||||
D0E0F1E424FC49FC002C04BF /* Mastodon */,
|
||||
D0C7D43824F76169001EBDBB /* Model */,
|
||||
D0C7D47324F76169001EBDBB /* Networking */,
|
||||
D0E5361A24E3EB4D00FB1CE1 /* Notification Service Extension */,
|
||||
D047FA8D24C3E21200AF17C5 /* Products */,
|
||||
D0C7D48924F76169001EBDBB /* Services */,
|
||||
D075C28324FCD27300D35112 /* Services */,
|
||||
D0C7D41D24F76169001EBDBB /* Supporting Files */,
|
||||
D0C7D45324F76169001EBDBB /* System */,
|
||||
D0666A2224C677B400F3F04B /* Tests */,
|
||||
|
@ -324,7 +250,6 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
D0666A2524C677B400F3F04B /* Info.plist */,
|
||||
D0EC8DD024DFE34F00A08489 /* Services */,
|
||||
D0ED1B6C24CE0EED00B4899C /* View Models */,
|
||||
);
|
||||
path = Tests;
|
||||
|
@ -381,9 +306,6 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
D0C7D45024F76169001EBDBB /* AlertItem.swift */,
|
||||
D0C7D44F24F76169001EBDBB /* AppEnvironment.swift */,
|
||||
D0C7D43B24F76169001EBDBB /* Identity.swift */,
|
||||
D0C7D44724F76169001EBDBB /* TransientStatusCollection.swift */,
|
||||
);
|
||||
path = Model;
|
||||
sourceTree = "<group>";
|
||||
|
@ -427,23 +349,12 @@
|
|||
path = "View Models";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D0C7D46424F76169001EBDBB /* Databases */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D0C7D46624F76169001EBDBB /* ContentDatabase.swift */,
|
||||
D0C7D46724F76169001EBDBB /* DatabaseError.swift */,
|
||||
D0C7D46524F76169001EBDBB /* IdentityDatabase.swift */,
|
||||
);
|
||||
path = Databases;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D0C7D46824F76169001EBDBB /* Extensions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D0C7D47124F76169001EBDBB /* Data+Extensions.swift */,
|
||||
D0C7D47024F76169001EBDBB /* Date+Extensions.swift */,
|
||||
D0C7D46E24F76169001EBDBB /* KingfisherOptionsInfo+Extensions.swift */,
|
||||
D0C7D46924F76169001EBDBB /* NSError+Extensions.swift */,
|
||||
D0C7D46B24F76169001EBDBB /* NSMutableAttributedString+Extensions.swift */,
|
||||
D0C7D46D24F76169001EBDBB /* Publisher+Extensions.swift */,
|
||||
D0C7D46A24F76169001EBDBB /* String+Extensions.swift */,
|
||||
|
@ -453,54 +364,6 @@
|
|||
path = Extensions;
|
||||
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 */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -511,14 +374,6 @@
|
|||
path = "Notification Service Extension";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D0EC8DD024DFE34F00A08489 /* Services */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D0EC8DD324DFE38900A08489 /* AuthenticationServiceTests.swift */,
|
||||
);
|
||||
path = Services;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D0ED1B6C24CE0EED00B4899C /* View Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -531,16 +386,7 @@
|
|||
D0ED1BB224CE3A1600B4899C /* Development Assets */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D054950024EA4FFE008B00A5 /* DevelopmentAssets.xcassets */,
|
||||
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";
|
||||
sourceTree = "<group>";
|
||||
|
@ -565,9 +411,9 @@
|
|||
);
|
||||
name = Metatext;
|
||||
packageProductDependencies = (
|
||||
D0666A4824C6C1A300F3F04B /* GRDB */,
|
||||
D06B492224D4611300642749 /* KingfisherSwiftUI */,
|
||||
D0E0F1E524FC4B76002C04BF /* Mastodon */,
|
||||
D075C28424FCD41D00D35112 /* Services */,
|
||||
D0ADCBF024FD05510062ACCE /* ServiceMocks */,
|
||||
);
|
||||
productName = "Metatext (iOS)";
|
||||
productReference = D047FA8C24C3E21200AF17C5 /* Metatext.app */;
|
||||
|
@ -608,7 +454,7 @@
|
|||
);
|
||||
name = "Notification Service Extension";
|
||||
packageProductDependencies = (
|
||||
D0E0F1E724FC5A61002C04BF /* Mastodon */,
|
||||
D075C28624FCD92400D35112 /* Services */,
|
||||
);
|
||||
productName = "Notification Service Extension";
|
||||
productReference = D0E5361924E3EB4D00FB1CE1 /* Notification Service Extension.appex */;
|
||||
|
@ -647,7 +493,6 @@
|
|||
);
|
||||
mainGroup = D047FA7F24C3E21000AF17C5;
|
||||
packageReferences = (
|
||||
D0666A4724C6C1A300F3F04B /* XCRemoteSwiftPackageReference "GRDB" */,
|
||||
D065F53724D37E5100741304 /* XCRemoteSwiftPackageReference "CombineExpectations" */,
|
||||
D06B492124D4611300642749 /* XCRemoteSwiftPackageReference "Kingfisher" */,
|
||||
);
|
||||
|
@ -669,7 +514,6 @@
|
|||
files = (
|
||||
D0C7D4C524F7616A001EBDBB /* Localizable.strings in Resources */,
|
||||
D01F41D724F880C400D55A2D /* StatusTableViewCell.xib in Resources */,
|
||||
D054950124EA4FFE008B00A5 /* DevelopmentAssets.xcassets in Resources */,
|
||||
D0C7D4C224F7616A001EBDBB /* Assets.xcassets in Resources */,
|
||||
D0C7D4C624F7616A001EBDBB /* Localizable.stringsdict in Resources */,
|
||||
);
|
||||
|
@ -717,81 +561,48 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D0C7D4CA24F7616A001EBDBB /* NotificationTypesPreferencesViewModel.swift in Sources */,
|
||||
D0C7D4F424F7616A001EBDBB /* StatusListService.swift in Sources */,
|
||||
D0C7D4B724F7616A001EBDBB /* TransientStatusCollection.swift in Sources */,
|
||||
D01F41DF24F8868800D55A2D /* AttachmentViewModel.swift in Sources */,
|
||||
D0C7D4A324F7616A001EBDBB /* TabNavigationView.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 */,
|
||||
D0C7D4FA24F7616A001EBDBB /* AllIdentitiesService.swift in Sources */,
|
||||
D0C7D4CD24F7616A001EBDBB /* AddIdentityViewModel.swift in Sources */,
|
||||
D03658D124EDD80900AC17EC /* ContextEndpoint+Stubbing.swift in Sources */,
|
||||
D0BEB1F324F8EE8C001B0F04 /* AttachmentView.swift in Sources */,
|
||||
D0DC174A24CFF15F00A75C65 /* AppAuthorizationEndpoint+Stubbing.swift in Sources */,
|
||||
D0C7D49A24F7616A001EBDBB /* StatusListView.swift in Sources */,
|
||||
D01F41D924F880C400D55A2D /* TouchFallthroughTextView.swift in Sources */,
|
||||
D0C7D4A524F7616A001EBDBB /* StatusListViewController.swift in Sources */,
|
||||
D0C7D4CC24F7616A001EBDBB /* IdentitiesViewModel.swift in Sources */,
|
||||
D0C7D4E024F7616A001EBDBB /* WebAuthSession.swift in Sources */,
|
||||
D0C7D4CB24F7616A001EBDBB /* RootViewModel.swift in Sources */,
|
||||
D0C7D4CE24F7616A001EBDBB /* PreferencesViewModel.swift in Sources */,
|
||||
D0C7D4D124F7616A001EBDBB /* IdentityDatabase.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 */,
|
||||
D0C7D4D024F7616A001EBDBB /* StatusListViewModel.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 */,
|
||||
D0C7D4DA24F7616A001EBDBB /* View+Extensions.swift in Sources */,
|
||||
D0C7D4C824F7616A001EBDBB /* SecondaryNavigationViewModel.swift in Sources */,
|
||||
D0C7D4D524F7616A001EBDBB /* String+Extensions.swift in Sources */,
|
||||
D0C7D4AB24F7616A001EBDBB /* Identity.swift in Sources */,
|
||||
D0C7D4C024F7616A001EBDBB /* AlertItem.swift in Sources */,
|
||||
D0C7D4A224F7616A001EBDBB /* NotificationTypesPreferencesView.swift in Sources */,
|
||||
D0C7D4CF24F7616A001EBDBB /* StatusViewModel.swift in Sources */,
|
||||
D0C7D4C724F7616A001EBDBB /* PostingReadingPreferencesViewModel.swift in Sources */,
|
||||
D0BEB1F724F9A84B001B0F04 /* LoadingTableFooterView.swift in Sources */,
|
||||
D0DC175224D008E300A75C65 /* MastodonTarget+Stubbing.swift in Sources */,
|
||||
D0C7D4F124F7616A001EBDBB /* IdentityService.swift in Sources */,
|
||||
D04FD74224D4AA34007D572D /* DevelopmentModels.swift in Sources */,
|
||||
D0C7D4F524F7616A001EBDBB /* AuthenticationService.swift in Sources */,
|
||||
D0DC175824D0130800A75C65 /* HTTPStubs.swift in Sources */,
|
||||
D0C7D4D924F7616A001EBDBB /* KingfisherOptionsInfo+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 */,
|
||||
D0C7D4F824F7616A001EBDBB /* SecretsService.swift in Sources */,
|
||||
D0C7D4F624F7616A001EBDBB /* KeychainService.swift in Sources */,
|
||||
D0DC174D24CFF1F100A75C65 /* Stubbing.swift in Sources */,
|
||||
D0C7D49724F7616A001EBDBB /* IdentitiesView.swift in Sources */,
|
||||
D074577724D29006004758DB /* MockWebAuthSession.swift in Sources */,
|
||||
D0C7D4F924F7616A001EBDBB /* UserNotificationService.swift in Sources */,
|
||||
D0C7D49824F7616A001EBDBB /* CustomEmojiText.swift in Sources */,
|
||||
D01F41E424F8889700D55A2D /* AttachmentsView.swift in Sources */,
|
||||
D0BEB20724FA1121001B0F04 /* FiltersViewModel.swift in Sources */,
|
||||
D0C7D4C924F7616A001EBDBB /* TabNavigationViewModel.swift in Sources */,
|
||||
D0BEB21124FA2A91001B0F04 /* EditFilterView.swift in Sources */,
|
||||
D0C7D4C424F7616A001EBDBB /* AppDelegate.swift in Sources */,
|
||||
D074577A24D29366004758DB /* URLSessionConfiguration+Extensions.swift in Sources */,
|
||||
D0C7D49924F7616A001EBDBB /* AddIdentityView.swift in Sources */,
|
||||
D0BEB1FD24F9E4E5001B0F04 /* ListsViewModel.swift in Sources */,
|
||||
D0C7D4C324F7616A001EBDBB /* MetatextApp.swift in Sources */,
|
||||
D0C7D4F324F7616A001EBDBB /* ContextService.swift in Sources */,
|
||||
D0C7D4D824F7616A001EBDBB /* Publisher+Extensions.swift in Sources */,
|
||||
D0BEB20524FA1107001B0F04 /* FiltersView.swift in Sources */,
|
||||
D01F41D824F880C400D55A2D /* StatusTableViewCell.swift in Sources */,
|
||||
D04FD73C24D4A83A007D572D /* InstanceEndpoint+Stubbing.swift in Sources */,
|
||||
D0C7D49B24F7616A001EBDBB /* PreferencesView.swift in Sources */,
|
||||
D0C7D4D724F7616A001EBDBB /* UIColor+Extensions.swift in Sources */,
|
||||
);
|
||||
|
@ -801,7 +612,6 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D0EC8DD424DFE38900A08489 /* AuthenticationServiceTests.swift in Sources */,
|
||||
D0ED1B6E24CE100C00B4899C /* AddIdentityViewModelTests.swift in Sources */,
|
||||
D052BBC724D749C800A80A7A /* RootViewModelTests.swift in Sources */,
|
||||
);
|
||||
|
@ -811,10 +621,7 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D0C7D4FE24F761C9001EBDBB /* SecretsService.swift in Sources */,
|
||||
D0E5361C24E3EB4D00FB1CE1 /* NotificationService.swift in Sources */,
|
||||
D0C7D50024F761E0001EBDBB /* NSError+Extensions.swift in Sources */,
|
||||
D0C7D4FF24F761D0001EBDBB /* KeychainService.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -953,7 +760,7 @@
|
|||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_ENTITLEMENTS = "Supporting Files/Metatext.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_ASSET_PATHS = "Development\\ Assets Development\\ Assets/Mastodon\\ API\\ Stubs";
|
||||
DEVELOPMENT_ASSET_PATHS = "Development\\ Assets";
|
||||
DEVELOPMENT_TEAM = 82HL67AXQ2;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
INFOPLIST_FILE = "Supporting Files/Info.plist";
|
||||
|
@ -979,7 +786,7 @@
|
|||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_ENTITLEMENTS = "Supporting Files/Metatext.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_ASSET_PATHS = "Development\\ Assets Development\\ Assets/Mastodon\\ API\\ Stubs";
|
||||
DEVELOPMENT_ASSET_PATHS = "Development\\ Assets";
|
||||
DEVELOPMENT_TEAM = 82HL67AXQ2;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
INFOPLIST_FILE = "Supporting Files/Info.plist";
|
||||
|
@ -1143,14 +950,6 @@
|
|||
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" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/onevcat/Kingfisher";
|
||||
|
@ -1167,23 +966,22 @@
|
|||
package = D065F53724D37E5100741304 /* XCRemoteSwiftPackageReference "CombineExpectations" */;
|
||||
productName = CombineExpectations;
|
||||
};
|
||||
D0666A4824C6C1A300F3F04B /* GRDB */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = D0666A4724C6C1A300F3F04B /* XCRemoteSwiftPackageReference "GRDB" */;
|
||||
productName = GRDB;
|
||||
};
|
||||
D06B492224D4611300642749 /* KingfisherSwiftUI */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = D06B492124D4611300642749 /* XCRemoteSwiftPackageReference "Kingfisher" */;
|
||||
productName = KingfisherSwiftUI;
|
||||
};
|
||||
D0E0F1E524FC4B76002C04BF /* Mastodon */ = {
|
||||
D075C28424FCD41D00D35112 /* Services */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = Mastodon;
|
||||
productName = Services;
|
||||
};
|
||||
D0E0F1E724FC5A61002C04BF /* Mastodon */ = {
|
||||
D075C28624FCD92400D35112 /* Services */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = Mastodon;
|
||||
productName = Services;
|
||||
};
|
||||
D0ADCBF024FD05510062ACCE /* ServiceMocks */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = ServiceMocks;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
},
|
||||
{
|
||||
"package": "GRDB",
|
||||
"repositoryURL": "https://github.com/groue/GRDB.swift",
|
||||
"repositoryURL": "https://github.com/groue/GRDB.swift.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"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 CryptoKit
|
||||
import Mastodon
|
||||
import Services
|
||||
|
||||
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.
|
||||
|
||||
import Foundation
|
||||
import Services
|
||||
|
||||
struct MockKeychainService {}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright © 2020 Metabolist. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import Services
|
||||
|
||||
class MockWebAuthSession: WebAuthSession {
|
||||
let completionHandler: WebAuthSessionCompletionHandler
|
|
@ -4,14 +4,14 @@ import Foundation
|
|||
import Combine
|
||||
import Mastodon
|
||||
|
||||
struct AllIdentitiesService {
|
||||
let mostRecentlyUsedIdentityID: AnyPublisher<UUID?, Never>
|
||||
public struct AllIdentitiesService {
|
||||
public let mostRecentlyUsedIdentityID: AnyPublisher<UUID?, Never>
|
||||
|
||||
private let identityDatabase: IdentityDatabase
|
||||
private let environment: AppEnvironment
|
||||
|
||||
init(identityDatabase: IdentityDatabase, environment: AppEnvironment) {
|
||||
self.identityDatabase = identityDatabase
|
||||
public init(environment: AppEnvironment) throws {
|
||||
self.identityDatabase = try IdentityDatabase(inMemory: environment.inMemoryContent)
|
||||
self.environment = environment
|
||||
|
||||
mostRecentlyUsedIdentityID = identityDatabase.mostRecentlyUsedIdentityIDObservation()
|
||||
|
@ -20,7 +20,7 @@ struct AllIdentitiesService {
|
|||
}
|
||||
}
|
||||
|
||||
extension AllIdentitiesService {
|
||||
public extension AllIdentitiesService {
|
||||
func identityService(id: UUID) throws -> IdentityService {
|
||||
try IdentityService(identityID: id,
|
||||
identityDatabase: identityDatabase,
|
|
@ -4,18 +4,18 @@ import Foundation
|
|||
import Combine
|
||||
import Mastodon
|
||||
|
||||
struct AuthenticationService {
|
||||
public struct AuthenticationService {
|
||||
private let networkClient: APIClient
|
||||
private let webAuthSessionType: WebAuthSession.Type
|
||||
private let webAuthSessionContextProvider = WebAuthSessionContextProvider()
|
||||
|
||||
init(environment: AppEnvironment) {
|
||||
public init(environment: AppEnvironment) {
|
||||
networkClient = APIClient(session: environment.session)
|
||||
webAuthSessionType = environment.webAuthSessionType
|
||||
}
|
||||
}
|
||||
|
||||
extension AuthenticationService {
|
||||
public extension AuthenticationService {
|
||||
func authorizeApp(instanceURL: URL) -> AnyPublisher<AppAuthorization, Error> {
|
||||
let endpoint = AppAuthorizationEndpoint.apps(
|
||||
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 {
|
||||
APIDecoder()
|
||||
}
|
||||
|
@ -251,14 +251,14 @@ extension Account: TableRecord, FetchableRecord, PersistableRecord {
|
|||
}
|
||||
}
|
||||
|
||||
protocol StatusCollection: FetchableRecord, PersistableRecord {
|
||||
public protocol StatusCollection: FetchableRecord, PersistableRecord {
|
||||
var id: String { get }
|
||||
var fetch: (Database) throws -> [StatusResult] { get }
|
||||
|
||||
func joinRecord(status: Status) -> PersistableRecord
|
||||
}
|
||||
|
||||
private struct TimelineStatusJoin: Codable, TableRecord, FetchableRecord, PersistableRecord {
|
||||
private struct TimelineStatusJoin: Codable, FetchableRecord, PersistableRecord {
|
||||
let timelineId: String
|
||||
let statusId: String
|
||||
|
||||
|
@ -293,7 +293,7 @@ extension Timeline: StatusCollection {
|
|||
}
|
||||
}
|
||||
|
||||
var fetch: (Database) throws -> [StatusResult] {
|
||||
public var fetch: (Database) throws -> [StatusResult] {
|
||||
statuses
|
||||
.including(required: StoredStatus.account)
|
||||
.including(optional: StoredStatus.reblogAccount)
|
||||
|
@ -302,7 +302,7 @@ extension Timeline: StatusCollection {
|
|||
.fetchAll
|
||||
}
|
||||
|
||||
func joinRecord(status: Status) -> PersistableRecord {
|
||||
public func joinRecord(status: Status) -> PersistableRecord {
|
||||
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 {
|
||||
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 statusId: String
|
||||
|
||||
|
@ -341,7 +341,7 @@ private struct TransientStatusCollectionElement: Codable, TableRecord, Fetchable
|
|||
}
|
||||
|
||||
extension TransientStatusCollection: StatusCollection {
|
||||
var fetch: (Database) throws -> [StatusResult] {
|
||||
public var fetch: (Database) throws -> [StatusResult] {
|
||||
{
|
||||
try StatusResult.fetchAll(
|
||||
$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)
|
||||
}
|
||||
}
|
||||
|
@ -451,7 +451,7 @@ private extension StoredStatus {
|
|||
}
|
||||
}
|
||||
|
||||
extension StoredStatus: TableRecord, FetchableRecord, PersistableRecord {
|
||||
extension StoredStatus: FetchableRecord, PersistableRecord {
|
||||
static func databaseJSONDecoder(for column: String) -> JSONDecoder {
|
||||
APIDecoder()
|
||||
}
|
||||
|
@ -461,7 +461,7 @@ extension StoredStatus: TableRecord, FetchableRecord, PersistableRecord {
|
|||
}
|
||||
}
|
||||
|
||||
struct StatusResult: Codable, Hashable, FetchableRecord {
|
||||
public struct StatusResult: Codable, Hashable, FetchableRecord {
|
||||
let account: Account
|
||||
fileprivate let status: StoredStatus
|
||||
let reblogAccount: Account?
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
enum DatabaseError: Error {
|
||||
public enum DatabaseError: Error {
|
||||
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 url: URL
|
||||
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 Mastodon
|
||||
|
||||
struct AppEnvironment {
|
||||
public struct AppEnvironment {
|
||||
let session: Session
|
||||
let webAuthSessionType: WebAuthSession.Type
|
||||
let keychainServiceType: KeychainService.Type
|
||||
let userDefaults: UserDefaults
|
||||
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(
|
||||
session: Session(configuration: .default),
|
||||
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 Combine
|
||||
|
||||
protocol WebAuthSession: AnyObject {
|
||||
public protocol WebAuthSession: AnyObject {
|
||||
init(url URL: URL,
|
||||
callbackURLScheme: String?,
|
||||
completionHandler: @escaping WebAuthSessionCompletionHandler)
|
||||
|
@ -41,9 +41,9 @@ class WebAuthSessionContextProvider: NSObject, ASWebAuthenticationPresentationCo
|
|||
}
|
||||
}
|
||||
|
||||
typealias WebAuthSessionCompletionHandler = ASWebAuthenticationSession.CompletionHandler
|
||||
typealias WebAuthSessionError = ASWebAuthenticationSessionError
|
||||
typealias WebAuthPresentationContextProviding = ASWebAuthenticationPresentationContextProviding
|
||||
typealias LiveWebAuthSession = ASWebAuthenticationSession
|
||||
public typealias WebAuthSessionCompletionHandler = ASWebAuthenticationSession.CompletionHandler
|
||||
public typealias WebAuthSessionError = ASWebAuthenticationSessionError
|
||||
public typealias WebAuthPresentationContextProviding = ASWebAuthenticationPresentationContextProviding
|
||||
public typealias LiveWebAuthSession = ASWebAuthenticationSession
|
||||
|
||||
extension LiveWebAuthSession: WebAuthSession {}
|
|
@ -4,9 +4,9 @@ import Foundation
|
|||
import Combine
|
||||
import Mastodon
|
||||
|
||||
class IdentityService {
|
||||
@Published private(set) var identity: Identity
|
||||
let observationErrors: AnyPublisher<Error, Never>
|
||||
public class IdentityService {
|
||||
@Published public private(set) var identity: Identity
|
||||
public let observationErrors: AnyPublisher<Error, Never>
|
||||
|
||||
private let identityDatabase: IdentityDatabase
|
||||
private let contentDatabase: ContentDatabase
|
||||
|
@ -50,7 +50,7 @@ class IdentityService {
|
|||
}
|
||||
}
|
||||
|
||||
extension IdentityService {
|
||||
public extension IdentityService {
|
||||
var isAuthorized: Bool { networkClient.accessToken != nil }
|
||||
|
||||
func updateLastUse() -> AnyPublisher<Never, Error> {
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
protocol KeychainService {
|
||||
public protocol KeychainService {
|
||||
static func setGenericPassword(data: Data, forAccount key: String, service: String) throws
|
||||
static func deleteGenericPassword(account: String, service: String) throws
|
||||
static func getGenericPassword(account: String, service: String) throws -> Data?
|
||||
|
@ -11,10 +11,10 @@ protocol KeychainService {
|
|||
static func deleteKey(applicationTag: String) throws
|
||||
}
|
||||
|
||||
struct LiveKeychainService {}
|
||||
public struct LiveKeychainService {}
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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 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 error: Unmanaged<CFError>?
|
||||
|
||||
|
@ -78,7 +78,7 @@ extension LiveKeychainService: KeychainService {
|
|||
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 error: Unmanaged<CFError>?
|
||||
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)
|
||||
|
||||
if status != errSecSuccess {
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
protocol SecretsStorable {
|
||||
public protocol SecretsStorable {
|
||||
var dataStoredInSecrets: Data { get }
|
||||
static func fromDataStoredInSecrets(_ data: Data) throws -> Self
|
||||
}
|
||||
|
@ -11,17 +11,17 @@ enum SecretsStorableError: Error {
|
|||
case conversionFromDataStoredInSecrets(Data)
|
||||
}
|
||||
|
||||
struct SecretsService {
|
||||
let identityID: UUID
|
||||
public struct SecretsService {
|
||||
public let identityID: UUID
|
||||
private let keychainService: KeychainService.Type
|
||||
|
||||
init(identityID: UUID, keychainService: KeychainService.Type) {
|
||||
public init(identityID: UUID, keychainService: KeychainService.Type) {
|
||||
self.identityID = identityID
|
||||
self.keychainService = keychainService
|
||||
}
|
||||
}
|
||||
|
||||
extension SecretsService {
|
||||
public extension SecretsService {
|
||||
enum Item: String, CaseIterable {
|
||||
case clientID
|
||||
case clientSecret
|
||||
|
@ -49,7 +49,7 @@ extension SecretsService.Item {
|
|||
}
|
||||
}
|
||||
|
||||
extension SecretsService {
|
||||
public extension SecretsService {
|
||||
func set(_ data: SecretsStorable, forItem item: Item) throws {
|
||||
try keychainService.setGenericPassword(
|
||||
data: data.dataStoredInSecrets,
|
||||
|
@ -118,17 +118,17 @@ private extension SecretsService {
|
|||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
throw SecretsStorableError.conversionFromDataStoredInSecrets(data)
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ extension String: SecretsStorable {
|
|||
}
|
||||
}
|
||||
|
||||
struct PushKey {
|
||||
private struct PushKey {
|
||||
static let authLength = 16
|
||||
static let sizeInBits = 256
|
||||
static let attributes: [String: Any] = [
|
|
@ -4,9 +4,9 @@ import Foundation
|
|||
import Combine
|
||||
import Mastodon
|
||||
|
||||
struct ContextService {
|
||||
let statusSections: AnyPublisher<[[Status]], Error>
|
||||
let paginates = false
|
||||
public struct ContextService {
|
||||
public let statusSections: AnyPublisher<[[Status]], Error>
|
||||
public let paginates = false
|
||||
|
||||
private let status: Status
|
||||
private let context = CurrentValueSubject<Context, Never>(Context(ancestors: [], descendants: []))
|
||||
|
@ -34,13 +34,13 @@ struct ContextService {
|
|||
}
|
||||
|
||||
extension ContextService: StatusListService {
|
||||
var filters: AnyPublisher<[Filter], Error> {
|
||||
public var filters: AnyPublisher<[Filter], Error> {
|
||||
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()
|
||||
|
||||
guard
|
||||
|
@ -53,7 +53,7 @@ extension ContextService: StatusListService {
|
|||
return previousStatus.id != contextParentID && status.inReplyToId == previousStatus.id
|
||||
}
|
||||
|
||||
func hasReplyFollowing(status: Status) -> Bool {
|
||||
public func hasReplyFollowing(status: Status) -> Bool {
|
||||
let flatContext = flattenedContext()
|
||||
|
||||
guard
|
||||
|
@ -66,7 +66,7 @@ extension ContextService: StatusListService {
|
|||
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(
|
||||
networkClient.request(StatusEndpoint.status(id: status.id))
|
||||
.map { ([$0], collection) }
|
||||
|
@ -78,11 +78,11 @@ extension ContextService: StatusListService {
|
|||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func statusService(status: Status) -> StatusService {
|
||||
public func statusService(status: Status) -> StatusService {
|
||||
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)
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ import Foundation
|
|||
import Combine
|
||||
import Mastodon
|
||||
|
||||
protocol StatusListService {
|
||||
public protocol StatusListService {
|
||||
var statusSections: AnyPublisher<[[Status]], Error> { get }
|
||||
var filters: AnyPublisher<[Filter], Error> { get }
|
||||
var paginates: Bool { get }
|
||||
|
@ -17,7 +17,7 @@ protocol StatusListService {
|
|||
func contextService(status: Status) -> ContextService
|
||||
}
|
||||
|
||||
extension StatusListService {
|
||||
public extension StatusListService {
|
||||
var paginates: Bool { true }
|
||||
|
||||
var contextParentID: String? { nil }
|
|
@ -4,8 +4,8 @@ import Foundation
|
|||
import Combine
|
||||
import Mastodon
|
||||
|
||||
struct StatusService {
|
||||
let status: Status
|
||||
public struct StatusService {
|
||||
public let status: Status
|
||||
private let networkClient: APIClient
|
||||
private let contentDatabase: ContentDatabase
|
||||
|
||||
|
@ -16,7 +16,7 @@ struct StatusService {
|
|||
}
|
||||
}
|
||||
|
||||
extension StatusService {
|
||||
public extension StatusService {
|
||||
func toggleFavorited() -> AnyPublisher<Never, Error> {
|
||||
networkClient.request(status.favourited
|
||||
? StatusEndpoint.unfavourite(id: status.id)
|
|
@ -4,10 +4,10 @@ import Foundation
|
|||
import Combine
|
||||
import UserNotifications
|
||||
|
||||
class UserNotificationService: NSObject {
|
||||
public class UserNotificationService: NSObject {
|
||||
private let userNotificationCenter: UNUserNotificationCenter
|
||||
|
||||
init(userNotificationCenter: UNUserNotificationCenter = .current()) {
|
||||
public init(userNotificationCenter: UNUserNotificationCenter = .current()) {
|
||||
self.userNotificationCenter = userNotificationCenter
|
||||
|
||||
super.init()
|
||||
|
@ -16,7 +16,7 @@ class UserNotificationService: NSObject {
|
|||
}
|
||||
}
|
||||
|
||||
extension UserNotificationService {
|
||||
public extension UserNotificationService {
|
||||
func isAuthorized() -> AnyPublisher<Bool, Error> {
|
||||
getNotificationSettings()
|
||||
.map(\.authorizationStatus)
|
||||
|
@ -59,7 +59,7 @@ private extension UserNotificationService {
|
|||
}
|
||||
|
||||
extension UserNotificationService: UNUserNotificationCenterDelegate {
|
||||
func userNotificationCenter(
|
||||
public func userNotificationCenter(
|
||||
_ center: UNUserNotificationCenter,
|
||||
willPresent notification: UNNotification,
|
||||
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
|
|
@ -3,11 +3,12 @@
|
|||
import XCTest
|
||||
import Combine
|
||||
import CombineExpectations
|
||||
@testable import Metatext
|
||||
@testable import Services
|
||||
@testable import ServiceMocks
|
||||
|
||||
class AuthenticationServiceTests: XCTestCase {
|
||||
func testAuthentication() throws {
|
||||
let sut = AuthenticationService(environment: .development)
|
||||
let sut = AuthenticationService(environment: .mock)
|
||||
let instanceURL = URL(string: "https://mastodon.social")!
|
||||
let appAuthorizationRecorder = sut.authorizeApp(instanceURL: instanceURL).record()
|
||||
let appAuthorization = try wait(for: appAuthorizationRecorder.next(), timeout: 1)
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright © 2020 Metabolist. All rights reserved.
|
||||
|
||||
import SwiftUI
|
||||
import Services
|
||||
|
||||
@main
|
||||
struct MetatextApp: App {
|
||||
|
@ -8,23 +9,13 @@ struct MetatextApp: App {
|
|||
@UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
|
||||
// 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 {
|
||||
WindowGroup {
|
||||
RootView(
|
||||
viewModel: RootViewModel(appDelegate: appDelegate,
|
||||
allIdentitiesService: allIdentitiesService,
|
||||
// swiftlint:disable force_try
|
||||
allIdentitiesService: try! AllIdentitiesService(environment: .live),
|
||||
// swiftlint:enable force_try
|
||||
userNotificationService: UserNotificationService()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,10 +7,11 @@ import HTTP
|
|||
import Mastodon
|
||||
@testable import Metatext
|
||||
|
||||
import Services
|
||||
|
||||
class AddIdentityViewModelTests: XCTestCase {
|
||||
func testAddIdentity() throws {
|
||||
let identityDatabase = IdentityDatabase.fresh()
|
||||
let sut = AddIdentityViewModel(allIdentitiesService: .fresh(identityDatabase: identityDatabase))
|
||||
let sut = AddIdentityViewModel(allIdentitiesService: .fresh)
|
||||
let addedIDRecorder = sut.addedIdentityID.record()
|
||||
|
||||
sut.urlFieldText = "https://mastodon.social"
|
||||
|
@ -20,8 +21,7 @@ class AddIdentityViewModelTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testAddIdentityWithoutScheme() throws {
|
||||
let identityDatabase = IdentityDatabase.fresh()
|
||||
let sut = AddIdentityViewModel(allIdentitiesService: .fresh(identityDatabase: identityDatabase))
|
||||
let sut = AddIdentityViewModel(allIdentitiesService: .fresh)
|
||||
let addedIDRecorder = sut.addedIdentityID.record()
|
||||
|
||||
sut.urlFieldText = "mastodon.social"
|
||||
|
@ -31,7 +31,7 @@ class AddIdentityViewModelTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testInvalidURL() throws {
|
||||
let sut = AddIdentityViewModel(allIdentitiesService: .fresh())
|
||||
let sut = AddIdentityViewModel(allIdentitiesService: .fresh)
|
||||
let recorder = sut.$alertItem.record()
|
||||
|
||||
XCTAssertNil(try wait(for: recorder.next(), timeout: 1))
|
||||
|
@ -51,9 +51,7 @@ class AddIdentityViewModelTests: XCTestCase {
|
|||
keychainServiceType: MockKeychainService.self,
|
||||
userDefaults: MockUserDefaults(),
|
||||
inMemoryContent: true)
|
||||
let allIdentitiesService = AllIdentitiesService(
|
||||
identityDatabase: .fresh(),
|
||||
environment: environment)
|
||||
let allIdentitiesService = try AllIdentitiesService(environment: environment)
|
||||
let sut = AddIdentityViewModel(allIdentitiesService: allIdentitiesService)
|
||||
let recorder = sut.$alertItem.record()
|
||||
|
||||
|
@ -64,4 +62,8 @@ class AddIdentityViewModelTests: XCTestCase {
|
|||
|
||||
try wait(for: recorder.next().inverted, timeout: 1)
|
||||
}
|
||||
|
||||
func testFuck() {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import XCTest
|
||||
import Combine
|
||||
import CombineExpectations
|
||||
import Services
|
||||
@testable import Metatext
|
||||
|
||||
class RootViewModelTests: XCTestCase {
|
||||
|
@ -10,9 +11,7 @@ class RootViewModelTests: XCTestCase {
|
|||
|
||||
func testAddIdentity() throws {
|
||||
let sut = RootViewModel(appDelegate: AppDelegate(),
|
||||
allIdentitiesService: AllIdentitiesService(
|
||||
identityDatabase: .fresh(),
|
||||
environment: .development),
|
||||
allIdentitiesService: .fresh,
|
||||
userNotificationService: UserNotificationService())
|
||||
let recorder = sut.$tabNavigationViewModel.record()
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import Foundation
|
||||
import Combine
|
||||
import Services
|
||||
|
||||
class AddIdentityViewModel: ObservableObject {
|
||||
@Published var urlFieldText = ""
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import Foundation
|
||||
import Combine
|
||||
import Mastodon
|
||||
import Services
|
||||
|
||||
class EditFilterViewModel: ObservableObject {
|
||||
@Published var filter: Filter
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import Foundation
|
||||
import Combine
|
||||
import Mastodon
|
||||
import Services
|
||||
|
||||
class FiltersViewModel: ObservableObject {
|
||||
@Published var activeFilters = [Filter]()
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import Combine
|
||||
import Foundation
|
||||
import Services
|
||||
|
||||
class IdentitiesViewModel: ObservableObject {
|
||||
@Published private(set) var identity: Identity
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import Foundation
|
||||
import Combine
|
||||
import Mastodon
|
||||
import Services
|
||||
|
||||
class ListsViewModel: ObservableObject {
|
||||
@Published private(set) var lists = [MastodonList]()
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import Foundation
|
||||
import Combine
|
||||
import Mastodon
|
||||
import Services
|
||||
|
||||
class NotificationTypesPreferencesViewModel: ObservableObject {
|
||||
@Published var pushSubscriptionAlerts: PushSubscription.Alerts
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import Foundation
|
||||
import Combine
|
||||
import Services
|
||||
|
||||
class PostingReadingPreferencesViewModel: ObservableObject {
|
||||
@Published var preferences: Identity.Preferences
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright © 2020 Metabolist. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import Services
|
||||
|
||||
class PreferencesViewModel: ObservableObject {
|
||||
let handle: String
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import Foundation
|
||||
import Combine
|
||||
import Services
|
||||
|
||||
class RootViewModel: ObservableObject {
|
||||
@Published private(set) var tabNavigationViewModel: TabNavigationViewModel?
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright © 2020 Metabolist. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import Services
|
||||
|
||||
class SecondaryNavigationViewModel: ObservableObject {
|
||||
@Published private(set) var identity: Identity
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import Foundation
|
||||
import Combine
|
||||
import Mastodon
|
||||
import Services
|
||||
|
||||
class StatusListViewModel: ObservableObject {
|
||||
@Published private(set) var statusIDs = [[String]]()
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import Foundation
|
||||
import Combine
|
||||
import Mastodon
|
||||
import Services
|
||||
|
||||
struct StatusViewModel {
|
||||
let content: NSAttributedString
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import Foundation
|
||||
import Combine
|
||||
import Mastodon
|
||||
import Services
|
||||
|
||||
class TabNavigationViewModel: ObservableObject {
|
||||
@Published private(set) var identity: Identity
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import SwiftUI
|
||||
import KingfisherSwiftUI
|
||||
import struct Services.Identity
|
||||
|
||||
struct IdentitiesView: View {
|
||||
@StateObject var viewModel: IdentitiesViewModel
|
||||
|
|
Loading…
Reference in a new issue