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
7b9836682d
commit
a4297cf1c5
@ -161,7 +161,6 @@ private final class CameraContext {
|
||||
}
|
||||
}
|
||||
|
||||
private var videoOrientation: AVCaptureVideoOrientation?
|
||||
init(queue: Queue, session: CameraSession, configuration: Camera.Configuration, metrics: Camera.Metrics, previewView: CameraSimplePreviewView?, secondaryPreviewView: CameraSimplePreviewView?) {
|
||||
self.queue = queue
|
||||
self.session = session
|
||||
@ -450,7 +449,7 @@ private final class CameraContext {
|
||||
}
|
||||
|
||||
func takePhoto() -> Signal<PhotoCaptureResult, NoError> {
|
||||
let orientation = self.videoOrientation ?? .portrait
|
||||
let orientation = self.simplePreviewView?.videoPreviewLayer.connection?.videoOrientation ?? .portrait
|
||||
if let additionalDeviceContext = self.additionalDeviceContext {
|
||||
let dualPosition = self.positionValue
|
||||
return combineLatest(
|
||||
|
@ -32,8 +32,7 @@ public class CameraSimplePreviewView: UIView {
|
||||
} else {
|
||||
statusBarOrientation = UIApplication.shared.statusBarOrientation
|
||||
}
|
||||
let videoOrientation: AVCaptureVideoOrientation = statusBarOrientation.videoOrientation
|
||||
// videoPreviewLayer.frame = view.layer.bounds
|
||||
let videoOrientation = statusBarOrientation.videoOrientation
|
||||
self.videoPreviewLayer.connection?.videoOrientation = videoOrientation
|
||||
self.videoPreviewLayer.removeAllAnimations()
|
||||
}
|
||||
|
@ -157,6 +157,8 @@ public final class Button: Component {
|
||||
|
||||
super.init(frame: frame)
|
||||
|
||||
self.isExclusiveTouch = true
|
||||
|
||||
self.addSubview(self.contentView)
|
||||
|
||||
self.addTarget(self, action: #selector(self.pressed), for: .touchUpInside)
|
||||
|
@ -297,9 +297,8 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView {
|
||||
|
||||
if let shape = entity as? DrawingSimpleShapeEntity {
|
||||
shape.position = center
|
||||
shape.rotation = rotation
|
||||
|
||||
if setup {
|
||||
shape.rotation = rotation
|
||||
let size = self.newEntitySize()
|
||||
shape.referenceDrawingSize = self.size
|
||||
if shape.shapeType == .star {
|
||||
@ -319,15 +318,15 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView {
|
||||
}
|
||||
} else if let sticker = entity as? DrawingStickerEntity {
|
||||
sticker.position = center
|
||||
sticker.rotation = rotation
|
||||
if setup {
|
||||
sticker.rotation = rotation
|
||||
sticker.referenceDrawingSize = self.size
|
||||
sticker.scale = zoomScale
|
||||
}
|
||||
} else if let bubble = entity as? DrawingBubbleEntity {
|
||||
bubble.position = center
|
||||
bubble.rotation = rotation
|
||||
if setup {
|
||||
bubble.rotation = rotation
|
||||
let size = self.newEntitySize()
|
||||
bubble.referenceDrawingSize = self.size
|
||||
bubble.size = CGSize(width: size.width, height: round(size.height * 0.7))
|
||||
@ -335,8 +334,8 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView {
|
||||
}
|
||||
} else if let text = entity as? DrawingTextEntity {
|
||||
text.position = center
|
||||
text.rotation = rotation
|
||||
if setup {
|
||||
text.rotation = rotation
|
||||
text.referenceDrawingSize = self.size
|
||||
text.width = floor(self.size.width * 0.9)
|
||||
text.fontSize = 0.08
|
||||
|
@ -911,7 +911,8 @@ public class StickerPickerScreen: ViewController {
|
||||
externalExpansionView: nil,
|
||||
useOpaqueTheme: false,
|
||||
hideBackground: true,
|
||||
stateContext: nil
|
||||
stateContext: nil,
|
||||
addImage: nil
|
||||
)
|
||||
|
||||
var stickerPeekBehavior: EmojiContentPeekBehaviorImpl?
|
||||
@ -1168,7 +1169,10 @@ public class StickerPickerScreen: ViewController {
|
||||
externalExpansionView: nil,
|
||||
useOpaqueTheme: false,
|
||||
hideBackground: true,
|
||||
stateContext: nil
|
||||
stateContext: nil,
|
||||
addImage: {
|
||||
|
||||
}
|
||||
)
|
||||
|
||||
if let (layout, navigationHeight) = self.currentLayout {
|
||||
|
@ -1595,7 +1595,8 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
externalExpansionView: self.view,
|
||||
useOpaqueTheme: false,
|
||||
hideBackground: false,
|
||||
stateContext: nil
|
||||
stateContext: nil,
|
||||
addImage: nil
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -688,7 +688,8 @@ final class AvatarEditorScreenComponent: Component {
|
||||
externalExpansionView: nil,
|
||||
useOpaqueTheme: true,
|
||||
hideBackground: true,
|
||||
stateContext: nil
|
||||
stateContext: nil,
|
||||
addImage: nil
|
||||
)
|
||||
|
||||
data.stickers?.inputInteractionHolder.inputInteraction = EmojiPagerContentComponent.InputInteraction(
|
||||
@ -816,7 +817,8 @@ final class AvatarEditorScreenComponent: Component {
|
||||
externalExpansionView: nil,
|
||||
useOpaqueTheme: true,
|
||||
hideBackground: true,
|
||||
stateContext: nil
|
||||
stateContext: nil,
|
||||
addImage: nil
|
||||
)
|
||||
|
||||
self.state?.updated(transition: .immediate)
|
||||
|
@ -81,6 +81,8 @@ public final class CameraButton: Component {
|
||||
|
||||
super.init(frame: frame)
|
||||
|
||||
self.isExclusiveTouch = true
|
||||
|
||||
self.addSubview(self.contentView)
|
||||
|
||||
self.addTarget(self, action: #selector(self.pressed), for: .touchUpInside)
|
||||
|
@ -377,6 +377,9 @@ private final class CameraScreenComponent: CombinedComponent {
|
||||
if let lastFlipTimestamp = self.lastFlipTimestamp, currentTimestamp - lastFlipTimestamp < 1.0 {
|
||||
return
|
||||
}
|
||||
if let lastDualCameraTimestamp = self.lastDualCameraTimestamp, currentTimestamp - lastDualCameraTimestamp < 1.5 {
|
||||
return
|
||||
}
|
||||
self.lastFlipTimestamp = currentTimestamp
|
||||
|
||||
self.camera.togglePosition()
|
||||
@ -391,6 +394,9 @@ private final class CameraScreenComponent: CombinedComponent {
|
||||
if let lastDualCameraTimestamp = self.lastDualCameraTimestamp, currentTimestamp - lastDualCameraTimestamp < 1.5 {
|
||||
return
|
||||
}
|
||||
if let lastFlipTimestamp = self.lastFlipTimestamp, currentTimestamp - lastFlipTimestamp < 1.0 {
|
||||
return
|
||||
}
|
||||
self.lastDualCameraTimestamp = currentTimestamp
|
||||
|
||||
let isEnabled = !self.cameraState.isDualCamEnabled
|
||||
@ -532,122 +538,6 @@ private final class CameraScreenComponent: CombinedComponent {
|
||||
}
|
||||
}
|
||||
|
||||
let topControlInset: CGFloat = 20.0
|
||||
if case .none = state.cameraState.recording, !state.isTransitioning {
|
||||
let cancelButton = cancelButton.update(
|
||||
component: CameraButton(
|
||||
content: AnyComponentWithIdentity(
|
||||
id: "cancel",
|
||||
component: AnyComponent(
|
||||
Image(
|
||||
image: state.image(.cancel),
|
||||
size: CGSize(width: 40.0, height: 40.0)
|
||||
)
|
||||
)
|
||||
),
|
||||
action: {
|
||||
guard let controller = controller() as? CameraScreen else {
|
||||
return
|
||||
}
|
||||
controller.requestDismiss(animated: true)
|
||||
}
|
||||
).tagged(cancelButtonTag),
|
||||
availableSize: CGSize(width: 40.0, height: 40.0),
|
||||
transition: .immediate
|
||||
)
|
||||
context.add(cancelButton
|
||||
.position(CGPoint(x: isTablet ? smallPanelWidth / 2.0 : topControlInset + cancelButton.size.width / 2.0, y: max(environment.statusBarHeight + 5.0, environment.safeInsets.top + topControlInset) + cancelButton.size.height / 2.0))
|
||||
.appear(.default(scale: true))
|
||||
.disappear(.default(scale: true))
|
||||
)
|
||||
|
||||
let flashContentComponent: AnyComponentWithIdentity<Empty>
|
||||
if component.hasAppeared {
|
||||
let flashIconName: String
|
||||
switch state.cameraState.flashMode {
|
||||
case .off:
|
||||
flashIconName = "flash_off"
|
||||
case .on:
|
||||
flashIconName = "flash_on"
|
||||
case .auto:
|
||||
flashIconName = "flash_auto"
|
||||
@unknown default:
|
||||
flashIconName = "flash_off"
|
||||
}
|
||||
|
||||
flashContentComponent = AnyComponentWithIdentity(
|
||||
id: "animatedIcon",
|
||||
component: AnyComponent(
|
||||
LottieAnimationComponent(
|
||||
animation: LottieAnimationComponent.AnimationItem(
|
||||
name: flashIconName,
|
||||
mode: !state.cameraState.flashModeDidChange ? .still(position: .end) : .animating(loop: false),
|
||||
range: nil,
|
||||
waitForCompletion: false
|
||||
),
|
||||
colors: [:],
|
||||
size: CGSize(width: 40.0, height: 40.0)
|
||||
)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
flashContentComponent = AnyComponentWithIdentity(
|
||||
id: "staticIcon",
|
||||
component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Camera/FlashOffIcon",
|
||||
tintColor: nil
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
let flashButton = flashButton.update(
|
||||
component: CameraButton(
|
||||
content: flashContentComponent,
|
||||
action: { [weak state] in
|
||||
guard let state else {
|
||||
return
|
||||
}
|
||||
state.toggleFlashMode()
|
||||
}
|
||||
).tagged(flashButtonTag),
|
||||
availableSize: CGSize(width: 40.0, height: 40.0),
|
||||
transition: .immediate
|
||||
)
|
||||
context.add(flashButton
|
||||
.position(CGPoint(x: isTablet ? availableSize.width - smallPanelWidth / 2.0 : availableSize.width - topControlInset - flashButton.size.width / 2.0 - 5.0, y: max(environment.statusBarHeight + 5.0, environment.safeInsets.top + topControlInset) + flashButton.size.height / 2.0))
|
||||
.appear(.default(scale: true))
|
||||
.disappear(.default(scale: true))
|
||||
)
|
||||
|
||||
if !isTablet && Camera.isDualCamSupported {
|
||||
let dualButton = dualButton.update(
|
||||
component: CameraButton(
|
||||
content: AnyComponentWithIdentity(
|
||||
id: "dual",
|
||||
component: AnyComponent(
|
||||
DualIconComponent(isSelected: state.cameraState.isDualCamEnabled)
|
||||
)
|
||||
),
|
||||
action: { [weak state] in
|
||||
guard let state else {
|
||||
return
|
||||
}
|
||||
state.toggleDualCamera()
|
||||
}
|
||||
).tagged(dualButtonTag),
|
||||
availableSize: CGSize(width: 40.0, height: 40.0),
|
||||
transition: .immediate
|
||||
)
|
||||
context.add(dualButton
|
||||
.position(CGPoint(x: availableSize.width - topControlInset - flashButton.size.width / 2.0 - 52.0, y: max(environment.statusBarHeight + 5.0, environment.safeInsets.top + topControlInset) + dualButton.size.height / 2.0 + 1.0))
|
||||
.appear(.default(scale: true))
|
||||
.disappear(.default(scale: true))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if case .holding = state.cameraState.recording {
|
||||
|
||||
} else {
|
||||
@ -771,6 +661,122 @@ private final class CameraScreenComponent: CombinedComponent {
|
||||
.position(captureControlsPosition)
|
||||
)
|
||||
|
||||
let topControlInset: CGFloat = 20.0
|
||||
if case .none = state.cameraState.recording, !state.isTransitioning {
|
||||
let cancelButton = cancelButton.update(
|
||||
component: CameraButton(
|
||||
content: AnyComponentWithIdentity(
|
||||
id: "cancel",
|
||||
component: AnyComponent(
|
||||
Image(
|
||||
image: state.image(.cancel),
|
||||
size: CGSize(width: 40.0, height: 40.0)
|
||||
)
|
||||
)
|
||||
),
|
||||
action: {
|
||||
guard let controller = controller() as? CameraScreen else {
|
||||
return
|
||||
}
|
||||
controller.requestDismiss(animated: true)
|
||||
}
|
||||
).tagged(cancelButtonTag),
|
||||
availableSize: CGSize(width: 40.0, height: 40.0),
|
||||
transition: .immediate
|
||||
)
|
||||
context.add(cancelButton
|
||||
.position(CGPoint(x: isTablet ? smallPanelWidth / 2.0 : topControlInset + cancelButton.size.width / 2.0, y: max(environment.statusBarHeight + 5.0, environment.safeInsets.top + topControlInset) + cancelButton.size.height / 2.0))
|
||||
.appear(.default(scale: true))
|
||||
.disappear(.default(scale: true))
|
||||
)
|
||||
|
||||
let flashContentComponent: AnyComponentWithIdentity<Empty>
|
||||
if component.hasAppeared {
|
||||
let flashIconName: String
|
||||
switch state.cameraState.flashMode {
|
||||
case .off:
|
||||
flashIconName = "flash_off"
|
||||
case .on:
|
||||
flashIconName = "flash_on"
|
||||
case .auto:
|
||||
flashIconName = "flash_auto"
|
||||
@unknown default:
|
||||
flashIconName = "flash_off"
|
||||
}
|
||||
|
||||
flashContentComponent = AnyComponentWithIdentity(
|
||||
id: "animatedIcon",
|
||||
component: AnyComponent(
|
||||
LottieAnimationComponent(
|
||||
animation: LottieAnimationComponent.AnimationItem(
|
||||
name: flashIconName,
|
||||
mode: !state.cameraState.flashModeDidChange ? .still(position: .end) : .animating(loop: false),
|
||||
range: nil,
|
||||
waitForCompletion: false
|
||||
),
|
||||
colors: [:],
|
||||
size: CGSize(width: 40.0, height: 40.0)
|
||||
)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
flashContentComponent = AnyComponentWithIdentity(
|
||||
id: "staticIcon",
|
||||
component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Camera/FlashOffIcon",
|
||||
tintColor: nil
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
let flashButton = flashButton.update(
|
||||
component: CameraButton(
|
||||
content: flashContentComponent,
|
||||
action: { [weak state] in
|
||||
guard let state else {
|
||||
return
|
||||
}
|
||||
state.toggleFlashMode()
|
||||
}
|
||||
).tagged(flashButtonTag),
|
||||
availableSize: CGSize(width: 40.0, height: 40.0),
|
||||
transition: .immediate
|
||||
)
|
||||
context.add(flashButton
|
||||
.position(CGPoint(x: isTablet ? availableSize.width - smallPanelWidth / 2.0 : availableSize.width - topControlInset - flashButton.size.width / 2.0 - 5.0, y: max(environment.statusBarHeight + 5.0, environment.safeInsets.top + topControlInset) + flashButton.size.height / 2.0))
|
||||
.appear(.default(scale: true))
|
||||
.disappear(.default(scale: true))
|
||||
)
|
||||
|
||||
if !isTablet && Camera.isDualCamSupported {
|
||||
let dualButton = dualButton.update(
|
||||
component: CameraButton(
|
||||
content: AnyComponentWithIdentity(
|
||||
id: "dual",
|
||||
component: AnyComponent(
|
||||
DualIconComponent(isSelected: state.cameraState.isDualCamEnabled)
|
||||
)
|
||||
),
|
||||
action: { [weak state] in
|
||||
guard let state else {
|
||||
return
|
||||
}
|
||||
state.toggleDualCamera()
|
||||
}
|
||||
).tagged(dualButtonTag),
|
||||
availableSize: CGSize(width: 40.0, height: 40.0),
|
||||
transition: .immediate
|
||||
)
|
||||
context.add(dualButton
|
||||
.position(CGPoint(x: availableSize.width - topControlInset - flashButton.size.width / 2.0 - 52.0, y: max(environment.statusBarHeight + 5.0, environment.safeInsets.top + topControlInset) + dualButton.size.height / 2.0 + 1.0))
|
||||
.appear(.default(scale: true))
|
||||
.disappear(.default(scale: true))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if isTablet {
|
||||
let flipButton = flipButton.update(
|
||||
component: CameraButton(
|
||||
@ -1037,7 +1043,7 @@ public class CameraScreen: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate final class Node: ViewControllerTracingNode {
|
||||
fileprivate final class Node: ViewControllerTracingNode, UIGestureRecognizerDelegate {
|
||||
private weak var controller: CameraScreen?
|
||||
private let context: AccountContext
|
||||
private let updateState: ActionSlot<CameraState>
|
||||
@ -1297,6 +1303,7 @@ public class CameraScreen: ViewController {
|
||||
self.changingPositionDisposable?.dispose()
|
||||
}
|
||||
|
||||
private var pipPanGestureRecognizer: UIPanGestureRecognizer?
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
@ -1304,26 +1311,47 @@ public class CameraScreen: ViewController {
|
||||
self.view.disablesInteractiveKeyboardGestureRecognizer = true
|
||||
|
||||
let pinchGestureRecognizer = UIPinchGestureRecognizer(target: self, action: #selector(self.handlePinch(_:)))
|
||||
self.mainPreviewContainerView.addGestureRecognizer(pinchGestureRecognizer)
|
||||
self.previewContainerView.addGestureRecognizer(pinchGestureRecognizer)
|
||||
|
||||
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.handlePan(_:)))
|
||||
panGestureRecognizer.delegate = self
|
||||
panGestureRecognizer.maximumNumberOfTouches = 1
|
||||
self.mainPreviewContainerView.addGestureRecognizer(panGestureRecognizer)
|
||||
self.previewContainerView.addGestureRecognizer(panGestureRecognizer)
|
||||
|
||||
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
|
||||
self.mainPreviewContainerView.addGestureRecognizer(tapGestureRecognizer)
|
||||
self.previewContainerView.addGestureRecognizer(tapGestureRecognizer)
|
||||
|
||||
let doubleGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.handleDoubleTap(_:)))
|
||||
doubleGestureRecognizer.numberOfTapsRequired = 2
|
||||
self.mainPreviewContainerView.addGestureRecognizer(doubleGestureRecognizer)
|
||||
self.previewContainerView.addGestureRecognizer(doubleGestureRecognizer)
|
||||
|
||||
let pipPanGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.handlePipPan(_:)))
|
||||
self.additionalPreviewContainerView.addGestureRecognizer(pipPanGestureRecognizer)
|
||||
pipPanGestureRecognizer.delegate = self
|
||||
self.previewContainerView.addGestureRecognizer(pipPanGestureRecognizer)
|
||||
self.pipPanGestureRecognizer = pipPanGestureRecognizer
|
||||
|
||||
self.camera.focus(at: CGPoint(x: 0.5, y: 0.5), autoFocus: true)
|
||||
self.camera.startCapture()
|
||||
}
|
||||
|
||||
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
if gestureRecognizer is UIPanGestureRecognizer && otherGestureRecognizer is UIPanGestureRecognizer {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
let location = gestureRecognizer.location(in: gestureRecognizer.view)
|
||||
if gestureRecognizer === self.pipPanGestureRecognizer {
|
||||
if !self.isDualCamEnabled {
|
||||
return false
|
||||
}
|
||||
return self.additionalPreviewContainerView.frame.contains(location)
|
||||
}
|
||||
return self.hasAppeared
|
||||
}
|
||||
|
||||
@objc private func handlePinch(_ gestureRecognizer: UIPinchGestureRecognizer) {
|
||||
switch gestureRecognizer.state {
|
||||
case .changed:
|
||||
@ -1469,7 +1497,9 @@ public class CameraScreen: ViewController {
|
||||
let sourceLocalFrame = sourceView.convert(transitionIn.sourceRect, to: self.view)
|
||||
|
||||
let sourceScale = sourceLocalFrame.width / self.previewContainerView.frame.width
|
||||
self.previewContainerView.layer.animatePosition(from: sourceLocalFrame.center, to: self.previewContainerView.center, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
self.previewContainerView.layer.animatePosition(from: sourceLocalFrame.center, to: self.previewContainerView.center, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, completion: { _ in
|
||||
self.requestUpdateLayout(hasAppeared: true, transition: .immediate)
|
||||
})
|
||||
self.previewContainerView.layer.animateScale(from: sourceScale, to: 1.0, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
|
||||
let minSide = min(self.previewContainerView.bounds.width, self.previewContainerView.bounds.height)
|
||||
@ -1977,7 +2007,7 @@ public class CameraScreen: ViewController {
|
||||
additionalPreviewView = self.additionalPreviewView
|
||||
}
|
||||
|
||||
let mainPreviewInnerFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((previewSize.width - mainPreviewInnerSize.width) / 2.0), y: floorToScreenPixels((previewSize.height - mainPreviewInnerSize.height) / 2.0)), size: mainPreviewInnerSize)
|
||||
let mainPreviewInnerFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((previewFrame.width - mainPreviewInnerSize.width) / 2.0), y: floorToScreenPixels((previewFrame.height - mainPreviewInnerSize.height) / 2.0)), size: mainPreviewInnerSize)
|
||||
let additionalPreviewInnerFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((circleSide - additionalPreviewInnerSize.width) / 2.0), y: floorToScreenPixels((circleSide - additionalPreviewInnerSize.height) / 2.0)), size: additionalPreviewInnerSize)
|
||||
|
||||
if mainPreviewView.superview != self.mainPreviewContainerView {
|
||||
|
@ -62,6 +62,8 @@ final class ModeComponent: Component {
|
||||
init() {
|
||||
super.init(frame: .zero)
|
||||
|
||||
self.isExclusiveTouch = true
|
||||
|
||||
self.addTarget(self, action: #selector(self.buttonPressed), for: .touchUpInside)
|
||||
}
|
||||
|
||||
|
@ -1311,7 +1311,8 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
externalExpansionView: nil,
|
||||
useOpaqueTheme: false,
|
||||
hideBackground: false,
|
||||
stateContext: self.stateContext?.emojiState
|
||||
stateContext: self.stateContext?.emojiState,
|
||||
addImage: nil
|
||||
)
|
||||
|
||||
self.stickerInputInteraction = EmojiPagerContentComponent.InputInteraction(
|
||||
@ -1609,7 +1610,8 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
externalExpansionView: nil,
|
||||
useOpaqueTheme: false,
|
||||
hideBackground: false,
|
||||
stateContext: nil
|
||||
stateContext: nil,
|
||||
addImage: nil
|
||||
)
|
||||
|
||||
|
||||
@ -2499,7 +2501,8 @@ public final class EntityInputView: UIInputView, AttachmentTextInputPanelInputVi
|
||||
externalExpansionView: nil,
|
||||
useOpaqueTheme: false,
|
||||
hideBackground: hideBackground,
|
||||
stateContext: nil
|
||||
stateContext: nil,
|
||||
addImage: nil
|
||||
)
|
||||
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
|
@ -676,7 +676,8 @@ public final class EmojiStatusSelectionController: ViewController {
|
||||
externalExpansionView: nil,
|
||||
useOpaqueTheme: true,
|
||||
hideBackground: false,
|
||||
stateContext: nil
|
||||
stateContext: nil,
|
||||
addImage: nil
|
||||
)
|
||||
|
||||
strongSelf.refreshLayout(transition: .immediate)
|
||||
|
@ -2322,6 +2322,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
public let hideBackground: Bool
|
||||
public let scrollingStickersGridPromise = ValuePromise<Bool>(false)
|
||||
public let stateContext: StateContext?
|
||||
public let addImage: (() -> Void)?
|
||||
|
||||
public init(
|
||||
performItemAction: @escaping (AnyHashable, Item, UIView, CGRect, CALayer, Bool) -> Void,
|
||||
@ -2347,7 +2348,8 @@ public final class EmojiPagerContentComponent: Component {
|
||||
externalExpansionView: UIView?,
|
||||
useOpaqueTheme: Bool,
|
||||
hideBackground: Bool,
|
||||
stateContext: StateContext?
|
||||
stateContext: StateContext?,
|
||||
addImage: (() -> Void)?
|
||||
) {
|
||||
self.performItemAction = performItemAction
|
||||
self.deleteBackwards = deleteBackwards
|
||||
@ -2373,6 +2375,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
self.useOpaqueTheme = useOpaqueTheme
|
||||
self.hideBackground = hideBackground
|
||||
self.stateContext = stateContext
|
||||
self.addImage = addImage
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -409,7 +409,8 @@ public final class EmojiSearchContent: ASDisplayNode, EntitySearchContainerNode
|
||||
externalExpansionView: nil,
|
||||
useOpaqueTheme: true,
|
||||
hideBackground: false,
|
||||
stateContext: nil
|
||||
stateContext: nil,
|
||||
addImage: nil
|
||||
)
|
||||
|
||||
self.dataDisposable = (
|
||||
|
@ -690,6 +690,18 @@ public final class EntityKeyboardComponent: Component {
|
||||
}
|
||||
).minSize(CGSize(width: 38.0, height: 38.0)))))
|
||||
}
|
||||
if let addImage = component.stickerContent?.inputInteractionHolder.inputInteraction?.addImage {
|
||||
contentAccessoryLeftButtons.append(AnyComponentWithIdentity(id: "image", component: AnyComponent(Button(
|
||||
content: AnyComponent(BundleIconComponent(
|
||||
name: "Media Editor/AddImage",
|
||||
tintColor: component.theme.chat.inputMediaPanel.panelIconColor,
|
||||
maxSize: nil
|
||||
)),
|
||||
action: {
|
||||
addImage()
|
||||
}
|
||||
).minSize(CGSize(width: 38.0, height: 38.0)))))
|
||||
}
|
||||
}
|
||||
|
||||
if let _ = deleteBackwards {
|
||||
|
@ -950,7 +950,8 @@ private final class ForumCreateTopicScreenComponent: CombinedComponent {
|
||||
externalExpansionView: nil,
|
||||
useOpaqueTheme: true,
|
||||
hideBackground: false,
|
||||
stateContext: nil
|
||||
stateContext: nil,
|
||||
addImage: nil
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -85,7 +85,21 @@ public final class DrawingStickerEntity: DrawingEntity, Codable {
|
||||
|
||||
public var baseSize: CGSize {
|
||||
let size = max(10.0, min(self.referenceDrawingSize.width, self.referenceDrawingSize.height) * 0.25)
|
||||
return CGSize(width: size, height: size)
|
||||
|
||||
let dimensions: CGSize
|
||||
switch self.content {
|
||||
case let .image(image, _):
|
||||
dimensions = image.size
|
||||
case let .file(file):
|
||||
dimensions = file.dimensions?.cgSize ?? CGSize(width: 512.0, height: 512.0)
|
||||
case let .video(_, image, _):
|
||||
dimensions = image?.size ?? CGSize(width: 512.0, height: 512.0)
|
||||
case .dualVideoReference:
|
||||
dimensions = CGSize(width: 512.0, height: 512.0)
|
||||
}
|
||||
|
||||
let boundingSize = CGSize(width: size, height: size)
|
||||
return dimensions.fitted(boundingSize)
|
||||
}
|
||||
|
||||
public var isAnimated: Bool {
|
||||
|
@ -269,6 +269,9 @@ private func makeEditorImageFrameComposition(context: CIContext, inputImage: CII
|
||||
var baseScale: CGFloat = 1.0
|
||||
if let baseSize = entity.baseSize {
|
||||
baseScale = baseSize.width / image.extent.width
|
||||
if baseSize.width != baseSize.height {
|
||||
baseScale *= min(baseSize.width, baseSize.height) / max(baseSize.width, baseSize.height)
|
||||
}
|
||||
}
|
||||
|
||||
var transform = CGAffineTransform.identity
|
||||
|
@ -126,6 +126,7 @@ private class MediaEditorComposerStickerEntity: MediaEditorComposerEntity {
|
||||
|
||||
switch content {
|
||||
case let .file(file):
|
||||
let dimensions = file.dimensions ?? PixelDimensions(width: 512, height: 512)
|
||||
if file.isAnimatedSticker || file.isVideoSticker || file.mimeType == "video/webm" {
|
||||
self.isAnimated = true
|
||||
self.isVideoSticker = file.isVideoSticker || file.mimeType == "video/webm"
|
||||
@ -133,7 +134,6 @@ private class MediaEditorComposerStickerEntity: MediaEditorComposerEntity {
|
||||
self.source = AnimatedStickerResourceSource(account: account, resource: file.resource, isVideo: isVideoSticker)
|
||||
let pathPrefix = account.postbox.mediaBox.shortLivedResourceCachePathPrefix(file.resource.id)
|
||||
if let source = self.source {
|
||||
let dimensions = file.dimensions ?? PixelDimensions(width: 512, height: 512)
|
||||
let fitToSize: CGSize
|
||||
if self.isStatic {
|
||||
fitToSize = CGSize(width: 768, height: 768)
|
||||
@ -334,6 +334,7 @@ private class MediaEditorComposerStickerEntity: MediaEditorComposerEntity {
|
||||
let options = NSMutableDictionary()
|
||||
options.setObject(ioSurfaceProperties, forKey: kCVPixelBufferIOSurfacePropertiesKey as NSString)
|
||||
|
||||
|
||||
var pixelBuffer: CVPixelBuffer?
|
||||
CVPixelBufferCreate(
|
||||
kCFAllocatorDefault,
|
||||
|
@ -383,6 +383,9 @@ public final class MediaEditorValues: Codable, Equatable {
|
||||
if self.videoTrimRange != nil {
|
||||
return true
|
||||
}
|
||||
if self.drawing != nil {
|
||||
return true
|
||||
}
|
||||
if !self.entities.isEmpty {
|
||||
return true
|
||||
}
|
||||
|
@ -930,10 +930,10 @@ final class MediaEditorScreenComponent: Component {
|
||||
}
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - scrubberInset * 2.0, height: availableSize.height)
|
||||
containerSize: CGSize(width: previewSize.width - scrubberInset * 2.0, height: availableSize.height)
|
||||
)
|
||||
|
||||
let scrubberFrame = CGRect(origin: CGPoint(x: scrubberInset, y: availableSize.height - environment.safeInsets.bottom - scrubberSize.height - 8.0 + controlsBottomInset), size: scrubberSize)
|
||||
let scrubberFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - scrubberSize.width) / 2.0), y: availableSize.height - environment.safeInsets.bottom - scrubberSize.height - 8.0 + controlsBottomInset), size: scrubberSize)
|
||||
if let scrubberView = self.scrubber.view {
|
||||
if scrubberView.superview == nil {
|
||||
if let inputPanelBackgroundView = self.inputPanelBackground.view, inputPanelBackgroundView.superview != nil {
|
||||
|
@ -928,6 +928,7 @@ public final class MessageInputPanelComponent: Component {
|
||||
}
|
||||
|
||||
self.currentMediaInputIsVoice = !self.currentMediaInputIsVoice
|
||||
self.hapticFeedback.impact(.medium)
|
||||
self.state?.updated(transition: Transition(animation: .curve(duration: 0.4, curve: .spring)))
|
||||
},
|
||||
updateMediaCancelFraction: { [weak self] mediaCancelFraction in
|
||||
|
@ -139,6 +139,105 @@ private final class StoryLongPressRecognizer: UILongPressGestureRecognizer {
|
||||
}
|
||||
}
|
||||
|
||||
private final class StoryPinchGesture: UIPinchGestureRecognizer {
|
||||
private final class Target {
|
||||
var updated: (() -> Void)?
|
||||
|
||||
@objc func onGesture(_ gesture: UIPinchGestureRecognizer) {
|
||||
self.updated?()
|
||||
}
|
||||
}
|
||||
|
||||
private let target: Target
|
||||
|
||||
private(set) var currentTransform: (CGFloat, CGPoint, CGPoint)?
|
||||
|
||||
var began: (() -> Void)?
|
||||
var updated: ((CGFloat, CGPoint, CGPoint) -> Void)?
|
||||
var ended: (() -> Void)?
|
||||
|
||||
private var initialLocation: CGPoint?
|
||||
private var pinchLocation = CGPoint()
|
||||
private var currentOffset = CGPoint()
|
||||
|
||||
private var currentNumberOfTouches = 0
|
||||
|
||||
init() {
|
||||
self.target = Target()
|
||||
|
||||
super.init(target: self.target, action: #selector(self.target.onGesture(_:)))
|
||||
|
||||
self.target.updated = { [weak self] in
|
||||
self?.gestureUpdated()
|
||||
}
|
||||
}
|
||||
|
||||
override func reset() {
|
||||
super.reset()
|
||||
|
||||
self.currentNumberOfTouches = 0
|
||||
self.initialLocation = nil
|
||||
}
|
||||
|
||||
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
|
||||
super.touchesBegan(touches, with: event)
|
||||
|
||||
//self.currentTouches.formUnion(touches)
|
||||
}
|
||||
|
||||
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
|
||||
super.touchesEnded(touches, with: event)
|
||||
}
|
||||
|
||||
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent) {
|
||||
super.touchesCancelled(touches, with: event)
|
||||
}
|
||||
|
||||
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
|
||||
super.touchesMoved(touches, with: event)
|
||||
}
|
||||
|
||||
private func gestureUpdated() {
|
||||
switch self.state {
|
||||
case .began:
|
||||
self.currentOffset = CGPoint()
|
||||
|
||||
let pinchLocation = self.location(in: self.view)
|
||||
self.pinchLocation = pinchLocation
|
||||
self.initialLocation = pinchLocation
|
||||
let scale = max(1.0, self.scale)
|
||||
self.currentTransform = (scale, self.pinchLocation, self.currentOffset)
|
||||
|
||||
self.currentNumberOfTouches = self.numberOfTouches
|
||||
|
||||
self.began?()
|
||||
case .changed:
|
||||
let locationSum = self.location(in: self.view)
|
||||
|
||||
if self.numberOfTouches < 2 && self.currentNumberOfTouches >= 2 {
|
||||
self.initialLocation = CGPoint(x: locationSum.x - self.currentOffset.x, y: locationSum.y - self.currentOffset.y)
|
||||
}
|
||||
self.currentNumberOfTouches = self.numberOfTouches
|
||||
|
||||
if let initialLocation = self.initialLocation {
|
||||
self.currentOffset = CGPoint(x: locationSum.x - initialLocation.x, y: locationSum.y - initialLocation.y)
|
||||
}
|
||||
if let (scale, pinchLocation, _) = self.currentTransform {
|
||||
self.currentTransform = (scale, pinchLocation, self.currentOffset)
|
||||
self.updated?(scale, pinchLocation, self.currentOffset)
|
||||
}
|
||||
|
||||
let scale = max(1.0, self.scale)
|
||||
self.currentTransform = (scale, self.pinchLocation, self.currentOffset)
|
||||
self.updated?(scale, self.pinchLocation, self.currentOffset)
|
||||
case .ended, .cancelled:
|
||||
self.ended?()
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class StoryContainerScreenComponent: Component {
|
||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||
|
||||
@ -351,7 +450,28 @@ private final class StoryContainerScreenComponent: Component {
|
||||
self.longPressRecognizer = longPressRecognizer
|
||||
self.addGestureRecognizer(longPressRecognizer)
|
||||
|
||||
let pinchRecognizer = UIPinchGestureRecognizer(target: self, action: #selector(self.pinchGesture(_:)))
|
||||
let pinchRecognizer = StoryPinchGesture()
|
||||
pinchRecognizer.delegate = self
|
||||
pinchRecognizer.updated = { [weak self] scale, pinchLocation, offset in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
var pinchLocation = pinchLocation
|
||||
if let component = self.component, let stateValue = component.content.stateValue, let slice = stateValue.slice, let itemSetView = self.visibleItemSetViews[slice.peer.id] {
|
||||
if let itemSetComponentView = itemSetView.view.view as? StoryItemSetContainerComponent.View {
|
||||
pinchLocation = self.convert(pinchLocation, to: itemSetComponentView)
|
||||
}
|
||||
}
|
||||
self.itemSetPinchState = StoryItemSetContainerComponent.PinchState(scale: scale, location: pinchLocation, offset: offset)
|
||||
self.state?.updated(transition: .immediate)
|
||||
}
|
||||
pinchRecognizer.ended = { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.itemSetPinchState = nil
|
||||
self.state?.updated(transition: Transition(animation: .curve(duration: 0.3, curve: .spring)))
|
||||
}
|
||||
self.addGestureRecognizer(pinchRecognizer)
|
||||
|
||||
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))
|
||||
@ -431,6 +551,13 @@ private final class StoryContainerScreenComponent: Component {
|
||||
self.volumeButtonsListenerShouldBeActiveDisposable?.dispose()
|
||||
}
|
||||
|
||||
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
if gestureRecognizer is StoryPinchGesture {
|
||||
return !hasFirstResponder(self)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
|
||||
guard let component = self.component, let stateValue = component.content.stateValue, let slice = stateValue.slice, let itemSetView = self.visibleItemSetViews[slice.peer.id], let itemSetComponentView = itemSetView.view.view as? StoryItemSetContainerComponent.View else {
|
||||
return false
|
||||
@ -581,10 +708,21 @@ private final class StoryContainerScreenComponent: Component {
|
||||
@objc private func dismissPanGesture(_ recognizer: UIPanGestureRecognizer) {
|
||||
switch recognizer.state {
|
||||
case .began:
|
||||
self.dismissAllTooltips()
|
||||
|
||||
if let component = self.component, let stateValue = component.content.stateValue, let slice = stateValue.slice, let itemSetView = self.visibleItemSetViews[slice.peer.id] {
|
||||
if let itemSetComponentView = itemSetView.view.view as? StoryItemSetContainerComponent.View {
|
||||
if itemSetComponentView.hasActiveDeactivateableInput() {
|
||||
itemSetComponentView.deactivateInput()
|
||||
recognizer.isEnabled = false
|
||||
recognizer.isEnabled = true
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.verticalPanState = ItemSetPanState(fraction: 0.0, didBegin: true)
|
||||
self.state?.updated(transition: .immediate)
|
||||
|
||||
self.dismissAllTooltips()
|
||||
case .changed:
|
||||
let translation = recognizer.translation(in: self)
|
||||
self.verticalPanState = ItemSetPanState(fraction: max(-1.0, min(1.0, translation.y / self.bounds.height)), didBegin: true)
|
||||
@ -656,34 +794,17 @@ private final class StoryContainerScreenComponent: Component {
|
||||
guard case .recognized = recognizer.state else {
|
||||
return
|
||||
}
|
||||
|
||||
let location = recognizer.location(in: recognizer.view)
|
||||
if let currentItemView = self.visibleItemSetViews.first?.value {
|
||||
if location.x < currentItemView.frame.minX {
|
||||
self.navigate(direction: .previous)
|
||||
} else if location.x > currentItemView.frame.maxX {
|
||||
self.navigate(direction: .next)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func pinchGesture(_ recognizer: UIPinchGestureRecognizer) {
|
||||
switch recognizer.state {
|
||||
case .began, .changed:
|
||||
let location = recognizer.location(in: self)
|
||||
let scale = max(1.0, recognizer.scale)
|
||||
if let itemSetPinchState = self.itemSetPinchState {
|
||||
let offset = CGPoint(x: location.x - itemSetPinchState.location.x , y: location.y - itemSetPinchState.location.y)
|
||||
self.itemSetPinchState = StoryItemSetContainerComponent.PinchState(scale: scale, location: itemSetPinchState.location, offset: offset)
|
||||
if let component = self.component, let stateValue = component.content.stateValue, let slice = stateValue.slice, let itemSetView = self.visibleItemSetViews[slice.peer.id], let currentItemView = itemSetView.view.view as? StoryItemSetContainerComponent.View {
|
||||
if currentItemView.hasActiveDeactivateableInput() {
|
||||
currentItemView.deactivateInput()
|
||||
} else {
|
||||
self.itemSetPinchState = StoryItemSetContainerComponent.PinchState(scale: scale, location: location, offset: .zero)
|
||||
if location.x < currentItemView.frame.minX {
|
||||
self.navigate(direction: .previous)
|
||||
} else if location.x > currentItemView.frame.maxX {
|
||||
self.navigate(direction: .next)
|
||||
}
|
||||
}
|
||||
self.state?.updated(transition: .immediate)
|
||||
case .cancelled, .ended:
|
||||
self.itemSetPinchState = nil
|
||||
self.state?.updated(transition: Transition(animation: .curve(duration: 0.3, curve: .spring)))
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@ -996,6 +1117,7 @@ private final class StoryContainerScreenComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
var presentationContextInsets = UIEdgeInsets()
|
||||
if !currentSlices.isEmpty, let focusedIndex {
|
||||
for i in max(0, focusedIndex - 1) ... min(focusedIndex + 1, currentSlices.count - 1) {
|
||||
var isItemVisible = false
|
||||
@ -1053,6 +1175,10 @@ private final class StoryContainerScreenComponent: Component {
|
||||
itemSetContainerInsets.top = 0.0
|
||||
itemSetContainerInsets.bottom = floorToScreenPixels((availableSize.height - itemSetContainerSize.height) / 2.0)
|
||||
itemSetContainerSafeInsets.bottom = 0.0
|
||||
|
||||
presentationContextInsets.left = floorToScreenPixels((availableSize.width - itemSetContainerSize.width) / 2.0)
|
||||
presentationContextInsets.right = presentationContextInsets.left
|
||||
presentationContextInsets.bottom = itemSetContainerInsets.bottom
|
||||
}
|
||||
|
||||
let _ = itemSetView.view.update(
|
||||
@ -1327,8 +1453,8 @@ private final class StoryContainerScreenComponent: Component {
|
||||
size: availableSize,
|
||||
metrics: environment.metrics,
|
||||
deviceMetrics: environment.deviceMetrics,
|
||||
intrinsicInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: contentDerivedBottomInset, right: 0.0),
|
||||
safeInsets: UIEdgeInsets(),
|
||||
intrinsicInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: contentDerivedBottomInset + presentationContextInsets.bottom, right: 0.0),
|
||||
safeInsets: UIEdgeInsets(top: 0.0, left: presentationContextInsets.left, bottom: 0.0, right: presentationContextInsets.right),
|
||||
additionalInsets: UIEdgeInsets(),
|
||||
statusBarHeight: nil,
|
||||
inputHeight: nil,
|
||||
|
@ -648,25 +648,30 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
return false
|
||||
}
|
||||
|
||||
private func deactivateInput() {
|
||||
func hasActiveDeactivateableInput() -> Bool {
|
||||
if let view = self.inputPanel.view as? MessageInputPanelComponent.View {
|
||||
if view.canDeactivateInput() && (hasFirstResponder(self) || self.sendMessageContext.currentInputMode == .media) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func deactivateInput() {
|
||||
if let view = self.inputPanel.view as? MessageInputPanelComponent.View, view.canDeactivateInput() {
|
||||
self.sendMessageContext.currentInputMode = .text
|
||||
if hasFirstResponder(self) {
|
||||
view.deactivateInput()
|
||||
} else {
|
||||
self.state?.updated(transition: .spring(duration: 0.4).withUserData(TextFieldComponent.AnimationHint(kind: .textFocusChanged)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func tapGesture(_ recognizer: UITapGestureRecognizer) {
|
||||
if case .ended = recognizer.state, let component = self.component, let itemLayout = self.itemLayout {
|
||||
if hasFirstResponder(self) || self.sendMessageContext.currentInputMode == .media {
|
||||
if let view = self.inputPanel.view as? MessageInputPanelComponent.View {
|
||||
if view.canDeactivateInput() {
|
||||
self.sendMessageContext.currentInputMode = .text
|
||||
if hasFirstResponder(self) {
|
||||
view.deactivateInput()
|
||||
} else {
|
||||
self.state?.updated(transition: .spring(duration: 0.4).withUserData(TextFieldComponent.AnimationHint(kind: .textFocusChanged)))
|
||||
}
|
||||
} else {
|
||||
view.animateError()
|
||||
}
|
||||
}
|
||||
self.deactivateInput()
|
||||
} else if self.displayViewList {
|
||||
let point = recognizer.location(in: self)
|
||||
|
||||
@ -2271,7 +2276,7 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
let tooltipScreen = TooltipScreen(
|
||||
account: component.context.account,
|
||||
sharedContext: component.context.sharedContext,
|
||||
text: .plain(text: "This video has no sound"), style: .default, location: TooltipScreen.Location.point(soundButtonView.convert(soundButtonView.bounds, to: self).offsetBy(dx: 1.0, dy: -10.0), .top), displayDuration: .infinite, shouldDismissOnTouch: { _, _ in
|
||||
text: .plain(text: "This video has no sound"), style: .default, location: TooltipScreen.Location.point(soundButtonView.convert(soundButtonView.bounds, to: nil).offsetBy(dx: 1.0, dy: -10.0), .top), displayDuration: .infinite, shouldDismissOnTouch: { _, _ in
|
||||
return .dismiss(consume: true)
|
||||
}
|
||||
)
|
||||
@ -3154,9 +3159,6 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
}
|
||||
|
||||
let subject: Signal<MediaEditorScreen.Subject?, NoError>
|
||||
// if let source {
|
||||
// subject = .single(.draft(source, Int64(id)))
|
||||
// } else {
|
||||
|
||||
var duration: Double?
|
||||
let media = item.media._asMedia()
|
||||
|
12
submodules/TelegramUI/Images.xcassets/Media Editor/AddImage.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Media Editor/AddImage.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "photo_24.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
154
submodules/TelegramUI/Images.xcassets/Media Editor/AddImage.imageset/photo_24.pdf
vendored
Normal file
154
submodules/TelegramUI/Images.xcassets/Media Editor/AddImage.imageset/photo_24.pdf
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 3.835083 3.834961 cm
|
||||
1.000000 1.000000 1.000000 scn
|
||||
5.465000 16.330017 m
|
||||
5.436178 16.330017 l
|
||||
5.436174 16.330017 l
|
||||
4.620535 16.330023 3.967872 16.330027 3.440454 16.286936 c
|
||||
2.899074 16.242702 2.431364 16.149773 2.001125 15.930555 c
|
||||
1.311511 15.579180 0.750837 15.018506 0.399461 14.328892 c
|
||||
0.180244 13.898653 0.087314 13.430943 0.043081 12.889563 c
|
||||
-0.000010 12.362144 -0.000006 11.709482 0.000000 10.893843 c
|
||||
0.000000 10.893839 l
|
||||
0.000000 10.865017 l
|
||||
0.000000 5.465017 l
|
||||
0.000000 5.436195 l
|
||||
-0.000006 4.620555 -0.000010 3.967890 0.043081 3.440471 c
|
||||
0.087314 2.899090 0.180244 2.431380 0.399461 2.001142 c
|
||||
0.750837 1.311528 1.311511 0.750854 2.001125 0.399478 c
|
||||
2.431364 0.180260 2.899074 0.087330 3.440454 0.043098 c
|
||||
3.967863 0.000008 4.620512 0.000011 5.436130 0.000017 c
|
||||
5.436194 0.000017 l
|
||||
5.465001 0.000017 l
|
||||
10.865000 0.000017 l
|
||||
10.893806 0.000017 l
|
||||
10.893871 0.000017 l
|
||||
11.709489 0.000011 12.362138 0.000008 12.889546 0.043098 c
|
||||
13.430927 0.087330 13.898637 0.180260 14.328876 0.399478 c
|
||||
15.018489 0.750854 15.579163 1.311528 15.930539 2.001142 c
|
||||
16.149757 2.431380 16.242687 2.899091 16.286919 3.440471 c
|
||||
16.330009 3.967880 16.330006 4.620529 16.330000 5.436146 c
|
||||
16.330000 5.436212 l
|
||||
16.330000 5.465017 l
|
||||
16.330000 10.865017 l
|
||||
16.330000 10.893824 l
|
||||
16.330000 10.893888 l
|
||||
16.330006 11.709505 16.330009 12.362154 16.286919 12.889563 c
|
||||
16.242687 13.430943 16.149757 13.898653 15.930539 14.328892 c
|
||||
15.579163 15.018506 15.018489 15.579180 14.328876 15.930555 c
|
||||
13.898637 16.149773 13.430926 16.242702 12.889546 16.286936 c
|
||||
12.362126 16.330029 11.709461 16.330023 10.893822 16.330017 c
|
||||
10.865000 16.330017 l
|
||||
5.465000 16.330017 l
|
||||
h
|
||||
2.604932 14.745517 m
|
||||
2.816429 14.853280 3.089626 14.923841 3.548759 14.961352 c
|
||||
4.015654 14.999499 4.613948 15.000017 5.465000 15.000017 c
|
||||
10.865000 15.000017 l
|
||||
11.716052 15.000017 12.314346 14.999499 12.781241 14.961352 c
|
||||
13.240374 14.923841 13.513572 14.853280 13.725068 14.745517 c
|
||||
14.164426 14.521652 14.521636 14.164443 14.745501 13.725084 c
|
||||
14.853263 13.513588 14.923823 13.240391 14.961336 12.781259 c
|
||||
14.999483 12.314363 15.000000 11.716068 15.000000 10.865017 c
|
||||
15.000000 5.465017 l
|
||||
15.000000 5.137442 14.999924 4.847313 14.997654 4.587710 c
|
||||
12.903418 6.817746 l
|
||||
12.230759 7.534022 11.087341 7.515037 10.438833 6.776826 c
|
||||
9.645941 5.874260 l
|
||||
5.897148 9.831320 l
|
||||
5.226022 10.539732 4.092310 10.521740 3.444000 9.792391 c
|
||||
1.330000 7.414142 l
|
||||
1.330000 10.865017 l
|
||||
1.330000 11.716068 1.330518 12.314363 1.368664 12.781259 c
|
||||
1.406177 13.240391 1.476737 13.513588 1.584500 13.725084 c
|
||||
1.808364 14.164443 2.165574 14.521652 2.604932 14.745517 c
|
||||
h
|
||||
11.933909 5.907277 m
|
||||
14.833861 2.819281 l
|
||||
14.807792 2.739742 14.778378 2.669474 14.745501 2.604949 c
|
||||
14.521636 2.165591 14.164426 1.808381 13.725068 1.584517 c
|
||||
13.714809 1.579343 l
|
||||
10.564494 4.904676 l
|
||||
11.438032 5.899043 l
|
||||
11.568513 6.047573 11.798571 6.051393 11.933909 5.907277 c
|
||||
h
|
||||
1.330001 5.412228 m
|
||||
1.330038 4.589128 1.331311 4.005958 1.368664 3.548775 c
|
||||
1.406177 3.089643 1.476737 2.816445 1.584500 2.604949 c
|
||||
1.808364 2.165591 2.165574 1.808381 2.604932 1.584517 c
|
||||
2.816429 1.476754 3.089626 1.406194 3.548759 1.368681 c
|
||||
4.015654 1.330534 4.613949 1.330017 5.465001 1.330017 c
|
||||
10.865000 1.330017 l
|
||||
11.357291 1.330017 11.765009 1.330190 12.111642 1.337719 c
|
||||
4.931631 8.916620 l
|
||||
4.796600 9.059153 4.568496 9.055533 4.438055 8.908787 c
|
||||
1.330001 5.412228 l
|
||||
h
|
||||
11.664969 10.165024 m
|
||||
12.493397 10.165024 13.164969 10.836597 13.164969 11.665024 c
|
||||
13.164969 12.493451 12.493397 13.165024 11.664969 13.165024 c
|
||||
10.836542 13.165024 10.164969 12.493451 10.164969 11.665024 c
|
||||
10.164969 10.836597 10.836542 10.165024 11.664969 10.165024 c
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
3694
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 24.000000 24.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000003784 00000 n
|
||||
0000003807 00000 n
|
||||
0000003980 00000 n
|
||||
0000004054 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
4113
|
||||
%%EOF
|
@ -8067,7 +8067,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
case .proxy:
|
||||
self.controller?.push(proxySettingsController(context: self.context))
|
||||
case .stories:
|
||||
self.controller?.push(PeerInfoStoryGridScreen(context: self.context, peerId: self.context.account.peerId, scope: .saved))
|
||||
push(PeerInfoStoryGridScreen(context: self.context, peerId: self.context.account.peerId, scope: .saved))
|
||||
case .savedMessages:
|
||||
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId))
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peer in
|
||||
@ -8247,7 +8247,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
case .emojiStatus:
|
||||
self.headerNode.invokeDisplayPremiumIntro()
|
||||
case .powerSaving:
|
||||
self.controller?.push(energySavingSettingsScreen(context: self.context))
|
||||
push(energySavingSettingsScreen(context: self.context))
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user