[WIP] Chat Import

This commit is contained in:
Ali 2021-01-23 22:45:41 +04:00
parent 8eaf939a92
commit 22b04a7ffb
37 changed files with 180 additions and 76 deletions

View File

@ -757,6 +757,8 @@ public final class AnimatedStickerNode: ASDisplayNode {
private var canDisplayFirstFrame: Bool = false
private var playbackMode: AnimatedStickerPlaybackMode = .loop
public var stopAtNearestLoop: Bool = false
private let playbackStatus = Promise<AnimatedStickerStatus>()
public var status: Signal<AnimatedStickerStatus, NoError> {
return self.playbackStatus.get()
@ -966,7 +968,13 @@ public final class AnimatedStickerNode: ASDisplayNode {
if frame.isLastFrame {
var stopped = false
var stopNow = false
if case .once = strongSelf.playbackMode {
stopNow = true
} else if strongSelf.stopAtNearestLoop {
stopNow = true
}
if stopNow {
strongSelf.stop()
strongSelf.isPlaying = false
stopped = true
@ -1043,7 +1051,13 @@ public final class AnimatedStickerNode: ASDisplayNode {
if frame.isLastFrame {
var stopped = false
var stopNow = false
if case .once = strongSelf.playbackMode {
stopNow = true
} else if strongSelf.stopAtNearestLoop {
stopNow = true
}
if stopNow {
strongSelf.stop()
strongSelf.isPlaying = false
stopped = true

View File

@ -22,6 +22,7 @@ swift_library(
"//submodules/AnimatedStickerNode:AnimatedStickerNode",
"//submodules/ChatHistoryImportTasks:ChatHistoryImportTasks",
"//submodules/MimeTypes:MimeTypes",
"//submodules/ConfettiEffect:ConfettiEffect",
],
visibility = [
"//visibility:public",

View File

@ -13,6 +13,7 @@ import AnimatedStickerNode
import AppBundle
import ZIPFoundation
import MimeTypes
import ConfettiEffect
public final class ChatImportActivityScreen: ViewController {
private final class Node: ViewControllerTracingNode {
@ -22,6 +23,7 @@ public final class ChatImportActivityScreen: ViewController {
private var presentationData: PresentationData
private let animationNode: AnimatedStickerNode
private let doneAnimationNode: AnimatedStickerNode
private let radialStatus: RadialStatusNode
private let radialCheck: RadialStatusNode
private let radialStatusBackground: ASImageNode
@ -38,6 +40,8 @@ public final class ChatImportActivityScreen: ViewController {
private let totalBytes: Int
private var isDone: Bool = false
private var feedback: HapticFeedback?
init(controller: ChatImportActivityScreen, context: AccountContext, totalBytes: Int) {
self.controller = controller
self.context = context
@ -46,6 +50,8 @@ public final class ChatImportActivityScreen: ViewController {
self.presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
self.animationNode = AnimatedStickerNode()
self.doneAnimationNode = AnimatedStickerNode()
self.doneAnimationNode.isHidden = true
self.radialStatus = RadialStatusNode(backgroundNodeColor: .clear)
self.radialCheck = RadialStatusNode(backgroundNodeColor: .clear)
@ -89,8 +95,19 @@ public final class ChatImportActivityScreen: ViewController {
self.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(path: path), width: 170 * 2, height: 170 * 2, playbackMode: .loop, mode: .direct(cachePathPrefix: nil))
self.animationNode.visibility = true
}
if let path = getAppBundle().path(forResource: "HistoryImportDone", ofType: "tgs") {
self.doneAnimationNode.setup(source: AnimatedStickerNodeLocalFileSource(path: path), width: 170 * 2, height: 170 * 2, playbackMode: .once, mode: .direct(cachePathPrefix: nil))
self.doneAnimationNode.started = { [weak self] in
guard let strongSelf = self else {
return
}
strongSelf.animationNode.isHidden = true
}
self.doneAnimationNode.visibility = false
}
self.addSubnode(self.animationNode)
self.addSubnode(self.doneAnimationNode)
self.addSubnode(self.radialStatusBackground)
self.addSubnode(self.radialStatus)
self.addSubnode(self.radialCheck)
@ -112,6 +129,15 @@ public final class ChatImportActivityScreen: ViewController {
}
}
}
self.animationNode.completed = { [weak self] stopped in
guard let strongSelf = self, stopped else {
return
}
strongSelf.animationNode.visibility = false
strongSelf.doneAnimationNode.visibility = true
strongSelf.doneAnimationNode.isHidden = false
}
}
@objc private func statusButtonPressed() {
@ -119,6 +145,7 @@ public final class ChatImportActivityScreen: ViewController {
}
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationHeight: CGFloat, transition: ContainedViewLayoutTransition) {
let isFirstLayout = self.validLayout == nil
self.validLayout = (layout, navigationHeight)
//TODO:localize
@ -156,11 +183,14 @@ public final class ChatImportActivityScreen: ViewController {
}
transition.updateAlpha(node: self.animationNode, alpha: hideIcon ? 0.0 : 1.0)
transition.updateAlpha(node: self.doneAnimationNode, alpha: hideIcon ? 0.0 : 1.0)
let contentOriginY = navigationHeight + floor((layout.size.height - contentHeight) / 2.0)
self.animationNode.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - iconSize.width) / 2.0), y: contentOriginY), size: iconSize)
self.animationNode.updateLayout(size: iconSize)
self.doneAnimationNode.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - iconSize.width) / 2.0), y: contentOriginY), size: iconSize)
self.doneAnimationNode.updateLayout(size: iconSize)
self.radialStatus.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - radialStatusSize.width) / 2.0), y: hideIcon ? contentOriginY : (contentOriginY + iconSize.height + maxIconStatusSpacing)), size: radialStatusSize)
let checkSize: CGFloat = 130.0
@ -184,17 +214,22 @@ public final class ChatImportActivityScreen: ViewController {
self.statusButtonText.isHidden = !self.isDone
self.statusButton.isHidden = !self.isDone
self.progressText.isHidden = self.isDone
if isFirstLayout {
self.updateProgress(totalProgress: self.totalProgress, isDone: self.isDone, animated: false)
}
}
func updateProgress(totalProgress: CGFloat, isDone: Bool, animated: Bool) {
self.totalProgress = totalProgress
let wasDone = self.isDone
self.isDone = isDone
if let (layout, navigationHeight) = self.validLayout {
self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .immediate)
self.radialStatus.transitionToState(.progress(color: self.presentationData.theme.list.itemAccentColor, lineWidth: 6.0, value: max(0.02, self.totalProgress), cancelEnabled: false), animated: animated, synchronous: true, completion: {})
self.radialStatus.transitionToState(.progress(color: self.presentationData.theme.list.itemAccentColor, lineWidth: 6.0, value: max(0.02, self.totalProgress), cancelEnabled: false, animateRotation: false), animated: animated, synchronous: true, completion: {})
if isDone {
self.radialCheck.transitionToState(.progress(color: .clear, lineWidth: 6.0, value: self.totalProgress, cancelEnabled: false), animated: false, synchronous: true, completion: {})
self.radialCheck.transitionToState(.progress(color: .clear, lineWidth: 6.0, value: self.totalProgress, cancelEnabled: false, animateRotation: false), animated: false, synchronous: true, completion: {})
self.radialCheck.transitionToState(.check(self.presentationData.theme.list.itemAccentColor), animated: animated, synchronous: true, completion: {})
self.radialStatus.layer.animateScale(from: 1.0, to: 1.05, duration: 0.07, delay: 0.0, timingFunction: CAMediaTimingFunctionName.linear.rawValue, removeOnCompletion: false, additive: false, completion: { [weak self] _ in
guard let strongSelf = self else {
@ -216,6 +251,17 @@ public final class ChatImportActivityScreen: ViewController {
transition = .immediate
}
transition.updateAlpha(node: self.radialStatusText, alpha: 0.0)
if !wasDone {
self.view.addSubview(ConfettiView(frame: self.view.bounds))
if self.feedback == nil {
self.feedback = HapticFeedback()
}
self.feedback?.success()
self.animationNode.stopAtNearestLoop = true
}
}
}
}

View File

@ -234,7 +234,7 @@ private final class VisualMediaItemNode: ASDisplayNode {
switch status {
case let .Fetching(_, progress):
let adjustedProgress = max(progress, 0.027)
statusState = .progress(color: .white, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true)
statusState = .progress(color: .white, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true, animateRotation: true)
case .Local:
statusState = .none
case .Remote:

View File

@ -459,14 +459,14 @@ private class ChatListStatusProgressNode: ChatListStatusContentNode {
super.init()
self.statusNode.transitionToState(.progress(color: color, lineWidth: 1.0, value: progress, cancelEnabled: false))
self.statusNode.transitionToState(.progress(color: color, lineWidth: 1.0, value: progress, cancelEnabled: false, animateRotation: true))
self.addSubnode(self.statusNode)
}
override func updateWithState(_ state: ChatListStatusNodeState, animated: Bool) {
if case let .progress(color, progress) = state {
self.statusNode.transitionToState(.progress(color: color, lineWidth: 1.0, value: progress, cancelEnabled: false), animated: animated, completion: {})
self.statusNode.transitionToState(.progress(color: color, lineWidth: 1.0, value: progress, cancelEnabled: false, animateRotation: true), animated: animated, completion: {})
}
}

View File

@ -279,7 +279,7 @@ public final class ChatMessageInteractiveMediaBadge: ASDisplayNode {
isCompact = true
originY = -1.0 - UIScreenPixel
case .compactFetching:
state = .progress(color: .white, lineWidth: nil, value: 0.0, cancelEnabled: true)
state = .progress(color: .white, lineWidth: nil, value: 0.0, cancelEnabled: true, animateRotation: true)
isCompact = true
originY = -1.0
}

View File

@ -0,0 +1,16 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "ConfettiEffect",
module_name = "ConfettiEffect",
srcs = glob([
"Sources/**/*.swift",
]),
deps = [
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
"//submodules/Display:Display",
],
visibility = [
"//visibility:public",
],
)

View File

@ -44,13 +44,13 @@ private final class ParticleLayer: CALayer {
}
}
final class ConfettiView: UIView {
public final class ConfettiView: UIView {
private var particles: [ParticleLayer] = []
private var displayLink: ConstantDisplayLinkAnimator?
private var localTime: Float = 0.0
override init(frame: CGRect) {
override public init(frame: CGRect) {
super.init(frame: frame)
self.isUserInteractionEnabled = false
@ -142,7 +142,7 @@ final class ConfettiView: UIView {
self.displayLink?.isPaused = false
}
required init?(coder: NSCoder) {
required public init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

View File

@ -214,10 +214,10 @@ final class ChatAnimationGalleryItemNode: ZoomableContentGalleryItemNode {
strongSelf.statusNode.alpha = 1.0
strongSelf.statusNodeContainer.isUserInteractionEnabled = true
let adjustedProgress = max(progress, 0.027)
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true), completion: {})
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true, animateRotation: true), completion: {})
case .Local:
if let previousStatus = previousStatus, case .Fetching = previousStatus {
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: 1.0, cancelEnabled: true), completion: {
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: 1.0, cancelEnabled: true, animateRotation: true), completion: {
if let strongSelf = self {
strongSelf.statusNode.alpha = 0.0
strongSelf.statusNodeContainer.isUserInteractionEnabled = false

View File

@ -203,10 +203,10 @@ class ChatDocumentGalleryItemNode: ZoomableContentGalleryItemNode, WKNavigationD
strongSelf.statusNode.alpha = 1.0
strongSelf.statusNodeContainer.isUserInteractionEnabled = true
let adjustedProgress = max(progress, 0.027)
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true), completion: {})
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true, animateRotation: true), completion: {})
case .Local:
if let previousStatus = previousStatus, case .Fetching = previousStatus {
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: 1.0, cancelEnabled: true), completion: {
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: 1.0, cancelEnabled: true, animateRotation: true), completion: {
if let strongSelf = self {
strongSelf.statusNode.alpha = 0.0
strongSelf.statusNodeContainer.isUserInteractionEnabled = false

View File

@ -201,10 +201,10 @@ class ChatExternalFileGalleryItemNode: GalleryItemNode {
strongSelf.statusNode.alpha = 1.0
strongSelf.statusNodeContainer.isUserInteractionEnabled = true
let adjustedProgress = max(progress, 0.027)
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true), completion: {})
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true, animateRotation: true), completion: {})
case .Local:
if let previousStatus = previousStatus, case .Fetching = previousStatus {
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: 1.0, cancelEnabled: true), completion: {
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: 1.0, cancelEnabled: true, animateRotation: true), completion: {
if let strongSelf = self {
strongSelf.statusNode.alpha = 0.0
strongSelf.statusNodeContainer.isUserInteractionEnabled = false

View File

@ -426,10 +426,10 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
strongSelf.statusNode.alpha = 1.0
strongSelf.statusNodeContainer.isUserInteractionEnabled = true
let adjustedProgress = max(progress, 0.027)
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true), completion: {})
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true, animateRotation: true), completion: {})
case .Local:
if let previousStatus = previousStatus, case .Fetching = previousStatus {
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: 1.0, cancelEnabled: true), completion: {
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: 1.0, cancelEnabled: true, animateRotation: true), completion: {
if let strongSelf = self {
strongSelf.statusNode.alpha = 0.0
strongSelf.statusNodeContainer.isUserInteractionEnabled = false

View File

@ -723,7 +723,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
var fetching = false
if initialBuffering {
if displayProgress {
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: nil, cancelEnabled: false), animated: false, completion: {})
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: nil, cancelEnabled: false, animateRotation: true), animated: false, completion: {})
} else {
strongSelf.statusNode.transitionToState(.none, animated: false, completion: {})
}
@ -740,7 +740,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
fetching = true
isPaused = true
}
state = .progress(color: .white, lineWidth: nil, value: CGFloat(progress), cancelEnabled: true)
state = .progress(color: .white, lineWidth: nil, value: CGFloat(progress), cancelEnabled: true, animateRotation: true)
default:
break
}

