mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-09-30 13:19:44 +02:00
feat(player): add native audio output controls
This commit is contained in:
1 parent
6b72aed3f6
commit
1d6ff18d06
10 files changed
+392
-4
No files matched your search
@@ -7,6 +7,7 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
A0D100000000000000000001 /* AudioOutputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0D100000000000000000002 /* AudioOutputView.swift */; };
|
||||
F59500000000000000000011 /* PlayerWidgetState.swift in Sources */ = {isa = PBXBuildFile; fileRef = F59500000000000000000001 /* PlayerWidgetState.swift */; };
|
||||
F59500000000000000000012 /* PlayerControlIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = F59500000000000000000002 /* PlayerControlIntent.swift */; };
|
||||
F59500000000000000000013 /* PlayerWidgetBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = F59500000000000000000004 /* PlayerWidgetBridge.swift */; };
|
||||
@@ -69,6 +70,7 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
A0D100000000000000000002 /* AudioOutputView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioOutputView.swift; sourceTree = "<group>"; };
|
||||
F59500000000000000000009 /* PlayerWidget.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = PlayerWidget.xcconfig; sourceTree = "<group>"; };
|
||||
F59500000000000000000001 /* PlayerWidgetState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerWidgetState.swift; sourceTree = "<group>"; };
|
||||
F59500000000000000000002 /* PlayerControlIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerControlIntent.swift; sourceTree = "<group>"; };
|
||||
@@ -210,6 +212,7 @@
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
||||
F59500000000000000000004 /* PlayerWidgetBridge.swift */,
|
||||
A0D100000000000000000002 /* AudioOutputView.swift */,
|
||||
F59500000000000000000007 /* Runner.entitlements */,
|
||||
C03400000000000000000002 /* CoreBackend.swift */,
|
||||
D08A594730CF000100000002 /* DownloadProgressSubscription.swift */,
|
||||
@@ -471,6 +474,7 @@
|
||||
F59500000000000000000011 /* PlayerWidgetState.swift in Sources */,
|
||||
F59500000000000000000012 /* PlayerControlIntent.swift in Sources */,
|
||||
F59500000000000000000013 /* PlayerWidgetBridge.swift in Sources */,
|
||||
A0D100000000000000000001 /* AudioOutputView.swift in Sources */,
|
||||
C03400000000000000000001 /* CoreBackend.swift in Sources */,
|
||||
D08A594730CF000100000001 /* DownloadProgressSubscription.swift in Sources */,
|
||||
A11CE0012F00000000000001 /* ExtensionCallbackParser.swift in Sources */,
|
||||
|
||||
@@ -106,6 +106,10 @@ import UniformTypeIdentifiers
|
||||
)
|
||||
|
||||
GeneratedPluginRegistrant.register(with: registry)
|
||||
registry.registrar(forPlugin: "AudioOutputView")?.register(
|
||||
AudioOutputViewFactory(messenger: messenger),
|
||||
withId: "com.zarz.spotiflac/audio_output"
|
||||
)
|
||||
}
|
||||
|
||||
/// The window of the foreground scene. Under the UIScene lifecycle the
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import AVKit
|
||||
import Flutter
|
||||
import UIKit
|
||||
|
||||
final class AudioOutputViewFactory: NSObject, FlutterPlatformViewFactory {
|
||||
private let messenger: FlutterBinaryMessenger
|
||||
|
||||
init(messenger: FlutterBinaryMessenger) {
|
||||
self.messenger = messenger
|
||||
super.init()
|
||||
}
|
||||
|
||||
func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol {
|
||||
FlutterStandardMessageCodec.sharedInstance()
|
||||
}
|
||||
|
||||
func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView {
|
||||
AudioOutputView(frame: frame, id: viewId, messenger: messenger, arguments: args)
|
||||
}
|
||||
}
|
||||
|
||||
private final class AudioOutputView: NSObject, FlutterPlatformView, AVRoutePickerViewDelegate {
|
||||
private let picker: AVRoutePickerView
|
||||
private let channel: FlutterMethodChannel
|
||||
|
||||
init(frame: CGRect, id: Int64, messenger: FlutterBinaryMessenger, arguments: Any?) {
|
||||
picker = AVRoutePickerView(frame: frame)
|
||||
channel = FlutterMethodChannel(name: "com.zarz.spotiflac/audio_output/\(id)", binaryMessenger: messenger)
|
||||
super.init()
|
||||
picker.backgroundColor = .clear
|
||||
picker.prioritizesVideoDevices = false
|
||||
picker.delegate = self
|
||||
update(arguments)
|
||||
channel.setMethodCallHandler { [weak self] call, result in
|
||||
if call.method == "update" {
|
||||
self?.update(call.arguments)
|
||||
result(nil)
|
||||
} else {
|
||||
result(FlutterMethodNotImplemented)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func update(_ arguments: Any?) {
|
||||
guard let values = arguments as? [String: Any] else { return }
|
||||
if let value = values["color"] as? NSNumber {
|
||||
let argb = value.uint32Value
|
||||
picker.tintColor = UIColor(
|
||||
red: CGFloat((argb >> 16) & 0xff) / 255,
|
||||
green: CGFloat((argb >> 8) & 0xff) / 255,
|
||||
blue: CGFloat(argb & 0xff) / 255,
|
||||
alpha: CGFloat((argb >> 24) & 0xff) / 255
|
||||
)
|
||||
picker.activeTintColor = picker.tintColor
|
||||
}
|
||||
picker.accessibilityLabel = values["label"] as? String
|
||||
}
|
||||
|
||||
func view() -> UIView { picker }
|
||||
|
||||
func routePickerViewWillBeginPresentingRoutes(_ routePickerView: AVRoutePickerView) {
|
||||
channel.invokeMethod("pickerChanged", arguments: true)
|
||||
}
|
||||
|
||||
func routePickerViewDidEndPresentingRoutes(_ routePickerView: AVRoutePickerView) {
|
||||
channel.invokeMethod("pickerChanged", arguments: false)
|
||||
}
|
||||
|
||||
deinit {
|
||||
channel.setMethodCallHandler(nil)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user