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
a84ee0ffd7
commit
52a0f5c811
@ -10,7 +10,7 @@ final class CameraSession {
|
||||
private let multiSession: Any?
|
||||
|
||||
let hasMultiCam: Bool
|
||||
|
||||
|
||||
init() {
|
||||
if #available(iOS 13.0, *), AVCaptureMultiCamSession.isMultiCamSupported {
|
||||
self.multiSession = AVCaptureMultiCamSession()
|
||||
@ -21,6 +21,7 @@ final class CameraSession {
|
||||
self.multiSession = nil
|
||||
self.hasMultiCam = false
|
||||
}
|
||||
self.session.sessionPreset = .inputPriority
|
||||
}
|
||||
|
||||
var session: AVCaptureSession {
|
||||
@ -64,10 +65,10 @@ final class CameraDeviceContext {
|
||||
self.previewView = previewView
|
||||
|
||||
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.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.device.resetZoom(neutral: self.exclusive || !self.additional)
|
||||
@ -83,8 +84,6 @@ final class CameraDeviceContext {
|
||||
|
||||
private var preferredMaxDimensions: CMVideoDimensions {
|
||||
if self.additional {
|
||||
//if case .iPhoneXS = DeviceModel.current {
|
||||
// return CMVideoDimensions(width: 1440, height: 1080)
|
||||
return CMVideoDimensions(width: 1920, height: 1440)
|
||||
} else {
|
||||
return CMVideoDimensions(width: 1920, height: 1080)
|
||||
|
@ -44,11 +44,8 @@ final class CameraDevice {
|
||||
selectedDevice = device
|
||||
}
|
||||
} 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 {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,7 +169,7 @@ final class CameraOutput: NSObject {
|
||||
} else {
|
||||
Logger.shared.log("Camera", "Can't add video connection")
|
||||
}
|
||||
|
||||
|
||||
if photo {
|
||||
let photoConnection = AVCaptureConnection(inputPorts: ports, output: self.photoOutput)
|
||||
if session.session.canAddConnection(photoConnection) {
|
||||
|
@ -215,6 +215,10 @@ final class DrawingBubbleEntitySelectionView: DrawingEntitySelectionView {
|
||||
self.currentHandle = self.layer
|
||||
entityView.onInteractionUpdated(true)
|
||||
case .changed:
|
||||
if self.currentHandle == nil {
|
||||
self.currentHandle = self.layer
|
||||
}
|
||||
|
||||
let delta = gestureRecognizer.translation(in: entityView.superview)
|
||||
let velocity = gestureRecognizer.velocity(in: entityView.superview)
|
||||
|
||||
|
@ -2,8 +2,11 @@ import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import LegacyComponents
|
||||
import SwiftSignalKit
|
||||
import AccountContext
|
||||
import MediaEditor
|
||||
import ComponentFlow
|
||||
import LottieAnimationComponent
|
||||
|
||||
public func decodeDrawingEntities(data: Data) -> [DrawingEntity] {
|
||||
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 yAxisView = UIView()
|
||||
private let angleLayer = SimpleShapeLayer()
|
||||
private let bin = ComponentView<Empty>()
|
||||
|
||||
public var onInteractionUpdated: (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) {
|
||||
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] = []
|
||||
for case let view as DrawingEntityView in self.subviews {
|
||||
if view.precisePoint(inside: self.convert(location, to: view)) {
|
||||
intersectedViews.append(view)
|
||||
}
|
||||
}
|
||||
|
||||
if let entityView = intersectedViews.last {
|
||||
self.selectEntity(entityView.entity)
|
||||
}
|
||||
return intersectedViews.last
|
||||
}
|
||||
|
||||
public func selectEntity(_ entity: DrawingEntity?) {
|
||||
@ -622,8 +628,9 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView {
|
||||
|
||||
if let selectionView = entityView.makeSelectionView() {
|
||||
selectionView.tapped = { [weak self, weak entityView] in
|
||||
if let strongSelf = self, let entityView = entityView {
|
||||
strongSelf.requestedMenuForEntityView(entityView, strongSelf.subviews.last === entityView)
|
||||
if let self, let entityView = entityView {
|
||||
let entityViews = self.subviews.filter { $0 is DrawingEntityView }
|
||||
self.requestedMenuForEntityView(entityView, entityViews.last === entityView)
|
||||
}
|
||||
}
|
||||
entityView.selectionView = selectionView
|
||||
@ -679,10 +686,74 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) {
|
||||
let location = gestureRecognizer.location(in: self)
|
||||
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 {
|
||||
mediaEntityView.handlePan(gestureRecognizer)
|
||||
}
|
||||
@ -703,6 +774,40 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView {
|
||||
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 {
|
||||
@ -716,6 +821,8 @@ public class DrawingEntityView: UIView {
|
||||
public let entity: DrawingEntity
|
||||
var isTracking = false
|
||||
|
||||
var isTrappedInBin = false
|
||||
|
||||
public weak var selectionView: DrawingEntitySelectionView?
|
||||
weak var containerView: DrawingEntitiesView?
|
||||
|
||||
@ -878,3 +985,97 @@ public class DrawingSelectionContainerView: UIView {
|
||||
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
|
||||
entityView.onInteractionUpdated(true)
|
||||
case .changed:
|
||||
if self.currentHandle == nil {
|
||||
self.currentHandle = self.layer
|
||||
}
|
||||
|
||||
let delta = gestureRecognizer.translation(in: entityView.superview)
|
||||
let velocity = gestureRecognizer.velocity(in: entityView.superview)
|
||||
|
||||
|
@ -521,6 +521,10 @@ final class DrawingStickerEntititySelectionView: DrawingEntitySelectionView {
|
||||
self.currentHandle = self.layer
|
||||
entityView.onInteractionUpdated(true)
|
||||
case .changed:
|
||||
if self.currentHandle == nil {
|
||||
self.currentHandle = self.layer
|
||||
}
|
||||
|
||||
let delta = gestureRecognizer.translation(in: entityView.superview)
|
||||
let parentLocation = gestureRecognizer.location(in: self.superview)
|
||||
let velocity = gestureRecognizer.velocity(in: entityView.superview)
|
||||
|
@ -785,6 +785,10 @@ final class DrawingTextEntititySelectionView: DrawingEntitySelectionView {
|
||||
self.currentHandle = self.layer
|
||||
entityView.onInteractionUpdated(true)
|
||||
case .changed:
|
||||
if self.currentHandle == nil {
|
||||
self.currentHandle = self.layer
|
||||
}
|
||||
|
||||
let delta = gestureRecognizer.translation(in: entityView.superview)
|
||||
let parentLocation = gestureRecognizer.location(in: self.superview)
|
||||
let velocity = gestureRecognizer.velocity(in: entityView.superview)
|
||||
|
@ -517,3 +517,30 @@ func normalizeDrawingRect(_ rect: CGRect, drawingSize: CGSize) -> CGRect {
|
||||
}
|
||||
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
|
||||
case .changed:
|
||||
if self.currentHandle == nil {
|
||||
self.currentHandle = self.layer
|
||||
}
|
||||
|
||||
if gestureRecognizer.numberOfTouches > 1 {
|
||||
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 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) {
|
||||
let _ = ApplicationSpecificNotice.incrementStoriesCameraTip(accountManager: accountManager).start()
|
||||
return .dismiss(consume: true)
|
||||
|
@ -267,9 +267,13 @@ private final class MediaToolsScreenComponent: Component {
|
||||
var delay: Double = 0.0
|
||||
for button in buttons {
|
||||
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.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, delay: delay)
|
||||
view.layer.animateScale(from: 0.1, to: 1.0, duration: 0.2, delay: delay)
|
||||
view.alpha = 0.0
|
||||
Queue.mainQueue().after(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
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ public final class AvatarStoryIndicatorComponent: Component {
|
||||
public let activeLineWidth: CGFloat
|
||||
public let inactiveLineWidth: CGFloat
|
||||
public let isGlassBackground: Bool
|
||||
public let backgroundColor: UIColor?
|
||||
public let counters: Counters?
|
||||
|
||||
public init(
|
||||
@ -30,6 +31,7 @@ public final class AvatarStoryIndicatorComponent: Component {
|
||||
activeLineWidth: CGFloat,
|
||||
inactiveLineWidth: CGFloat,
|
||||
isGlassBackground: Bool = false,
|
||||
backgroundColor: UIColor? = nil,
|
||||
counters: Counters?
|
||||
) {
|
||||
self.hasUnseen = hasUnseen
|
||||
@ -38,6 +40,7 @@ public final class AvatarStoryIndicatorComponent: Component {
|
||||
self.activeLineWidth = activeLineWidth
|
||||
self.inactiveLineWidth = inactiveLineWidth
|
||||
self.isGlassBackground = isGlassBackground
|
||||
self.backgroundColor = backgroundColor
|
||||
self.counters = counters
|
||||
}
|
||||
|
||||
@ -60,6 +63,9 @@ public final class AvatarStoryIndicatorComponent: Component {
|
||||
if lhs.isGlassBackground != rhs.isGlassBackground {
|
||||
return false
|
||||
}
|
||||
if lhs.backgroundColor != rhs.backgroundColor {
|
||||
return false
|
||||
}
|
||||
if lhs.counters != rhs.counters {
|
||||
return false
|
||||
}
|
||||
@ -120,6 +126,12 @@ public final class AvatarStoryIndicatorComponent: Component {
|
||||
|
||||
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)
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
func updateStoryView(transition: ContainedViewLayoutTransition, theme: PresentationTheme) {
|
||||
func updateStoryView(transition: ContainedViewLayoutTransition, theme: PresentationTheme, avatarMaskValue: CGFloat) {
|
||||
if let storyData = self.storyData {
|
||||
let avatarStoryView: ComponentView<Empty>
|
||||
if let current = self.avatarStoryView {
|
||||
@ -464,6 +464,8 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
||||
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(
|
||||
transition: Transition(transition),
|
||||
component: AnyComponent(AvatarStoryIndicatorComponent(
|
||||
@ -472,16 +474,23 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
||||
theme: theme,
|
||||
activeLineWidth: 3.0,
|
||||
inactiveLineWidth: 2.0,
|
||||
backgroundColor: theme.list.blocksBackgroundColor,
|
||||
counters: nil
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: self.avatarNode.bounds.size
|
||||
containerSize: avatarFrame.size
|
||||
)
|
||||
if let avatarStoryComponentView = avatarStoryView.view {
|
||||
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 {
|
||||
if let avatarStoryView = self.avatarStoryView {
|
||||
@ -529,12 +538,17 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
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 {
|
||||
let previousItem = self.item
|
||||
var item = item
|
||||
self.item = item
|
||||
|
||||
var avatarSize = avatarSize
|
||||
if self.storyData != nil {
|
||||
avatarSize = avatarSize - 6.0
|
||||
}
|
||||
|
||||
var overrideImage: AvatarNodeImageOverride?
|
||||
if peer.isDeleted {
|
||||
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>()
|
||||
|
||||
var arguments: (Peer?, Int64?, EngineMessageHistoryThread.Info?, PresentationTheme, CGFloat, Bool)?
|
||||
var arguments: (Peer?, Int64?, EngineMessageHistoryThread.Info?, PresentationTheme, CGFloat, Bool, CGFloat)?
|
||||
var item: PeerInfoAvatarListItem?
|
||||
|
||||
var itemsUpdated: (([PeerInfoAvatarListItem]) -> Void)?
|
||||
@ -1233,14 +1247,14 @@ final class PeerInfoAvatarListNode: ASDisplayNode {
|
||||
if let strongSelf = self {
|
||||
strongSelf.item = items.first
|
||||
strongSelf.itemsUpdated?(items)
|
||||
if let (peer, threadId, threadInfo, theme, avatarSize, isExpanded) = strongSelf.arguments {
|
||||
strongSelf.avatarContainerNode.update(peer: peer, threadId: threadId, threadInfo: threadInfo, item: strongSelf.item, theme: theme, avatarSize: avatarSize, isExpanded: isExpanded, isSettings: strongSelf.isSettings)
|
||||
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, avatarMaskValue: avatarMaskValue, isSettings: strongSelf.isSettings)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
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) {
|
||||
self.arguments = (peer, threadId, threadInfo, theme, avatarSize, isExpanded)
|
||||
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, avatarMaskValue)
|
||||
self.maskNode.isForum = isForum
|
||||
self.pinchSourceNode.update(size: size, transition: transition)
|
||||
self.containerNode.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? {
|
||||
@ -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.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 {
|
||||
@ -3499,9 +3514,8 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
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
|
||||
if maskValue > 0.03 {
|
||||
if avatarMaskValue > 0.03 {
|
||||
self.avatarListNode.bottomCoverNode.isHidden = false
|
||||
self.avatarListNode.topCoverNode.isHidden = false
|
||||
self.avatarListNode.maskNode.backgroundColor = .clear
|
||||
@ -3510,8 +3524,8 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
self.avatarListNode.topCoverNode.isHidden = true
|
||||
self.avatarListNode.maskNode.backgroundColor = .white
|
||||
}
|
||||
self.avatarListNode.topCoverNode.update(maskValue)
|
||||
self.avatarListNode.maskNode.update(maskValue)
|
||||
self.avatarListNode.topCoverNode.update(avatarMaskValue)
|
||||
self.avatarListNode.maskNode.update(avatarMaskValue)
|
||||
|
||||
self.avatarListNode.listContainerNode.topShadowNode.isHidden = !self.isAvatarExpanded
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user