View File

@ -176,7 +176,7 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode {
switch fetchStatus {
case let .Fetching(_, progress):
let adjustedProgress = max(progress, 0.027)
state = .progress(color: .white, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true)
state = .progress(color: .white, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true, animateRotation: true)
case .Remote:
state = .download(.white)
default:

View File

@ -119,7 +119,7 @@ final class InstantPagePlayableVideoNode: ASDisplayNode, InstantPageNode, Galler
switch fetchStatus {
case let .Fetching(_, progress):
let adjustedProgress = max(progress, 0.027)
state = .progress(color: .white, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true)
state = .progress(color: .white, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true, animateRotation: true)
case .Remote:
state = .download(.white)
default:

View File

@ -28,7 +28,7 @@ private final class LegacyDataImportSplashImpl: WindowCoveringView, LegacyDataIm
self.updateLayout(size)
}
}
self.progressNode.transitionToState(.progress(color: self.theme?.list.itemAccentColor ?? UIColor(rgb: 0x007ee5), lineWidth: 2.0, value: CGFloat(max(0.025, self.progress.1)), cancelEnabled: false), animated: false, completion: {})
self.progressNode.transitionToState(.progress(color: self.theme?.list.itemAccentColor ?? UIColor(rgb: 0x007ee5), lineWidth: 2.0, value: CGFloat(max(0.025, self.progress.1)), cancelEnabled: false, animateRotation: true), animated: false, completion: {})
}
}

