mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
266 lines
8.7 KiB
Swift
266 lines
8.7 KiB
Swift
import Foundation
|
|
import UIKit
|
|
import AVKit
|
|
import SwiftSignalKit
|
|
import MediaPlayer
|
|
import LegacyComponents
|
|
import AccountContext
|
|
|
|
private protocol VolumeButtonHandlerImpl {
|
|
}
|
|
|
|
private final class LegacyHandlerImpl: VolumeButtonHandlerImpl {
|
|
private let handler: PGCameraVolumeButtonHandler
|
|
|
|
init(
|
|
context: SharedAccountContext,
|
|
performAction: @escaping (VolumeButtonsListener.Action) -> Void
|
|
) {
|
|
self.handler = PGCameraVolumeButtonHandler(upButtonPressedBlock: {
|
|
performAction(.up)
|
|
}, upButtonReleasedBlock: {
|
|
performAction(.upRelease)
|
|
}, downButtonPressedBlock: {
|
|
performAction(.down)
|
|
}, downButtonReleasedBlock: {
|
|
performAction(.downRelease)
|
|
})
|
|
self.handler.enabled = true
|
|
}
|
|
|
|
deinit {
|
|
self.handler.enabled = false
|
|
}
|
|
}
|
|
|
|
@available(iOS 17.2, *)
|
|
private final class AVCaptureEventHandlerImpl: VolumeButtonHandlerImpl {
|
|
private weak var context: SharedAccountContext?
|
|
private let interaction: AVCaptureEventInteraction
|
|
|
|
init(
|
|
context: SharedAccountContext,
|
|
performAction: @escaping (VolumeButtonsListener.Action) -> Void
|
|
) {
|
|
self.context = context
|
|
self.interaction = AVCaptureEventInteraction(
|
|
primary: { event in
|
|
switch event.phase {
|
|
case .began:
|
|
performAction(.down)
|
|
case .ended:
|
|
performAction(.downRelease)
|
|
case .cancelled:
|
|
performAction(.downRelease)
|
|
@unknown default:
|
|
break
|
|
}
|
|
},
|
|
secondary: { event in
|
|
switch event.phase {
|
|
case .began:
|
|
performAction(.up)
|
|
case .ended:
|
|
performAction(.upRelease)
|
|
case .cancelled:
|
|
performAction(.upRelease)
|
|
@unknown default:
|
|
break
|
|
}
|
|
}
|
|
)
|
|
self.interaction.isEnabled = true
|
|
context.mainWindow?.viewController?.view.addInteraction(self.interaction)
|
|
}
|
|
|
|
deinit {
|
|
self.interaction.isEnabled = false
|
|
self.context?.mainWindow?.viewController?.view.removeInteraction(self.interaction)
|
|
}
|
|
}
|
|
|
|
public class VolumeButtonsListener {
|
|
private final class ListenerReference {
|
|
let id: Int
|
|
weak var listener: VolumeButtonsListener?
|
|
|
|
init(id: Int, listener: VolumeButtonsListener) {
|
|
self.id = id
|
|
self.listener = listener
|
|
}
|
|
}
|
|
|
|
fileprivate enum Action {
|
|
case up
|
|
case upRelease
|
|
case down
|
|
case downRelease
|
|
}
|
|
|
|
private final class SharedContext: NSObject {
|
|
private var handler: VolumeButtonHandlerImpl?
|
|
private var cameraSpecificHandler: VolumeButtonHandlerImpl?
|
|
|
|
private weak var sharedAccountContext: SharedAccountContext?
|
|
|
|
private var nextListenerId: Int = 0
|
|
private var listeners: [ListenerReference] = []
|
|
|
|
override init() {
|
|
super.init()
|
|
}
|
|
|
|
func add(listener: VolumeButtonsListener) -> Int {
|
|
self.sharedAccountContext = listener.sharedAccountContext
|
|
|
|
let id = self.nextListenerId
|
|
self.nextListenerId += 1
|
|
|
|
self.listeners.append(ListenerReference(id: id, listener: listener))
|
|
self.updateListeners()
|
|
|
|
return id
|
|
}
|
|
|
|
func update(id: Int) {
|
|
self.updateListeners()
|
|
}
|
|
|
|
func remove(id: Int) {
|
|
if let index = self.listeners.firstIndex(where: { $0.id == id }) {
|
|
self.listeners.remove(at: index)
|
|
self.updateListeners()
|
|
}
|
|
}
|
|
|
|
private func performAction(_ action: Action, isCameraSpecific: Bool) {
|
|
for i in (0 ..< self.listeners.count).reversed() {
|
|
if let listener = self.listeners[i].listener, listener.isActive, listener.isCameraSpecific == isCameraSpecific {
|
|
switch action {
|
|
case .up:
|
|
listener.upPressed()
|
|
case .upRelease:
|
|
listener.upReleased()
|
|
case .down:
|
|
listener.downPressed()
|
|
case .downRelease:
|
|
listener.downReleased()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private func updateListeners() {
|
|
var isGeneralActive = false
|
|
var isCameraSpecificActive = false
|
|
|
|
for i in (0 ..< self.listeners.count).reversed() {
|
|
if let listener = self.listeners[i].listener {
|
|
if listener.isActive {
|
|
if #available(iOS 17.2, *) {
|
|
if listener.isCameraSpecific {
|
|
isCameraSpecificActive = true
|
|
} else {
|
|
isGeneralActive = true
|
|
}
|
|
} else {
|
|
isGeneralActive = true
|
|
}
|
|
}
|
|
} else {
|
|
self.listeners.remove(at: i)
|
|
}
|
|
}
|
|
|
|
if isGeneralActive {
|
|
if self.handler == nil {
|
|
if let sharedAccountContext = self.sharedAccountContext {
|
|
let performAction: (VolumeButtonsListener.Action) -> Void = { [weak self] action in
|
|
self?.performAction(action, isCameraSpecific: false)
|
|
}
|
|
self.handler = LegacyHandlerImpl(
|
|
context: sharedAccountContext,
|
|
performAction: performAction
|
|
)
|
|
}
|
|
}
|
|
} else {
|
|
self.handler = nil
|
|
}
|
|
|
|
if isCameraSpecificActive {
|
|
if self.cameraSpecificHandler == nil {
|
|
if let sharedAccountContext = self.sharedAccountContext {
|
|
let performAction: (VolumeButtonsListener.Action) -> Void = { [weak self] action in
|
|
self?.performAction(action, isCameraSpecific: true)
|
|
}
|
|
if #available(iOS 17.2, *) {
|
|
self.cameraSpecificHandler = AVCaptureEventHandlerImpl(
|
|
context: sharedAccountContext,
|
|
performAction: performAction
|
|
)
|
|
} else {
|
|
self.cameraSpecificHandler = nil
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
self.cameraSpecificHandler = nil
|
|
}
|
|
}
|
|
}
|
|
|
|
fileprivate let sharedAccountContext: SharedAccountContext
|
|
fileprivate let isCameraSpecific: Bool
|
|
|
|
private static var sharedContext: SharedContext = {
|
|
return SharedContext()
|
|
}()
|
|
|
|
fileprivate let upPressed: () -> Void
|
|
fileprivate let upReleased: () -> Void
|
|
fileprivate let downPressed: () -> Void
|
|
fileprivate let downReleased: () -> Void
|
|
|
|
private var index: Int?
|
|
|
|
fileprivate var isActive: Bool = false
|
|
private var disposable: Disposable?
|
|
|
|
public init(
|
|
sharedContext: SharedAccountContext,
|
|
isCameraSpecific: Bool,
|
|
shouldBeActive: Signal<Bool, NoError>,
|
|
upPressed: @escaping () -> Void,
|
|
upReleased: @escaping () -> Void = {},
|
|
downPressed: @escaping () -> Void,
|
|
downReleased: @escaping () -> Void = {}
|
|
) {
|
|
self.sharedAccountContext = sharedContext
|
|
self.isCameraSpecific = isCameraSpecific
|
|
self.upPressed = upPressed
|
|
self.upReleased = upReleased
|
|
self.downPressed = downPressed
|
|
self.downReleased = downReleased
|
|
|
|
self.index = VolumeButtonsListener.sharedContext.add(listener: self)
|
|
|
|
self.disposable = (shouldBeActive
|
|
|> distinctUntilChanged
|
|
|> deliverOnMainQueue).start(next: { [weak self] value in
|
|
guard let self, let index = self.index else {
|
|
return
|
|
}
|
|
self.isActive = value
|
|
VolumeButtonsListener.sharedContext.update(id: index)
|
|
})
|
|
}
|
|
|
|
deinit {
|
|
if let index = self.index {
|
|
VolumeButtonsListener.sharedContext.remove(id: index)
|
|
}
|
|
self.disposable?.dispose()
|
|
}
|
|
}
|