Compare commits

..

5 Commits

Author SHA1 Message Date
Shadowfacts b28792eb29 Report string when mention url decoding fails 2023-09-09 11:41:54 -04:00
Shadowfacts 9c3be68e1c Don't report 422 or 500 errors 2023-09-09 11:40:18 -04:00
Shadowfacts df9ce81060 Fix crash when ComposeUIConfig.dismiss called after hosting controller dealloc'd
I'm not sure how this can happen (possibly if the user dismissed the
compose screen while the status was being posted? but I haven't been
able to reproduce that), but guard against it since it's causing crashes
2023-09-09 11:37:25 -04:00
Shadowfacts 173eda1757 Prevent dismissing compose screen while posting 2023-09-09 11:35:46 -04:00
Shadowfacts b2b15b8b6e Disallow posting direct messages on Pixelfed 2023-09-09 11:07:27 -04:00
6 changed files with 34 additions and 9 deletions

View File

@ -58,7 +58,7 @@ public final class ComposeController: ViewController {
private var isDisappearing = false private var isDisappearing = false
private var userConfirmedDelete = false private var userConfirmedDelete = false
var isPosting: Bool { public var isPosting: Bool {
poster != nil poster != nil
} }
@ -424,6 +424,7 @@ public final class ComposeController: ViewController {
// otherwise all Buttons in the nav bar are made semibold // otherwise all Buttons in the nav bar are made semibold
.font(.system(size: 17, weight: .regular)) .font(.system(size: 17, weight: .regular))
} }
.disabled(controller.isPosting)
.confirmationDialog("Are you sure?", isPresented: $controller.isShowingSaveDraftSheet) { .confirmationDialog("Are you sure?", isPresented: $controller.isShowingSaveDraftSheet) {
// edit drafts can't be saved // edit drafts can't be saved
if draft.editedStatusID == nil { if draft.editedStatusID == nil {

View File

@ -11,9 +11,6 @@ import TuskerComponents
class ToolbarController: ViewController { class ToolbarController: ViewController {
static let height: CGFloat = 44 static let height: CGFloat = 44
private static let visibilityOptions: [MenuPicker<Pachyderm.Visibility>.Option] = Pachyderm.Visibility.allCases.map { vis in
.init(value: vis, title: vis.displayName, subtitle: vis.subtitle, image: UIImage(systemName: vis.unfilledImageName), accessibilityLabel: "Visibility: \(vis.displayName)")
}
unowned let parent: ComposeController unowned let parent: ComposeController
@ -56,7 +53,7 @@ class ToolbarController: ViewController {
HStack(spacing: 0) { HStack(spacing: 0) {
cwButton cwButton
MenuPicker(selection: $draft.visibility, options: ToolbarController.visibilityOptions, buttonStyle: .iconOnly) MenuPicker(selection: $draft.visibility, options: visibilityOptions, buttonStyle: .iconOnly)
// the button has a bunch of extra space by default, but combined with what we add it's too much // the button has a bunch of extra space by default, but combined with what we add it's too much
.padding(.horizontal, -8) .padding(.horizontal, -8)
.disabled(draft.editedStatusID != nil) .disabled(draft.editedStatusID != nil)
@ -121,6 +118,18 @@ class ToolbarController: ViewController {
.hoverEffect() .hoverEffect()
} }
private var visibilityOptions: [MenuPicker<Pachyderm.Visibility>.Option] {
let visibilities: [Pachyderm.Visibility]
if !controller.parent.mastodonController.instanceFeatures.composeDirectStatuses {
visibilities = [.public, .unlisted, .private]
} else {
visibilities = Pachyderm.Visibility.allCases
}
return visibilities.map { vis in
.init(value: vis, title: vis.displayName, subtitle: vis.subtitle, image: UIImage(systemName: vis.unfilledImageName), accessibilityLabel: "Visibility: \(vis.displayName)")
}
}
private var localOnlyPicker: some View { private var localOnlyPicker: some View {
let domain = composeController.mastodonController.accountInfo!.instanceURL.host! let domain = composeController.mastodonController.accountInfo!.instanceURL.host!
return MenuPicker(selection: $draft.localOnly, options: [ return MenuPicker(selection: $draft.localOnly, options: [

View File

@ -147,6 +147,14 @@ public class InstanceFeatures: ObservableObject {
instanceType.isPleroma(.akkoma(nil)) instanceType.isPleroma(.akkoma(nil))
} }
public var composeDirectStatuses: Bool {
if case .pixelfed = instanceType {
return false
} else {
return true
}
}
public init() { public init() {
} }

View File

@ -21,7 +21,12 @@ public struct Mention: Codable, Sendable {
self.username = try container.decode(String.self, forKey: .username) self.username = try container.decode(String.self, forKey: .username)
self.acct = try container.decode(String.self, forKey: .acct) self.acct = try container.decode(String.self, forKey: .acct)
self.id = try container.decode(String.self, forKey: .id) self.id = try container.decode(String.self, forKey: .id)
do {
self.url = try container.decode(WebURL.self, forKey: .url) self.url = try container.decode(WebURL.self, forKey: .url)
} catch {
let s = try? container.decode(String.self, forKey: .url)
throw DecodingError.dataCorruptedError(forKey: .url, in: container, debugDescription: "Could not decode URL '\(s ?? "<failed to decode string>")'")
}
} }
public init(url: WebURL, username: String, acct: String, id: String) { public init(url: WebURL, username: String, acct: String, id: String) {

View File

@ -88,7 +88,7 @@ class ComposeHostingController: UIHostingController<ComposeHostingController.Vie
config.contentType = Preferences.shared.statusContentType config.contentType = Preferences.shared.statusContentType
config.requireAttachmentDescriptions = Preferences.shared.requireAttachmentDescriptions config.requireAttachmentDescriptions = Preferences.shared.requireAttachmentDescriptions
config.dismiss = { [unowned self] in self.dismiss(mode: $0) } config.dismiss = { [weak self] in self?.dismiss(mode: $0) }
config.presentAssetPicker = { [unowned self] in self.presentAssetPicker(completion: $0) } config.presentAssetPicker = { [unowned self] in self.presentAssetPicker(completion: $0) }
config.presentDrawing = { [unowned self] in self.presentDrawing($0, completion: $1) } config.presentDrawing = { [unowned self] in self.presentDrawing($0, completion: $1) }
config.userActivityForDraft = { [unowned self] in config.userActivityForDraft = { [unowned self] in
@ -144,7 +144,9 @@ class ComposeHostingController: UIHostingController<ComposeHostingController.Vie
// MARK: Duckable // MARK: Duckable
func duckableViewControllerShouldDuck() -> DuckAttemptAction { func duckableViewControllerShouldDuck() -> DuckAttemptAction {
if controller.draft.hasContent { if controller.isPosting {
return .block
} else if controller.draft.hasContent {
return .duck return .duck
} else { } else {
return .dismiss return .dismiss

View File

@ -125,7 +125,7 @@ private func captureError(_ error: Client.Error, in mastodonController: Mastodon
return return
} }
if let code = event.tags!["response_code"], if let code = event.tags!["response_code"],
code == "401" || code == "403" || code == "404" || code == "502" || code == "503" { code == "401" || code == "403" || code == "404" || code == "422" || code == "500" || code == "502" || code == "503" {
return return
} }
switch mastodonController.instanceFeatures.instanceType { switch mastodonController.instanceFeatures.instanceType {