Fix compiling for visionOS

This commit is contained in:
Shadowfacts 2024-04-15 09:49:42 -04:00
parent 66af946766
commit 910e18fb5e
11 changed files with 89 additions and 6 deletions

View File

@ -301,6 +301,7 @@ extension MainActor {
@available(iOS, obsoleted: 17.0) @available(iOS, obsoleted: 17.0)
@available(watchOS, obsoleted: 10.0) @available(watchOS, obsoleted: 10.0)
@available(tvOS, obsoleted: 17.0) @available(tvOS, obsoleted: 17.0)
@available(visionOS 1.0, *)
static func runUnsafely<T>(_ body: @MainActor () throws -> T) rethrows -> T { static func runUnsafely<T>(_ body: @MainActor () throws -> T) rethrows -> T {
if #available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *) { if #available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *) {
return try MainActor.assumeIsolated(body) return try MainActor.assumeIsolated(body)

View File

@ -9,8 +9,10 @@ import SwiftUI
public struct AsyncPicker<V: Hashable, Content: View>: View { public struct AsyncPicker<V: Hashable, Content: View>: View {
let titleKey: LocalizedStringKey let titleKey: LocalizedStringKey
#if !os(visionOS)
@available(iOS, obsoleted: 16.0, message: "Switch to LabeledContent") @available(iOS, obsoleted: 16.0, message: "Switch to LabeledContent")
let labelHidden: Bool let labelHidden: Bool
#endif
let alignment: Alignment let alignment: Alignment
@Binding var value: V @Binding var value: V
let onChange: (V) async -> Bool let onChange: (V) async -> Bool
@ -19,7 +21,9 @@ public struct AsyncPicker<V: Hashable, Content: View>: View {
public init(_ titleKey: LocalizedStringKey, labelHidden: Bool = false, alignment: Alignment = .center, value: Binding<V>, onChange: @escaping (V) async -> Bool, @ViewBuilder content: () -> Content) { public init(_ titleKey: LocalizedStringKey, labelHidden: Bool = false, alignment: Alignment = .center, value: Binding<V>, onChange: @escaping (V) async -> Bool, @ViewBuilder content: () -> Content) {
self.titleKey = titleKey self.titleKey = titleKey
#if !os(visionOS)
self.labelHidden = labelHidden self.labelHidden = labelHidden
#endif
self.alignment = alignment self.alignment = alignment
self._value = value self._value = value
self.onChange = onChange self.onChange = onChange
@ -27,6 +31,11 @@ public struct AsyncPicker<V: Hashable, Content: View>: View {
} }
public var body: some View { public var body: some View {
#if os(visionOS)
LabeledContent(titleKey) {
picker
}
#else
if #available(iOS 16.0, *) { if #available(iOS 16.0, *) {
LabeledContent(titleKey) { LabeledContent(titleKey) {
picker picker
@ -40,6 +49,7 @@ public struct AsyncPicker<V: Hashable, Content: View>: View {
picker picker
} }
} }
#endif
} }
private var picker: some View { private var picker: some View {

View File

@ -10,19 +10,28 @@ import SwiftUI
public struct AsyncToggle: View { public struct AsyncToggle: View {
let titleKey: LocalizedStringKey let titleKey: LocalizedStringKey
#if !os(visionOS)
@available(iOS, obsoleted: 16.0, message: "Switch to LabeledContent") @available(iOS, obsoleted: 16.0, message: "Switch to LabeledContent")
let labelHidden: Bool let labelHidden: Bool
#endif
@Binding var mode: Mode @Binding var mode: Mode
let onChange: (Bool) async -> Bool let onChange: (Bool) async -> Bool
public init(_ titleKey: LocalizedStringKey, labelHidden: Bool = false, mode: Binding<Mode>, onChange: @escaping (Bool) async -> Bool) { public init(_ titleKey: LocalizedStringKey, labelHidden: Bool = false, mode: Binding<Mode>, onChange: @escaping (Bool) async -> Bool) {
self.titleKey = titleKey self.titleKey = titleKey
#if !os(visionOS)
self.labelHidden = labelHidden self.labelHidden = labelHidden
#endif
self._mode = mode self._mode = mode
self.onChange = onChange self.onChange = onChange
} }
public var body: some View { public var body: some View {
#if os(visionOS)
LabeledContent(titleKey) {
toggleOrSpinner
}
#else
if #available(iOS 16.0, *) { if #available(iOS 16.0, *) {
LabeledContent(titleKey) { LabeledContent(titleKey) {
toggleOrSpinner toggleOrSpinner
@ -36,6 +45,7 @@ public struct AsyncToggle: View {
toggleOrSpinner toggleOrSpinner
} }
} }
#endif
} }
@ViewBuilder @ViewBuilder

View File

@ -2499,11 +2499,12 @@
PRODUCT_BUNDLE_IDENTIFIER = space.vaccor.Tusker.NotificationExtension; PRODUCT_BUNDLE_IDENTIFIER = space.vaccor.Tusker.NotificationExtension;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator xros xrsimulator";
SUPPORTS_MACCATALYST = YES; SUPPORTS_MACCATALYST = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2,7";
}; };
name = Debug; name = Debug;
}; };
@ -2530,10 +2531,11 @@
PRODUCT_BUNDLE_IDENTIFIER = space.vaccor.Tusker.NotificationExtension; PRODUCT_BUNDLE_IDENTIFIER = space.vaccor.Tusker.NotificationExtension;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator xros xrsimulator";
SUPPORTS_MACCATALYST = YES; SUPPORTS_MACCATALYST = YES;
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2,7";
}; };
name = Release; name = Release;
}; };
@ -2560,10 +2562,11 @@
PRODUCT_BUNDLE_IDENTIFIER = space.vaccor.Tusker.NotificationExtension; PRODUCT_BUNDLE_IDENTIFIER = space.vaccor.Tusker.NotificationExtension;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator xros xrsimulator";
SUPPORTS_MACCATALYST = YES; SUPPORTS_MACCATALYST = YES;
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2,7";
}; };
name = Dist; name = Dist;
}; };

View File

@ -26,7 +26,11 @@ class SaveToPhotosActivity: UIActivity {
// Just using the symbol image directly causes it to be stretched. // Just using the symbol image directly causes it to be stretched.
let symbol = UIImage(systemName: "square.and.arrow.down", withConfiguration: UIImage.SymbolConfiguration(scale: .large))! let symbol = UIImage(systemName: "square.and.arrow.down", withConfiguration: UIImage.SymbolConfiguration(scale: .large))!
let format = UIGraphicsImageRendererFormat() let format = UIGraphicsImageRendererFormat()
#if os(visionOS)
format.scale = 2
#else
format.scale = UIScreen.main.scale format.scale = UIScreen.main.scale
#endif
return UIGraphicsImageRenderer(size: CGSize(width: 76, height: 76), format: format).image { ctx in return UIGraphicsImageRenderer(size: CGSize(width: 76, height: 76), format: format).image { ctx in
let rect = AVMakeRect(aspectRatio: symbol.size, insideRect: CGRect(x: 0, y: 0, width: 76, height: 76)) let rect = AVMakeRect(aspectRatio: symbol.size, insideRect: CGRect(x: 0, y: 0, width: 76, height: 76))
symbol.draw(in: rect) symbol.draw(in: rect)

View File

@ -175,7 +175,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
private func initializePushNotifications() { private func initializePushNotifications() {
UNUserNotificationCenter.current().delegate = self UNUserNotificationCenter.current().delegate = self
Task { Task {
#if canImport(Sentry)
PushManager.captureError = { SentrySDK.capture(error: $0) } PushManager.captureError = { SentrySDK.capture(error: $0) }
#endif
await PushManager.shared.updateIfNecessary(updateSubscription: { await PushManager.shared.updateIfNecessary(updateSubscription: {
guard let account = UserAccountsManager.shared.getAccount(id: $0.accountID) else { guard let account = UserAccountsManager.shared.getAccount(id: $0.accountID) else {
return false return false

View File

@ -51,6 +51,7 @@ public extension MainActor {
@available(iOS, obsoleted: 17.0) @available(iOS, obsoleted: 17.0)
@available(watchOS, obsoleted: 10.0) @available(watchOS, obsoleted: 10.0)
@available(tvOS, obsoleted: 17.0) @available(tvOS, obsoleted: 17.0)
@available(visionOS 1.0, *)
static func runUnsafely<T>(_ body: @MainActor () throws -> T) rethrows -> T { static func runUnsafely<T>(_ body: @MainActor () throws -> T) rethrows -> T {
if #available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *) { if #available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *) {
return try MainActor.assumeIsolated(body) return try MainActor.assumeIsolated(body)

View File

@ -18,7 +18,9 @@ class VideoControlsViewController: UIViewController {
}() }()
private let player: AVPlayer private let player: AVPlayer
#if !os(visionOS)
@Box private var playbackSpeed: Float @Box private var playbackSpeed: Float
#endif
private lazy var muteButton = MuteButton().configure { private lazy var muteButton = MuteButton().configure {
$0.addTarget(self, action: #selector(muteButtonPressed), for: .touchUpInside) $0.addTarget(self, action: #selector(muteButtonPressed), for: .touchUpInside)
@ -44,8 +46,13 @@ class VideoControlsViewController: UIViewController {
private lazy var optionsButton = MenuButton { [unowned self] in private lazy var optionsButton = MenuButton { [unowned self] in
let imageName: String let imageName: String
#if os(visionOS)
let playbackSpeed = player.defaultRate
#else
let playbackSpeed = self.playbackSpeed
#endif
if #available(iOS 17.0, *) { if #available(iOS 17.0, *) {
switch self.playbackSpeed { switch playbackSpeed {
case 0.5: case 0.5:
imageName = "gauge.with.dots.needle.0percent" imageName = "gauge.with.dots.needle.0percent"
case 1: case 1:
@ -61,8 +68,12 @@ class VideoControlsViewController: UIViewController {
imageName = "speedometer" imageName = "speedometer"
} }
let speedMenu = UIMenu(title: "Playback Speed", image: UIImage(systemName: imageName), children: PlaybackSpeed.allCases.map { speed in let speedMenu = UIMenu(title: "Playback Speed", image: UIImage(systemName: imageName), children: PlaybackSpeed.allCases.map { speed in
UIAction(title: speed.displayName, state: self.playbackSpeed == speed.rate ? .on : .off) { [unowned self] _ in UIAction(title: speed.displayName, state: playbackSpeed == speed.rate ? .on : .off) { [unowned self] _ in
#if os(visionOS)
self.player.defaultRate = speed.rate
#else
self.playbackSpeed = speed.rate self.playbackSpeed = speed.rate
#endif
if self.player.rate > 0 { if self.player.rate > 0 {
self.player.rate = speed.rate self.player.rate = speed.rate
} }
@ -90,12 +101,20 @@ class VideoControlsViewController: UIViewController {
private var scrubbingTargetTime: CMTime? private var scrubbingTargetTime: CMTime?
private var isSeeking = false private var isSeeking = false
#if os(visionOS)
init(player: AVPlayer) {
self.player = player
super.init(nibName: nil, bundle: nil)
}
#else
init(player: AVPlayer, playbackSpeed: Box<Float>) { init(player: AVPlayer, playbackSpeed: Box<Float>) {
self.player = player self.player = player
self._playbackSpeed = playbackSpeed self._playbackSpeed = playbackSpeed
super.init(nibName: nil, bundle: nil) super.init(nibName: nil, bundle: nil)
} }
#endif
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
@ -170,7 +189,11 @@ class VideoControlsViewController: UIViewController {
@objc private func scrubbingEnded() { @objc private func scrubbingEnded() {
scrubbingChanged() scrubbingChanged()
if wasPlayingWhenScrubbingStarted { if wasPlayingWhenScrubbingStarted {
#if os(visionOS)
player.play()
#else
player.rate = playbackSpeed player.rate = playbackSpeed
#endif
} }
} }

View File

@ -17,8 +17,10 @@ class VideoGalleryContentViewController: UIViewController, GalleryContentViewCon
private var item: AVPlayerItem private var item: AVPlayerItem
let player: AVPlayer let player: AVPlayer
#if !os(visionOS)
@available(iOS, obsoleted: 16.0, message: "Use AVPlayer.defaultRate") @available(iOS, obsoleted: 16.0, message: "Use AVPlayer.defaultRate")
@Box private var playbackSpeed: Float = 1 @Box private var playbackSpeed: Float = 1
#endif
private var isGrayscale: Bool private var isGrayscale: Bool
@ -125,7 +127,11 @@ class VideoGalleryContentViewController: UIViewController, GalleryContentViewCon
player.replaceCurrentItem(with: item) player.replaceCurrentItem(with: item)
updateItemObservations() updateItemObservations()
if isPlaying { if isPlaying {
#if os(visionOS)
player.play()
#else
player.rate = playbackSpeed player.rate = playbackSpeed
#endif
} }
} }
} }
@ -142,12 +148,20 @@ class VideoGalleryContentViewController: UIViewController, GalleryContentViewCon
[VideoActivityItemSource(asset: item.asset, url: url)] [VideoActivityItemSource(asset: item.asset, url: url)]
} }
#if os(visionOS)
private lazy var overlayVC = VideoOverlayViewController(player: player)
#else
private lazy var overlayVC = VideoOverlayViewController(player: player, playbackSpeed: _playbackSpeed) private lazy var overlayVC = VideoOverlayViewController(player: player, playbackSpeed: _playbackSpeed)
#endif
var contentOverlayAccessoryViewController: UIViewController? { var contentOverlayAccessoryViewController: UIViewController? {
overlayVC overlayVC
} }
#if os(visionOS)
private(set) lazy var bottomControlsAccessoryViewController: UIViewController? = VideoControlsViewController(player: player)
#else
private(set) lazy var bottomControlsAccessoryViewController: UIViewController? = VideoControlsViewController(player: player, playbackSpeed: _playbackSpeed) private(set) lazy var bottomControlsAccessoryViewController: UIViewController? = VideoControlsViewController(player: player, playbackSpeed: _playbackSpeed)
#endif
func setControlsVisible(_ visible: Bool, animated: Bool) { func setControlsVisible(_ visible: Bool, animated: Bool) {
overlayVC.setVisible(visible) overlayVC.setVisible(visible)

View File

@ -15,7 +15,9 @@ class VideoOverlayViewController: UIViewController {
private static let pauseImage = UIImage(systemName: "pause.fill")! private static let pauseImage = UIImage(systemName: "pause.fill")!
private let player: AVPlayer private let player: AVPlayer
#if !os(visionOS)
@Box private var playbackSpeed: Float @Box private var playbackSpeed: Float
#endif
private var dimmingView: UIView! private var dimmingView: UIView!
private var controlsStack: UIStackView! private var controlsStack: UIStackView!
@ -24,11 +26,18 @@ class VideoOverlayViewController: UIViewController {
private var rateObservation: NSKeyValueObservation? private var rateObservation: NSKeyValueObservation?
#if os(visionOS)
init(player: AVPlayer) {
self.player = player
super.init(nibName: nil, bundle: nil)
}
#else
init(player: AVPlayer, playbackSpeed: Box<Float>) { init(player: AVPlayer, playbackSpeed: Box<Float>) {
self.player = player self.player = player
self._playbackSpeed = playbackSpeed self._playbackSpeed = playbackSpeed
super.init(nibName: nil, bundle: nil) super.init(nibName: nil, bundle: nil)
} }
#endif
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
@ -97,7 +106,11 @@ class VideoOverlayViewController: UIViewController {
if player.rate > 0 { if player.rate > 0 {
player.rate = 0 player.rate = 0
} else { } else {
#if os(visionOS)
player.play()
#else
player.rate = playbackSpeed player.rate = playbackSpeed
#endif
} }
} }

View File

@ -29,7 +29,9 @@ class GifvController {
self.isGrayscale = Preferences.shared.grayscaleImages self.isGrayscale = Preferences.shared.grayscaleImages
player.isMuted = true player.isMuted = true
#if !os(visionOS)
player.preventsDisplaySleepDuringVideoPlayback = false player.preventsDisplaySleepDuringVideoPlayback = false
#endif
NotificationCenter.default.addObserver(self, selector: #selector(restartItem), name: .AVPlayerItemDidPlayToEndTime, object: item) NotificationCenter.default.addObserver(self, selector: #selector(restartItem), name: .AVPlayerItemDidPlayToEndTime, object: item)
NotificationCenter.default.addObserver(self, selector: #selector(preferencesChanged), name: .preferencesChanged, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(preferencesChanged), name: .preferencesChanged, object: nil)