mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2024-12-22 21:08:15 +01:00
Updated to resolve all possible Sendability warnings from Swift 6 compatibility mode. (#1072)
Co-authored-by: Jim Dovey <jimdovey@apple.com>
This commit is contained in:
parent
9f026fbc42
commit
d1209e6704
@ -15,7 +15,7 @@ import Network
|
||||
// Sample code was sending this from a thread to another, let asume @Sendable for this
|
||||
extension NSExtensionContext: @unchecked Sendable {}
|
||||
|
||||
class ActionRequestHandler: NSObject, NSExtensionRequestHandling {
|
||||
final class ActionRequestHandler: NSObject, NSExtensionRequestHandling, Sendable {
|
||||
enum Error: Swift.Error {
|
||||
case inputProviderNotFound
|
||||
case loadedItemHasWrongType
|
||||
|
@ -63,6 +63,15 @@
|
||||
"version" : "0.13.3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-atomics",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-atomics.git",
|
||||
"state" : {
|
||||
"revision" : "ff3d2212b6b093db7f177d0855adbc4ef9c5f036",
|
||||
"version" : "1.0.3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swiftsoup",
|
||||
"kind" : "remoteSourceControl",
|
||||
|
@ -82,6 +82,11 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
let fileURL = temporaryDirectoryURL.appendingPathComponent(filename)
|
||||
|
||||
Task {
|
||||
// Warning: Non-sendable type '(any URLSessionTaskDelegate)?' exiting main actor-isolated
|
||||
// context in call to non-isolated instance method 'data(for:delegate:)' cannot cross actor
|
||||
// boundary.
|
||||
// This is on the defaulted-to-nil second parameter of `.data(from:delegate:)`.
|
||||
// There is a Radar tracking this & others like it.
|
||||
if let (data, _) = try? await URLSession.shared.data(for: .init(url: url)) {
|
||||
if let image = UIImage(data: data) {
|
||||
try? image.pngData()?.write(to: fileURL)
|
||||
|
@ -82,6 +82,9 @@ public struct AccountDetailView: View {
|
||||
isCurrentUser = currentAccount.account?.id == viewModel.accountId
|
||||
viewModel.isCurrentUser = isCurrentUser
|
||||
viewModel.client = client
|
||||
|
||||
// Avoid capturing non-Sendable `self` just to access the view model.
|
||||
let viewModel = self.viewModel
|
||||
Task {
|
||||
await withTaskGroup(of: Void.self) { group in
|
||||
group.addTask { await viewModel.fetchAccount() }
|
||||
|
@ -1,3 +1,4 @@
|
||||
import Combine
|
||||
import DesignSystem
|
||||
import EmojiText
|
||||
import Env
|
||||
|
@ -1,3 +1,4 @@
|
||||
import Combine
|
||||
import Foundation
|
||||
import Models
|
||||
import Network
|
||||
|
@ -1,3 +1,4 @@
|
||||
import Combine
|
||||
import DesignSystem
|
||||
import Models
|
||||
import Network
|
||||
@ -61,6 +62,11 @@ public class AppAccountViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
private func refreshAvatar(account: Account) async {
|
||||
// Warning: Non-sendable type '(any URLSessionTaskDelegate)?' exiting main actor-isolated
|
||||
// context in call to non-isolated instance method 'data(for:delegate:)' cannot cross actor
|
||||
// boundary.
|
||||
// This is on the defaulted-to-nil second parameter of `.data(from:delegate:)`.
|
||||
// There is a Radar tracking this & others like it.
|
||||
if let (data, _) = try? await URLSession.shared.data(from: account.avatar),
|
||||
let image = UIImage(data: data)?.roundedImage
|
||||
{
|
||||
|
@ -1,3 +1,4 @@
|
||||
import Combine
|
||||
import Env
|
||||
import Models
|
||||
import Network
|
||||
|
@ -1,3 +1,4 @@
|
||||
import Combine
|
||||
import UIKit
|
||||
|
||||
public class SceneDelegate: NSObject, ObservableObject, UIWindowSceneDelegate {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import Combine
|
||||
import Foundation
|
||||
import Models
|
||||
import Network
|
||||
|
@ -1,3 +1,4 @@
|
||||
import Combine
|
||||
import Foundation
|
||||
import Models
|
||||
import Network
|
||||
|
@ -1,3 +1,4 @@
|
||||
import Combine
|
||||
import CryptoKit
|
||||
import Foundation
|
||||
import KeychainSwift
|
||||
|
@ -1,3 +1,4 @@
|
||||
import Combine
|
||||
import QuickLook
|
||||
import SwiftUI
|
||||
|
||||
@ -69,6 +70,12 @@ public class QuickLook: ObservableObject {
|
||||
private func localPathFor(url: URL) async throws -> URL {
|
||||
try? FileManager.default.createDirectory(at: quickLookDir, withIntermediateDirectories: true)
|
||||
let path = quickLookDir.appendingPathComponent(url.lastPathComponent)
|
||||
|
||||
// Warning: Non-sendable type '(any URLSessionTaskDelegate)?' exiting main actor-isolated
|
||||
// context in call to non-isolated instance method 'data(for:delegate:)' cannot cross actor
|
||||
// boundary.
|
||||
// This is on the defaulted-to-nil second parameter of `.data(from:delegate:)`.
|
||||
// There is a Radar tracking this & others like it.
|
||||
let data = try await URLSession.shared.data(from: url).0
|
||||
try data.write(to: path)
|
||||
return path
|
||||
|
@ -1,3 +1,4 @@
|
||||
import Combine
|
||||
import Foundation
|
||||
import Models
|
||||
import Network
|
||||
@ -140,7 +141,7 @@ public class RouterPath: ObservableObject {
|
||||
if let account = results?.accounts.first {
|
||||
navigate(to: .accountDetailWithAccount(account: account))
|
||||
} else {
|
||||
await UIApplication.shared.open(url)
|
||||
_ = await UIApplication.shared.open(url)
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,7 +155,7 @@ public class RouterPath: ObservableObject {
|
||||
if let account = results?.accounts.first {
|
||||
navigate(to: .accountDetailWithAccount(account: account))
|
||||
} else {
|
||||
await UIApplication.shared.open(url)
|
||||
_ = await UIApplication.shared.open(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import Combine
|
||||
import Foundation
|
||||
import Models
|
||||
import Network
|
||||
|
@ -1,3 +1,4 @@
|
||||
import Combine
|
||||
import Foundation
|
||||
import Models
|
||||
import Network
|
||||
@ -61,6 +62,16 @@ public class UserPreferences: ObservableObject {
|
||||
return "enum.swipeactions.icon-only"
|
||||
}
|
||||
}
|
||||
|
||||
// Have to implement this manually here due to compiler not implicitly
|
||||
// inserting `nonisolated`, which leads to a warning:
|
||||
//
|
||||
// Main actor-isolated static property 'allCases' cannot be used to
|
||||
// satisfy nonisolated protocol requirement
|
||||
//
|
||||
nonisolated public static var allCases: [Self] {
|
||||
[.iconWithText, .iconOnly]
|
||||
}
|
||||
}
|
||||
|
||||
public var postVisibility: Models.Visibility {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import Combine
|
||||
import Models
|
||||
import Network
|
||||
import SwiftUI
|
||||
|
@ -17,11 +17,15 @@ let package = Package(
|
||||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/scinfu/SwiftSoup.git", from: "2.4.3"),
|
||||
.package(url: "https://github.com/apple/swift-atomics.git", from: "1.0.3"),
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "Models",
|
||||
dependencies: ["SwiftSoup"]
|
||||
dependencies: [
|
||||
"SwiftSoup",
|
||||
.product(name: "Atomics", package: "swift-atomics")
|
||||
]
|
||||
),
|
||||
.testTarget(
|
||||
name: "ModelsTests",
|
||||
|
@ -121,3 +121,5 @@ public struct FamiliarAccounts: Decodable {
|
||||
public let id: String
|
||||
public let accounts: [Account]
|
||||
}
|
||||
|
||||
extension FamiliarAccounts: Sendable {}
|
||||
|
@ -27,3 +27,5 @@ public struct AppAccount: Codable, Identifiable, Hashable {
|
||||
self.oauthToken = oauthToken
|
||||
}
|
||||
}
|
||||
|
||||
extension AppAccount: Sendable {}
|
||||
|
@ -11,3 +11,5 @@ public struct Card: Codable, Identifiable, Equatable, Hashable {
|
||||
public let type: String
|
||||
public let image: URL?
|
||||
}
|
||||
|
||||
extension Card: Sendable {}
|
||||
|
@ -41,3 +41,5 @@ public struct ConsolidatedNotification: Identifiable {
|
||||
[.placeholder(), .placeholder(), .placeholder(), .placeholder(), .placeholder(), .placeholder(), .placeholder(), .placeholder()]
|
||||
}
|
||||
}
|
||||
|
||||
extension ConsolidatedNotification: Sendable {}
|
||||
|
@ -22,3 +22,5 @@ public struct Conversation: Identifiable, Decodable, Hashable, Equatable {
|
||||
.placeholder(), .placeholder(), .placeholder(), .placeholder(), .placeholder()]
|
||||
}
|
||||
}
|
||||
|
||||
extension Conversation: Sendable {}
|
||||
|
@ -20,3 +20,8 @@ public struct Filter: Codable, Identifiable, Equatable, Hashable {
|
||||
public let context: [String]
|
||||
public let filterAction: Action
|
||||
}
|
||||
|
||||
extension Filtered: Sendable {}
|
||||
extension Filter: Sendable {}
|
||||
extension Filter.Action: Sendable {}
|
||||
extension Filter.Context: Sendable {}
|
||||
|
@ -9,3 +9,5 @@ public struct InstanceApp: Codable, Identifiable {
|
||||
public let clientSecret: String
|
||||
public let vapidKey: String?
|
||||
}
|
||||
|
||||
extension InstanceApp: Sendable {}
|
||||
|
@ -18,3 +18,5 @@ public struct Language: Identifiable, Equatable, Hashable {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension Language: Sendable {}
|
||||
|
@ -5,3 +5,5 @@ public struct List: Codable, Identifiable, Equatable, Hashable {
|
||||
public let title: String
|
||||
public let repliesPolicy: String
|
||||
}
|
||||
|
||||
extension List: Sendable {}
|
||||
|
@ -21,3 +21,5 @@ public struct MastodonPushNotification: Codable {
|
||||
case body
|
||||
}
|
||||
}
|
||||
|
||||
extension MastodonPushNotification: Sendable {}
|
||||
|
@ -29,3 +29,8 @@ public struct MediaAttachment: Codable, Identifiable, Hashable, Equatable {
|
||||
public let description: String?
|
||||
public let meta: MetaContainer?
|
||||
}
|
||||
|
||||
extension MediaAttachment: Sendable {}
|
||||
extension MediaAttachment.MetaContainer: Sendable {}
|
||||
extension MediaAttachment.MetaContainer.Meta: Sendable {}
|
||||
extension MediaAttachment.SupportedType: Sendable {}
|
||||
|
@ -6,3 +6,5 @@ public struct Mention: Codable, Equatable, Hashable {
|
||||
public let url: URL
|
||||
public let acct: String
|
||||
}
|
||||
|
||||
extension Mention: Sendable {}
|
||||
|
@ -23,3 +23,6 @@ public struct Notification: Decodable, Identifiable, Equatable {
|
||||
status: .placeholder())
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification: Sendable {}
|
||||
extension Notification.NotificationType: Sendable {}
|
||||
|
@ -48,3 +48,7 @@ public struct NullableString: Codable, Equatable, Hashable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Poll: Sendable {}
|
||||
extension Poll.Option: Sendable {}
|
||||
extension NullableString: Sendable {}
|
||||
|
@ -15,3 +15,6 @@ public struct PushSubscription: Identifiable, Decodable {
|
||||
public let serverKey: String
|
||||
public let alerts: Alerts
|
||||
}
|
||||
|
||||
extension PushSubscription: Sendable {}
|
||||
extension PushSubscription.Alerts: Sendable {}
|
||||
|
@ -50,3 +50,5 @@ public extension Relationship {
|
||||
notifying = try values.decodeIfPresent(Bool.self, forKey: .notifying) ?? false
|
||||
}
|
||||
}
|
||||
|
||||
extension Relationship: Sendable {}
|
||||
|
@ -14,3 +14,5 @@ public struct SearchResults: Decodable {
|
||||
accounts.isEmpty && statuses.isEmpty && hashtags.isEmpty
|
||||
}
|
||||
}
|
||||
|
||||
extension SearchResults: Sendable {}
|
||||
|
@ -3,3 +3,5 @@ import Foundation
|
||||
public struct ServerError: Decodable, Error {
|
||||
public let error: String?
|
||||
}
|
||||
|
||||
extension ServerError: Sendable {}
|
||||
|
@ -33,3 +33,6 @@ public struct ServerPreferences: Decodable {
|
||||
case autoExpandSpoilers = "reading:expand:spoilers"
|
||||
}
|
||||
}
|
||||
|
||||
extension ServerPreferences: Sendable {}
|
||||
extension ServerPreferences.AutoExpandMedia: Sendable {}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import Foundation
|
||||
import Atomics
|
||||
|
||||
public struct Application: Codable, Identifiable, Hashable, Equatable {
|
||||
public var id: String {
|
||||
@ -103,6 +104,7 @@ public final class Status: AnyStatus, Codable, Identifiable, Equatable, Hashable
|
||||
public let sensitive: Bool
|
||||
public let language: String?
|
||||
|
||||
|
||||
public init(id: String, content: HTMLString, account: Account, createdAt: ServerDate, editedAt: ServerDate?, reblog: ReblogStatus?, mediaAttachments: [MediaAttachment], mentions: [Mention], repliesCount: Int, reblogsCount: Int, favouritesCount: Int, card: Card?, favourited: Bool?, reblogged: Bool?, pinned: Bool?, bookmarked: Bool?, emojis: [Emoji], url: String?, application: Application?, inReplyToId: String?, inReplyToAccountId: String?, visibility: Visibility, poll: Poll?, spoilerText: HTMLString, filtered: [Filtered]?, sensitive: Bool, language: String?) {
|
||||
self.id = id
|
||||
self.content = content
|
||||
@ -228,7 +230,7 @@ public final class ReblogStatus: AnyStatus, Codable, Identifiable, Equatable, Ha
|
||||
public let bookmarked: Bool?
|
||||
public let emojis: [Emoji]
|
||||
public let url: String?
|
||||
public var application: Application?
|
||||
public let application: Application?
|
||||
public let inReplyToId: String?
|
||||
public let inReplyToAccountId: String?
|
||||
public let visibility: Visibility
|
||||
@ -267,3 +269,14 @@ public final class ReblogStatus: AnyStatus, Codable, Identifiable, Equatable, Ha
|
||||
self.language = language
|
||||
}
|
||||
}
|
||||
|
||||
extension Application: Sendable {}
|
||||
extension StatusViewId: Sendable {}
|
||||
|
||||
// Every property in Status is immutable.
|
||||
extension Status: Sendable {}
|
||||
|
||||
// Every property in ReblogStatus is immutable.
|
||||
extension ReblogStatus: Sendable {}
|
||||
|
||||
|
||||
|
@ -8,3 +8,5 @@ public struct StatusContext: Decodable {
|
||||
.init(ancestors: [], descendants: [])
|
||||
}
|
||||
}
|
||||
|
||||
extension StatusContext: Sendable {}
|
||||
|
@ -9,3 +9,5 @@ public struct StatusHistory: Decodable, Identifiable {
|
||||
public let createdAt: ServerDate
|
||||
public let emojis: [Emoji]
|
||||
}
|
||||
|
||||
extension StatusHistory: Sendable {}
|
||||
|
@ -11,3 +11,5 @@ public struct StatusTranslation: Decodable {
|
||||
self.provider = provider
|
||||
}
|
||||
}
|
||||
|
||||
extension StatusTranslation: Sendable {}
|
||||
|
@ -58,3 +58,7 @@ public struct FeaturedTag: Codable, Identifiable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Tag: Sendable {}
|
||||
extension Tag.History: Sendable {}
|
||||
extension FeaturedTag: Sendable {}
|
||||
|
@ -1,12 +1,17 @@
|
||||
import Combine
|
||||
import Foundation
|
||||
import Models
|
||||
import SwiftUI
|
||||
import os
|
||||
|
||||
public final class Client: ObservableObject, Equatable, Identifiable, Hashable {
|
||||
public static func == (lhs: Client, rhs: Client) -> Bool {
|
||||
lhs.isAuth == rhs.isAuth &&
|
||||
let lhsToken = lhs.critical.withLock { $0.oauthToken }
|
||||
let rhsToken = rhs.critical.withLock { $0.oauthToken }
|
||||
|
||||
return (lhsToken != nil) == (rhsToken != nil) &&
|
||||
lhs.server == rhs.server &&
|
||||
lhs.oauthToken?.accessToken == rhs.oauthToken?.accessToken
|
||||
lhsToken?.accessToken == rhsToken?.accessToken
|
||||
}
|
||||
|
||||
public enum Version: String, Sendable {
|
||||
@ -19,7 +24,10 @@ public final class Client: ObservableObject, Equatable, Identifiable, Hashable {
|
||||
}
|
||||
|
||||
public var id: String {
|
||||
"\(isAuth)\(server)\(oauthToken?.createdAt ?? 0)"
|
||||
critical.withLock {
|
||||
let isAuth = $0.oauthToken != nil
|
||||
return "\(isAuth)\(server)\($0.oauthToken?.createdAt ?? 0)"
|
||||
}
|
||||
}
|
||||
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
@ -28,42 +36,52 @@ public final class Client: ObservableObject, Equatable, Identifiable, Hashable {
|
||||
|
||||
public let server: String
|
||||
public let version: Version
|
||||
public private(set) var connections: Set<String>
|
||||
private let urlSession: URLSession
|
||||
private let decoder = JSONDecoder()
|
||||
|
||||
/// Only used as a transitionary app while in the oauth flow.
|
||||
private var oauthApp: InstanceApp?
|
||||
|
||||
private var oauthToken: OauthToken?
|
||||
// Putting all mutable state inside an `OSAllocatedUnfairLock` makes `Client`
|
||||
// provably `Sendable`. The lock is a struct, but it uses a `ManagedBuffer`
|
||||
// reference type to hold its associated state.
|
||||
private let critical: OSAllocatedUnfairLock<Critical>
|
||||
private struct Critical: Sendable {
|
||||
/// Only used as a transitionary app while in the oauth flow.
|
||||
var oauthApp: InstanceApp?
|
||||
var oauthToken: OauthToken?
|
||||
var connections: Set<String> = []
|
||||
}
|
||||
|
||||
public var isAuth: Bool {
|
||||
oauthToken != nil
|
||||
critical.withLock { $0.oauthToken != nil }
|
||||
}
|
||||
|
||||
public var connections: Set<String> {
|
||||
critical.withLock { $0.connections }
|
||||
}
|
||||
|
||||
public init(server: String, version: Version = .v1, oauthToken: OauthToken? = nil) {
|
||||
self.server = server
|
||||
self.version = version
|
||||
self.critical = .init(initialState: Critical(oauthToken: oauthToken, connections: [server]))
|
||||
urlSession = URLSession.shared
|
||||
decoder.keyDecodingStrategy = .convertFromSnakeCase
|
||||
self.oauthToken = oauthToken
|
||||
connections = Set([server])
|
||||
}
|
||||
|
||||
public func addConnections(_ connections: [String]) {
|
||||
connections.forEach {
|
||||
self.connections.insert($0)
|
||||
critical.withLock {
|
||||
$0.connections.formUnion(connections)
|
||||
}
|
||||
}
|
||||
|
||||
public func hasConnection(with url: URL) -> Bool {
|
||||
guard let host = url.host else { return false }
|
||||
if let rootHost = host.split(separator: ".", maxSplits: 1).last {
|
||||
// Sometimes the connection is with the root host instead of a subdomain
|
||||
// eg. Mastodon runs on mastdon.domain.com but the connection is with domain.com
|
||||
return connections.contains(host) || connections.contains(String(rootHost))
|
||||
} else {
|
||||
return connections.contains(host)
|
||||
return critical.withLock {
|
||||
if let rootHost = host.split(separator: ".", maxSplits: 1).last {
|
||||
// Sometimes the connection is with the root host instead of a subdomain
|
||||
// eg. Mastodon runs on mastdon.domain.com but the connection is with domain.com
|
||||
return $0.connections.contains(host) || $0.connections.contains(String(rootHost))
|
||||
} else {
|
||||
return $0.connections.contains(host)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,7 +105,7 @@ public final class Client: ObservableObject, Equatable, Identifiable, Hashable {
|
||||
private func makeURLRequest(url: URL, endpoint: Endpoint, httpMethod: String) -> URLRequest {
|
||||
var request = URLRequest(url: url)
|
||||
request.httpMethod = httpMethod
|
||||
if let oauthToken {
|
||||
if let oauthToken = critical.withLock({ $0.oauthToken }) {
|
||||
request.setValue("Bearer \(oauthToken.accessToken)", forHTTPHeaderField: "Authorization")
|
||||
}
|
||||
if let json = endpoint.jsonValue {
|
||||
@ -175,12 +193,12 @@ public final class Client: ObservableObject, Equatable, Identifiable, Hashable {
|
||||
|
||||
public func oauthURL() async throws -> URL {
|
||||
let app: InstanceApp = try await post(endpoint: Apps.registerApp)
|
||||
oauthApp = app
|
||||
critical.withLock { $0.oauthApp = app }
|
||||
return makeURL(endpoint: Oauth.authorize(clientId: app.clientId))
|
||||
}
|
||||
|
||||
public func continueOauthFlow(url: URL) async throws -> OauthToken {
|
||||
guard let app = oauthApp else {
|
||||
guard let app = critical.withLock({ $0.oauthApp }) else {
|
||||
throw OauthError.missingApp
|
||||
}
|
||||
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
|
||||
@ -191,7 +209,7 @@ public final class Client: ObservableObject, Equatable, Identifiable, Hashable {
|
||||
let token: OauthToken = try await post(endpoint: Oauth.token(code: code,
|
||||
clientId: app.clientId,
|
||||
clientSecret: app.clientSecret))
|
||||
oauthToken = token
|
||||
critical.withLock { $0.oauthToken = token }
|
||||
return token
|
||||
}
|
||||
|
||||
@ -239,3 +257,5 @@ public final class Client: ObservableObject, Equatable, Identifiable, Hashable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Client: Sendable {}
|
||||
|
@ -16,3 +16,5 @@ public struct LinkHandler {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
extension LinkHandler: Sendable {}
|
||||
|
@ -105,3 +105,9 @@ public struct OpenAIClient {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension OpenAIClient: Sendable {}
|
||||
extension OpenAIClient.Prompt: Sendable {}
|
||||
extension OpenAIClient.Request: Sendable {}
|
||||
extension OpenAIClient.Response: Sendable {}
|
||||
extension OpenAIClient.Response.Choice: Sendable {}
|
||||
|
@ -24,6 +24,17 @@ enum StatusEditorUTTypeSupported: String, CaseIterable {
|
||||
|
||||
case uiimage = "com.apple.uikit.image"
|
||||
|
||||
// Have to implement this manually here due to compiler not implicitly
|
||||
// inserting `nonisolated`, which leads to a warning:
|
||||
//
|
||||
// Main actor-isolated static property 'allCases' cannot be used to
|
||||
// satisfy nonisolated protocol requirement
|
||||
//
|
||||
nonisolated public static var allCases: [StatusEditorUTTypeSupported] {
|
||||
[.url, .text, .plaintext, .image, .jpeg, .png, .tiff, .video,
|
||||
.movie, .mp4, .gif, .gif2, .quickTimeMovie, .uiimage]
|
||||
}
|
||||
|
||||
static func types() -> [UTType] {
|
||||
[.url, .text, .plainText, .image, .jpeg, .png, .tiff, .video, .mpeg4Movie, .gif, .movie, .quickTimeMovie]
|
||||
}
|
||||
@ -47,6 +58,8 @@ enum StatusEditorUTTypeSupported: String, CaseIterable {
|
||||
}
|
||||
|
||||
func loadItemContent(item: NSItemProvider) async throws -> Any? {
|
||||
// Many warnings here about non-sendable type `[AnyHashable: Any]?` crossing
|
||||
// actor boundaries. Many Radars have been filed.
|
||||
let result = try await item.loadItem(forTypeIdentifier: rawValue)
|
||||
if isVideo, let transferable = await getVideoTransferable(item: item) {
|
||||
return transferable
|
||||
|
@ -1,3 +1,4 @@
|
||||
import Combine
|
||||
import DesignSystem
|
||||
import Env
|
||||
import Models
|
||||
|
@ -1,3 +1,4 @@
|
||||
import Combine
|
||||
import Models
|
||||
import SwiftUI
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
import Combine
|
||||
import Models
|
||||
import Network
|
||||
import SwiftUI
|
||||
|
@ -1,3 +1,4 @@
|
||||
import Combine
|
||||
import Env
|
||||
import Models
|
||||
import NaturalLanguage
|
||||
|
@ -17,6 +17,16 @@ struct StatusRowActionsView: View {
|
||||
enum Action: CaseIterable {
|
||||
case respond, boost, favorite, bookmark, share
|
||||
|
||||
// Have to implement this manually here due to compiler not implicitly
|
||||
// inserting `nonisolated`, which leads to a warning:
|
||||
//
|
||||
// Main actor-isolated static property 'allCases' cannot be used to
|
||||
// satisfy nonisolated protocol requirement
|
||||
//
|
||||
nonisolated public static var allCases: [StatusRowActionsView.Action] {
|
||||
[.respond, .boost, .favorite, .bookmark, .share]
|
||||
}
|
||||
|
||||
func iconName(viewModel: StatusRowViewModel, privateBoost: Bool = false) -> String {
|
||||
switch self {
|
||||
case .respond:
|
||||
|
@ -59,3 +59,9 @@ public actor TimelineCache {
|
||||
UserDefaults.standard.array(forKey: "timeline-last-seen-\(client.id)") as? [String]
|
||||
}
|
||||
}
|
||||
|
||||
// Quiets down the warnings from this one. Bodega is nicely async so we don't
|
||||
// want to just use `@preconcurrency`, but the CacheKey type is (incorrectly)
|
||||
// not marked as `Sendable`---it's a value type containing two `String`
|
||||
// properties.
|
||||
extension Bodega.CacheKey: @unchecked Sendable {}
|
||||
|
Loading…
Reference in New Issue
Block a user