mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 09:20:08 +00:00
Various fixes
This commit is contained in:
parent
a84ee0ffd7
commit
52a0f5c811
@ -21,6 +21,7 @@ final class CameraSession {
|
|||||||
self.multiSession = nil
|
self.multiSession = nil
|
||||||
self.hasMultiCam = false
|
self.hasMultiCam = false
|
||||||
}
|
}
|
||||||
|
self.session.sessionPreset = .inputPriority
|
||||||
}
|
}
|
||||||
|
|
||||||
var session: AVCaptureSession {
|
var session: AVCaptureSession {
|
||||||
@ -64,10 +65,10 @@ final class CameraDeviceContext {
|
|||||||
self.previewView = previewView
|
self.previewView = previewView
|
||||||
|
|
||||||
self.device.configure(for: session, position: position, dual: !exclusive || additional)
|
self.device.configure(for: session, position: position, dual: !exclusive || additional)
|
||||||
|
self.device.configureDeviceFormat(maxDimensions: self.preferredMaxDimensions, maxFramerate: self.preferredMaxFrameRate)
|
||||||
self.input.configure(for: session, device: self.device, audio: audio)
|
self.input.configure(for: session, device: self.device, audio: audio)
|
||||||
self.output.configure(for: session, device: self.device, input: self.input, previewView: previewView, audio: audio, photo: photo, metadata: metadata)
|
self.output.configure(for: session, device: self.device, input: self.input, previewView: previewView, audio: audio, photo: photo, metadata: metadata)
|
||||||
|
|
||||||
self.device.configureDeviceFormat(maxDimensions: self.preferredMaxDimensions, maxFramerate: self.preferredMaxFrameRate)
|
|
||||||
self.output.configureVideoStabilization()
|
self.output.configureVideoStabilization()
|
||||||
|
|
||||||
self.device.resetZoom(neutral: self.exclusive || !self.additional)
|
self.device.resetZoom(neutral: self.exclusive || !self.additional)
|
||||||
@ -83,8 +84,6 @@ final class CameraDeviceContext {
|
|||||||
|
|
||||||
private var preferredMaxDimensions: CMVideoDimensions {
|
private var preferredMaxDimensions: CMVideoDimensions {
|
||||||
if self.additional {
|
if self.additional {
|
||||||
//if case .iPhoneXS = DeviceModel.current {
|
|
||||||
// return CMVideoDimensions(width: 1440, height: 1080)
|
|
||||||
return CMVideoDimensions(width: 1920, height: 1440)
|
return CMVideoDimensions(width: 1920, height: 1440)
|
||||||
} else {
|
} else {
|
||||||
return CMVideoDimensions(width: 1920, height: 1080)
|
return CMVideoDimensions(width: 1920, height: 1080)
|
||||||
|
|||||||
@ -44,11 +44,8 @@ final class CameraDevice {
|
|||||||
selectedDevice = device
|
selectedDevice = device
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
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 {
|
if selectedDevice == nil {
|
||||||
selectedDevice = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInDualCamera, .builtInWideAngleCamera, .builtInTelephotoCamera], mediaType: .video, position: position).devices.first
|
selectedDevice = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera, .builtInTelephotoCamera], mediaType: .video, position: position).devices.first
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -215,6 +215,10 @@ final class DrawingBubbleEntitySelectionView: DrawingEntitySelectionView {
|
|||||||
self.currentHandle = self.layer
|
self.currentHandle = self.layer
|
||||||
entityView.onInteractionUpdated(true)
|
entityView.onInteractionUpdated(true)
|
||||||
case .changed:
|
case .changed:
|
||||||
|
if self.currentHandle == nil {
|
||||||
|
self.currentHandle = self.layer
|
||||||
|
}
|
||||||
|
|
||||||
let delta = gestureRecognizer.translation(in: entityView.superview)
|
let delta = gestureRecognizer.translation(in: entityView.superview)
|
||||||
let velocity = gestureRecognizer.velocity(in: entityView.superview)
|
let velocity = gestureRecognizer.velocity(in: entityView.superview)
|
||||||
|
|
||||||
|
|||||||
@ -2,8 +2,11 @@ import Foundation
|
|||||||
import UIKit
|
import UIKit
|
||||||
import Display
|
import Display
|
||||||
import LegacyComponents
|
import LegacyComponents
|
||||||
|
import SwiftSignalKit
|
||||||
import AccountContext
|
import AccountContext
|
||||||
import MediaEditor
|
import MediaEditor
|
||||||
|
import ComponentFlow
|
||||||
|
import LottieAnimationComponent
|
||||||
|
|
||||||
public func decodeDrawingEntities(data: Data) -> [DrawingEntity] {
|
public func decodeDrawingEntities(data: Data) -> [DrawingEntity] {
|
||||||
if let codableEntities = try? JSONDecoder().decode([CodableDrawingEntity].self, from: data) {
|
if let codableEntities = try? JSONDecoder().decode([CodableDrawingEntity].self, from: data) {
|
||||||
@ -75,6 +78,7 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView {
|
|||||||
private let xAxisView = UIView()
|
private let xAxisView = UIView()
|
||||||
private let yAxisView = UIView()
|
private let yAxisView = UIView()
|
||||||
private let angleLayer = SimpleShapeLayer()
|
private let angleLayer = SimpleShapeLayer()
|
||||||
|
private let bin = ComponentView<Empty>()
|
||||||
|
|
||||||
public var onInteractionUpdated: (Bool) -> Void = { _ in }
|
public var onInteractionUpdated: (Bool) -> Void = { _ in }
|
||||||
public var edgePreviewUpdated: (Bool) -> Void = { _ in }
|
public var edgePreviewUpdated: (Bool) -> Void = { _ in }
|
||||||
@ -582,17 +586,19 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView {
|
|||||||
|
|
||||||
@objc private func handleTap(_ gestureRecognzier: UITapGestureRecognizer) {
|
@objc private func handleTap(_ gestureRecognzier: UITapGestureRecognizer) {
|
||||||
let location = gestureRecognzier.location(in: self)
|
let location = gestureRecognzier.location(in: self)
|
||||||
|
if let entityView = self.entity(at: location) {
|
||||||
|
self.selectEntity(entityView.entity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func entity(at location: CGPoint) -> DrawingEntityView? {
|
||||||
var intersectedViews: [DrawingEntityView] = []
|
var intersectedViews: [DrawingEntityView] = []
|
||||||
for case let view as DrawingEntityView in self.subviews {
|
for case let view as DrawingEntityView in self.subviews {
|
||||||
if view.precisePoint(inside: self.convert(location, to: view)) {
|
if view.precisePoint(inside: self.convert(location, to: view)) {
|
||||||
intersectedViews.append(view)
|
intersectedViews.append(view)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return intersectedViews.last
|
||||||
if let entityView = intersectedViews.last {
|
|
||||||
self.selectEntity(entityView.entity)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func selectEntity(_ entity: DrawingEntity?) {
|
public func selectEntity(_ entity: DrawingEntity?) {
|
||||||
@ -622,8 +628,9 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView {
|
|||||||
|
|
||||||
if let selectionView = entityView.makeSelectionView() {
|
if let selectionView = entityView.makeSelectionView() {
|
||||||
selectionView.tapped = { [weak self, weak entityView] in
|
selectionView.tapped = { [weak self, weak entityView] in
|
||||||
if let strongSelf = self, let entityView = entityView {
|
if let self, let entityView = entityView {
|
||||||
strongSelf.requestedMenuForEntityView(entityView, strongSelf.subviews.last === entityView)
|
let entityViews = self.subviews.filter { $0 is DrawingEntityView }
|
||||||
|
self.requestedMenuForEntityView(entityView, entityViews.last === entityView)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
entityView.selectionView = selectionView
|
entityView.selectionView = selectionView
|
||||||
@ -681,8 +688,72 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) {
|
public func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) {
|
||||||
|
let location = gestureRecognizer.location(in: self)
|
||||||
if let selectedEntityView = self.selectedEntityView, let selectionView = selectedEntityView.selectionView {
|
if let selectedEntityView = self.selectedEntityView, let selectionView = selectedEntityView.selectionView {
|
||||||
selectionView.handlePan(gestureRecognizer)
|
var isTrappedInBin = false
|
||||||
|
let scale = 100.0 / selectedEntityView.bounds.size.width
|
||||||
|
switch gestureRecognizer.state {
|
||||||
|
case .changed:
|
||||||
|
if self.updateBin(location: location) {
|
||||||
|
isTrappedInBin = true
|
||||||
|
}
|
||||||
|
case .ended, .cancelled:
|
||||||
|
let _ = self.updateBin(location: nil)
|
||||||
|
if selectedEntityView.isTrappedInBin {
|
||||||
|
selectedEntityView.layer.animateScale(from: scale, to: 0.01, duration: 0.2, removeOnCompletion: false)
|
||||||
|
selectedEntityView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { _ in
|
||||||
|
self.remove(uuid: selectedEntityView.entity.uuid)
|
||||||
|
})
|
||||||
|
self.selectEntity(nil)
|
||||||
|
|
||||||
|
Queue.mainQueue().after(0.3, {
|
||||||
|
self.onInteractionUpdated(false)
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
let transition = Transition.easeInOut(duration: 0.2)
|
||||||
|
if isTrappedInBin, let binView = self.bin.view {
|
||||||
|
if !selectedEntityView.isTrappedInBin {
|
||||||
|
let refs = [
|
||||||
|
self.xAxisView,
|
||||||
|
self.yAxisView,
|
||||||
|
self.topEdgeView,
|
||||||
|
self.leftEdgeView,
|
||||||
|
self.rightEdgeView,
|
||||||
|
self.bottomEdgeView
|
||||||
|
]
|
||||||
|
for ref in refs {
|
||||||
|
transition.setAlpha(view: ref, alpha: 0.0)
|
||||||
|
}
|
||||||
|
self.edgePreviewUpdated(false)
|
||||||
|
|
||||||
|
selectedEntityView.isTrappedInBin = true
|
||||||
|
transition.setAlpha(view: selectionView, alpha: 0.0)
|
||||||
|
transition.animatePosition(view: selectionView, from: selectionView.center, to: self.convert(binView.center, to: selectionView.superview))
|
||||||
|
transition.animateScale(view: selectionView, from: 0.0, to: -0.5, additive: true)
|
||||||
|
|
||||||
|
transition.setPosition(view: selectedEntityView, position: binView.center)
|
||||||
|
|
||||||
|
let rotation = selectedEntityView.layer.transform.decompose().rotation
|
||||||
|
var transform = CATransform3DMakeScale(scale, scale, 1.0)
|
||||||
|
transform = CATransform3DRotate(transform, CGFloat(rotation.z), 0.0, 0.0, 1.0)
|
||||||
|
|
||||||
|
transition.setTransform(view: selectedEntityView, transform: transform)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if selectedEntityView.isTrappedInBin {
|
||||||
|
selectedEntityView.isTrappedInBin = false
|
||||||
|
transition.setAlpha(view: selectionView, alpha: 1.0)
|
||||||
|
selectedEntityView.layer.animateScale(from: scale, to: selectedEntityView.entity.scale, duration: 0.13)
|
||||||
|
}
|
||||||
|
selectionView.handlePan(gestureRecognizer)
|
||||||
|
}
|
||||||
|
} else if gestureRecognizer.numberOfTouches == 1, let viewToSelect = self.entity(at: location) {
|
||||||
|
self.selectEntity(viewToSelect.entity)
|
||||||
} else if gestureRecognizer.numberOfTouches == 2, let mediaEntityView = self.subviews.first(where: { $0 is DrawingEntityMediaView }) as? DrawingEntityMediaView {
|
} else if gestureRecognizer.numberOfTouches == 2, let mediaEntityView = self.subviews.first(where: { $0 is DrawingEntityMediaView }) as? DrawingEntityMediaView {
|
||||||
mediaEntityView.handlePan(gestureRecognizer)
|
mediaEntityView.handlePan(gestureRecognizer)
|
||||||
}
|
}
|
||||||
@ -703,6 +774,40 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView {
|
|||||||
selectionView.handleRotate(gestureRecognizer)
|
selectionView.handleRotate(gestureRecognizer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var binWasOpened = false
|
||||||
|
private func updateBin(location: CGPoint?) -> Bool {
|
||||||
|
let binSize = CGSize(width: 180.0, height: 180.0)
|
||||||
|
let binFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((self.bounds.width - binSize.width) / 2.0), y: self.bounds.height - binSize.height - 20.0), size: binSize)
|
||||||
|
|
||||||
|
let wasOpened = self.binWasOpened
|
||||||
|
var isOpened = false
|
||||||
|
if let location {
|
||||||
|
isOpened = binFrame.insetBy(dx: 20.0, dy: 20.0).contains(location)
|
||||||
|
}
|
||||||
|
self.binWasOpened = isOpened
|
||||||
|
|
||||||
|
if wasOpened != isOpened {
|
||||||
|
self.hapticFeedback.impact(.medium)
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = self.bin.update(
|
||||||
|
transition: .immediate,
|
||||||
|
component: AnyComponent(EntityBinComponent(isOpened: isOpened)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: binSize
|
||||||
|
)
|
||||||
|
if let binView = self.bin.view {
|
||||||
|
if binView.superview == nil {
|
||||||
|
self.addSubview(binView)
|
||||||
|
} else if self.subviews.last !== binView {
|
||||||
|
self.bringSubviewToFront(binView)
|
||||||
|
}
|
||||||
|
binView.frame = binFrame
|
||||||
|
Transition.easeInOut(duration: 0.2).setAlpha(view: binView, alpha: location != nil ? 1.0 : 0.0, delay: location == nil && wasOpened ? 0.4 : 0.0)
|
||||||
|
}
|
||||||
|
return isOpened
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol DrawingEntityMediaView: DrawingEntityView {
|
protocol DrawingEntityMediaView: DrawingEntityView {
|
||||||
@ -716,6 +821,8 @@ public class DrawingEntityView: UIView {
|
|||||||
public let entity: DrawingEntity
|
public let entity: DrawingEntity
|
||||||
var isTracking = false
|
var isTracking = false
|
||||||
|
|
||||||
|
var isTrappedInBin = false
|
||||||
|
|
||||||
public weak var selectionView: DrawingEntitySelectionView?
|
public weak var selectionView: DrawingEntitySelectionView?
|
||||||
weak var containerView: DrawingEntitiesView?
|
weak var containerView: DrawingEntitiesView?
|
||||||
|
|
||||||
@ -878,3 +985,97 @@ public class DrawingSelectionContainerView: UIView {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final class EntityBinComponent: Component {
|
||||||
|
typealias EnvironmentType = Empty
|
||||||
|
|
||||||
|
let isOpened: Bool
|
||||||
|
|
||||||
|
init(
|
||||||
|
isOpened: Bool
|
||||||
|
) {
|
||||||
|
self.isOpened = isOpened
|
||||||
|
}
|
||||||
|
|
||||||
|
static func ==(lhs: EntityBinComponent, rhs: EntityBinComponent) -> Bool {
|
||||||
|
if lhs.isOpened != rhs.isOpened {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class View: UIView {
|
||||||
|
private let circle = SimpleShapeLayer()
|
||||||
|
private let animation = ComponentView<Empty>()
|
||||||
|
|
||||||
|
private var component: EntityBinComponent?
|
||||||
|
private weak var state: EmptyComponentState?
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
self.backgroundColor = .clear
|
||||||
|
|
||||||
|
self.circle.strokeColor = UIColor.white.cgColor
|
||||||
|
self.circle.fillColor = UIColor.clear.cgColor
|
||||||
|
self.circle.lineWidth = 5.0
|
||||||
|
|
||||||
|
self.layer.addSublayer(self.circle)
|
||||||
|
|
||||||
|
self.circle.path = CGPath(ellipseIn: CGRect(origin: .zero, size: CGSize(width: 160.0, height: 160.0)).insetBy(dx: 3.0, dy: 3.0), transform: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
private var wasOpened = false
|
||||||
|
func update(component: EntityBinComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||||
|
self.component = component
|
||||||
|
self.state = state
|
||||||
|
|
||||||
|
if !self.wasOpened {
|
||||||
|
self.wasOpened = component.isOpened
|
||||||
|
}
|
||||||
|
|
||||||
|
let animationSize = self.animation.update(
|
||||||
|
transition: transition,
|
||||||
|
component: AnyComponent(LottieAnimationComponent(
|
||||||
|
animation: LottieAnimationComponent.AnimationItem(
|
||||||
|
name: "anim_entitybin",
|
||||||
|
mode: component.isOpened ? .animating(loop: false) : (self.wasOpened ? .animating(loop: false) : .still(position: .end)),
|
||||||
|
range: component.isOpened ? (0.0, 0.5) : (0.5, 1.0)
|
||||||
|
),
|
||||||
|
colors: [:],
|
||||||
|
size: CGSize(width: 140.0, height: 140.0)
|
||||||
|
)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: CGSize(width: 140.0, height: 140.0)
|
||||||
|
)
|
||||||
|
let animationFrame = CGRect(
|
||||||
|
origin: CGPoint(x: 20.0, y: 20.0),
|
||||||
|
size: animationSize
|
||||||
|
)
|
||||||
|
if let animationView = self.animation.view {
|
||||||
|
if animationView.superview == nil {
|
||||||
|
self.addSubview(animationView)
|
||||||
|
}
|
||||||
|
transition.setPosition(view: animationView, position: animationFrame.center)
|
||||||
|
transition.setBounds(view: animationView, bounds: CGRect(origin: .zero, size: animationFrame.size))
|
||||||
|
}
|
||||||
|
|
||||||
|
let circleSize = CGSize(width: 160.0, height: 160.0)
|
||||||
|
self.circle.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - circleSize.width) / 2.0), y: floorToScreenPixels((availableSize.height - circleSize.height) / 2.0)), size: CGSize(width: 100.0, height: 100.0))
|
||||||
|
|
||||||
|
return availableSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeView() -> View {
|
||||||
|
return View()
|
||||||
|
}
|
||||||
|
|
||||||
|
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||||
|
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -222,6 +222,10 @@ final class DrawingSimpleShapeEntititySelectionView: DrawingEntitySelectionView
|
|||||||
self.currentHandle = self.layer
|
self.currentHandle = self.layer
|
||||||
entityView.onInteractionUpdated(true)
|
entityView.onInteractionUpdated(true)
|
||||||
case .changed:
|
case .changed:
|
||||||
|
if self.currentHandle == nil {
|
||||||
|
self.currentHandle = self.layer
|
||||||
|
}
|
||||||
|
|
||||||
let delta = gestureRecognizer.translation(in: entityView.superview)
|
let delta = gestureRecognizer.translation(in: entityView.superview)
|
||||||
let velocity = gestureRecognizer.velocity(in: entityView.superview)
|
let velocity = gestureRecognizer.velocity(in: entityView.superview)
|
||||||
|
|
||||||
|
|||||||
@ -521,6 +521,10 @@ final class DrawingStickerEntititySelectionView: DrawingEntitySelectionView {
|
|||||||
self.currentHandle = self.layer
|
self.currentHandle = self.layer
|
||||||
entityView.onInteractionUpdated(true)
|
entityView.onInteractionUpdated(true)
|
||||||
case .changed:
|
case .changed:
|
||||||
|
if self.currentHandle == nil {
|
||||||
|
self.currentHandle = self.layer
|
||||||
|
}
|
||||||
|
|
||||||
let delta = gestureRecognizer.translation(in: entityView.superview)
|
let delta = gestureRecognizer.translation(in: entityView.superview)
|
||||||
let parentLocation = gestureRecognizer.location(in: self.superview)
|
let parentLocation = gestureRecognizer.location(in: self.superview)
|
||||||
let velocity = gestureRecognizer.velocity(in: entityView.superview)
|
let velocity = gestureRecognizer.velocity(in: entityView.superview)
|
||||||
|
|||||||
@ -785,6 +785,10 @@ final class DrawingTextEntititySelectionView: DrawingEntitySelectionView {
|
|||||||
self.currentHandle = self.layer
|
self.currentHandle = self.layer
|
||||||
entityView.onInteractionUpdated(true)
|
entityView.onInteractionUpdated(true)
|
||||||
case .changed:
|
case .changed:
|
||||||
|
if self.currentHandle == nil {
|
||||||
|
self.currentHandle = self.layer
|
||||||
|
}
|
||||||
|
|
||||||
let delta = gestureRecognizer.translation(in: entityView.superview)
|
let delta = gestureRecognizer.translation(in: entityView.superview)
|
||||||
let parentLocation = gestureRecognizer.location(in: self.superview)
|
let parentLocation = gestureRecognizer.location(in: self.superview)
|
||||||
let velocity = gestureRecognizer.velocity(in: entityView.superview)
|
let velocity = gestureRecognizer.velocity(in: entityView.superview)
|
||||||
|
|||||||
@ -517,3 +517,30 @@ func normalizeDrawingRect(_ rect: CGRect, drawingSize: CGSize) -> CGRect {
|
|||||||
}
|
}
|
||||||
return rect
|
return rect
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension CATransform3D {
|
||||||
|
func decompose() -> (translation: SIMD3<Float>, rotation: SIMD3<Float>, scale: SIMD3<Float>) {
|
||||||
|
let m0 = SIMD3<Float>(Float(self.m11), Float(self.m12), Float(self.m13))
|
||||||
|
let m1 = SIMD3<Float>(Float(self.m21), Float(self.m22), Float(self.m23))
|
||||||
|
let m2 = SIMD3<Float>(Float(self.m31), Float(self.m32), Float(self.m33))
|
||||||
|
let m3 = SIMD3<Float>(Float(self.m41), Float(self.m42), Float(self.m43))
|
||||||
|
|
||||||
|
let t = m3
|
||||||
|
|
||||||
|
let sx = length(m0)
|
||||||
|
let sy = length(m1)
|
||||||
|
let sz = length(m2)
|
||||||
|
let s = SIMD3<Float>(sx, sy, sz)
|
||||||
|
|
||||||
|
let rx = m0 / sx
|
||||||
|
let ry = m1 / sy
|
||||||
|
let rz = m2 / sz
|
||||||
|
|
||||||
|
let pitch = atan2(ry.z, rz.z)
|
||||||
|
let yaw = atan2(-rx.z, hypot(ry.z, rz.z))
|
||||||
|
let roll = atan2(rx.y, rx.x)
|
||||||
|
let r = SIMD3<Float>(pitch, yaw, roll)
|
||||||
|
|
||||||
|
return (t, r, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -188,6 +188,10 @@ final class DrawingVectorEntititySelectionView: DrawingEntitySelectionView {
|
|||||||
}
|
}
|
||||||
self.currentHandle = self.layer
|
self.currentHandle = self.layer
|
||||||
case .changed:
|
case .changed:
|
||||||
|
if self.currentHandle == nil {
|
||||||
|
self.currentHandle = self.layer
|
||||||
|
}
|
||||||
|
|
||||||
if gestureRecognizer.numberOfTouches > 1 {
|
if gestureRecognizer.numberOfTouches > 1 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1731,7 +1731,7 @@ public class CameraScreen: ViewController {
|
|||||||
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.minY + 3.0), size: CGSize())
|
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.minY + 3.0), size: CGSize())
|
||||||
|
|
||||||
let accountManager = self.context.sharedContext.accountManager
|
let accountManager = self.context.sharedContext.accountManager
|
||||||
let tooltipController = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: .plain(text: "Take photos or videos to share with all\nyour contacts or close friends at once."), textAlignment: .center, location: .point(location, .bottom), displayDuration: .custom(3.0), inset: 16.0, shouldDismissOnTouch: { point, containerFrame in
|
let tooltipController = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: .plain(text: "Take photos or videos to share with all\nyour contacts or close friends at once."), textAlignment: .center, location: .point(location, .bottom), displayDuration: .custom(4.5), inset: 16.0, shouldDismissOnTouch: { point, containerFrame in
|
||||||
if containerFrame.contains(point) {
|
if containerFrame.contains(point) {
|
||||||
let _ = ApplicationSpecificNotice.incrementStoriesCameraTip(accountManager: accountManager).start()
|
let _ = ApplicationSpecificNotice.incrementStoriesCameraTip(accountManager: accountManager).start()
|
||||||
return .dismiss(consume: true)
|
return .dismiss(consume: true)
|
||||||
|
|||||||
@ -267,9 +267,13 @@ private final class MediaToolsScreenComponent: Component {
|
|||||||
var delay: Double = 0.0
|
var delay: Double = 0.0
|
||||||
for button in buttons {
|
for button in buttons {
|
||||||
if let view = button.view {
|
if let view = button.view {
|
||||||
view.layer.animatePosition(from: CGPoint(x: 0.0, y: 64.0), to: .zero, duration: 0.3, delay: delay, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
view.alpha = 0.0
|
||||||
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, delay: delay)
|
Queue.mainQueue().after(delay, {
|
||||||
view.layer.animateScale(from: 0.1, to: 1.0, duration: 0.2, delay: delay)
|
view.alpha = 1.0
|
||||||
|
view.layer.animatePosition(from: CGPoint(x: 0.0, y: 64.0), to: .zero, duration: 0.3, delay: 0.0, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
||||||
|
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, delay: 0.0)
|
||||||
|
view.layer.animateScale(from: 0.1, to: 1.0, duration: 0.2, delay: 0.0)
|
||||||
|
})
|
||||||
delay += 0.03
|
delay += 0.03
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,7 @@ public final class AvatarStoryIndicatorComponent: Component {
|
|||||||
public let activeLineWidth: CGFloat
|
public let activeLineWidth: CGFloat
|
||||||
public let inactiveLineWidth: CGFloat
|
public let inactiveLineWidth: CGFloat
|
||||||
public let isGlassBackground: Bool
|
public let isGlassBackground: Bool
|
||||||
|
public let backgroundColor: UIColor?
|
||||||
public let counters: Counters?
|
public let counters: Counters?
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
@ -30,6 +31,7 @@ public final class AvatarStoryIndicatorComponent: Component {
|
|||||||
activeLineWidth: CGFloat,
|
activeLineWidth: CGFloat,
|
||||||
inactiveLineWidth: CGFloat,
|
inactiveLineWidth: CGFloat,
|
||||||
isGlassBackground: Bool = false,
|
isGlassBackground: Bool = false,
|
||||||
|
backgroundColor: UIColor? = nil,
|
||||||
counters: Counters?
|
counters: Counters?
|
||||||
) {
|
) {
|
||||||
self.hasUnseen = hasUnseen
|
self.hasUnseen = hasUnseen
|
||||||
@ -38,6 +40,7 @@ public final class AvatarStoryIndicatorComponent: Component {
|
|||||||
self.activeLineWidth = activeLineWidth
|
self.activeLineWidth = activeLineWidth
|
||||||
self.inactiveLineWidth = inactiveLineWidth
|
self.inactiveLineWidth = inactiveLineWidth
|
||||||
self.isGlassBackground = isGlassBackground
|
self.isGlassBackground = isGlassBackground
|
||||||
|
self.backgroundColor = backgroundColor
|
||||||
self.counters = counters
|
self.counters = counters
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,6 +63,9 @@ public final class AvatarStoryIndicatorComponent: Component {
|
|||||||
if lhs.isGlassBackground != rhs.isGlassBackground {
|
if lhs.isGlassBackground != rhs.isGlassBackground {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.backgroundColor != rhs.backgroundColor {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.counters != rhs.counters {
|
if lhs.counters != rhs.counters {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -120,6 +126,12 @@ public final class AvatarStoryIndicatorComponent: Component {
|
|||||||
|
|
||||||
var locations: [CGFloat] = [0.0, 1.0]
|
var locations: [CGFloat] = [0.0, 1.0]
|
||||||
|
|
||||||
|
if let backgroundColor = component.backgroundColor {
|
||||||
|
context.setLineWidth(lineWidth)
|
||||||
|
context.setStrokeColor(backgroundColor.cgColor)
|
||||||
|
context.strokeEllipse(in: CGRect(origin: CGPoint(x: size.width * 0.5 - diameter * 0.5, y: size.height * 0.5 - diameter * 0.5), size: size).insetBy(dx: lineWidth * 0.5, dy: lineWidth * 0.5).insetBy(dx: lineWidth, dy: lineWidth))
|
||||||
|
}
|
||||||
|
|
||||||
context.setLineWidth(lineWidth)
|
context.setLineWidth(lineWidth)
|
||||||
|
|
||||||
if let counters = component.counters, counters.totalCount > 1 {
|
if let counters = component.counters, counters.totalCount > 1 {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -454,7 +454,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
|||||||
self.playbackStartDisposable.dispose()
|
self.playbackStartDisposable.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateStoryView(transition: ContainedViewLayoutTransition, theme: PresentationTheme) {
|
func updateStoryView(transition: ContainedViewLayoutTransition, theme: PresentationTheme, avatarMaskValue: CGFloat) {
|
||||||
if let storyData = self.storyData {
|
if let storyData = self.storyData {
|
||||||
let avatarStoryView: ComponentView<Empty>
|
let avatarStoryView: ComponentView<Empty>
|
||||||
if let current = self.avatarStoryView {
|
if let current = self.avatarStoryView {
|
||||||
@ -464,6 +464,8 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
|||||||
self.avatarStoryView = avatarStoryView
|
self.avatarStoryView = avatarStoryView
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let inset: CGFloat = storyData.hasUnseen ? 3.0 ? 2.0
|
||||||
|
let avatarFrame = self.avatarNode.frame.insetBy(dx: inset, dy: inset)
|
||||||
let _ = avatarStoryView.update(
|
let _ = avatarStoryView.update(
|
||||||
transition: Transition(transition),
|
transition: Transition(transition),
|
||||||
component: AnyComponent(AvatarStoryIndicatorComponent(
|
component: AnyComponent(AvatarStoryIndicatorComponent(
|
||||||
@ -472,16 +474,23 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
|||||||
theme: theme,
|
theme: theme,
|
||||||
activeLineWidth: 3.0,
|
activeLineWidth: 3.0,
|
||||||
inactiveLineWidth: 2.0,
|
inactiveLineWidth: 2.0,
|
||||||
|
backgroundColor: theme.list.blocksBackgroundColor,
|
||||||
counters: nil
|
counters: nil
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
containerSize: self.avatarNode.bounds.size
|
containerSize: avatarFrame.size
|
||||||
)
|
)
|
||||||
if let avatarStoryComponentView = avatarStoryView.view {
|
if let avatarStoryComponentView = avatarStoryView.view {
|
||||||
if avatarStoryComponentView.superview == nil {
|
if avatarStoryComponentView.superview == nil {
|
||||||
self.containerNode.view.insertSubview(avatarStoryComponentView, at: 0)
|
self.containerNode.view.addSubview(avatarStoryComponentView)
|
||||||
}
|
}
|
||||||
avatarStoryComponentView.frame = self.avatarNode.frame
|
avatarStoryComponentView.bounds = CGRect(origin: .zero, size: avatarFrame.size)
|
||||||
|
|
||||||
|
let scaleValue = avatarMaskValue * 0.15
|
||||||
|
let scale = 1.0 - scaleValue
|
||||||
|
let offset = min(1.5, avatarMaskValue * 2.5)
|
||||||
|
avatarStoryComponentView.transform = CGAffineTransformMakeScale(scale, scale)
|
||||||
|
avatarStoryComponentView.center = avatarFrame.center.offsetBy(dx: 0.0, dy: offset)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let avatarStoryView = self.avatarStoryView {
|
if let avatarStoryView = self.avatarStoryView {
|
||||||
@ -529,12 +538,17 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var removedPhotoResourceIds = Set<String>()
|
var removedPhotoResourceIds = Set<String>()
|
||||||
func update(peer: Peer?, threadId: Int64?, threadInfo: EngineMessageHistoryThread.Info?, item: PeerInfoAvatarListItem?, theme: PresentationTheme, avatarSize: CGFloat, isExpanded: Bool, isSettings: Bool) {
|
func update(peer: Peer?, threadId: Int64?, threadInfo: EngineMessageHistoryThread.Info?, item: PeerInfoAvatarListItem?, theme: PresentationTheme, avatarSize: CGFloat, isExpanded: Bool, avatarMaskValue: CGFloat, isSettings: Bool) {
|
||||||
if let peer = peer {
|
if let peer = peer {
|
||||||
let previousItem = self.item
|
let previousItem = self.item
|
||||||
var item = item
|
var item = item
|
||||||
self.item = item
|
self.item = item
|
||||||
|
|
||||||
|
var avatarSize = avatarSize
|
||||||
|
if self.storyData != nil {
|
||||||
|
avatarSize = avatarSize - 6.0
|
||||||
|
}
|
||||||
|
|
||||||
var overrideImage: AvatarNodeImageOverride?
|
var overrideImage: AvatarNodeImageOverride?
|
||||||
if peer.isDeleted {
|
if peer.isDeleted {
|
||||||
overrideImage = .deletedIcon
|
overrideImage = .deletedIcon
|
||||||
@ -788,7 +802,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.updateStoryView(transition: .immediate, theme: theme)
|
self.updateStoryView(transition: .immediate, theme: theme, avatarMaskValue: avatarMaskValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1162,7 +1176,7 @@ final class PeerInfoAvatarListNode: ASDisplayNode {
|
|||||||
|
|
||||||
let isReady = Promise<Bool>()
|
let isReady = Promise<Bool>()
|
||||||
|
|
||||||
var arguments: (Peer?, Int64?, EngineMessageHistoryThread.Info?, PresentationTheme, CGFloat, Bool)?
|
var arguments: (Peer?, Int64?, EngineMessageHistoryThread.Info?, PresentationTheme, CGFloat, Bool, CGFloat)?
|
||||||
var item: PeerInfoAvatarListItem?
|
var item: PeerInfoAvatarListItem?
|
||||||
|
|
||||||
var itemsUpdated: (([PeerInfoAvatarListItem]) -> Void)?
|
var itemsUpdated: (([PeerInfoAvatarListItem]) -> Void)?
|
||||||
@ -1233,14 +1247,14 @@ final class PeerInfoAvatarListNode: ASDisplayNode {
|
|||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.item = items.first
|
strongSelf.item = items.first
|
||||||
strongSelf.itemsUpdated?(items)
|
strongSelf.itemsUpdated?(items)
|
||||||
if let (peer, threadId, threadInfo, theme, avatarSize, isExpanded) = strongSelf.arguments {
|
if let (peer, threadId, threadInfo, theme, avatarSize, isExpanded, avatarMaskValue) = strongSelf.arguments {
|
||||||
strongSelf.avatarContainerNode.update(peer: peer, threadId: threadId, threadInfo: threadInfo, item: strongSelf.item, theme: theme, avatarSize: avatarSize, isExpanded: isExpanded, isSettings: strongSelf.isSettings)
|
strongSelf.avatarContainerNode.update(peer: peer, threadId: threadId, threadInfo: threadInfo, item: strongSelf.item, theme: theme, avatarSize: avatarSize, isExpanded: isExpanded, avatarMaskValue: avatarMaskValue, isSettings: strongSelf.isSettings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.pinchSourceNode.activate = { [weak self] sourceNode in
|
self.pinchSourceNode.activate = { [weak self] sourceNode in
|
||||||
guard let strongSelf = self, let (_, _, _, _, _, isExpanded) = strongSelf.arguments, isExpanded else {
|
guard let strongSelf = self, let (_, _, _, _, _, isExpanded, _) = strongSelf.arguments, isExpanded else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let pinchController = PinchController(sourceNode: sourceNode, getContentAreaInScreenSpace: {
|
let pinchController = PinchController(sourceNode: sourceNode, getContentAreaInScreenSpace: {
|
||||||
@ -1266,13 +1280,13 @@ final class PeerInfoAvatarListNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(size: CGSize, avatarSize: CGFloat, isExpanded: Bool, peer: Peer?, isForum: Bool, threadId: Int64?, threadInfo: EngineMessageHistoryThread.Info?, theme: PresentationTheme, transition: ContainedViewLayoutTransition) {
|
func update(size: CGSize, avatarSize: CGFloat, isExpanded: Bool, peer: Peer?, isForum: Bool, threadId: Int64?, threadInfo: EngineMessageHistoryThread.Info?, theme: PresentationTheme, avatarMaskValue: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
self.arguments = (peer, threadId, threadInfo, theme, avatarSize, isExpanded)
|
self.arguments = (peer, threadId, threadInfo, theme, avatarSize, isExpanded, avatarMaskValue)
|
||||||
self.maskNode.isForum = isForum
|
self.maskNode.isForum = isForum
|
||||||
self.pinchSourceNode.update(size: size, transition: transition)
|
self.pinchSourceNode.update(size: size, transition: transition)
|
||||||
self.containerNode.frame = CGRect(origin: CGPoint(), size: size)
|
self.containerNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||||
self.pinchSourceNode.frame = CGRect(origin: CGPoint(), size: size)
|
self.pinchSourceNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||||
self.avatarContainerNode.update(peer: peer, threadId: threadId, threadInfo: threadInfo, item: self.item, theme: theme, avatarSize: avatarSize, isExpanded: isExpanded, isSettings: self.isSettings)
|
self.avatarContainerNode.update(peer: peer, threadId: threadId, threadInfo: threadInfo, item: self.item, theme: theme, avatarSize: avatarSize, isExpanded: isExpanded, avatarMaskValue: avatarMaskValue, isSettings: self.isSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
@ -3420,7 +3434,8 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
self.avatarListNode.update(size: CGSize(), avatarSize: avatarSize, isExpanded: self.isAvatarExpanded, peer: peer, isForum: isForum, threadId: self.forumTopicThreadId, threadInfo: threadData?.info, theme: presentationData.theme, transition: transition)
|
let avatarMaskValue = max(0.0, min(1.0, contentOffset / 120.0))
|
||||||
|
self.avatarListNode.update(size: CGSize(), avatarSize: avatarSize, isExpanded: self.isAvatarExpanded, peer: peer, isForum: isForum, threadId: self.forumTopicThreadId, threadInfo: threadData?.info, theme: presentationData.theme, avatarMaskValue: avatarMaskValue, transition: transition)
|
||||||
self.editingContentNode.avatarNode.update(peer: peer, threadData: threadData, chatLocation: self.chatLocation, item: self.avatarListNode.item, updatingAvatar: state.updatingAvatar, uploadProgress: state.avatarUploadProgress, theme: presentationData.theme, avatarSize: avatarSize, isEditing: state.isEditing)
|
self.editingContentNode.avatarNode.update(peer: peer, threadData: threadData, chatLocation: self.chatLocation, item: self.avatarListNode.item, updatingAvatar: state.updatingAvatar, uploadProgress: state.avatarUploadProgress, theme: presentationData.theme, avatarSize: avatarSize, isEditing: state.isEditing)
|
||||||
self.avatarOverlayNode.update(peer: peer, threadData: threadData, chatLocation: self.chatLocation, item: self.avatarListNode.item, updatingAvatar: state.updatingAvatar, uploadProgress: state.avatarUploadProgress, theme: presentationData.theme, avatarSize: avatarSize, isEditing: state.isEditing)
|
self.avatarOverlayNode.update(peer: peer, threadData: threadData, chatLocation: self.chatLocation, item: self.avatarListNode.item, updatingAvatar: state.updatingAvatar, uploadProgress: state.avatarUploadProgress, theme: presentationData.theme, avatarSize: avatarSize, isEditing: state.isEditing)
|
||||||
if additive {
|
if additive {
|
||||||
@ -3499,9 +3514,8 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if deviceMetrics.hasDynamicIsland && self.forumTopicThreadId == nil && self.navigationTransition == nil && !isLandscape {
|
if deviceMetrics.hasDynamicIsland && self.forumTopicThreadId == nil && self.navigationTransition == nil && !isLandscape {
|
||||||
let maskValue = max(0.0, min(1.0, contentOffset / 120.0))
|
|
||||||
self.avatarListNode.containerNode.view.mask = self.avatarListNode.maskNode.view
|
self.avatarListNode.containerNode.view.mask = self.avatarListNode.maskNode.view
|
||||||
if maskValue > 0.03 {
|
if avatarMaskValue > 0.03 {
|
||||||
self.avatarListNode.bottomCoverNode.isHidden = false
|
self.avatarListNode.bottomCoverNode.isHidden = false
|
||||||
self.avatarListNode.topCoverNode.isHidden = false
|
self.avatarListNode.topCoverNode.isHidden = false
|
||||||
self.avatarListNode.maskNode.backgroundColor = .clear
|
self.avatarListNode.maskNode.backgroundColor = .clear
|
||||||
@ -3510,8 +3524,8 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
self.avatarListNode.topCoverNode.isHidden = true
|
self.avatarListNode.topCoverNode.isHidden = true
|
||||||
self.avatarListNode.maskNode.backgroundColor = .white
|
self.avatarListNode.maskNode.backgroundColor = .white
|
||||||
}
|
}
|
||||||
self.avatarListNode.topCoverNode.update(maskValue)
|
self.avatarListNode.topCoverNode.update(avatarMaskValue)
|
||||||
self.avatarListNode.maskNode.update(maskValue)
|
self.avatarListNode.maskNode.update(avatarMaskValue)
|
||||||
|
|
||||||
self.avatarListNode.listContainerNode.topShadowNode.isHidden = !self.isAvatarExpanded
|
self.avatarListNode.listContainerNode.topShadowNode.isHidden = !self.isAvatarExpanded
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user