forked from shadowfacts/Tusker
Move InstanceFeatures to separate package
This commit is contained in:
parent
247bb31c56
commit
391ea1b46a
|
@ -0,0 +1,9 @@
|
|||
.DS_Store
|
||||
/.build
|
||||
/Packages
|
||||
/*.xcodeproj
|
||||
xcuserdata/
|
||||
DerivedData/
|
||||
.swiftpm/config/registries.json
|
||||
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
||||
.netrc
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "swift-system",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-system.git",
|
||||
"state" : {
|
||||
"revision" : "025bcb1165deab2e20d4eaba79967ce73013f496",
|
||||
"version" : "1.2.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-url",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/karwa/swift-url.git",
|
||||
"state" : {
|
||||
"branch" : "main",
|
||||
"revision" : "220f6ab9d8a7e0742f85eb9f21b745942e001ae6"
|
||||
}
|
||||
}
|
||||
],
|
||||
"version" : 2
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
// swift-tools-version: 5.7
|
||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "InstanceFeatures",
|
||||
platforms: [
|
||||
.iOS(.v15),
|
||||
],
|
||||
products: [
|
||||
// Products define the executables and libraries a package produces, and make them visible to other packages.
|
||||
.library(
|
||||
name: "InstanceFeatures",
|
||||
targets: ["InstanceFeatures"]),
|
||||
],
|
||||
dependencies: [
|
||||
// Dependencies declare other packages that this package depends on.
|
||||
.package(path: "../Pachyderm"),
|
||||
],
|
||||
targets: [
|
||||
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
||||
// Targets can depend on other targets in this package, and on products in packages this package depends on.
|
||||
.target(
|
||||
name: "InstanceFeatures",
|
||||
dependencies: ["Pachyderm"]),
|
||||
.testTarget(
|
||||
name: "InstanceFeaturesTests",
|
||||
dependencies: ["InstanceFeatures"]),
|
||||
]
|
||||
)
|
|
@ -0,0 +1,3 @@
|
|||
# InstanceFeatures
|
||||
|
||||
A description of this package.
|
|
@ -7,17 +7,20 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import Pachyderm
|
||||
import Sentry
|
||||
|
||||
struct InstanceFeatures {
|
||||
public class InstanceFeatures: ObservableObject {
|
||||
private static let pleromaVersionRegex = try! NSRegularExpression(pattern: "\\(compatible; pleroma (.*)\\)", options: .caseInsensitive)
|
||||
private static let akkomaVersionRegex = try! NSRegularExpression(pattern: "\\(compatible; akkoma (.*)\\)", options: .caseInsensitive)
|
||||
|
||||
private var instanceType: InstanceType = .mastodon(.vanilla, nil)
|
||||
private(set) var maxStatusChars = 500
|
||||
private let _featuresUpdated = PassthroughSubject<Void, Never>()
|
||||
public var featuresUpdated: some Publisher<Void, Never> { _featuresUpdated }
|
||||
|
||||
var localOnlyPosts: Bool {
|
||||
@Published private var instanceType: InstanceType = .mastodon(.vanilla, nil)
|
||||
@Published public private(set) var maxStatusChars = 500
|
||||
|
||||
public var localOnlyPosts: Bool {
|
||||
switch instanceType {
|
||||
case .mastodon(.hometown(_), _), .mastodon(.glitch, _):
|
||||
return true
|
||||
|
@ -26,19 +29,19 @@ struct InstanceFeatures {
|
|||
}
|
||||
}
|
||||
|
||||
var mastodonAttachmentRestrictions: Bool {
|
||||
public var mastodonAttachmentRestrictions: Bool {
|
||||
instanceType.isMastodon
|
||||
}
|
||||
|
||||
var pollsAndAttachments: Bool {
|
||||
public var pollsAndAttachments: Bool {
|
||||
instanceType.isPleroma
|
||||
}
|
||||
|
||||
var boostToOriginalAudience: Bool {
|
||||
public var boostToOriginalAudience: Bool {
|
||||
instanceType.isPleroma || instanceType.isMastodon
|
||||
}
|
||||
|
||||
var profilePinnedStatuses: Bool {
|
||||
public var profilePinnedStatuses: Bool {
|
||||
switch instanceType {
|
||||
case .pixelfed:
|
||||
return false
|
||||
|
@ -47,24 +50,24 @@ struct InstanceFeatures {
|
|||
}
|
||||
}
|
||||
|
||||
var trends: Bool {
|
||||
public var trends: Bool {
|
||||
instanceType.isMastodon
|
||||
}
|
||||
|
||||
var profileSuggestions: Bool {
|
||||
public var profileSuggestions: Bool {
|
||||
instanceType.isMastodon && hasMastodonVersion(3, 4, 0)
|
||||
}
|
||||
|
||||
var trendingStatusesAndLinks: Bool {
|
||||
public var trendingStatusesAndLinks: Bool {
|
||||
instanceType.isMastodon && hasMastodonVersion(3, 5, 0)
|
||||
}
|
||||
|
||||
var reblogVisibility: Bool {
|
||||
public var reblogVisibility: Bool {
|
||||
(instanceType.isMastodon && hasMastodonVersion(2, 8, 0))
|
||||
|| (instanceType.isPleroma && hasPleromaVersion(2, 0, 0))
|
||||
}
|
||||
|
||||
var probablySupportsMarkdown: Bool {
|
||||
public var probablySupportsMarkdown: Bool {
|
||||
switch instanceType {
|
||||
case .pleroma(_), .mastodon(.glitch, _), .mastodon(.hometown(_), _):
|
||||
return true
|
||||
|
@ -73,7 +76,7 @@ struct InstanceFeatures {
|
|||
}
|
||||
}
|
||||
|
||||
var needsLocalOnlyEmojiHack: Bool {
|
||||
public var needsLocalOnlyEmojiHack: Bool {
|
||||
if case .mastodon(.glitch, _) = instanceType {
|
||||
return true
|
||||
} else {
|
||||
|
@ -81,7 +84,7 @@ struct InstanceFeatures {
|
|||
}
|
||||
}
|
||||
|
||||
var needsWideColorGamutHack: Bool {
|
||||
public var needsWideColorGamutHack: Bool {
|
||||
if case .mastodon(_, .some(let version)) = instanceType {
|
||||
return version < Version(4, 0, 0)
|
||||
} else {
|
||||
|
@ -89,23 +92,26 @@ struct InstanceFeatures {
|
|||
}
|
||||
}
|
||||
|
||||
var canFollowHashtags: Bool {
|
||||
public var canFollowHashtags: Bool {
|
||||
hasMastodonVersion(4, 0, 0)
|
||||
}
|
||||
|
||||
var filtersV2: Bool {
|
||||
public var filtersV2: Bool {
|
||||
hasMastodonVersion(4, 0, 0)
|
||||
}
|
||||
|
||||
var notificationsAllowedTypes: Bool {
|
||||
public var notificationsAllowedTypes: Bool {
|
||||
hasMastodonVersion(3, 5, 0)
|
||||
}
|
||||
|
||||
var pollVotersCount: Bool {
|
||||
public var pollVotersCount: Bool {
|
||||
instanceType.isMastodon
|
||||
}
|
||||
|
||||
mutating func update(instance: Instance, nodeInfo: NodeInfo?) {
|
||||
public init() {
|
||||
}
|
||||
|
||||
public func update(instance: Instance, nodeInfo: NodeInfo?) {
|
||||
let ver = instance.version.lowercased()
|
||||
if ver.contains("glitch") {
|
||||
instanceType = .mastodon(.glitch, Version(string: ver))
|
||||
|
@ -150,10 +156,10 @@ struct InstanceFeatures {
|
|||
|
||||
maxStatusChars = instance.maxStatusCharacters ?? 500
|
||||
|
||||
setInstanceBreadcrumb(instance: instance, nodeInfo: nodeInfo)
|
||||
_featuresUpdated.send()
|
||||
}
|
||||
|
||||
func hasMastodonVersion(_ major: Int, _ minor: Int, _ patch: Int) -> Bool {
|
||||
public func hasMastodonVersion(_ major: Int, _ minor: Int, _ patch: Int) -> Bool {
|
||||
if case .mastodon(_, .some(let version)) = instanceType {
|
||||
return version >= Version(major, minor, patch)
|
||||
} else {
|
||||
|
@ -259,19 +265,3 @@ extension InstanceFeatures {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func setInstanceBreadcrumb(instance: Instance, nodeInfo: NodeInfo?) {
|
||||
let crumb = Breadcrumb(level: .info, category: "MastodonController")
|
||||
crumb.data = [
|
||||
"instance": [
|
||||
"version": instance.version
|
||||
],
|
||||
]
|
||||
if let nodeInfo {
|
||||
crumb.data!["nodeInfo"] = [
|
||||
"software": nodeInfo.software.name,
|
||||
"version": nodeInfo.software.version,
|
||||
]
|
||||
}
|
||||
SentrySDK.addBreadcrumb(crumb)
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
//
|
||||
// VersionTests.swift
|
||||
// TuskerTests
|
||||
// InstanceFeaturesTests
|
||||
//
|
||||
// Created by Shadowfacts on 4/2/22.
|
||||
// Copyright © 2022 Shadowfacts. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Tusker
|
||||
@testable import InstanceFeatures
|
||||
|
||||
class VersionTests: XCTestCase {
|
||||
|
|
@ -113,7 +113,6 @@
|
|||
D62D2426217ABF63005076CC /* UserActivityType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2425217ABF63005076CC /* UserActivityType.swift */; };
|
||||
D62E9985279CA23900C26176 /* URLSession+Development.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62E9984279CA23900C26176 /* URLSession+Development.swift */; };
|
||||
D62E9987279D094F00C26176 /* StatusMetaIndicatorsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62E9986279D094F00C26176 /* StatusMetaIndicatorsView.swift */; };
|
||||
D62E9989279DB2D100C26176 /* InstanceFeatures.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62E9988279DB2D100C26176 /* InstanceFeatures.swift */; };
|
||||
D62FF04823D7CDD700909D6E /* AttributedStringHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62FF04723D7CDD700909D6E /* AttributedStringHelperTests.swift */; };
|
||||
D6311C5025B3765B00B27539 /* ImageDataCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6311C4F25B3765B00B27539 /* ImageDataCache.swift */; };
|
||||
D6333B372137838300CE884A /* AttributedString+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B362137838300CE884A /* AttributedString+Helpers.swift */; };
|
||||
|
@ -373,6 +372,7 @@
|
|||
D6F6A557291F4F1600F496A8 /* MuteAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F6A556291F4F1600F496A8 /* MuteAccountView.swift */; };
|
||||
D6F6A5592920676800F496A8 /* ComposeToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F6A5582920676800F496A8 /* ComposeToolbar.swift */; };
|
||||
D6F953F021251A2900CF0F2B /* MastodonController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F953EF21251A2900CF0F2B /* MastodonController.swift */; };
|
||||
D6FA94E129B52898006AAC51 /* InstanceFeatures in Frameworks */ = {isa = PBXBuildFile; productRef = D6FA94E029B52898006AAC51 /* InstanceFeatures */; };
|
||||
D6FF9860255C717400845181 /* AccountSwitchingContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6FF985F255C717400845181 /* AccountSwitchingContainerViewController.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
|
@ -530,7 +530,6 @@
|
|||
D62D2425217ABF63005076CC /* UserActivityType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivityType.swift; sourceTree = "<group>"; };
|
||||
D62E9984279CA23900C26176 /* URLSession+Development.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLSession+Development.swift"; sourceTree = "<group>"; };
|
||||
D62E9986279D094F00C26176 /* StatusMetaIndicatorsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusMetaIndicatorsView.swift; sourceTree = "<group>"; };
|
||||
D62E9988279DB2D100C26176 /* InstanceFeatures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceFeatures.swift; sourceTree = "<group>"; };
|
||||
D62FF04723D7CDD700909D6E /* AttributedStringHelperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringHelperTests.swift; sourceTree = "<group>"; };
|
||||
D6311C4F25B3765B00B27539 /* ImageDataCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageDataCache.swift; sourceTree = "<group>"; };
|
||||
D6333B362137838300CE884A /* AttributedString+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AttributedString+Helpers.swift"; sourceTree = "<group>"; };
|
||||
|
@ -803,6 +802,7 @@
|
|||
D6F6A556291F4F1600F496A8 /* MuteAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MuteAccountView.swift; sourceTree = "<group>"; };
|
||||
D6F6A5582920676800F496A8 /* ComposeToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeToolbar.swift; sourceTree = "<group>"; };
|
||||
D6F953EF21251A2900CF0F2B /* MastodonController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonController.swift; sourceTree = "<group>"; };
|
||||
D6FA94DF29B52891006AAC51 /* InstanceFeatures */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = InstanceFeatures; path = Packages/InstanceFeatures; sourceTree = "<group>"; };
|
||||
D6FF985F255C717400845181 /* AccountSwitchingContainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountSwitchingContainerViewController.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
|
@ -811,6 +811,7 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D6FA94E129B52898006AAC51 /* InstanceFeatures in Frameworks */,
|
||||
D674A50927F9128D00BA03AC /* Pachyderm in Frameworks */,
|
||||
D659F35E2953A212002D944A /* TTTKit in Frameworks */,
|
||||
D6B0026E29B5248800C70BE2 /* UserAccounts in Frameworks */,
|
||||
|
@ -1539,6 +1540,7 @@
|
|||
D6BEA243291A0C83002F4D01 /* Duckable */,
|
||||
D68A76F22953915C001DA1B3 /* TTTKit */,
|
||||
D6B0026C29B5245400C70BE2 /* UserAccounts */,
|
||||
D6FA94DF29B52891006AAC51 /* InstanceFeatures */,
|
||||
D6D4DDCE212518A000E1C4BB /* Tusker */,
|
||||
D6D4DDE3212518A200E1C4BB /* TuskerTests */,
|
||||
D6D4DDEE212518A200E1C4BB /* TuskerUITests */,
|
||||
|
@ -1694,7 +1696,6 @@
|
|||
D6F953F121251A2F00CF0F2B /* API */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D62E9988279DB2D100C26176 /* InstanceFeatures.swift */,
|
||||
D6F953EF21251A2900CF0F2B /* MastodonController.swift */,
|
||||
D6E9CDA7281A427800BBC98E /* PostService.swift */,
|
||||
D61ABEFD28F1C92600B29151 /* FavoriteService.swift */,
|
||||
|
@ -1743,6 +1744,7 @@
|
|||
D6BEA244291A0EDE002F4D01 /* Duckable */,
|
||||
D659F35D2953A212002D944A /* TTTKit */,
|
||||
D6B0026D29B5248800C70BE2 /* UserAccounts */,
|
||||
D6FA94E029B52898006AAC51 /* InstanceFeatures */,
|
||||
);
|
||||
productName = Tusker;
|
||||
productReference = D6D4DDCC212518A000E1C4BB /* Tusker.app */;
|
||||
|
@ -1999,7 +2001,6 @@
|
|||
D6969E9E240C81B9002843CE /* NSTextAttachment+Emoji.swift in Sources */,
|
||||
D6BC9DB3232D4C07002CA326 /* WellnessPrefsView.swift in Sources */,
|
||||
D64BC18F23C18B9D000D0238 /* FollowRequestNotificationTableViewCell.swift in Sources */,
|
||||
D62E9989279DB2D100C26176 /* InstanceFeatures.swift in Sources */,
|
||||
D6ADB6F028ED1F25009924AB /* CachedImageView.swift in Sources */,
|
||||
D693DE5923FE24310061E07D /* InteractivePushTransition.swift in Sources */,
|
||||
D69693FA25859A8000F4E116 /* ComposeSceneDelegate.swift in Sources */,
|
||||
|
@ -2975,6 +2976,10 @@
|
|||
isa = XCSwiftPackageProductDependency;
|
||||
productName = Duckable;
|
||||
};
|
||||
D6FA94E029B52898006AAC51 /* InstanceFeatures */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = InstanceFeatures;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
|
||||
/* Begin XCVersionGroup section */
|
||||
|
|
|
@ -10,6 +10,8 @@ import Foundation
|
|||
import Pachyderm
|
||||
import Combine
|
||||
import UserAccounts
|
||||
import InstanceFeatures
|
||||
import Sentry
|
||||
|
||||
class MastodonController: ObservableObject {
|
||||
|
||||
|
@ -48,11 +50,11 @@ class MastodonController: ObservableObject {
|
|||
var accountPreferences: AccountPreferences!
|
||||
|
||||
let client: Client!
|
||||
let instanceFeatures = InstanceFeatures()
|
||||
|
||||
@Published private(set) var account: Account!
|
||||
@Published private(set) var instance: Instance!
|
||||
@Published private(set) var nodeInfo: NodeInfo!
|
||||
@Published private(set) var instanceFeatures = InstanceFeatures()
|
||||
@Published private(set) var lists: [List] = []
|
||||
@Published private(set) var customEmojis: [Emoji]?
|
||||
@Published private(set) var followedHashtags: [FollowedHashtag] = []
|
||||
|
@ -84,11 +86,12 @@ class MastodonController: ObservableObject {
|
|||
}
|
||||
.sink { [unowned self] (instance, nodeInfo) in
|
||||
self.instanceFeatures.update(instance: instance, nodeInfo: nodeInfo)
|
||||
setInstanceBreadcrumb(instance: instance, nodeInfo: nodeInfo)
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
$instanceFeatures
|
||||
.filter { [unowned self] in $0.canFollowHashtags && self.followedHashtags.isEmpty }
|
||||
instanceFeatures.featuresUpdated
|
||||
.filter { [unowned self] _ in self.instanceFeatures.canFollowHashtags && self.followedHashtags.isEmpty }
|
||||
.sink { [unowned self] _ in
|
||||
Task {
|
||||
await self.loadFollowedHashtags()
|
||||
|
@ -454,3 +457,19 @@ class MastodonController: ObservableObject {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
private func setInstanceBreadcrumb(instance: Instance, nodeInfo: NodeInfo?) {
|
||||
let crumb = Breadcrumb(level: .info, category: "MastodonController")
|
||||
crumb.data = [
|
||||
"instance": [
|
||||
"version": instance.version
|
||||
],
|
||||
]
|
||||
if let nodeInfo {
|
||||
crumb.data!["nodeInfo"] = [
|
||||
"software": nodeInfo.software.name,
|
||||
"version": nodeInfo.software.version,
|
||||
]
|
||||
}
|
||||
SentrySDK.addBreadcrumb(crumb)
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import UIKit
|
|||
import Photos
|
||||
import UniformTypeIdentifiers
|
||||
import PencilKit
|
||||
import InstanceFeatures
|
||||
|
||||
enum CompositionAttachmentData {
|
||||
case asset(PHAsset)
|
||||
|
|
Loading…
Reference in New Issue