2023-01-10 07:24:05 +00:00
|
|
|
import Models
|
|
|
|
import Network
|
2023-09-18 05:01:23 +00:00
|
|
|
import Observation
|
2024-01-02 20:16:27 +00:00
|
|
|
import PhotosUI
|
2024-01-06 18:27:26 +00:00
|
|
|
import StatusKit
|
2024-02-14 11:48:14 +00:00
|
|
|
import SwiftUI
|
2023-01-10 07:24:05 +00:00
|
|
|
|
|
|
|
@MainActor
|
2023-09-18 05:01:23 +00:00
|
|
|
@Observable class EditAccountViewModel {
|
|
|
|
@Observable class FieldEditViewModel: Identifiable {
|
2023-02-24 06:55:24 +00:00
|
|
|
let id = UUID().uuidString
|
2023-09-18 05:01:23 +00:00
|
|
|
var name: String = ""
|
|
|
|
var value: String = ""
|
2023-02-26 05:45:57 +00:00
|
|
|
|
2023-02-24 06:55:24 +00:00
|
|
|
init(name: String, value: String) {
|
|
|
|
self.name = name
|
|
|
|
self.value = value
|
|
|
|
}
|
|
|
|
}
|
2023-02-26 05:45:57 +00:00
|
|
|
|
2023-01-10 07:24:05 +00:00
|
|
|
public var client: Client?
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2023-09-18 05:01:23 +00:00
|
|
|
var displayName: String = ""
|
|
|
|
var note: String = ""
|
|
|
|
var postPrivacy = Models.Visibility.pub
|
|
|
|
var isSensitive: Bool = false
|
|
|
|
var isBot: Bool = false
|
|
|
|
var isLocked: Bool = false
|
|
|
|
var isDiscoverable: Bool = false
|
|
|
|
var fields: [FieldEditViewModel] = []
|
2024-01-02 20:16:27 +00:00
|
|
|
var avatar: URL?
|
|
|
|
var header: URL?
|
2024-02-14 11:48:14 +00:00
|
|
|
|
2024-01-02 20:16:27 +00:00
|
|
|
var isPhotoPickerPresented: Bool = false {
|
|
|
|
didSet {
|
2024-02-14 11:48:14 +00:00
|
|
|
if !isPhotoPickerPresented, mediaPickers.isEmpty {
|
2024-01-02 20:16:27 +00:00
|
|
|
isChangingAvatar = false
|
|
|
|
isChangingHeader = false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-02-14 11:48:14 +00:00
|
|
|
|
2024-01-02 20:16:27 +00:00
|
|
|
var isChangingAvatar: Bool = false
|
|
|
|
var isChangingHeader: Bool = false
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2023-09-18 05:01:23 +00:00
|
|
|
var isLoading: Bool = true
|
|
|
|
var isSaving: Bool = false
|
|
|
|
var saveError: Bool = false
|
2024-02-14 11:48:14 +00:00
|
|
|
|
2024-01-02 20:16:27 +00:00
|
|
|
var mediaPickers: [PhotosPickerItem] = [] {
|
|
|
|
didSet {
|
|
|
|
if let item = mediaPickers.first {
|
|
|
|
Task {
|
|
|
|
if let data = await getItemImageData(item: item) {
|
|
|
|
if isChangingAvatar {
|
2024-01-06 10:21:07 +00:00
|
|
|
_ = await uploadAvatar(data: data)
|
2024-01-02 20:16:27 +00:00
|
|
|
} else if isChangingHeader {
|
2024-01-06 10:21:07 +00:00
|
|
|
_ = await uploadHeader(data: data)
|
2024-01-02 20:16:27 +00:00
|
|
|
}
|
|
|
|
await fetchAccount()
|
|
|
|
isChangingAvatar = false
|
|
|
|
isChangingHeader = false
|
|
|
|
mediaPickers = []
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-01-17 10:36:01 +00:00
|
|
|
|
|
|
|
init() {}
|
|
|
|
|
2023-01-10 07:24:05 +00:00
|
|
|
func fetchAccount() async {
|
|
|
|
guard let client else { return }
|
|
|
|
do {
|
|
|
|
let account: Account = try await client.get(endpoint: Accounts.verifyCredentials)
|
2023-03-02 19:15:07 +00:00
|
|
|
displayName = account.displayName ?? ""
|
2023-01-10 07:24:05 +00:00
|
|
|
note = account.source?.note ?? ""
|
|
|
|
postPrivacy = account.source?.privacy ?? .pub
|
|
|
|
isSensitive = account.source?.sensitive ?? false
|
|
|
|
isBot = account.bot
|
|
|
|
isLocked = account.locked
|
|
|
|
isDiscoverable = account.discoverable ?? false
|
2024-01-02 20:16:27 +00:00
|
|
|
avatar = account.avatar
|
|
|
|
header = account.header
|
2023-02-26 05:45:57 +00:00
|
|
|
fields = account.source?.fields.map { .init(name: $0.name, value: $0.value.asRawText) } ?? []
|
2023-01-10 07:24:05 +00:00
|
|
|
withAnimation {
|
|
|
|
isLoading = false
|
|
|
|
}
|
2023-01-17 10:36:01 +00:00
|
|
|
} catch {}
|
2023-01-10 07:24:05 +00:00
|
|
|
}
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2023-01-10 07:24:05 +00:00
|
|
|
func save() async {
|
|
|
|
isSaving = true
|
|
|
|
do {
|
2023-02-24 06:55:24 +00:00
|
|
|
let data = UpdateCredentialsData(displayName: displayName,
|
|
|
|
note: note,
|
|
|
|
source: .init(privacy: postPrivacy, sensitive: isSensitive),
|
|
|
|
bot: isBot,
|
|
|
|
locked: isLocked,
|
|
|
|
discoverable: isDiscoverable,
|
2023-02-26 05:45:57 +00:00
|
|
|
fieldsAttributes: fields.map { .init(name: $0.name, value: $0.value) })
|
2023-02-24 06:55:24 +00:00
|
|
|
let response = try await client?.patch(endpoint: Accounts.updateCredentials(json: data))
|
2023-01-10 07:24:05 +00:00
|
|
|
if response?.statusCode != 200 {
|
|
|
|
saveError = true
|
|
|
|
}
|
|
|
|
isSaving = false
|
|
|
|
} catch {
|
|
|
|
isSaving = false
|
|
|
|
saveError = true
|
|
|
|
}
|
|
|
|
}
|
2024-02-14 11:48:14 +00:00
|
|
|
|
2024-01-02 20:16:27 +00:00
|
|
|
private func uploadHeader(data: Data) async -> Bool {
|
|
|
|
guard let client else { return false }
|
|
|
|
do {
|
|
|
|
let response = try await client.mediaUpload(endpoint: Accounts.updateCredentialsMedia,
|
2024-02-14 11:48:14 +00:00
|
|
|
version: .v1,
|
|
|
|
method: "PATCH",
|
|
|
|
mimeType: "image/jpeg",
|
|
|
|
filename: "header",
|
|
|
|
data: data)
|
2024-01-02 20:16:27 +00:00
|
|
|
return response?.statusCode == 200
|
|
|
|
} catch {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
2024-02-14 11:48:14 +00:00
|
|
|
|
2024-01-02 20:16:27 +00:00
|
|
|
private func uploadAvatar(data: Data) async -> Bool {
|
|
|
|
guard let client else { return false }
|
|
|
|
do {
|
|
|
|
let response = try await client.mediaUpload(endpoint: Accounts.updateCredentialsMedia,
|
2024-02-14 11:48:14 +00:00
|
|
|
version: .v1,
|
|
|
|
method: "PATCH",
|
|
|
|
mimeType: "image/jpeg",
|
|
|
|
filename: "avatar",
|
|
|
|
data: data)
|
2024-01-02 20:16:27 +00:00
|
|
|
return response?.statusCode == 200
|
|
|
|
} catch {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
2024-02-14 11:48:14 +00:00
|
|
|
|
2024-01-02 20:16:27 +00:00
|
|
|
private func getItemImageData(item: PhotosPickerItem) async -> Data? {
|
2024-01-06 17:43:26 +00:00
|
|
|
guard let imageFile = try? await item.loadTransferable(type: StatusEditor.ImageFileTranseferable.self) else { return nil }
|
2024-01-02 20:16:27 +00:00
|
|
|
|
2024-01-06 17:43:26 +00:00
|
|
|
let compressor = StatusEditor.Compressor()
|
2024-01-02 20:16:27 +00:00
|
|
|
|
|
|
|
guard let compressedData = await compressor.compressImageFrom(url: imageFile.url),
|
2024-02-14 11:48:14 +00:00
|
|
|
let image = UIImage(data: compressedData),
|
|
|
|
let uploadData = try? await compressor.compressImageForUpload(image)
|
2024-01-02 20:16:27 +00:00
|
|
|
else { return nil }
|
2024-02-14 11:48:14 +00:00
|
|
|
|
2024-01-02 20:16:27 +00:00
|
|
|
return uploadData
|
|
|
|
}
|
2023-01-10 07:24:05 +00:00
|
|
|
}
|