View File

@ -138,7 +138,7 @@ final class SecureIdValueFormFileItemNode: FormEditableBlockItemNode<SecureIdVal
let progressState: RadialStatusNodeState
if let progress = progress {
progressState = .progress(color: .white, lineWidth: nil, value: progress, cancelEnabled: false)
progressState = .progress(color: .white, lineWidth: nil, value: progress, cancelEnabled: false, animateRotation: true)
} else {
progressState = .none
}

View File

@ -99,9 +99,12 @@ private final class RadialProgressContentSpinnerNode: ASDisplayNode {
let lineWidth: CGFloat?
init(color: UIColor, lineWidth: CGFloat?) {
private let animateRotation: Bool
init(color: UIColor, lineWidth: CGFloat?, animateRotation: Bool) {
self.color = color
self.lineWidth = lineWidth
self.animateRotation = animateRotation
super.init()
@ -159,25 +162,29 @@ private final class RadialProgressContentSpinnerNode: ASDisplayNode {
override func willEnterHierarchy() {
super.willEnterHierarchy()
let basicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
basicAnimation.duration = 1.5
var fromValue = Float.pi + 0.58
if let presentation = self.layer.presentation(), let value = (presentation.value(forKeyPath: "transform.rotation.z") as? NSNumber)?.floatValue {
fromValue = value
if self.animateRotation {
let basicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
basicAnimation.duration = 1.5
var fromValue = Float.pi + 0.58
if let presentation = self.layer.presentation(), let value = (presentation.value(forKeyPath: "transform.rotation.z") as? NSNumber)?.floatValue {
fromValue = value
}
basicAnimation.fromValue = NSNumber(value: fromValue)
basicAnimation.toValue = NSNumber(value: fromValue + Float.pi * 2.0)
basicAnimation.repeatCount = Float.infinity
basicAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
basicAnimation.beginTime = 0.0
self.layer.add(basicAnimation, forKey: "progressRotation")
}
basicAnimation.fromValue = NSNumber(value: fromValue)
basicAnimation.toValue = NSNumber(value: fromValue + Float.pi * 2.0)
basicAnimation.repeatCount = Float.infinity
basicAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
basicAnimation.beginTime = 0.0
self.layer.add(basicAnimation, forKey: "progressRotation")
}
override func didExitHierarchy() {
super.didExitHierarchy()
self.layer.removeAnimation(forKey: "progressRotation")
if self.animateRotation {
self.layer.removeAnimation(forKey: "progressRotation")
}
}
}
@ -258,13 +265,16 @@ final class RadialProgressContentNode: RadialStatusContentNode {
let displayCancel: Bool
var ready: Bool = false
let animateRotation: Bool
private var enqueuedReadyForTransition: (() -> Void)?
init(color: UIColor, lineWidth: CGFloat?, displayCancel: Bool) {
init(color: UIColor, lineWidth: CGFloat?, displayCancel: Bool, animateRotation: Bool) {
self.color = color
self.displayCancel = displayCancel
self.animateRotation = animateRotation
self.spinnerNode = RadialProgressContentSpinnerNode(color: color, lineWidth: lineWidth)
self.spinnerNode = RadialProgressContentSpinnerNode(color: color, lineWidth: lineWidth, animateRotation: animateRotation)
self.cancelNode = RadialProgressContentCancelNode(color: color, displayCancel: displayCancel)
super.init()

View File

@ -7,7 +7,7 @@ public enum RadialStatusNodeState: Equatable {
case download(UIColor)
case play(UIColor)
case pause(UIColor)
case progress(color: UIColor, lineWidth: CGFloat?, value: CGFloat?, cancelEnabled: Bool)
case progress(color: UIColor, lineWidth: CGFloat?, value: CGFloat?, cancelEnabled: Bool, animateRotation: Bool)
case cloudProgress(color: UIColor, strokeBackgroundColor: UIColor, lineWidth: CGFloat, value: CGFloat?)
case check(UIColor)
case customIcon(UIImage)
@ -39,8 +39,8 @@ public enum RadialStatusNodeState: Equatable {
} else {
return false
}
case let .progress(lhsColor, lhsLineWidth, lhsValue, lhsCancelEnabled):
if case let .progress(rhsColor, rhsLineWidth, rhsValue, rhsCancelEnabled) = rhs, lhsColor.isEqual(rhsColor), lhsValue == rhsValue, lhsLineWidth == rhsLineWidth, lhsCancelEnabled == rhsCancelEnabled {
case let .progress(lhsColor, lhsLineWidth, lhsValue, lhsCancelEnabled, lhsAnimateRotation):
if case let .progress(rhsColor, rhsLineWidth, rhsValue, rhsCancelEnabled, rhsAnimateRotation) = rhs, lhsColor.isEqual(rhsColor), lhsValue == rhsValue, lhsLineWidth == rhsLineWidth, lhsCancelEnabled == rhsCancelEnabled, lhsAnimateRotation == rhsAnimateRotation {
return true
} else {
return false
@ -98,8 +98,8 @@ public enum RadialStatusNodeState: Equatable {
} else {
return false
}
case let .progress(lhsColor, lhsLineWidth, lhsValue, lhsCancelEnabled):
if case let .progress(rhsColor, rhsLineWidth, rhsValue, rhsCancelEnabled) = rhs, lhsColor.isEqual(rhsColor), lhsValue == rhsValue, lhsLineWidth == rhsLineWidth, lhsCancelEnabled == rhsCancelEnabled {
case let .progress(lhsColor, lhsLineWidth, lhsValue, lhsCancelEnabled, lhsAnimateRotation):
if case let .progress(rhsColor, rhsLineWidth, rhsValue, rhsCancelEnabled, rhsAnimateRotation) = rhs, lhsColor.isEqual(rhsColor), lhsValue == rhsValue, lhsLineWidth == rhsLineWidth, lhsCancelEnabled == rhsCancelEnabled, lhsAnimateRotation == rhsAnimateRotation {
return true
} else {
return false
@ -154,15 +154,15 @@ public enum RadialStatusNodeState: Equatable {
return RadialStatusIconContentNode(icon: .custom(image), synchronous: synchronous)
case let .check(color):
return RadialCheckContentNode(color: color)
case let .progress(color, lineWidth, value, cancelEnabled):
if let current = current as? RadialProgressContentNode, current.displayCancel == cancelEnabled {
case let .progress(color, lineWidth, value, cancelEnabled, animateRotation):
if let current = current as? RadialProgressContentNode, current.displayCancel == cancelEnabled, current.animateRotation == animateRotation {
if !current.color.isEqual(color) {
current.color = color
}
current.progress = value
return current
} else {
let node = RadialProgressContentNode(color: color, lineWidth: lineWidth, displayCancel: cancelEnabled)
let node = RadialProgressContentNode(color: color, lineWidth: lineWidth, displayCancel: cancelEnabled, animateRotation: animateRotation)
node.progress = value
return node
}

View File

@ -501,12 +501,12 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
switch status {
case let .Fetching(_, progress):
let adjustedProgress = max(progress, 0.027)
state = .progress(color: statusForegroundColor, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: false)
state = .progress(color: statusForegroundColor, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: false, animateRotation: true)
case .Local:
state = .none
local = true
case .Remote:
state = .progress(color: statusForegroundColor, lineWidth: nil, value: 0.027, cancelEnabled: false)
state = .progress(color: statusForegroundColor, lineWidth: nil, value: 0.027, cancelEnabled: false, animateRotation: true)
}
strongSelf.statusNode.transitionToState(state, completion: {})

View File

@ -31,11 +31,11 @@ public final class ShareLoadingContainerNode: ASDisplayNode, ShareContentContain
case let .progress(value):
self.activityIndicator.isHidden = true
self.statusNode.isHidden = false
self.statusNode.transitionToState(.progress(color: self.theme.actionSheet.controlAccentColor, lineWidth: 2.0, value: max(0.12, CGFloat(value)), cancelEnabled: false), completion: {})
self.statusNode.transitionToState(.progress(color: self.theme.actionSheet.controlAccentColor, lineWidth: 2.0, value: max(0.12, CGFloat(value)), cancelEnabled: false, animateRotation: true), completion: {})
case .done:
self.activityIndicator.isHidden = true
self.statusNode.isHidden = false
self.statusNode.transitionToState(.progress(color: self.theme.actionSheet.controlAccentColor, lineWidth: 2.0, value: 1.0, cancelEnabled: false), completion: {})
self.statusNode.transitionToState(.progress(color: self.theme.actionSheet.controlAccentColor, lineWidth: 2.0, value: 1.0, cancelEnabled: false, animateRotation: true), completion: {})
self.doneStatusNode.transitionToState(.check(self.theme.actionSheet.controlAccentColor), completion: {})
}
}
@ -52,7 +52,7 @@ public final class ShareLoadingContainerNode: ASDisplayNode, ShareContentContain
self.addSubnode(self.activityIndicator)
self.addSubnode(self.statusNode)
self.addSubnode(self.doneStatusNode)
self.doneStatusNode.transitionToState(.progress(color: self.theme.actionSheet.controlAccentColor, lineWidth: 2.0, value: 0.0, cancelEnabled: false), completion: {})
self.doneStatusNode.transitionToState(.progress(color: self.theme.actionSheet.controlAccentColor, lineWidth: 2.0, value: 0.0, cancelEnabled: false, animateRotation: true), completion: {})
}
public func activate() {

View File

@ -217,6 +217,7 @@ swift_library(
"//submodules/ChatImportUI:ChatImportUI",
"//submodules/ChatHistoryImportTasks:ChatHistoryImportTasks",
"//submodules/DatePickerNode:DatePickerNode",
"//submodules/ConfettiEffect:ConfettiEffect",
],
visibility = [
"//visibility:public",

View File

@ -15,6 +15,7 @@ import ReactionSelectionNode
import TelegramUniversalVideoContent
import ChatInterfaceState
import FastBlur
import ConfettiEffect
final class VideoNavigationControllerDropContentItem: NavigationControllerDropContentItem {
let itemNode: OverlayMediaItemNode

View File

@ -335,7 +335,7 @@ final class ChatMessageCommentFooterContentNode: ChatMessageBubbleContentNode {
transition.updateFrameAdditive(node: statusNode, frame: statusFrame)
}
statusNode.transitionToState(.progress(color: messageTheme.accentTextColor, lineWidth: 1.5, value: nil, cancelEnabled: false), animated: false, synchronous: false, completion: {})
statusNode.transitionToState(.progress(color: messageTheme.accentTextColor, lineWidth: 1.5, value: nil, cancelEnabled: false, animateRotation: true), animated: false, synchronous: false, completion: {})
} else {
strongSelf.arrowNode.isHidden = false
if let statusNode = strongSelf.statusNode {

View File

@ -593,13 +593,13 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
case let .Fetching(_, progress):
if let isBuffering = isBuffering {
if isBuffering {
state = .progress(color: messageTheme.mediaOverlayControlColors.foregroundColor, lineWidth: nil, value: nil, cancelEnabled: true)
state = .progress(color: messageTheme.mediaOverlayControlColors.foregroundColor, lineWidth: nil, value: nil, cancelEnabled: true, animateRotation: true)
} else {
state = .none
}
} else {
let adjustedProgress = max(progress, 0.027)
state = .progress(color: messageTheme.mediaOverlayControlColors.foregroundColor, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true)
state = .progress(color: messageTheme.mediaOverlayControlColors.foregroundColor, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true, animateRotation: true)
}
case .Local:
if isSecretMedia && self.secretProgressIcon != nil {
@ -620,7 +620,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
isLocal = true
}
if (isBuffering ?? false) && !isLocal {
state = .progress(color: messageTheme.mediaOverlayControlColors.foregroundColor, lineWidth: nil, value: nil, cancelEnabled: true)
state = .progress(color: messageTheme.mediaOverlayControlColors.foregroundColor, lineWidth: nil, value: nil, cancelEnabled: true, animateRotation: true)
} else {
state = .none
}

View File

@ -1036,7 +1036,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
}
var animated: Bool = animated
if let updatingMedia = attributes.updatingMedia, case .update = updatingMedia.media {
state = .progress(color: messageTheme.mediaOverlayControlColors.foregroundColor, lineWidth: nil, value: CGFloat(updatingMedia.progress), cancelEnabled: true)
state = .progress(color: messageTheme.mediaOverlayControlColors.foregroundColor, lineWidth: nil, value: CGFloat(updatingMedia.progress), cancelEnabled: true, animateRotation: true)
} else if var fetchStatus = self.fetchStatus {
var playerPosition: Int32?
var playerDuration: Int32 = 0
@ -1087,7 +1087,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
if adjustedProgress.isEqual(to: 1.0), case .unconstrained = sizeCalculation, (message.flags.contains(.Unsent) || wasCheck) {
state = .check(messageTheme.mediaOverlayControlColors.foregroundColor)
} else {
state = .progress(color: messageTheme.mediaOverlayControlColors.foregroundColor, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true)
state = .progress(color: messageTheme.mediaOverlayControlColors.foregroundColor, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true, animateRotation: true)
}
if let file = self.media as? TelegramMediaFile {

View File

@ -216,7 +216,7 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
transition.updateSublayerTransformScale(node: strongSelf.buttonsContainer, scale: 0.1)
if let theme = strongSelf.theme {
strongSelf.activityIndicator.transitionToState(.progress(color: theme.chat.inputPanel.panelControlAccentColor, lineWidth: nil, value: nil, cancelEnabled: false), animated: false, completion: {
strongSelf.activityIndicator.transitionToState(.progress(color: theme.chat.inputPanel.panelControlAccentColor, lineWidth: nil, value: nil, cancelEnabled: false, animateRotation: true), animated: false, completion: {
})
}
}

View File

@ -50,7 +50,7 @@ final class EditAccessoryPanelNode: AccessoryPanelNode {
strongSelf.statusNode.transitionToState(.none, completion: {})
} else {
strongSelf.activityIndicator.isHidden = true
strongSelf.statusNode.transitionToState(.progress(color: strongSelf.theme.chat.inputPanel.panelControlAccentColor, lineWidth: nil, value: CGFloat(value), cancelEnabled: false), completion: {})
strongSelf.statusNode.transitionToState(.progress(color: strongSelf.theme.chat.inputPanel.panelControlAccentColor, lineWidth: nil, value: CGFloat(value), cancelEnabled: false, animateRotation: true), completion: {})
}
} else {
strongSelf.activityIndicator.isHidden = true

View File

@ -248,7 +248,7 @@ final class GridMessageItemNode: GridItemNode {
switch status {
case let .Fetching(_, progress):
let adjustedProgress = max(progress, 0.027)
statusState = .progress(color: .white, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true)
statusState = .progress(color: .white, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true, animateRotation: true)
case .Local:
statusState = .none
case .Remote:

View File

@ -460,7 +460,7 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode
switch status {
case let .Fetching(_, progress):
state = .progress(color: statusForegroundColor, lineWidth: nil, value: CGFloat(max(progress, 0.2)), cancelEnabled: false)
state = .progress(color: statusForegroundColor, lineWidth: nil, value: CGFloat(max(progress, 0.2)), cancelEnabled: false, animateRotation: true)
case .Remote:
//state = .download(statusForegroundColor)
state = .none

View File

@ -345,7 +345,7 @@ private final class VisualMediaItemNode: ASDisplayNode {
switch status {
case let .Fetching(_, progress):
let adjustedProgress = max(progress, 0.027)
statusState = .progress(color: .white, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true)
statusState = .progress(color: .white, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true, animateRotation: true)
case .Local:
statusState = .none
case .Remote:

View File

@ -287,10 +287,10 @@ final class PeerInfoAvatarListItemNode: ASDisplayNode {
}
if isLoading, let progress = progress {
strongSelf.hasProgress = true
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: CGFloat(max(0.027, progress)), cancelEnabled: false), completion: {})
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: CGFloat(max(0.027, progress)), cancelEnabled: false, animateRotation: true), completion: {})
} else if strongSelf.hasProgress {
strongSelf.hasProgress = false
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: 1.0, cancelEnabled: false), completion: { [weak self] in
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: 1.0, cancelEnabled: false, animateRotation: true), completion: { [weak self] in
guard let strongSelf = self else {
return
}
@ -1517,7 +1517,7 @@ final class PeerInfoEditingAvatarOverlayNode: ASDisplayNode {
if let updatingAvatar = updatingAvatar {
overlayHidden = false
self.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: max(0.027, uploadProgress ?? 0.0), cancelEnabled: true))
self.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: max(0.027, uploadProgress ?? 0.0), cancelEnabled: true, animateRotation: true))
if case let .image(representation) = updatingAvatar {
if representation != self.currentRepresentation {

View File

@ -22,6 +22,7 @@ import OverlayStatusController
import PresentationDataUtils
import ChatImportUI
import ZIPFoundation
import ActivityIndicator
private let inForeground = ValuePromise<Bool>(false, ignoreRepeated: true)
@ -462,10 +463,10 @@ public class ShareRootControllerImpl {
if let mainFile = mainFile, let mainFileText = try? String(contentsOf: URL(fileURLWithPath: mainFile.path)) {
let mainFileHeader: String
if mainFileText.count < 1000 {
if mainFileText.count < 2000 {
mainFileHeader = mainFileText
} else {
mainFileHeader = String(mainFileText[mainFileText.startIndex ..< mainFileText.index(mainFileText.startIndex, offsetBy: 1000)])
mainFileHeader = String(mainFileText[mainFileText.startIndex ..< mainFileText.index(mainFileText.startIndex, offsetBy: 2000)])
}
final class TempController: ViewController {
@ -476,11 +477,16 @@ public class ShareRootControllerImpl {
}
}
private let activityIndicator: ActivityIndicator
init(context: AccountContext) {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.activityIndicator = ActivityIndicator(type: .custom(presentationData.theme.list.itemAccentColor, 22.0, 1.0, false))
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: presentationData))
//TODO:localize
self.title = "Import Chat"
self.navigationItem.setLeftBarButton(UIBarButtonItem(title: presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed)), animated: false)
}
@ -492,6 +498,19 @@ public class ShareRootControllerImpl {
@objc private func cancelPressed() {
//self?.getExtensionContext()?.completeRequest(returningItems: nil, completionHandler: nil)
}
override func displayNodeDidLoad() {
super.displayNodeDidLoad()
self.displayNode.addSubnode(self.activityIndicator)
}
override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
super.containerLayoutUpdated(layout, transition: transition)
let indicatorSize = self.activityIndicator.measure(CGSize(width: 100.0, height: 100.0))
transition.updateFrame(node: self.activityIndicator, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - indicatorSize.width) / 2.0), y: floor((layout.size.height - indicatorSize.height - 50.0) / 2.0)), size: indicatorSize))
}
}
let presentationData = internalContext.sharedContext.currentPresentationData.with { $0 }
@ -620,10 +639,8 @@ public class ShareRootControllerImpl {
}
navigationController.viewControllers = [controller]
strongSelf.mainWindow?.present(navigationController, on: .root)
case let .privateChat(title):
let presentationData = internalContext.sharedContext.currentPresentationData.with { $0 }
let navigationController = NavigationController(mode: .single, theme: NavigationControllerTheme(presentationTheme: presentationData.theme))
//TODO:localize
var attemptSelectionImpl: ((Peer) -> Void)?
@ -684,7 +701,6 @@ public class ShareRootControllerImpl {
}
navigationController.viewControllers = [controller]
strongSelf.mainWindow?.present(navigationController, on: .root)
case let .unknown(peerTitle):
//TODO:localize
var attemptSelectionImpl: ((Peer) -> Void)?
@ -839,7 +855,6 @@ public class ShareRootControllerImpl {
}
navigationController.viewControllers = [controller]
strongSelf.mainWindow?.present(navigationController, on: .root)
}
}, error: { _ in
beginShare()

View File

@ -364,7 +364,7 @@ final class VerticalListContextResultsChatInputPanelItemNode: ListViewItemNode {
switch status {
case let .Fetching(_, progress):
state = RadialStatusNodeState.progress(color: statusForegroundColor, lineWidth: nil, value: CGFloat(max(progress, 0.2)), cancelEnabled: false)
state = RadialStatusNodeState.progress(color: statusForegroundColor, lineWidth: nil, value: CGFloat(max(progress, 0.2)), cancelEnabled: false, animateRotation: true)
case .Remote:
state = .download(statusForegroundColor)
case .Local:

View File

@ -188,7 +188,7 @@ final class OverlayVideoDecoration: UniversalVideoDecoration {
return
}
if let status = status, case .buffering = status.status {
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: nil, cancelEnabled: false))
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: nil, cancelEnabled: false, animateRotation: true))
} else {
strongSelf.statusNode.transitionToState(.none)
}

View File

@ -227,7 +227,7 @@ final class WebSearchVideoGalleryItemNode: ZoomableContentGalleryItemNode {
var fetching = false
if initialBuffering {
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: nil, cancelEnabled: false), animated: false, completion: {})
strongSelf.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: nil, cancelEnabled: false, animateRotation: true), animated: false, completion: {})
} else {
var state: RadialStatusNodeState = .none
@ -237,7 +237,7 @@ final class WebSearchVideoGalleryItemNode: ZoomableContentGalleryItemNode {
case let .Fetching(_, progress):
fetching = true
isPaused = true
state = .progress(color: .white, lineWidth: nil, value: CGFloat(max(0.027, progress)), cancelEnabled: false)
state = .progress(color: .white, lineWidth: nil, value: CGFloat(max(0.027, progress)), cancelEnabled: false, animateRotation: true)
default:
break
}