Various fixes

This commit is contained in:
Ilya Laktyushin 2023-07-05 23:54:51 +02:00
parent 0c851a6aec
commit 7b9836682d
5 changed files with 102 additions and 114 deletions

View File

@ -9,7 +9,7 @@ final class CameraSession {
private let multiSession: Any?
init() {
if #available(iOS 13.0, *) {
if #available(iOS 13.0, *), AVCaptureMultiCamSession.isMultiCamSupported {
self.multiSession = AVCaptureMultiCamSession()
self.singleSession = nil
} else {

View File

@ -40,20 +40,23 @@ final class CameraDevice {
selectedDevice = device
} else if let device = AVCaptureDevice.default(.builtInDualWideCamera, for: .video, position: position) {
selectedDevice = device
} else {
selectedDevice = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInDualCamera, .builtInWideAngleCamera, .builtInTelephotoCamera], mediaType: .video, position: position).devices.first
} else if let device = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera, .builtInTelephotoCamera], mediaType: .video, position: position).devices.first {
selectedDevice = device
}
} else {
if #available(iOS 11.1, *), dual, case .front = position {
if let trueDepthDevice = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInTrueDepthCamera], mediaType: .video, position: position).devices.first {
selectedDevice = trueDepthDevice
}
if #available(iOS 11.1, *), dual, case .front = position, let trueDepthDevice = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInTrueDepthCamera], mediaType: .video, position: position).devices.first {
selectedDevice = trueDepthDevice
}
if selectedDevice == nil {
selectedDevice = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInDualCamera, .builtInWideAngleCamera, .builtInTelephotoCamera], mediaType: .video, position: position).devices.first
}
}
if selectedDevice == nil, #available(iOS 13.0, *) {
let allDevices = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInDualCamera, .builtInTripleCamera, .builtInTelephotoCamera, .builtInDualWideCamera, .builtInTrueDepthCamera, .builtInWideAngleCamera, .builtInUltraWideCamera], mediaType: .video, position: position).devices
Logger.shared.log("Camera", "No device selected, availabled devices: \(allDevices)")
}
self.videoDevice = selectedDevice
self.videoDevicePromise.set(.single(selectedDevice))

View File

