Allow posting local-only from Glitch instances

See #130
This commit is contained in:
Shadowfacts 2022-01-24 22:49:18 -05:00
parent 02461ad46c
commit 41a31c23b7
11 changed files with 79 additions and 70 deletions

View File

@ -336,7 +336,7 @@ public class Client {
pollOptions: [String]? = nil,
pollExpiresIn: Int? = nil,
pollMultiple: Bool? = nil,
localOnly: Bool? = nil) -> Request<Status> {
localOnly: Bool? = nil /* hometown only, not glitch */) -> Request<Status> {
return Request<Status>(method: .post, path: "/api/v1/statuses", body: ParametersBody([
"status" => text,
"content_type" => contentType.mimeType,

View File

@ -1,24 +0,0 @@
//
// InstanceType.swift
// Pachyderm
//
// Created by Shadowfacts on 9/11/19.
// Copyright © 2019 Shadowfacts. All rights reserved.
//
import Foundation
public enum InstanceType {
case mastodon, pleroma
}
public extension Instance {
var instanceType: InstanceType {
let lowercased = version.lowercased()
if lowercased.contains("pleroma") {
return .pleroma
} else {
return .mastodon
}
}
}

View File

@ -176,7 +176,6 @@
D663626421360D2300C9CBA2 /* AvatarStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D663626321360D2300C9CBA2 /* AvatarStyle.swift */; };
D663626C21361C6700C9CBA2 /* Account+Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = D663626B21361C6700C9CBA2 /* Account+Preferences.swift */; };
D66362752137068A00C9CBA2 /* Visibility+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D66362742137068A00C9CBA2 /* Visibility+Helpers.swift */; };
D667383C23299340000A2373 /* InstanceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D667383B23299340000A2373 /* InstanceType.swift */; };
D6674AEA23341F7600E8DF94 /* AppShortcutItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6674AE923341F7600E8DF94 /* AppShortcutItems.swift */; };
D667E5E12134937B0057A976 /* TimelineStatusTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D667E5E02134937B0057A976 /* TimelineStatusTableViewCell.xib */; };
D667E5F12134D5050057A976 /* UIViewController+Delegates.swift in Sources */ = {isa = PBXBuildFile; fileRef = D667E5F02134D5050057A976 /* UIViewController+Delegates.swift */; };
@ -589,7 +588,6 @@
D663626321360D2300C9CBA2 /* AvatarStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarStyle.swift; sourceTree = "<group>"; };
D663626B21361C6700C9CBA2 /* Account+Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Account+Preferences.swift"; sourceTree = "<group>"; };
D66362742137068A00C9CBA2 /* Visibility+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Visibility+Helpers.swift"; sourceTree = "<group>"; };
D667383B23299340000A2373 /* InstanceType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceType.swift; sourceTree = "<group>"; };
D6674AE923341F7600E8DF94 /* AppShortcutItems.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppShortcutItems.swift; sourceTree = "<group>"; };
D667E5E02134937B0057A976 /* TimelineStatusTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TimelineStatusTableViewCell.xib; sourceTree = "<group>"; };
D667E5F02134D5050057A976 /* UIViewController+Delegates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Delegates.swift"; sourceTree = "<group>"; };
@ -1374,7 +1372,6 @@
D6E6F26221603F8B006A8599 /* CharacterCounter.swift */,
D6A3BC7323218C6E00FD64D5 /* TimelineSegment.swift */,
D6A3BC7823218E9200FD64D5 /* NotificationGroup.swift */,
D667383B23299340000A2373 /* InstanceType.swift */,
D61AC1D2232E928600C54D2D /* InstanceSelector.swift */,
);
path = Utilities;
@ -2007,7 +2004,6 @@
buildActionMask = 2147483647;
files = (
D61099E5214561AB00432DC2 /* Application.swift in Sources */,
D667383C23299340000A2373 /* InstanceType.swift in Sources */,
D62E9983279C69D400C26176 /* WellKnown.swift in Sources */,
D61099FF21456A4C00432DC2 /* Status.swift in Sources */,
D61099E32144C38900432DC2 /* Emoji.swift in Sources */,

View File

@ -10,11 +10,54 @@ import Foundation
import Pachyderm
struct InstanceFeatures {
private(set) var instanceType = InstanceType.mastodon
private(set) var maxStatusChars = 500
private(set) var localOnlyPosts = false
var localOnlyPosts: Bool {
instanceType == .hometown || instanceType == .glitch
}
var mastodonAttachmentRestrictions: Bool {
instanceType.isMastodon
}
var pollsAndAttachments: Bool {
instanceType == .pleroma
}
var boostToOriginalAudience: Bool {
instanceType == .pleroma
}
mutating func update(instance: Instance, nodeInfo: NodeInfo?) {
if instance.version.contains("glitch") {
instanceType = .glitch
} else if nodeInfo?.software.name == "hometown" {
instanceType = .hometown
} else if instance.version.contains("pleroma") {
instanceType = .pleroma
} else {
instanceType = .mastodon
}
maxStatusChars = instance.maxStatusCharacters ?? 500
localOnlyPosts = nodeInfo?.software.name == "hometown"
}
}
extension InstanceFeatures {
enum InstanceType: Equatable {
case mastodon // vanilla
case pleroma
case hometown
case glitch
var isMastodon: Bool {
switch self {
case .mastodon, .hometown, .glitch:
return true
default:
return false
}
}
}
}

View File

@ -32,12 +32,6 @@ class Draft: Codable, ObservableObject {
poll?.hasContent == true
}
var textForPosting: String {
// when using dictation, iOS sometimes leaves a U+FFFC OBJECT REPLACEMENT CHARACTER behind in the text,
// which we want to strip out before actually posting the status
text.replacingOccurrences(of: "\u{fffc}", with: "")
}
init(accountID: String) {
self.id = UUID()
self.lastModified = Date()
@ -92,6 +86,19 @@ class Draft: Codable, ObservableObject {
try container.encode(initialText, forKey: .initialText)
}
func textForPosting(on instance: InstanceFeatures) -> String {
var text = self.text
// when using dictation, iOS sometimes leaves a U+FFFC OBJECT REPLACEMENT CHARACTER behind in the text,
// which we want to strip out before actually posting the status
text = text.replacingOccurrences(of: "\u{fffc}", with: "")
if localOnly && instance.instanceType == .glitch {
text += " 👁"
}
return text
}
}
extension Draft: Equatable {

View File

@ -87,23 +87,17 @@ struct ComposeAttachmentsList: View {
}
private var canAddAttachment: Bool {
switch mastodonController.instance?.instanceType {
case nil:
return false
case .pleroma:
return true
case .mastodon:
if mastodonController.instanceFeatures.mastodonAttachmentRestrictions {
return draft.attachments.count < 4 && draft.attachments.allSatisfy { $0.data.type == .image } && draft.poll == nil
} else {
return true
}
}
private var canAddPoll: Bool {
switch mastodonController.instance?.instanceType {
case nil:
return false
case .pleroma:
if mastodonController.instanceFeatures.pollsAndAttachments {
return true
case .mastodon:
} else {
return draft.attachments.isEmpty
}
}

View File

@ -234,13 +234,12 @@ class ComposeHostingController: UIHostingController<ComposeContainerView> {
override func canPaste(_ itemProviders: [NSItemProvider]) -> Bool {
guard itemProviders.allSatisfy({ $0.canLoadObject(ofClass: CompositionAttachment.self) }) else { return false }
switch mastodonController.instance.instanceType {
case .pleroma:
return true
case .mastodon:
if mastodonController.instanceFeatures.mastodonAttachmentRestrictions {
guard draft.attachments.allSatisfy({ $0.data.type == .image }) else { return false }
// todo: if providers are videos, this technically allows invalid video/image combinations
return itemProviders.count + draft.attachments.count <= 4
} else {
return true
}
}
@ -321,16 +320,15 @@ extension ComposeHostingController: ComposeUIStateDelegate {
extension ComposeHostingController: AssetPickerViewControllerDelegate {
func assetPicker(_ assetPicker: AssetPickerViewController, shouldAllowAssetOfType type: CompositionAttachmentData.AttachmentType) -> Bool {
switch mastodonController.instance.instanceType {
case .pleroma:
return true
case .mastodon:
if mastodonController.instanceFeatures.mastodonAttachmentRestrictions {
if (type == .video && draft.attachments.count > 0) ||
draft.attachments.contains(where: { $0.data.type == .video }) ||
assetPicker.currentCollectionSelectedAssets.contains(where: { $0.type == .video }) {
return false
}
return draft.attachments.count + assetPicker.currentCollectionSelectedAssets.count < 4
} else {
return true
}
}

View File

@ -209,7 +209,7 @@ struct ComposeView: View {
self.isPosting = false
case let .success(uploadedAttachments):
let request = Client.createStatus(text: draft.textForPosting,
let request = Client.createStatus(text: draft.textForPosting(on: mastodonController.instanceFeatures),
contentType: Preferences.shared.statusContentType,
inReplyTo: draft.inReplyToID,
media: uploadedAttachments,
@ -220,7 +220,7 @@ struct ComposeView: View {
pollOptions: draft.poll?.options.map(\.text),
pollExpiresIn: draft.poll == nil ? nil : Int(draft.poll!.duration),
pollMultiple: draft.poll?.multiple,
localOnly: mastodonController.instanceFeatures.localOnlyPosts ? draft.localOnly : nil)
localOnly: mastodonController.instanceFeatures.instanceType == .hometown ? draft.localOnly : nil)
self.mastodonController.run(request) { (response) in
switch response {
case let .failure(error):

View File

@ -138,7 +138,7 @@ class ExploreViewController: UIViewController, UICollectionViewDelegate {
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
snapshot.appendSections(Section.allCases.filter { $0 != .discover })
snapshot.appendItems([.bookmarks], toSection: .bookmarks)
if case .mastodon = mastodonController.instance?.instanceType {
if mastodonController.instanceFeatures.instanceType.isMastodon {
snapshot.insertSections([.discover], afterSection: .bookmarks)
snapshot.appendItems([.trendingTags, .profileDirectory], toSection: .discover)
}
@ -154,7 +154,7 @@ class ExploreViewController: UIViewController, UICollectionViewDelegate {
private func ownInstanceLoaded(_ instance: Instance) {
var snapshot = self.dataSource.snapshot()
if case .mastodon = instance.instanceType {
if mastodonController.instanceFeatures.instanceType.isMastodon {
snapshot.insertSections([.discover], afterSection: .bookmarks)
snapshot.appendItems([.trendingTags, .profileDirectory], toSection: .discover)
}

View File

@ -145,7 +145,7 @@ class MainSidebarViewController: UIViewController {
snapshot.appendItems([
.tab(.compose)
], toSection: .compose)
if case .mastodon = mastodonController.instance?.instanceType {
if mastodonController.instanceFeatures.instanceType.isMastodon {
snapshot.insertSections([.discover], afterSection: .compose)
snapshot.appendItems([
.trendingTags,
@ -161,7 +161,7 @@ class MainSidebarViewController: UIViewController {
private func ownInstanceLoaded(_ instance: Instance) {
var snapshot = self.dataSource.snapshot()
if case .mastodon = mastodonController.instance?.instanceType {
if mastodonController.instanceFeatures.instanceType.isMastodon {
snapshot.insertSections([.discover], afterSection: .compose)
snapshot.appendItems([
.trendingTags,

View File

@ -166,16 +166,11 @@ class BaseStatusTableViewCell: UITableViewCell, MenuPreviewProvider {
}
let reblogDisabled: Bool
switch mastodonController.instance?.instanceType {
case nil:
// todo: this handle a race condition in instance public timelines
// a somewhat better solution would be waiting to load the timeline until after the instance is loaded
reblogDisabled = true
case .mastodon:
reblogDisabled = status.visibility == .private || status.visibility == .direct
case .pleroma:
if mastodonController.instanceFeatures.boostToOriginalAudience {
// Pleroma allows 'Boost to original audience' for your own private posts
reblogDisabled = status.visibility == .direct || (status.visibility == .private && status.account.id != mastodonController.account.id)
} else {
reblogDisabled = status.visibility == .private || status.visibility == .direct
}
reblogButton.isEnabled = !reblogDisabled && mastodonController.loggedIn