Files
plezy/ios/Runner/AppDelegate.swift
T
2026-06-14 14:04:52 +02:00

154 lines
5.3 KiB
Swift

import Flutter
import UIKit
import AVFoundation
import MediaPlayer
@main
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
private var deviceAdjustmentChannel: FlutterMethodChannel?
private var originalBrightness: CGFloat?
private var volumeView: MPVolumeView?
private weak var volumeSlider: UISlider?
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Configure audio session for media playback
do {
let session = AVAudioSession.sharedInstance()
try session.setCategory(.playback, mode: .default)
try session.setActive(true)
} catch {
print("Failed to configure audio session: \(error)")
}
application.beginReceivingRemoteControlEvents()
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
// Register MPV player plugin
if let registrar = engineBridge.pluginRegistry.registrar(forPlugin: "MpvPlayerPlugin") {
MpvPlayerPlugin.register(with: registrar)
}
if let registrar = engineBridge.pluginRegistry.registrar(forPlugin: "DeviceAdjustmentChannel") {
registerDeviceAdjustmentChannel(messenger: registrar.messenger())
}
}
private func registerDeviceAdjustmentChannel(messenger: FlutterBinaryMessenger) {
let channel = FlutterMethodChannel(name: "com.plezy/device_adjustment", binaryMessenger: messenger)
channel.setMethodCallHandler { [weak self] call, result in
DispatchQueue.main.async {
self?.handleDeviceAdjustmentCall(call, result: result)
}
}
deviceAdjustmentChannel = channel
}
private func handleDeviceAdjustmentCall(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "getBrightness":
result(Double(UIScreen.main.brightness))
case "setBrightness":
guard let value = normalizedArgument(call.arguments, result: result) else { return }
if originalBrightness == nil {
originalBrightness = UIScreen.main.brightness
}
UIScreen.main.brightness = CGFloat(value)
result(nil)
case "restoreBrightness":
if let originalBrightness = originalBrightness {
UIScreen.main.brightness = originalBrightness
self.originalBrightness = nil
}
result(nil)
case "getMediaVolume":
result(Double(AVAudioSession.sharedInstance().outputVolume))
case "setMediaVolume":
guard let value = normalizedArgument(call.arguments, result: result) else { return }
if setMediaVolume(value) {
result(nil)
} else {
result(
FlutterError(code: "DEVICE_ADJUSTMENT_UNAVAILABLE", message: "System volume slider unavailable", details: nil)
)
}
default:
result(FlutterMethodNotImplemented)
}
}
private func normalizedArgument(_ arguments: Any?, result: @escaping FlutterResult) -> Double? {
guard let value = arguments as? NSNumber else {
result(FlutterError(code: "INVALID_ARGUMENT", message: "Expected a numeric value", details: nil))
return nil
}
let doubleValue = value.doubleValue
guard doubleValue.isFinite else {
result(FlutterError(code: "INVALID_ARGUMENT", message: "Expected a finite numeric value", details: nil))
return nil
}
return min(1.0, max(0.0, doubleValue))
}
private func setMediaVolume(_ value: Double) -> Bool {
guard let slider = ensureVolumeSlider() else { return false }
slider.setValue(Float(value), animated: false)
slider.sendActions(for: .valueChanged)
slider.sendActions(for: .touchUpInside)
return true
}
private func ensureVolumeSlider() -> UISlider? {
if let volumeSlider = volumeSlider { return volumeSlider }
let volumeView = self.volumeView ?? MPVolumeView(frame: CGRect(x: -1000, y: -1000, width: 1, height: 1))
volumeView.showsRouteButton = false
volumeView.showsVolumeSlider = true
volumeView.alpha = 0.01
volumeView.isUserInteractionEnabled = false
if volumeView.superview == nil {
activeWindow?.addSubview(volumeView)
}
volumeView.layoutIfNeeded()
self.volumeView = volumeView
let slider = findVolumeSlider(in: volumeView)
volumeSlider = slider
return slider
}
private func findVolumeSlider(in view: UIView) -> UISlider? {
if let slider = view as? UISlider { return slider }
for subview in view.subviews {
if let slider = findVolumeSlider(in: subview) { return slider }
}
return nil
}
private var activeWindow: UIWindow? {
if #available(iOS 13.0, *) {
for scene in UIApplication.shared.connectedScenes {
guard let windowScene = scene as? UIWindowScene else { continue }
if let keyWindow = windowScene.windows.first(where: { $0.isKeyWindow }) {
return keyWindow
}
}
for scene in UIApplication.shared.connectedScenes {
guard let windowScene = scene as? UIWindowScene, let window = windowScene.windows.first else { continue }
return window
}
return nil
}
return UIApplication.shared.windows.first(where: { $0.isKeyWindow }) ?? UIApplication.shared.windows.first
}
}