@ -9,7 +9,35 @@ import CoreMedia
import Vision
import ImageBlur
private extension UIInterfaceOrientation {
var videoOrientation: AVCaptureVideoOrientation {
switch self {
case .portraitUpsideDown: return .portraitUpsideDown
case .landscapeRight: return .landscapeRight
case .landscapeLeft: return .landscapeLeft
case .portrait: return .portrait
default: return .portrait
}
}
}
public class CameraSimplePreviewView: UIView {
func updateOrientation() {
guard self.videoPreviewLayer.connection?.isVideoOrientationSupported == true else {
return
}
let statusBarOrientation: UIInterfaceOrientation
if #available(iOS 13.0, *) {
statusBarOrientation = UIApplication.shared.windows.first?.windowScene?.interfaceOrientation ?? .portrait
} else {
statusBarOrientation = UIApplication.shared.statusBarOrientation
}
let videoOrientation: AVCaptureVideoOrientation = statusBarOrientation.videoOrientation
// videoPreviewLayer.frame = view.layer.bounds
self.videoPreviewLayer.connection?.videoOrientation = videoOrientation
self.videoPreviewLayer.removeAllAnimations()
}
static func lastBackImage() -> UIImage {
let imagePath = NSTemporaryDirectory() + "backCameraImage.jpg"
if let data = try? Data(contentsOf: URL(fileURLWithPath: imagePath)), let image = UIImage(data: data) {
@ -80,6 +108,7 @@ public class CameraSimplePreviewView: UIView {
public override func layoutSubviews() {
super.layoutSubviews()
self.updateOrientation()
self.placeholderView.frame = self.bounds.insetBy(dx: -1.0, dy: -1.0)
}

View File

@ -101,6 +101,7 @@ private final class CameraScreenComponent: CombinedComponent {
let panelWidth: CGFloat
let animateFlipAction: ActionSlot<Void>
let animateShutter: () -> Void
let toggleCameraPositionAction: ActionSlot<Void>
let dismissAllTooltips: () -> Void
let present: (ViewController) -> Void
let push: (ViewController) -> Void
@ -116,6 +117,7 @@ private final class CameraScreenComponent: CombinedComponent {
panelWidth: CGFloat,
animateFlipAction: ActionSlot<Void>,
animateShutter: @escaping () -> Void,
toggleCameraPositionAction: ActionSlot<Void>,
dismissAllTooltips: @escaping () -> Void,
present: @escaping (ViewController) -> Void,
push: @escaping (ViewController) -> Void,
@ -130,6 +132,7 @@ private final class CameraScreenComponent: CombinedComponent {
self.panelWidth = panelWidth
self.animateFlipAction = animateFlipAction
self.animateShutter = animateShutter
self.toggleCameraPositionAction = toggleCameraPositionAction
self.dismissAllTooltips = dismissAllTooltips
self.present = present
self.push = push
@ -183,8 +186,10 @@ private final class CameraScreenComponent: CombinedComponent {
private let present: (ViewController) -> Void
private let completion: ActionSlot<Signal<CameraScreen.Result, NoError>>
private let updateState: ActionSlot<CameraState>
private let toggleCameraPositionAction: ActionSlot<Void>
private let animateShutter: () -> Void
private let animateFlipAction: ActionSlot<Void>
private let dismissAllTooltips: () -> Void
private var cameraStateDisposable: Disposable?
@ -214,6 +219,8 @@ private final class CameraScreenComponent: CombinedComponent {
completion: ActionSlot<Signal<CameraScreen.Result, NoError>>,
updateState: ActionSlot<CameraState>,
animateShutter: @escaping () -> Void = {},
animateFlipAction: ActionSlot<Void>,
toggleCameraPositionAction: ActionSlot<Void>,
dismissAllTooltips: @escaping () -> Void = {}
) {
self.context = context
@ -222,6 +229,8 @@ private final class CameraScreenComponent: CombinedComponent {
self.completion = completion
self.updateState = updateState
self.animateShutter = animateShutter
self.animateFlipAction = animateFlipAction
self.toggleCameraPositionAction = toggleCameraPositionAction
self.dismissAllTooltips = dismissAllTooltips
super.init()
@ -245,6 +254,12 @@ private final class CameraScreenComponent: CombinedComponent {
}
self.setupVolumeButtonsHandler()
self.toggleCameraPositionAction.connect({ [weak self] in
if let self {
self.togglePosition(self.animateFlipAction)
}
})
}
deinit {
@ -472,7 +487,7 @@ private final class CameraScreenComponent: CombinedComponent {
}
func makeState() -> State {
return State(context: self.context, camera: self.camera, present: self.present, completion: self.completion, updateState: self.updateState, animateShutter: self.animateShutter, dismissAllTooltips: self.dismissAllTooltips)
return State(context: self.context, camera: self.camera, present: self.present, completion: self.completion, updateState: self.updateState, animateShutter: self.animateShutter, animateFlipAction: self.animateFlipAction, toggleCameraPositionAction: self.toggleCameraPositionAction, dismissAllTooltips: self.dismissAllTooltips)
}
static var body: Body {
@ -1026,7 +1041,8 @@ public class CameraScreen: ViewController {
private weak var controller: CameraScreen?
private let context: AccountContext
private let updateState: ActionSlot<CameraState>
private let toggleCameraPositionAction: ActionSlot<Void>
fileprivate let backgroundView: UIView
fileprivate let containerView: UIView
private let componentExternalState = CameraScreenComponent.ExternalState()
@ -1070,6 +1086,7 @@ public class CameraScreen: ViewController {
self.controller = controller
self.context = controller.context
self.updateState = ActionSlot<CameraState>()
self.toggleCameraPositionAction = ActionSlot<Void>()
self.presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
@ -1296,6 +1313,10 @@ public class CameraScreen: ViewController {
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
self.mainPreviewContainerView.addGestureRecognizer(tapGestureRecognizer)
let doubleGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.handleDoubleTap(_:)))
doubleGestureRecognizer.numberOfTapsRequired = 2
self.mainPreviewContainerView.addGestureRecognizer(doubleGestureRecognizer)
let pipPanGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.handlePipPan(_:)))
self.additionalPreviewContainerView.addGestureRecognizer(pipPanGestureRecognizer)
@ -1354,6 +1375,10 @@ public class CameraScreen: ViewController {
self.camera.focus(at: point, autoFocus: false)
}
@objc private func handleDoubleTap(_ gestureRecognizer: UITapGestureRecognizer) {
self.toggleCameraPositionAction.invoke(Void())
}
private var pipTranslation: CGPoint?
@objc private func handlePipPan(_ gestureRecognizer: UIPanGestureRecognizer) {
guard let layout = self.validLayout else {
@ -1829,6 +1854,7 @@ public class CameraScreen: ViewController {
animateShutter: { [weak self] in
self?.mainPreviewContainerView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
},
toggleCameraPositionAction: self.toggleCameraPositionAction,
dismissAllTooltips: { [weak self] in
self?.dismissAllTooltips()
},
@ -1872,10 +1898,17 @@ public class CameraScreen: ViewController {
transition.setFrame(view: self.transitionDimView, frame: CGRect(origin: .zero, size: layout.size))
transition.setFrame(view: self.previewContainerView, frame: previewFrame)
transition.setFrame(view: self.mainPreviewContainerView, frame: CGRect(origin: .zero, size: previewFrame.size))
let previewContainerFrame: CGRect
if isTablet {
previewContainerFrame = CGRect(origin: .zero, size: layout.size)
} else {
previewContainerFrame = previewFrame
}
transition.setFrame(view: self.previewBlurView, frame: CGRect(origin: .zero, size: previewFrame.size))
transition.setFrame(view: self.previewContainerView, frame: previewContainerFrame)
transition.setFrame(view: self.mainPreviewContainerView, frame: CGRect(origin: .zero, size: previewContainerFrame.size))
transition.setFrame(view: self.previewBlurView, frame: CGRect(origin: .zero, size: previewContainerFrame.size))
let dualCamUpdated = self.appliedDualCam != self.isDualCamEnabled
self.appliedDualCam = self.isDualCamEnabled

View File

@ -1475,7 +1475,7 @@ final class StoryItemSetContainerSendMessage {
guard let self, let view, let controller else {
return
}
self.presentWebSearch(view: view, editingMessage: false, attachment: true, activateOnDisplay: activateOnDisplay, present: { [weak controller] c, a in
self.presentWebSearch(view: view, activateOnDisplay: activateOnDisplay, present: { [weak controller] c, a in
controller?.present(c, in: .current)
if let webSearchController = c as? WebSearchController {
webSearchController.searchingUpdated = { [weak mediaGroups] searching in
@ -1793,118 +1793,41 @@ final class StoryItemSetContainerSendMessage {
sendMessage(nil)
}
private func presentWebSearch(view: StoryItemSetContainerComponent.View, editingMessage: Bool, attachment: Bool, activateOnDisplay: Bool = true, present: @escaping (ViewController, Any?) -> Void) {
/*guard let peer = self.presentationInterfaceState.renderedPeer?.peer else {
private func presentWebSearch(view: StoryItemSetContainerComponent.View, activateOnDisplay: Bool = true, present: @escaping (ViewController, Any?) -> Void) {
guard let component = view.component else {
return
}
let context = component.context
let peer = component.slice.peer
let storyId = component.slice.item.storyItem.id
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Configuration.SearchBots())
|> deliverOnMainQueue).start(next: { [weak self] configuration in
if let strongSelf = self {
let controller = WebSearchController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: EnginePeer(peer), chatLocation: strongSelf.chatLocation, configuration: configuration, mode: .media(attachment: attachment, completion: { [weak self] results, selectionState, editingState, silentPosting in
self?.attachmentController?.dismiss(animated: true, completion: nil)
legacyEnqueueWebSearchMessages(selectionState, editingState, enqueueChatContextResult: { [weak self] result in
if let strongSelf = self {
strongSelf.enqueueChatContextResult(results, result, hideVia: true)
let theme = component.theme
let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>) = (component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: theme), component.context.sharedContext.presentationData |> map { $0.withUpdated(theme: theme) })
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Configuration.SearchBots())
|> deliverOnMainQueue).start(next: { [weak self, weak view] configuration in
if let self {
let controller = WebSearchController(context: context, updatedPresentationData: updatedPresentationData, peer: peer, chatLocation: .peer(id: peer.id), configuration: configuration, mode: .media(attachment: true, completion: { [weak self] results, selectionState, editingState, silentPosting in
legacyEnqueueWebSearchMessages(selectionState, editingState, enqueueChatContextResult: { [weak self, weak view] result in
if let self, let view {
self.performSendContextResultAction(view: view, results: results, result: result)
}
}, enqueueMediaMessages: { [weak self] signals in
if let strongSelf = self, !signals.isEmpty {
if editingMessage {
strongSelf.editMessageMediaWithLegacySignals(signals)
} else {
strongSelf.enqueueMediaMessages(signals: signals, silentPosting: silentPosting)
}
}, enqueueMediaMessages: { [weak self, weak view] signals in
if let self, let view, !signals.isEmpty {
self.enqueueMediaMessages(view: view, peer: peer, replyToMessageId: nil, replyToStoryId: StoryId(peerId: peer.id, id: storyId), signals: signals, silentPosting: false)
}
})
}), activateOnDisplay: activateOnDisplay)
controller.attemptItemSelection = { [weak strongSelf] item in
guard let strongSelf, let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer else {
return false
controller.getCaptionPanelView = { [weak self, weak view] in
if let view {
return self?.getCaptionPanelView(view: view, peer: peer)
} else {
return nil
}
enum ItemType {
case gif
case image
case video
}
var itemType: ItemType?
switch item {
case let .internalReference(reference):
if reference.type == "gif" {
itemType = .gif
} else if reference.type == "photo" {
itemType = .image
} else if reference.type == "video" {
itemType = .video
}
case let .externalReference(reference):
if reference.type == "gif" {
itemType = .gif
} else if reference.type == "photo" {
itemType = .image
} else if reference.type == "video" {
itemType = .video
}
}
var bannedSendPhotos: (Int32, Bool)?
var bannedSendVideos: (Int32, Bool)?
var bannedSendGifs: (Int32, Bool)?
if let channel = peer as? TelegramChannel {
if let value = channel.hasBannedPermission(.banSendPhotos) {
bannedSendPhotos = value
}
if let value = channel.hasBannedPermission(.banSendVideos) {
bannedSendVideos = value
}
if let value = channel.hasBannedPermission(.banSendGifs) {
bannedSendGifs = value
}
} else if let group = peer as? TelegramGroup {
if group.hasBannedPermission(.banSendPhotos) {
bannedSendPhotos = (Int32.max, false)
}
if group.hasBannedPermission(.banSendVideos) {
bannedSendVideos = (Int32.max, false)
}
if group.hasBannedPermission(.banSendGifs) {
bannedSendGifs = (Int32.max, false)
}
}
if let itemType {
switch itemType {
case .image:
if bannedSendPhotos != nil {
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: strongSelf.restrictedSendingContentsText(), actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
return false
}
case .video:
if bannedSendVideos != nil {
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: strongSelf.restrictedSendingContentsText(), actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
return false
}
case .gif:
if bannedSendGifs != nil {
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: strongSelf.restrictedSendingContentsText(), actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
return false
}
}
}
return true
}
controller.getCaptionPanelView = { [weak strongSelf] in
return strongSelf?.getCaptionPanelView()
}
present(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
}
})*/
})
}
private func getCaptionPanelView(view: StoryItemSetContainerComponent.View, peer: EnginePeer) -> TGCaptionPanelView? {