mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various fixes
This commit is contained in:
parent
0c851a6aec
commit
7b9836682d
@ -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 {
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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? {
|
||||
|
Loading…
x
Reference in New Issue
Block a user