[ABANDONED] Mastodon iOS client.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

321 lines
12 KiB

//
// MastodonDataManager.swift
// elpha-ios
//
// Created by Dwayne Harris on 10/1/18.
// Copyright © 2018 Elpha. All rights reserved.
//
import CoreData
import Foundation
import MastodonKit
class UpsertResult<T> {
var model: T
var new: Bool = false
init(model: T, new: Bool) {
self.model = model
self.new = new
}
}
public class MastodonDataManager {
static func setAccount(_ account: AccountMO, withRemoteAccount remoteAccount: Account) -> AccountMO {
account.id = remoteAccount.id
account.username = remoteAccount.username
account.acct = remoteAccount.acct
account.displayName = remoteAccount.displayName
account.note = remoteAccount.note
account.url = remoteAccount.url
account.avatarURL = URL(string: remoteAccount.avatar)
account.avatarStaticURL = URL(string: remoteAccount.avatarStatic)
account.headerURL = URL(string: remoteAccount.header)
account.headerStaticURL = URL(string: remoteAccount.headerStatic)
account.locked = remoteAccount.locked
account.createdAt = remoteAccount.createdAt
account.followersCount = Int32(remoteAccount.followersCount)
account.followingCount = Int32(remoteAccount.followingCount)
account.statusesCount = Int32(remoteAccount.statusesCount)
return account
}
static func upsertAccount(_ remoteAccount: Account) -> AccountMO? {
let request = NSFetchRequest<AccountMO>(entityName: "Account")
request.predicate = NSPredicate(format: "id == %@", remoteAccount.id)
do {
let results = try CoreDataManager.shared.context.fetch(request)
if let account = results.first {
return setAccount(account, withRemoteAccount: remoteAccount)
} else {
return setAccount(AccountMO(context: CoreDataManager.shared.context), withRemoteAccount: remoteAccount)
}
} catch {
print("\(error)")
return nil
}
}
static func setAttachment(_ attachment: AttachmentMO, withRemoteAttachment remoteAttachment: Attachment) -> AttachmentMO {
attachment.id = remoteAttachment.id
attachment.type = remoteAttachment.type.rawValue
attachment.url = URL(string: remoteAttachment.url)
attachment.previewURL = URL(string: remoteAttachment.previewURL)
attachment.remoteURL = remoteAttachment.remoteURL
attachment.textURL = remoteAttachment.textURL
return attachment
}
static func upsertAttachment(_ remoteAttachment: Attachment) -> AttachmentMO? {
let request = NSFetchRequest<AttachmentMO>(entityName: "Attachment")
request.predicate = NSPredicate(format: "id == %@", remoteAttachment.id)
do {
let results = try CoreDataManager.shared.context.fetch(request)
if let attachment = results.first {
return setAttachment(attachment, withRemoteAttachment: remoteAttachment)
} else {
return setAttachment(AttachmentMO(context: CoreDataManager.shared.context), withRemoteAttachment: remoteAttachment)
}
} catch {
print("\(error)")
return nil
}
}
static func setMention(_ mention: MentionMO, withRemoteMention remoteMention: Mention) -> MentionMO {
mention.id = remoteMention.id
mention.username = remoteMention.username
mention.acct = remoteMention.acct
mention.url = URL(string: remoteMention.url)
return mention
}
static func upsertMention(_ remoteMention: Mention) -> MentionMO? {
let request = NSFetchRequest<MentionMO>(entityName: "Mention")
request.predicate = NSPredicate(format: "id == %@", remoteMention.id)
do {
let results = try CoreDataManager.shared.context.fetch(request)
if let mention = results.first {
return setMention(mention, withRemoteMention: remoteMention)
} else {
return setMention(MentionMO(context: CoreDataManager.shared.context), withRemoteMention: remoteMention)
}
} catch {
print("\(error)")
return nil
}
}
static func setTag(_ tag: TagMO, withRemoteTag remoteTag: Tag) -> TagMO {
tag.name = remoteTag.name
tag.url = URL(string: remoteTag.url)
return tag
}
static func upsertTag(_ remoteTag: Tag) -> TagMO? {
let request = NSFetchRequest<TagMO>(entityName: "Tag")
request.predicate = NSPredicate(format: "name == %@", remoteTag.name)
do {
let results = try CoreDataManager.shared.context.fetch(request)
if let tag = results.first {
return setTag(tag, withRemoteTag: remoteTag)
} else {
return setTag(TagMO(context: CoreDataManager.shared.context), withRemoteTag: remoteTag)
}
} catch {
print("\(error)")
return nil
}
}
static func setApp(_ app: AppMO, withRemoteApp remoteApp: Application) -> AppMO {
app.name = remoteApp.name
if let website = remoteApp.website {
app.website = URL(string: website)
}
return app
}
static func upsertApp(_ remoteApp: Application) -> AppMO? {
let request = NSFetchRequest<AppMO>(entityName: "App")
request.predicate = NSPredicate(format: "name == %@", remoteApp.name)
do {
let results = try CoreDataManager.shared.context.fetch(request)
if let app = results.first {
return setApp(app, withRemoteApp: remoteApp)
} else {
return setApp(AppMO(context: CoreDataManager.shared.context), withRemoteApp: remoteApp)
}
} catch {
print("\(error)")
return nil
}
}
static func setEmoji(_ emoji: EmojiMO, withRemoteEmoji remoteEmoji: Emoji) -> EmojiMO {
emoji.shortcode = remoteEmoji.shortcode
emoji.staticURL = remoteEmoji.staticURL
emoji.url = remoteEmoji.url
emoji.visibleInPicker = false
return emoji
}
static func upsertEmoji(_ remoteEmoji: Emoji) -> EmojiMO? {
let request = NSFetchRequest<EmojiMO>(entityName: "Emoji")
request.predicate = NSPredicate(format: "url == %@", remoteEmoji.url.absoluteString)
do {
let results = try CoreDataManager.shared.context.fetch(request)
if let emoji = results.first {
return setEmoji(emoji, withRemoteEmoji: remoteEmoji)
} else {
return setEmoji(EmojiMO(context: CoreDataManager.shared.context), withRemoteEmoji: remoteEmoji)
}
} catch {
print("\(error)")
return nil
}
}
static func setStatus(_ status: StatusMO, withRemoteStatus remoteStatus: Status) -> StatusMO {
status.id = remoteStatus.id
status.uri = URL(string: remoteStatus.uri)
status.url = remoteStatus.url
status.account = MastodonDataManager.upsertAccount(remoteStatus.account)
status.inReplyToID = remoteStatus.inReplyToID
status.inReplyToAccountID = remoteStatus.inReplyToAccountID
status.content = remoteStatus.content
status.createdAt = remoteStatus.createdAt
status.reblogsCount = Int32(remoteStatus.reblogsCount)
status.favouritesCount = Int32(remoteStatus.favouritesCount)
status.reblogged = remoteStatus.reblogged ?? false
status.favourited = remoteStatus.favourited ?? false
status.sensitive = remoteStatus.sensitive ?? false
status.pinned = remoteStatus.pinned ?? false
status.spoilerText = remoteStatus.spoilerText
status.visibility = remoteStatus.visibility.rawValue
if let app = remoteStatus.application {
status.app = MastodonDataManager.upsertApp(app)
}
remoteStatus.mediaAttachments.forEach { attachment in
if let attachment = MastodonDataManager.upsertAttachment(attachment) {
status.mutableOrderedSetValue(forKey: "attachments").add(attachment)
}
}
remoteStatus.mentions.forEach { mention in
if let mention = MastodonDataManager.upsertMention(mention) {
status.mutableSetValue(forKey: "mentions").add(mention)
}
}
remoteStatus.tags.forEach { tag in
if let tag = MastodonDataManager.upsertTag(tag) {
status.mutableSetValue(forKey: "tags").add(tag)
}
}
remoteStatus.emojis.forEach { emoji in
if let emoji = MastodonDataManager.upsertEmoji(emoji) {
status.mutableSetValue(forKey: "emojis").add(emoji)
}
}
if let reblog = remoteStatus.reblog {
let savedReblogResult = upsertStatus(reblog)
status.reblog = savedReblogResult?.model
}
return status
}
static func upsertStatus(_ remoteStatus: Status) -> UpsertResult<StatusMO>? {
let request = NSFetchRequest<StatusMO>(entityName: "Status")
request.predicate = NSPredicate(format: "id == %@", remoteStatus.id)
do {
let results = try CoreDataManager.shared.context.fetch(request)
if let status = results.first {
return UpsertResult(
model: setStatus(status, withRemoteStatus: remoteStatus),
new: false
)
} else {
return UpsertResult(
model: setStatus(StatusMO(context: CoreDataManager.shared.context), withRemoteStatus: remoteStatus),
new: true
)
}
} catch {
print("\(error)")
return nil
}
}
static func saveClient(id: String, clientID: String, clientSecret: String, url: String) -> ClientMO {
let client = ClientMO(context: CoreDataManager.shared.context)
client.id = id
client.clientID = clientID
client.clientSecret = clientSecret
client.url = url
CoreDataManager.shared.saveContext()
return client
}
static func accountByID(_ id: String) -> AccountMO? {
let request = NSFetchRequest<AccountMO>(entityName: "Account")
request.predicate = NSPredicate(format: "id == %@", id)
do {
let results = try CoreDataManager.shared.context.fetch(request)
guard let account = results.first else {
return nil
}
return account
} catch {
print("\(error)")
return nil
}
}
static func remoteAccountByID(id: String, completion: @escaping (AccountMO?, Error?) -> Void ) {
if let account = accountByID(id) {
completion(account, nil)
return
}
guard let client = AuthenticationManager.shared.mkClient else {
completion(nil, NSError())
return
}
let request = Accounts.account(id: id)
client.run(request) { result in
switch result {
case .success(let account, _):
completion(upsertAccount(account), nil)
return
case .failure(let error):
completion(nil, error)
return
}
}
}
}