Implement TranslationLanguages fetching (IOS-271)

This commit is contained in:
Marcus Kida 2024-06-21 12:09:49 +02:00
parent d4132640c5
commit 7f8587913f
No known key found for this signature in database
GPG Key ID: 19FF64E08013CA40
8 changed files with 164 additions and 12 deletions

View File

@ -23,11 +23,40 @@ public class AuthenticationServiceProvider: ObservableObject {
}
}
func update(instance: Instance, where domain: String) {
@discardableResult
func updating(instance: Instance, where domain: String) -> Self {
authentications = authentications.map { authentication in
guard authentication.domain == domain else { return authentication }
return authentication.updating(instance: instance)
}
return self
}
@discardableResult
func updating(instanceV1 instance: Mastodon.Entity.Instance, for domain: String) -> Self {
authentications = authentications.map { authentication in
guard authentication.domain == domain else { return authentication }
return authentication.updating(instanceV1: instance)
}
return self
}
@discardableResult
func updating(instanceV2 instance: Mastodon.Entity.V2.Instance, for domain: String) -> Self {
authentications = authentications.map { authentication in
guard authentication.domain == domain else { return authentication }
return authentication.updating(instanceV2: instance)
}
return self
}
@discardableResult
func updating(translationLanguages: TranslationLanguages, for domain: String) -> Self {
authentications = authentications.map { authentication in
guard authentication.domain == domain else { return authentication }
return authentication.updating(translationLanguages: translationLanguages)
}
return self
}
func delete(authentication: MastodonAuthentication) throws {

View File

@ -5,6 +5,11 @@ import CoreDataStack
import MastodonSDK
public struct MastodonAuthentication: Codable, Hashable, UserIdentifier {
public enum InstanceConfiguration: Codable, Hashable {
case v1(Mastodon.Entity.Instance, TranslationLanguages)
case v2(Mastodon.Entity.V2.Instance, TranslationLanguages)
}
public typealias ID = UUID
public private(set) var identifier: ID
@ -22,6 +27,7 @@ public struct MastodonAuthentication: Codable, Hashable, UserIdentifier {
public private(set) var userID: String
public private(set) var instanceObjectIdURI: URL?
public private(set) var instanceConfiguration: InstanceConfiguration?
public var persistenceIdentifier: String {
"\(username)@\(domain)"
@ -49,7 +55,8 @@ public struct MastodonAuthentication: Codable, Hashable, UserIdentifier {
updatedAt: now,
activedAt: now,
userID: userID,
instanceObjectIdURI: nil
instanceObjectIdURI: nil,
instanceConfiguration: nil
)
}
@ -65,7 +72,8 @@ public struct MastodonAuthentication: Codable, Hashable, UserIdentifier {
updatedAt: Date? = nil,
activedAt: Date? = nil,
userID: String? = nil,
instanceObjectIdURI: URL? = nil
instanceObjectIdURI: URL? = nil,
instanceConfiguration: InstanceConfiguration? = nil
) -> Self {
MastodonAuthentication(
identifier: identifier ?? self.identifier,
@ -79,7 +87,8 @@ public struct MastodonAuthentication: Codable, Hashable, UserIdentifier {
updatedAt: updatedAt ?? self.updatedAt,
activedAt: activedAt ?? self.activedAt,
userID: userID ?? self.userID,
instanceObjectIdURI: instanceObjectIdURI ?? self.instanceObjectIdURI
instanceObjectIdURI: instanceObjectIdURI ?? self.instanceObjectIdURI,
instanceConfiguration: instanceConfiguration ?? self.instanceConfiguration
)
}
@ -117,6 +126,37 @@ public struct MastodonAuthentication: Codable, Hashable, UserIdentifier {
copy(instanceObjectIdURI: instance.objectID.uriRepresentation())
}
func updating(instanceV1 instance: Mastodon.Entity.Instance) -> Self {
guard
let instanceConfiguration = self.instanceConfiguration,
case let InstanceConfiguration.v1(_, translationLanguages) = instanceConfiguration
else {
return copy(instanceConfiguration: .v1(instance, [:]))
}
return copy(instanceConfiguration: .v1(instance, translationLanguages))
}
func updating(instanceV2 instance: Mastodon.Entity.V2.Instance) -> Self {
guard
let instanceConfiguration = self.instanceConfiguration,
case let InstanceConfiguration.v2(_, translationLanguages) = instanceConfiguration
else {
return copy(instanceConfiguration: .v2(instance, [:]))
}
return copy(instanceConfiguration: .v2(instance, translationLanguages))
}
func updating(translationLanguages: TranslationLanguages) -> Self {
switch self.instanceConfiguration {
case .v1(let instance, _):
return copy(instanceConfiguration: .v1(instance, translationLanguages))
case .v2(let instance, _):
return copy(instanceConfiguration: .v2(instance, translationLanguages))
case .none:
return self
}
}
func updating(activatedAt: Date) -> Self {
copy(activedAt: activatedAt)
}

View File

@ -33,4 +33,11 @@ extension APIService {
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.ExtendedDescription>, Error> {
return Mastodon.API.Instance.extendedDescription(session: session, authorization: authenticationBox?.userAuthorization, domain: domain)
}
public func translationLanguages(
domain: String,
authenticationBox: MastodonAuthenticationBox?
) -> AnyPublisher<Mastodon.Response.Content<TranslationLanguages>, Error> {
return Mastodon.API.Instance.translationLanguages(session: session, authorization: authenticationBox?.userAuthorization, domain: domain)
}
}

View File

@ -56,10 +56,13 @@ extension InstanceService {
return self.updateInstance(domain: domain, response: response)
}
}
// .flatMap { [unowned self] response -> AnyPublisher<Void, Error> in
// return
// }
.sink { _ in
.sink { [weak self] completion in
switch completion {
case .finished:
self?.updateTranslationLanguages(domain: domain)
case .failure:
break
}
} receiveValue: { [weak self] response in
guard let _ = self else { return }
// do nothing
@ -67,19 +70,37 @@ extension InstanceService {
.store(in: &disposeBag)
}
func updateTranslationLanguages(domain: String) {
apiService?.translationLanguages(domain: domain, authenticationBox: authenticationService?.mastodonAuthenticationBoxes.first)
.sink(receiveCompletion: { completion in
// no-op
}, receiveValue: { [weak self] response in
self?.updateTranslationLanguages(domain: domain, response: response)
})
.store(in: &disposeBag)
}
private func updateTranslationLanguages(domain: String, response: Mastodon.Response.Content<TranslationLanguages>) {
AuthenticationServiceProvider.shared
.updating(translationLanguages: response.value, for: domain)
}
private func updateInstance(domain: String, response: Mastodon.Response.Content<Mastodon.Entity.Instance>) -> AnyPublisher<Void, Error> {
let managedObjectContext = self.backgroundManagedObjectContext
let instanceEntity = response.value
return managedObjectContext.performChanges {
// get instance
let (instance, _) = APIService.CoreData.createOrMergeInstance(
into: managedObjectContext,
domain: domain,
entity: response.value,
entity: instanceEntity,
networkDate: response.networkDate
)
// update instance
AuthenticationServiceProvider.shared.update(instance: instance, where: domain)
AuthenticationServiceProvider.shared
.updating(instance: instance, where: domain)
.updating(instanceV1: instanceEntity, for: domain)
}
.setFailureType(to: Error.self)
.tryMap { result in
@ -95,19 +116,22 @@ extension InstanceService {
private func updateInstanceV2(domain: String, response: Mastodon.Response.Content<Mastodon.Entity.V2.Instance>) -> AnyPublisher<Void, Error> {
let managedObjectContext = self.backgroundManagedObjectContext
let instanceEntity = response.value
return managedObjectContext.performChanges {
// get instance
let (instance, _) = APIService.CoreData.createOrMergeInstance(
in: managedObjectContext,
context: .init(
domain: domain,
entity: response.value,
entity: instanceEntity,
networkDate: response.networkDate
)
)
// update instance
AuthenticationServiceProvider.shared.update(instance: instance, where: domain)
AuthenticationServiceProvider.shared
.updating(instance: instance, where: domain)
.updating(instanceV2: instanceEntity, for: domain)
}
.setFailureType(to: Error.self)
.tryMap { result in

View File

@ -0,0 +1,30 @@
//
// File.swift
//
//
// Created by Marcus Kida on 20.06.24.
//
import Foundation
import Combine
extension Mastodon.API.Instance {
static func translationLanguagesEndpointURL(domain: String) -> URL {
return Mastodon.API.endpointURL(domain: domain).appendingPathComponent("instance/translation_languages")
}
public static func translationLanguages(
session: URLSession,
authorization: Mastodon.API.OAuth.Authorization?,
domain: String
) -> AnyPublisher<Mastodon.Response.Content<TranslationLanguages>, Error> {
let request = Mastodon.API.get(url: translationLanguagesEndpointURL(domain: domain), authorization: authorization)
return session.dataTaskPublisher(for: request)
.tryMap { data, response in
let value = try Mastodon.API.decode(type: TranslationLanguages.self, from: data, response: response)
return Mastodon.Response.Content(value: value, response: response)
}
.eraseToAnyPublisher()
}
}

View File

@ -8,6 +8,8 @@
import Foundation
import Combine
public typealias TranslationLanguages = [String: [String]]
extension Mastodon.API.Instance {
static func instanceEndpointURL(domain: String) -> URL {

View File

@ -172,3 +172,13 @@ extension Mastodon.Entity.Instance.Configuration {
}
}
}
extension Mastodon.Entity.Instance: Hashable {
public static func == (lhs: Mastodon.Entity.Instance, rhs: Mastodon.Entity.Instance) -> Bool {
lhs.uri == rhs.uri
}
public func hash(into hasher: inout Hasher) {
hasher.combine(uri)
}
}

View File

@ -110,3 +110,13 @@ extension Mastodon.Entity.V2.Instance {
public let account: Mastodon.Entity.Account?
}
}
extension Mastodon.Entity.V2.Instance: Hashable {
public static func == (lhs: Mastodon.Entity.V2.Instance, rhs: Mastodon.Entity.V2.Instance) -> Bool {
lhs.domain == rhs.domain
}
public func hash(into hasher: inout Hasher) {
hasher.combine(domain)
}
}