mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Camera and editor improvements
This commit is contained in:
parent
ef4d6c51c2
commit
6dbd76bf7a
@ -75,6 +75,7 @@ swift_library(
|
|||||||
"//submodules/TelegramUI/Components/MediaEditor",
|
"//submodules/TelegramUI/Components/MediaEditor",
|
||||||
"//submodules/Components/MetalImageView",
|
"//submodules/Components/MetalImageView",
|
||||||
"//submodules/TelegramUI/Components/CameraButtonComponent",
|
"//submodules/TelegramUI/Components/CameraButtonComponent",
|
||||||
|
"//submodules/Utils/VolumeButtons"
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -19,6 +19,7 @@ import TooltipUI
|
|||||||
import MediaEditor
|
import MediaEditor
|
||||||
import BundleIconComponent
|
import BundleIconComponent
|
||||||
import CameraButtonComponent
|
import CameraButtonComponent
|
||||||
|
import VolumeButtons
|
||||||
|
|
||||||
let videoRedColor = UIColor(rgb: 0xff3b30)
|
let videoRedColor = UIColor(rgb: 0xff3b30)
|
||||||
|
|
||||||
@ -87,6 +88,7 @@ private final class CameraScreenComponent: CombinedComponent {
|
|||||||
let camera: Camera
|
let camera: Camera
|
||||||
let updateState: ActionSlot<CameraState>
|
let updateState: ActionSlot<CameraState>
|
||||||
let hasAppeared: Bool
|
let hasAppeared: Bool
|
||||||
|
let isVisible: Bool
|
||||||
let panelWidth: CGFloat
|
let panelWidth: CGFloat
|
||||||
let flipAnimationAction: ActionSlot<Void>
|
let flipAnimationAction: ActionSlot<Void>
|
||||||
let animateShutter: () -> Void
|
let animateShutter: () -> Void
|
||||||
@ -99,6 +101,7 @@ private final class CameraScreenComponent: CombinedComponent {
|
|||||||
camera: Camera,
|
camera: Camera,
|
||||||
updateState: ActionSlot<CameraState>,
|
updateState: ActionSlot<CameraState>,
|
||||||
hasAppeared: Bool,
|
hasAppeared: Bool,
|
||||||
|
isVisible: Bool,
|
||||||
panelWidth: CGFloat,
|
panelWidth: CGFloat,
|
||||||
flipAnimationAction: ActionSlot<Void>,
|
flipAnimationAction: ActionSlot<Void>,
|
||||||
animateShutter: @escaping () -> Void,
|
animateShutter: @escaping () -> Void,
|
||||||
@ -110,6 +113,7 @@ private final class CameraScreenComponent: CombinedComponent {
|
|||||||
self.camera = camera
|
self.camera = camera
|
||||||
self.updateState = updateState
|
self.updateState = updateState
|
||||||
self.hasAppeared = hasAppeared
|
self.hasAppeared = hasAppeared
|
||||||
|
self.isVisible = isVisible
|
||||||
self.panelWidth = panelWidth
|
self.panelWidth = panelWidth
|
||||||
self.flipAnimationAction = flipAnimationAction
|
self.flipAnimationAction = flipAnimationAction
|
||||||
self.animateShutter = animateShutter
|
self.animateShutter = animateShutter
|
||||||
@ -125,6 +129,9 @@ private final class CameraScreenComponent: CombinedComponent {
|
|||||||
if lhs.hasAppeared != rhs.hasAppeared {
|
if lhs.hasAppeared != rhs.hasAppeared {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.isVisible != rhs.isVisible {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.panelWidth != rhs.panelWidth {
|
if lhs.panelWidth != rhs.panelWidth {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -159,6 +166,8 @@ private final class CameraScreenComponent: CombinedComponent {
|
|||||||
private let completion: ActionSlot<Signal<CameraScreen.Result, NoError>>
|
private let completion: ActionSlot<Signal<CameraScreen.Result, NoError>>
|
||||||
private let updateState: ActionSlot<CameraState>
|
private let updateState: ActionSlot<CameraState>
|
||||||
|
|
||||||
|
private let animateShutter: () -> Void
|
||||||
|
|
||||||
private var cameraStateDisposable: Disposable?
|
private var cameraStateDisposable: Disposable?
|
||||||
private var resultDisposable = MetaDisposable()
|
private var resultDisposable = MetaDisposable()
|
||||||
|
|
||||||
@ -166,6 +175,9 @@ private final class CameraScreenComponent: CombinedComponent {
|
|||||||
fileprivate var lastGalleryAsset: PHAsset?
|
fileprivate var lastGalleryAsset: PHAsset?
|
||||||
private var lastGalleryAssetsDisposable: Disposable?
|
private var lastGalleryAssetsDisposable: Disposable?
|
||||||
|
|
||||||
|
private var volumeButtonsListener: VolumeButtonsListener?
|
||||||
|
private let volumeButtonsListenerShouldBeActive = ValuePromise<Bool>(false, ignoreRepeated: true)
|
||||||
|
|
||||||
var cameraState = CameraState(mode: .photo, position: .unspecified, flashMode: .off, flashModeDidChange: false, recording: .none, duration: 0.0, isDualCamEnabled: false) {
|
var cameraState = CameraState(mode: .photo, position: .unspecified, flashMode: .off, flashModeDidChange: false, recording: .none, duration: 0.0, isDualCamEnabled: false) {
|
||||||
didSet {
|
didSet {
|
||||||
self.updateState.invoke(self.cameraState)
|
self.updateState.invoke(self.cameraState)
|
||||||
@ -176,12 +188,20 @@ private final class CameraScreenComponent: CombinedComponent {
|
|||||||
|
|
||||||
private let hapticFeedback = HapticFeedback()
|
private let hapticFeedback = HapticFeedback()
|
||||||
|
|
||||||
init(context: AccountContext, camera: Camera, present: @escaping (ViewController) -> Void, completion: ActionSlot<Signal<CameraScreen.Result, NoError>>, updateState: ActionSlot<CameraState>) {
|
init(
|
||||||
|
context: AccountContext,
|
||||||
|
camera: Camera,
|
||||||
|
present: @escaping (ViewController) -> Void,
|
||||||
|
completion: ActionSlot<Signal<CameraScreen.Result, NoError>>,
|
||||||
|
updateState: ActionSlot<CameraState>,
|
||||||
|
animateShutter: @escaping () -> Void = {}
|
||||||
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.camera = camera
|
self.camera = camera
|
||||||
self.present = present
|
self.present = present
|
||||||
self.completion = completion
|
self.completion = completion
|
||||||
self.updateState = updateState
|
self.updateState = updateState
|
||||||
|
self.animateShutter = animateShutter
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
@ -202,6 +222,8 @@ private final class CameraScreenComponent: CombinedComponent {
|
|||||||
Queue.concurrentDefaultQueue().async {
|
Queue.concurrentDefaultQueue().async {
|
||||||
self.setupRecentAssetSubscription()
|
self.setupRecentAssetSubscription()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.setupVolumeButtonsHandler()
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
@ -226,6 +248,77 @@ private final class CameraScreenComponent: CombinedComponent {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setupVolumeButtonsHandler() {
|
||||||
|
guard self.volumeButtonsListener == nil else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.volumeButtonsListener = VolumeButtonsListener(
|
||||||
|
shouldBeActive: self.volumeButtonsListenerShouldBeActive.get(),
|
||||||
|
upPressed: { [weak self] in
|
||||||
|
if let self {
|
||||||
|
self.handleVolumePressed()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
upReleased: { [weak self] in
|
||||||
|
if let self {
|
||||||
|
self.handleVolumeReleased()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
downPressed: { [weak self] in
|
||||||
|
if let self {
|
||||||
|
self.handleVolumePressed()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
downReleased: { [weak self] in
|
||||||
|
if let self {
|
||||||
|
self.handleVolumeReleased()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
var volumeButtonsListenerActive = false {
|
||||||
|
didSet {
|
||||||
|
self.volumeButtonsListenerShouldBeActive.set(self.volumeButtonsListenerActive)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var buttonPressTimestamp: Double?
|
||||||
|
private var buttonPressTimer: SwiftSignalKit.Timer?
|
||||||
|
|
||||||
|
private func handleVolumePressed() {
|
||||||
|
self.buttonPressTimestamp = CACurrentMediaTime()
|
||||||
|
|
||||||
|
self.buttonPressTimer = SwiftSignalKit.Timer(timeout: 0.3, repeat: false, completion: { [weak self] in
|
||||||
|
if let self, let _ = self.buttonPressTimestamp {
|
||||||
|
if case .none = self.cameraState.recording {
|
||||||
|
self.startVideoRecording(pressing: true)
|
||||||
|
}
|
||||||
|
self.buttonPressTimestamp = nil
|
||||||
|
}
|
||||||
|
}, queue: Queue.mainQueue())
|
||||||
|
self.buttonPressTimer?.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleVolumeReleased() {
|
||||||
|
if case .none = self.cameraState.recording {
|
||||||
|
switch self.cameraState.mode {
|
||||||
|
case .photo:
|
||||||
|
self.animateShutter()
|
||||||
|
self.takePhoto()
|
||||||
|
case .video:
|
||||||
|
self.startVideoRecording(pressing: false)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.stopVideoRecording()
|
||||||
|
}
|
||||||
|
|
||||||
|
self.buttonPressTimer?.invalidate()
|
||||||
|
self.buttonPressTimer = nil
|
||||||
|
self.buttonPressTimestamp = nil
|
||||||
|
}
|
||||||
|
|
||||||
func updateCameraMode(_ mode: CameraMode) {
|
func updateCameraMode(_ mode: CameraMode) {
|
||||||
self.cameraState = self.cameraState.updatedMode(mode)
|
self.cameraState = self.cameraState.updatedMode(mode)
|
||||||
self.updated(transition: .spring(duration: 0.3))
|
self.updated(transition: .spring(duration: 0.3))
|
||||||
@ -329,7 +422,7 @@ private final class CameraScreenComponent: CombinedComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func makeState() -> State {
|
func makeState() -> State {
|
||||||
return State(context: self.context, camera: self.camera, present: self.present, completion: self.completion, updateState: self.updateState)
|
return State(context: self.context, camera: self.camera, present: self.present, completion: self.completion, updateState: self.updateState, animateShutter: self.animateShutter)
|
||||||
}
|
}
|
||||||
|
|
||||||
static var body: Body {
|
static var body: Body {
|
||||||
@ -352,6 +445,8 @@ private final class CameraScreenComponent: CombinedComponent {
|
|||||||
let controller = environment.controller
|
let controller = environment.controller
|
||||||
let availableSize = context.availableSize
|
let availableSize = context.availableSize
|
||||||
|
|
||||||
|
state.volumeButtonsListenerActive = component.hasAppeared && component.isVisible
|
||||||
|
|
||||||
let isTablet: Bool
|
let isTablet: Bool
|
||||||
if case .regular = environment.metrics.widthClass {
|
if case .regular = environment.metrics.widthClass {
|
||||||
isTablet = true
|
isTablet = true
|
||||||
@ -874,21 +969,23 @@ public class CameraScreen: ViewController {
|
|||||||
fileprivate let transitionCornersView: UIImageView
|
fileprivate let transitionCornersView: UIImageView
|
||||||
fileprivate let camera: Camera
|
fileprivate let camera: Camera
|
||||||
|
|
||||||
private var presentationData: PresentationData
|
|
||||||
private var validLayout: ContainerViewLayout?
|
|
||||||
|
|
||||||
private var changingPositionDisposable: Disposable?
|
private var changingPositionDisposable: Disposable?
|
||||||
private var isDualCamEnabled = false
|
private var isDualCamEnabled = false
|
||||||
private var appliedDualCam = false
|
private var appliedDualCam = false
|
||||||
private var cameraPosition: Camera.Position = .back
|
private var cameraPosition: Camera.Position = .back
|
||||||
|
|
||||||
private let completion = ActionSlot<Signal<CameraScreen.Result, NoError>>()
|
private var pipPosition: PIPPosition = .bottomRight
|
||||||
|
|
||||||
fileprivate var previewBlurPromise = ValuePromise<Bool>(false)
|
fileprivate var previewBlurPromise = ValuePromise<Bool>(false)
|
||||||
|
|
||||||
private let flipAnimationAction = ActionSlot<Void>()
|
private let flipAnimationAction = ActionSlot<Void>()
|
||||||
|
|
||||||
private var pipPosition: PIPPosition = .bottomRight
|
fileprivate var cameraIsActive = true
|
||||||
|
fileprivate var hasGallery = false
|
||||||
|
|
||||||
|
private var presentationData: PresentationData
|
||||||
|
private var validLayout: ContainerViewLayout?
|
||||||
|
|
||||||
|
private let completion = ActionSlot<Signal<CameraScreen.Result, NoError>>()
|
||||||
|
|
||||||
init(controller: CameraScreen) {
|
init(controller: CameraScreen) {
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
@ -972,21 +1069,6 @@ public class CameraScreen: ViewController {
|
|||||||
).start(next: { [weak self] modeChange, forceBlur in
|
).start(next: { [weak self] modeChange, forceBlur in
|
||||||
if let self {
|
if let self {
|
||||||
if modeChange != .none {
|
if modeChange != .none {
|
||||||
// if case .dualCamera = modeChange, self.cameraPosition == .front {
|
|
||||||
// if self.isDualCamEnabled {
|
|
||||||
// if let snapshot = self.mainPreviewView.snapshotView(afterScreenUpdates: false) {
|
|
||||||
// snapshot.frame = CGRect(origin: .zero, size: self.mainPreviewContainerView.bounds.size)
|
|
||||||
// self.mainPreviewView.addSubview(snapshot)
|
|
||||||
// self.previewSnapshotView = snapshot
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// if let snapshot = self.mainPreviewView.snapshotView(afterScreenUpdates: false) {
|
|
||||||
// snapshot.frame = CGRect(origin: .zero, size: self.mainPreviewContainerView.bounds.size)
|
|
||||||
// self.additionalPreviewView.addSubview(snapshot)
|
|
||||||
// self.additionalPreviewSnapshotView = snapshot
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
if case .dualCamera = modeChange, self.cameraPosition == .front {
|
if case .dualCamera = modeChange, self.cameraPosition == .front {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -1293,6 +1375,9 @@ public class CameraScreen: ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func animateOutToEditor() {
|
func animateOutToEditor() {
|
||||||
|
self.cameraIsActive = false
|
||||||
|
self.requestUpdateLayout(hasAppeared: self.hasAppeared, transition: .immediate)
|
||||||
|
|
||||||
let transition = Transition(animation: .curve(duration: 0.2, curve: .easeInOut))
|
let transition = Transition(animation: .curve(duration: 0.2, curve: .easeInOut))
|
||||||
if let view = self.componentHost.findTaggedView(tag: cancelButtonTag) {
|
if let view = self.componentHost.findTaggedView(tag: cancelButtonTag) {
|
||||||
view.layer.animateScale(from: 1.0, to: 0.1, duration: 0.2)
|
view.layer.animateScale(from: 1.0, to: 0.1, duration: 0.2)
|
||||||
@ -1324,6 +1409,9 @@ public class CameraScreen: ViewController {
|
|||||||
self.previewBlurPromise.set(true)
|
self.previewBlurPromise.set(true)
|
||||||
}
|
}
|
||||||
self.camera.stopCapture()
|
self.camera.stopCapture()
|
||||||
|
|
||||||
|
self.cameraIsActive = false
|
||||||
|
self.requestUpdateLayout(hasAppeared: self.hasAppeared, transition: .immediate)
|
||||||
}
|
}
|
||||||
|
|
||||||
func resumeCameraCapture() {
|
func resumeCameraCapture() {
|
||||||
@ -1355,6 +1443,9 @@ public class CameraScreen: ViewController {
|
|||||||
self.previewBlurPromise.set(false)
|
self.previewBlurPromise.set(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.cameraIsActive = true
|
||||||
|
self.requestUpdateLayout(hasAppeared: self.hasAppeared, transition: .immediate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1362,6 +1453,9 @@ public class CameraScreen: ViewController {
|
|||||||
if !toGallery {
|
if !toGallery {
|
||||||
self.resumeCameraCapture()
|
self.resumeCameraCapture()
|
||||||
|
|
||||||
|
self.cameraIsActive = true
|
||||||
|
self.requestUpdateLayout(hasAppeared: self.hasAppeared, transition: .immediate)
|
||||||
|
|
||||||
let transition = Transition(animation: .curve(duration: 0.2, curve: .easeInOut))
|
let transition = Transition(animation: .curve(duration: 0.2, curve: .easeInOut))
|
||||||
if let view = self.componentHost.findTaggedView(tag: cancelButtonTag) {
|
if let view = self.componentHost.findTaggedView(tag: cancelButtonTag) {
|
||||||
view.layer.animateScale(from: 0.1, to: 1.0, duration: 0.2)
|
view.layer.animateScale(from: 0.1, to: 1.0, duration: 0.2)
|
||||||
@ -1537,6 +1631,7 @@ public class CameraScreen: ViewController {
|
|||||||
camera: self.camera,
|
camera: self.camera,
|
||||||
updateState: self.updateState,
|
updateState: self.updateState,
|
||||||
hasAppeared: self.hasAppeared,
|
hasAppeared: self.hasAppeared,
|
||||||
|
isVisible: self.cameraIsActive && !self.hasGallery,
|
||||||
panelWidth: panelWidth,
|
panelWidth: panelWidth,
|
||||||
flipAnimationAction: self.flipAnimationAction,
|
flipAnimationAction: self.flipAnimationAction,
|
||||||
animateShutter: { [weak self] in
|
animateShutter: { [weak self] in
|
||||||
@ -1778,6 +1873,8 @@ public class CameraScreen: ViewController {
|
|||||||
|
|
||||||
self.dismissAllTooltips()
|
self.dismissAllTooltips()
|
||||||
|
|
||||||
|
self.node.hasGallery = true
|
||||||
|
|
||||||
self.didStopCameraCapture = false
|
self.didStopCameraCapture = false
|
||||||
let stopCameraCapture = { [weak self] in
|
let stopCameraCapture = { [weak self] in
|
||||||
guard let self, !self.didStopCameraCapture else {
|
guard let self, !self.didStopCameraCapture else {
|
||||||
@ -1825,7 +1922,8 @@ public class CameraScreen: ViewController {
|
|||||||
self.completion(.single(.draft(draft)), resultTransition, dismissed)
|
self.completion(.single(.draft(draft)), resultTransition, dismissed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, dismissed: {
|
}, dismissed: { [weak self] in
|
||||||
|
self?.node.hasGallery = false
|
||||||
resumeCameraCapture()
|
resumeCameraCapture()
|
||||||
})
|
})
|
||||||
self.galleryController = controller
|
self.galleryController = controller
|
||||||
|
@ -175,7 +175,7 @@ private final class StoryContainerScreenComponent: Component {
|
|||||||
private var transitionCloneMasterView: UIView
|
private var transitionCloneMasterView: UIView
|
||||||
|
|
||||||
private var volumeButtonsListener: VolumeButtonsListener?
|
private var volumeButtonsListener: VolumeButtonsListener?
|
||||||
private let volumeButtonsListenerShouldBeActvie = ValuePromise<Bool>(false, ignoreRepeated: true)
|
private let volumeButtonsListenerShouldBeActive = ValuePromise<Bool>(false, ignoreRepeated: true)
|
||||||
|
|
||||||
private var isAnimatingOut: Bool = false
|
private var isAnimatingOut: Bool = false
|
||||||
private var didAnimateOut: Bool = false
|
private var didAnimateOut: Bool = false
|
||||||
@ -580,19 +580,24 @@ private final class StoryContainerScreenComponent: Component {
|
|||||||
|
|
||||||
private func updateVolumeButtonMonitoring() {
|
private func updateVolumeButtonMonitoring() {
|
||||||
if self.volumeButtonsListener == nil {
|
if self.volumeButtonsListener == nil {
|
||||||
self.volumeButtonsListener = VolumeButtonsListener(shouldBeActive: self.volumeButtonsListenerShouldBeActvie.get(), valueChanged: { [weak self] in
|
let buttonAction = { [weak self] in
|
||||||
guard let self, self.storyItemSharedState.useAmbientMode else {
|
guard let self, self.storyItemSharedState.useAmbientMode else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.storyItemSharedState.useAmbientMode = false
|
self.storyItemSharedState.useAmbientMode = false
|
||||||
self.volumeButtonsListenerShouldBeActvie.set(false)
|
self.volumeButtonsListenerShouldBeActive.set(false)
|
||||||
|
|
||||||
for (_, itemSetView) in self.visibleItemSetViews {
|
for (_, itemSetView) in self.visibleItemSetViews {
|
||||||
if let componentView = itemSetView.view.view as? StoryItemSetContainerComponent.View {
|
if let componentView = itemSetView.view.view as? StoryItemSetContainerComponent.View {
|
||||||
componentView.leaveAmbientMode()
|
componentView.leaveAmbientMode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
self.volumeButtonsListener = VolumeButtonsListener(
|
||||||
|
shouldBeActive: self.volumeButtonsListenerShouldBeActive.get(),
|
||||||
|
upPressed: buttonAction,
|
||||||
|
downPressed: buttonAction
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -624,7 +629,7 @@ private final class StoryContainerScreenComponent: Component {
|
|||||||
self.focusedItem.set(focusedItemId)
|
self.focusedItem.set(focusedItemId)
|
||||||
|
|
||||||
if self.storyItemSharedState.useAmbientMode {
|
if self.storyItemSharedState.useAmbientMode {
|
||||||
self.volumeButtonsListenerShouldBeActvie.set(isVideo)
|
self.volumeButtonsListenerShouldBeActive.set(isVideo)
|
||||||
if isVideo {
|
if isVideo {
|
||||||
self.updateVolumeButtonMonitoring()
|
self.updateVolumeButtonMonitoring()
|
||||||
}
|
}
|
||||||
|
@ -10967,15 +10967,15 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.volumeButtonsListener = VolumeButtonsListener(shouldBeActive: shouldBeActive, valueChanged: { [weak self] in
|
let buttonAction = { [weak self] in
|
||||||
guard let strongSelf = self, strongSelf.traceVisibility() && isTopmostChatController(strongSelf) else {
|
guard let self, self.traceVisibility() && isTopmostChatController(self) else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
strongSelf.videoUnmuteTooltipController?.dismiss()
|
self.videoUnmuteTooltipController?.dismiss()
|
||||||
|
|
||||||
var actions: [(Bool, (Double?) -> Void)] = []
|
var actions: [(Bool, (Double?) -> Void)] = []
|
||||||
var hasUnconsumed = false
|
var hasUnconsumed = false
|
||||||
strongSelf.chatDisplayNode.historyNode.forEachVisibleItemNode { itemNode in
|
self.chatDisplayNode.historyNode.forEachVisibleItemNode { itemNode in
|
||||||
if let itemNode = itemNode as? ChatMessageItemView, let (action, _, _, isUnconsumed, _) = itemNode.playMediaWithSound() {
|
if let itemNode = itemNode as? ChatMessageItemView, let (action, _, _, isUnconsumed, _) = itemNode.playMediaWithSound() {
|
||||||
if case let .visible(fraction, _) = itemNode.visibility, fraction > 0.7 {
|
if case let .visible(fraction, _) = itemNode.visibility, fraction > 0.7 {
|
||||||
actions.insert((isUnconsumed, action), at: 0)
|
actions.insert((isUnconsumed, action), at: 0)
|
||||||
@ -10991,7 +10991,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
self.volumeButtonsListener = VolumeButtonsListener(
|
||||||
|
shouldBeActive: shouldBeActive,
|
||||||
|
upPressed: buttonAction,
|
||||||
|
downPressed: buttonAction
|
||||||
|
)
|
||||||
|
|
||||||
self.chatDisplayNode.historyNode.openNextChannelToRead = { [weak self] peer, location in
|
self.chatDisplayNode.historyNode.openNextChannelToRead = { [weak self] peer, location in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
|
@ -10,21 +10,25 @@ public class VolumeButtonsListener: NSObject {
|
|||||||
|
|
||||||
private var disposable: Disposable?
|
private var disposable: Disposable?
|
||||||
|
|
||||||
public init(shouldBeActive: Signal<Bool, NoError>, valueChanged: @escaping () -> Void) {
|
public init(
|
||||||
var impl: (() -> Void)?
|
shouldBeActive: Signal<Bool, NoError>,
|
||||||
|
upPressed: @escaping () -> Void,
|
||||||
|
upReleased: @escaping () -> Void = {},
|
||||||
|
downPressed: @escaping () -> Void,
|
||||||
|
downReleased: @escaping () -> Void = {}
|
||||||
|
) {
|
||||||
self.handler = PGCameraVolumeButtonHandler(upButtonPressedBlock: {
|
self.handler = PGCameraVolumeButtonHandler(upButtonPressedBlock: {
|
||||||
impl?()
|
upPressed()
|
||||||
}, upButtonReleasedBlock: {}, downButtonPressedBlock: {
|
}, upButtonReleasedBlock: {
|
||||||
impl?()
|
upReleased()
|
||||||
}, downButtonReleasedBlock: {})
|
}, downButtonPressedBlock: {
|
||||||
|
downPressed()
|
||||||
|
}, downButtonReleasedBlock: {
|
||||||
|
downReleased()
|
||||||
|
})
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
impl = {
|
|
||||||
valueChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
self.disposable = (shouldBeActive
|
self.disposable = (shouldBeActive
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] value in
|
|> deliverOnMainQueue).start(next: { [weak self] value in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user