Various fixes

This commit is contained in:
Ilya Laktyushin 2023-07-08 16:35:50 +02:00
parent a84ee0ffd7
commit 52a0f5c811
15 changed files with 316 additions and 41 deletions

View File

@ -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)

View File

@ -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
} }
} }

View File

@ -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)

View File

@ -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 {
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) 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)
}
}

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)
}
}

View File

@ -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
} }

View File

@ -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)

View File

@ -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
} }
} }

View File

@ -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

View File

@ -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