forked from shadowfacts/Tusker
parent
02461ad46c
commit
41a31c23b7
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 */,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue