forked from shadowfacts/Tusker
Fix crash when opening Compose screen before account/instance is loaded
Prevents when opening the Compose screen with poor network connectivity
This commit is contained in:
parent
9b85090884
commit
809584cc54
|
@ -9,7 +9,7 @@
|
|||
import Foundation
|
||||
import Pachyderm
|
||||
|
||||
class MastodonController {
|
||||
class MastodonController: ObservableObject {
|
||||
|
||||
static private(set) var all = [LocalData.UserAccountInfo: MastodonController]()
|
||||
|
||||
|
@ -42,8 +42,8 @@ class MastodonController {
|
|||
|
||||
let client: Client!
|
||||
|
||||
var account: Account!
|
||||
var instance: Instance!
|
||||
@Published private(set) var account: Account!
|
||||
@Published private(set) var instance: Instance!
|
||||
|
||||
var loggedIn: Bool {
|
||||
accountInfo != nil
|
||||
|
@ -95,7 +95,9 @@ class MastodonController {
|
|||
completion?(.failure(error))
|
||||
|
||||
case let .success(account, _):
|
||||
self.account = account
|
||||
DispatchQueue.main.async {
|
||||
self.account = account
|
||||
}
|
||||
self.persistentContainer.backgroundContext.perform {
|
||||
if let accountMO = self.persistentContainer.account(for: account.id, in: self.persistentContainer.backgroundContext) {
|
||||
accountMO.updateFrom(apiAccount: account, container: self.persistentContainer)
|
||||
|
@ -118,13 +120,12 @@ class MastodonController {
|
|||
let request = Client.getInstance()
|
||||
run(request) { (response) in
|
||||
guard case let .success(instance, _) = response else { fatalError() }
|
||||
self.instance = instance
|
||||
completion?(instance)
|
||||
DispatchQueue.main.async {
|
||||
self.instance = instance
|
||||
completion?(instance)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ObservableObject so that SwiftUI views can receive it through @EnvironmentObject
|
||||
extension MastodonController: ObservableObject {}
|
||||
|
|
|
@ -91,7 +91,9 @@ struct ComposeAttachmentsList: View {
|
|||
}
|
||||
|
||||
private var canAddAttachment: Bool {
|
||||
switch mastodonController.instance.instanceType {
|
||||
switch mastodonController.instance?.instanceType {
|
||||
case nil:
|
||||
return false
|
||||
case .pleroma:
|
||||
return true
|
||||
case .mastodon:
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import SwiftUI
|
||||
|
||||
struct ComposeAvatarImageView: View {
|
||||
let url: URL
|
||||
let url: URL?
|
||||
@State var request: ImageCache.Request? = nil
|
||||
@State var avatarImage: UIImage? = nil
|
||||
@ObservedObject var preferences = Preferences.shared
|
||||
|
@ -19,7 +19,9 @@ struct ComposeAvatarImageView: View {
|
|||
.resizable()
|
||||
.frame(width: 50, height: 50)
|
||||
.cornerRadius(preferences.avatarStyle.cornerRadiusFraction * 50)
|
||||
.onAppear(perform: self.loadImage)
|
||||
.conditionally(url != nil) {
|
||||
$0.onAppear(perform: self.loadImage)
|
||||
}
|
||||
.onDisappear(perform: self.cancelRequest)
|
||||
}
|
||||
|
||||
|
@ -27,24 +29,33 @@ struct ComposeAvatarImageView: View {
|
|||
if let avatarImage = avatarImage {
|
||||
return Image(uiImage: avatarImage)
|
||||
} else {
|
||||
let imageName: String
|
||||
switch preferences.avatarStyle {
|
||||
case .circle:
|
||||
imageName = "person.crop.circle"
|
||||
case .roundRect:
|
||||
imageName = "person.crop.square"
|
||||
}
|
||||
return Image(systemName: imageName)
|
||||
return placeholderImage
|
||||
}
|
||||
}
|
||||
|
||||
private var placeholderImage: Image {
|
||||
let imageName: String
|
||||
switch preferences.avatarStyle {
|
||||
case .circle:
|
||||
imageName = "person.crop.circle"
|
||||
case .roundRect:
|
||||
imageName = "person.crop.square"
|
||||
}
|
||||
return Image(systemName: imageName)
|
||||
}
|
||||
|
||||
private func loadImage() {
|
||||
guard let url = url else { return }
|
||||
request = ImageCache.avatars.get(url) { (data) in
|
||||
DispatchQueue.main.async {
|
||||
self.request = nil
|
||||
if let data = data, let image = UIImage(data: data) {
|
||||
if let data = data, let image = UIImage(data: data) {
|
||||
DispatchQueue.main.async {
|
||||
self.request = nil
|
||||
self.avatarImage = image
|
||||
}
|
||||
} else {
|
||||
DispatchQueue.main.async {
|
||||
self.request = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,24 +12,29 @@ import Pachyderm
|
|||
struct ComposeCurrentAccount: View {
|
||||
@EnvironmentObject var mastodonController: MastodonController
|
||||
|
||||
var account: Account {
|
||||
mastodonController.account!
|
||||
var account: Account? {
|
||||
mastodonController.account
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
HStack(alignment: .top) {
|
||||
ComposeAvatarImageView(url: account.avatar)
|
||||
.accessibility(label: Text("\(account.displayName) avatar"))
|
||||
ComposeAvatarImageView(url: account?.avatar)
|
||||
.accessibility(label: Text(account != nil ? "\(account!.displayName) avatar" : "Avatar"))
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
AccountDisplayNameLabel(account: mastodonController.persistentContainer.account(for: account.id)!, fontSize: 20)
|
||||
.lineLimit(1)
|
||||
|
||||
Text(verbatim: "@\(account.acct)")
|
||||
.font(.system(size: 17, weight: .light))
|
||||
.foregroundColor(.secondary)
|
||||
.lineLimit(1)
|
||||
if let id = account?.id,
|
||||
let account = mastodonController.persistentContainer.account(for: id) {
|
||||
VStack(alignment: .leading) {
|
||||
AccountDisplayNameLabel(account: account, fontSize: 20)
|
||||
.lineLimit(1)
|
||||
|
||||
Text(verbatim: "@\(account.acct)")
|
||||
.font(.system(size: 17, weight: .light))
|
||||
.foregroundColor(.secondary)
|
||||
.lineLimit(1)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ struct ComposeView: View {
|
|||
}
|
||||
|
||||
var charactersRemaining: Int {
|
||||
let limit = mastodonController.instance.maxStatusCharacters ?? 500
|
||||
let limit = mastodonController.instance?.maxStatusCharacters ?? 500
|
||||
let cwCount = draft.contentWarningEnabled ? draft.contentWarning.count : 0
|
||||
return limit - (cwCount + CharacterCounter.count(text: draft.text))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue