mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
Bluetooth HUD Animations
This commit is contained in:
parent
7cd5d1fc55
commit
2453ca89ff
12 changed files with 366 additions and 6 deletions
|
|
@ -21,8 +21,65 @@
|
|||
*/
|
||||
|
||||
import SwiftUI
|
||||
import AppKit
|
||||
import AVFoundation
|
||||
import Defaults
|
||||
|
||||
// MARK: - Inline HUD looping .mov icon
|
||||
|
||||
private final class LoopingPlayerController {
|
||||
let player: AVQueuePlayer
|
||||
private var looper: AVPlayerLooper?
|
||||
|
||||
init(url: URL) {
|
||||
let item = AVPlayerItem(url: url)
|
||||
self.player = AVQueuePlayer()
|
||||
self.player.isMuted = true
|
||||
self.player.actionAtItemEnd = .none
|
||||
self.looper = AVPlayerLooper(player: self.player, templateItem: item)
|
||||
self.player.play()
|
||||
}
|
||||
|
||||
deinit {
|
||||
player.pause()
|
||||
looper = nil
|
||||
}
|
||||
}
|
||||
|
||||
private struct LoopingVideoIcon: NSViewRepresentable {
|
||||
let url: URL
|
||||
let size: CGSize
|
||||
|
||||
func makeNSView(context: Context) -> NSView {
|
||||
let view = NSView(frame: NSRect(origin: .zero, size: size))
|
||||
view.wantsLayer = true
|
||||
|
||||
let layer = AVPlayerLayer()
|
||||
layer.videoGravity = .resizeAspect
|
||||
layer.frame = view.bounds
|
||||
|
||||
view.layer?.addSublayer(layer)
|
||||
|
||||
context.coordinator.attach(layer: layer, url: url)
|
||||
return view
|
||||
}
|
||||
|
||||
func updateNSView(_ nsView: NSView, context: Context) {
|
||||
// No-op; the animation loops via AVPlayerLooper.
|
||||
}
|
||||
|
||||
func makeCoordinator() -> Coordinator { Coordinator() }
|
||||
|
||||
final class Coordinator {
|
||||
private var controller: LoopingPlayerController?
|
||||
|
||||
func attach(layer: AVPlayerLayer, url: URL) {
|
||||
controller = LoopingPlayerController(url: url)
|
||||
layer.player = controller?.player
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct InlineHUD: View {
|
||||
@EnvironmentObject var vm: DynamicIslandViewModel
|
||||
@Binding var type: SneakContentType
|
||||
|
|
@ -39,6 +96,7 @@ struct InlineHUD: View {
|
|||
@Default(.useCircularBluetoothBatteryIndicator) var useCircularBluetoothBatteryIndicator
|
||||
@Default(.showBluetoothBatteryPercentageText) var showBluetoothBatteryPercentageText
|
||||
@Default(.showBluetoothDeviceNameMarquee) var showBluetoothDeviceNameMarquee
|
||||
@Default(.useBluetoothHUD3DIcon) var useBluetoothHUD3DIcon
|
||||
@Default(.enableMinimalisticUI) var enableMinimalisticUI
|
||||
@Default(.showCapsLockLabel) var showCapsLockLabel
|
||||
@Default(.capsLockIndicatorTintMode) var capsLockTintMode
|
||||
|
|
@ -173,10 +231,17 @@ struct InlineHUD: View {
|
|||
.contentTransition(.interpolate)
|
||||
.frame(width: 20, height: 15, alignment: .center)
|
||||
case .bluetoothAudio:
|
||||
Image(systemName: icon.isEmpty ? "bluetooth" : icon)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.contentTransition(.interpolate)
|
||||
.frame(width: 20, height: 15, alignment: .center)
|
||||
if useBluetoothHUD3DIcon,
|
||||
let deviceType = bluetoothManager.lastConnectedDevice?.deviceType,
|
||||
let url = Bundle.main.url(forResource: deviceType.inlineHUDAnimationBaseName, withExtension: "mov") {
|
||||
LoopingVideoIcon(url: url, size: CGSize(width: 20, height: 20))
|
||||
.frame(width: 20, height: 20, alignment: .center)
|
||||
} else {
|
||||
Image(systemName: icon.isEmpty ? "bluetooth" : icon)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.contentTransition(.interpolate)
|
||||
.frame(width: 20, height: 15, alignment: .center)
|
||||
}
|
||||
case .capsLock:
|
||||
Image(systemName: "capslock.fill")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue