Various Improvements

This commit is contained in:
Ilya Laktyushin 2022-01-25 19:59:22 +03:00
parent 7ccd563199
commit 87c6d4fdfe
19 changed files with 434 additions and 81 deletions

View File

@ -7250,3 +7250,6 @@ Sorry for the inconvenience.";
"Group.Members.Contacts" = "CONTACTS IN THIS GROUP";
"Group.Members.Other" = "OTHERS MEMBERS";
"SharedMedia.CommonGroupCount_1" = "%@ group in common";
"SharedMedia.CommonGroupCount_any" = "%@ groups in common";

View File

@ -679,7 +679,20 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
Queue.mainQueue().after(1.0) {
var firstItem: StickerPackItem?
if let firstStickerItem = firstStickerItem, let resource = firstStickerItem.resource as? TelegramMediaResource {
firstItem = StickerPackItem(index: ItemCollectionItemIndex(index: 0, id: 0), file: TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: firstStickerItem.mimeType, size: nil, attributes: [.FileName(fileName: ""), .ImageSize(size: firstStickerItem.dimensions)]), indexKeys: [])
var fileAttributes: [TelegramMediaFileAttribute] = []
if firstStickerItem.mimeType == "video/webm" {
fileAttributes.append(.FileName(fileName: "sticker.webm"))
fileAttributes.append(.Animated)
fileAttributes.append(.Sticker(displayText: "", packReference: nil, maskData: nil))
} else if firstStickerItem.mimeType == "application/x-tgsticker" {
fileAttributes.append(.FileName(fileName: "sticker.tgs"))
fileAttributes.append(.Animated)
fileAttributes.append(.Sticker(displayText: "", packReference: nil, maskData: nil))
} else {
fileAttributes.append(.FileName(fileName: "sticker.webp"))
}
fileAttributes.append(.ImageSize(size: firstStickerItem.dimensions))
firstItem = StickerPackItem(index: ItemCollectionItemIndex(index: 0, id: 0), file: TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: firstStickerItem.mimeType, size: nil, attributes: fileAttributes), indexKeys: [])
}
strongSelf.presentInGlobalOverlay?(UndoOverlayController(presentationData: strongSelf.presentationData, content: .stickersModified(title: strongSelf.presentationData.strings.StickerPackActionInfo_AddedTitle, text: strongSelf.presentationData.strings.StickerPackActionInfo_AddedText(info.title).string, undo: false, info: info, topItem: firstItem ?? items.first, context: strongSelf.context), elevatedLayout: false, action: { action in
if case .info = action {

View File

@ -25,6 +25,7 @@ swift_library(
"//submodules/AppBundle:AppBundle",
"//submodules/LocationResources:LocationResources",
"//submodules/UndoUI:UndoUI",
"//submodules/Translate:Translate",
],
visibility = [
"//visibility:public",

View File

@ -16,6 +16,7 @@ import OpenInExternalAppUI
import LocationUI
import UndoUI
import ContextUI
import Translate
final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
private weak var controller: InstantPageController?
@ -1020,23 +1021,46 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
coveringRect = coveringRect.union(rects[i])
}
let controller = ContextMenuController(actions: [ContextMenuAction(content: .text(title: self.strings.Conversation_ContextMenuCopy, accessibilityLabel: self.strings.Conversation_ContextMenuCopy), action: {
UIPasteboard.general.string = text
}), ContextMenuAction(content: .text(title: self.strings.Conversation_ContextMenuShare, accessibilityLabel: self.strings.Conversation_ContextMenuShare), action: { [weak self] in
if let strongSelf = self, let webPage = strongSelf.webPage, case let .Loaded(content) = webPage.content {
strongSelf.present(ShareController(context: strongSelf.context, subject: .quote(text: text, url: content.url)), nil)
}
})])
controller.dismissed = { [weak self] in
self?.updateTextSelectionRects([], text: nil)
}
self.present(controller, ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self] in
if let strongSelf = self {
return (strongSelf.scrollNode, coveringRect.insetBy(dx: -3.0, dy: -3.0), strongSelf, strongSelf.bounds)
let context = self.context
let strings = self.strings
let _ = (context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.translationSettings])
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self] sharedData in
let translationSettings: TranslationSettings
if let current = sharedData.entries[ApplicationSpecificSharedDataKeys.translationSettings]?.get(TranslationSettings.self) {
translationSettings = current
} else {
return nil
translationSettings = TranslationSettings.defaultSettings
}
}))
var actions: [ContextMenuAction] = [ContextMenuAction(content: .text(title: strings.Conversation_ContextMenuCopy, accessibilityLabel: strings.Conversation_ContextMenuCopy), action: {
UIPasteboard.general.string = text
}), ContextMenuAction(content: .text(title: strings.Conversation_ContextMenuShare, accessibilityLabel: strings.Conversation_ContextMenuShare), action: { [weak self] in
if let strongSelf = self, let webPage = strongSelf.webPage, case let .Loaded(content) = webPage.content {
strongSelf.present(ShareController(context: strongSelf.context, subject: .quote(text: text, url: content.url)), nil)
}
})]
if canTranslateText(context: context, text: text, showTranslate: translationSettings.showTranslate, ignoredLanguages: translationSettings.ignoredLanguages) {
actions.append(ContextMenuAction(content: .text(title: strings.Conversation_ContextMenuTranslate, accessibilityLabel: strings.Conversation_ContextMenuTranslate), action: {
translateText(context: context, text: text)
}))
}
let controller = ContextMenuController(actions: actions)
controller.dismissed = { [weak self] in
self?.updateTextSelectionRects([], text: nil)
}
self?.present(controller, ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self] in
if let strongSelf = self {
return (strongSelf.scrollNode, coveringRect.insetBy(dx: -3.0, dy: -3.0), strongSelf, strongSelf.bounds)
} else {
return nil
}
}))
})
textSelectionNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.18)
} else if let textSelectionNode = self.textSelectionNode {
self.textSelectionNode = nil

View File

@ -196,7 +196,9 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
let isVisible = self.visibility != .none
if wasVisible != isVisible {
self.animationNode?.visibility = isVisible && (self.layoutParams?.0.playAnimatedStickers ?? true)
let visibility = isVisible && (self.layoutParams?.0.playAnimatedStickers ?? true)
self.videoNode?.update(isPlaying: visibility)
self.animationNode?.visibility = visibility
}
}
}

View File

@ -354,7 +354,8 @@ public final class SparseDiscreteScrollingArea: ASDisplayNode {
backgroundColor: theme.list.itemBlocksBackgroundColor,
shadowColor: .black,
foregroundColor: theme.list.itemPrimaryTextColor,
dateString: "Date"
dateString: "Date",
previousDateString: nil
)),
environment: {},
containerSize: containerSize

View File

@ -555,22 +555,170 @@ private final class ShadowRoundedRectangle: Component {
}
}
public final class RollingText: Component {
private final class MeasureState: Equatable {
let attributedText: NSAttributedString
let availableSize: CGSize
let size: CGSize
init(attributedText: NSAttributedString, availableSize: CGSize, size: CGSize) {
self.attributedText = attributedText
self.availableSize = availableSize
self.size = size
}
static func ==(lhs: MeasureState, rhs: MeasureState) -> Bool {
if !lhs.attributedText.isEqual(rhs.attributedText) {
return false
}
if lhs.availableSize != rhs.availableSize {
return false
}
if lhs.size != rhs.size {
return false
}
return true
}
}
public final class View: UIView {
private var measureState: MeasureState?
private var containerView: UIImageView
private var snapshotView: UIView?
public override init(frame: CGRect) {
self.containerView = UIImageView()
super.init(frame: frame)
self.addSubview(self.containerView)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public func update(component: RollingText, availableSize: CGSize) -> CGSize {
let attributedText = NSAttributedString(string: component.text, attributes: [
NSAttributedString.Key.font: component.font,
NSAttributedString.Key.foregroundColor: component.color
])
if let measureState = self.measureState {
if measureState.attributedText.isEqual(to: attributedText) && measureState.availableSize == availableSize {
return measureState.size
}
}
var boundingRect = attributedText.boundingRect(with: availableSize, options: .usesLineFragmentOrigin, context: nil)
boundingRect.size.width = ceil(boundingRect.size.width)
boundingRect.size.height = ceil(boundingRect.size.height)
if let animation = component.animation {
if let snapshotView = self.snapshotView {
self.snapshotView = nil
snapshotView.removeFromSuperview()
self.containerView.layer.removeAnimation(forKey: "opacity")
}
if let snapshotView = self.containerView.snapshotView(afterScreenUpdates: true) {
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
snapshotView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: animation ? 12.0 : -12.0), duration: 0.2, removeOnCompletion: false, additive: true, completion: { [weak self, weak snapshotView] _ in
self?.snapshotView = nil
snapshotView?.removeFromSuperview()
})
snapshotView.frame = CGRect(origin: CGPoint(x: boundingRect.width - snapshotView.frame.width, y: 0.0), size: snapshotView.frame.size)
self.addSubview(snapshotView)
self.snapshotView = snapshotView
self.containerView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
self.containerView.layer.animatePosition(from: animation ? CGPoint(x: 0.0, y: -12.0) : CGPoint(x: 0.0, y: 12.0), to: CGPoint(), duration: 0.2, additive: true)
}
}
self.containerView.frame = CGRect(origin: CGPoint(), size: boundingRect.size)
let measureState = MeasureState(attributedText: attributedText, availableSize: availableSize, size: boundingRect.size)
if #available(iOS 10.0, *) {
let renderer = UIGraphicsImageRenderer(bounds: CGRect(origin: CGPoint(), size: measureState.size))
let image = renderer.image { context in
UIGraphicsPushContext(context.cgContext)
measureState.attributedText.draw(at: CGPoint())
UIGraphicsPopContext()
}
self.containerView.image = image
} else {
UIGraphicsBeginImageContextWithOptions(measureState.size, false, 0.0)
measureState.attributedText.draw(at: CGPoint())
self.containerView.image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
self.measureState = measureState
return boundingRect.size
}
}
public let text: String
public let font: UIFont
public let color: UIColor
public let animation: Bool?
public init(text: String, font: UIFont, color: UIColor, animation: Bool?) {
self.text = text
self.font = font
self.color = color
self.animation = animation
}
public static func ==(lhs: RollingText, rhs: RollingText) -> Bool {
if lhs.text != rhs.text {
return false
}
if !lhs.font.isEqual(rhs.font) {
return false
}
if !lhs.color.isEqual(rhs.color) {
return false
}
if lhs.animation != rhs.animation {
return false
}
return true
}
public func makeView() -> View {
return View()
}
public func update(view: View, availableSize: CGSize, environment: Environment<Empty>, transition: Transition) -> CGSize {
return view.update(component: self, availableSize: availableSize)
}
}
final class SparseItemGridScrollingIndicatorComponent: CombinedComponent {
let backgroundColor: UIColor
let shadowColor: UIColor
let foregroundColor: UIColor
let dateString: String
let previousDateString: String?
init(
backgroundColor: UIColor,
shadowColor: UIColor,
foregroundColor: UIColor,
dateString: String
dateString: String,
previousDateString: String?
) {
self.backgroundColor = backgroundColor
self.shadowColor = shadowColor
self.foregroundColor = foregroundColor
self.dateString = dateString
self.previousDateString = previousDateString
}
static func ==(lhs: SparseItemGridScrollingIndicatorComponent, rhs: SparseItemGridScrollingIndicatorComponent) -> Bool {
@ -586,19 +734,90 @@ final class SparseItemGridScrollingIndicatorComponent: CombinedComponent {
if lhs.dateString != rhs.dateString {
return false
}
if lhs.previousDateString != rhs.previousDateString {
return false
}
return true
}
static var body: Body {
let rect = Child(ShadowRoundedRectangle.self)
let text = Child(Text.self)
let textMonth = Child(RollingText.self)
let textYear = Child(RollingText.self)
return { context in
let text = text.update(
component: Text(
text: context.component.dateString,
font: Font.medium(13.0),
color: context.component.foregroundColor
let components = context.component.dateString.components(separatedBy: " ")
let month = components.first ?? ""
let year = components.last ?? ""
var monthAnimation: Bool?
var yearAnimation: Bool?
if let previousDateString = context.component.previousDateString {
func monthValue(_ string: String) -> Int {
switch string {
case "January":
return 1
case "February":
return 2
case "March":
return 3
case "April":
return 4
case "May":
return 5
case "June":
return 6
case "July":
return 7
case "August":
return 8
case "September":
return 9
case "October":
return 10
case "November":
return 11
case "December":
return 12
default:
return 0
}
}
let monValue = monthValue(month)
let yearValue = Int(year) ?? 0
let previousComponents = previousDateString.components(separatedBy: " ")
let previousMonth = previousComponents.first ?? ""
let previousYear = previousComponents.last ?? ""
let previousMonValue = monthValue(previousMonth)
let previousYearValue = Int(previousYear) ?? 0
if yearValue != previousYearValue {
yearAnimation = yearValue > previousYearValue
monthAnimation = yearAnimation
} else if monValue != previousMonValue {
monthAnimation = monValue > previousMonValue
}
}
let textMonth = textMonth.update(
component: RollingText(
text: month,
font: Font.with(size: 13.0, design: .regular, weight: .medium, traits: .monospacedNumbers),
color: context.component.foregroundColor,
animation: monthAnimation
),
availableSize: CGSize(width: 200.0, height: 100.0),
transition: .immediate
)
let textYear = textYear.update(
component: RollingText(
text: year,
font: Font.with(size: 13.0, design: .regular, weight: .medium, traits: .monospacedNumbers),
color: context.component.foregroundColor,
animation: yearAnimation
),
availableSize: CGSize(width: 200.0, height: 100.0),
transition: .immediate
@ -608,7 +827,7 @@ final class SparseItemGridScrollingIndicatorComponent: CombinedComponent {
component: ShadowRoundedRectangle(
color: context.component.backgroundColor
),
availableSize: CGSize(width: text.size.width + 26.0, height: 32.0),
availableSize: CGSize(width: textMonth.size.width + 3.0 + textYear.size.width + 26.0, height: 32.0),
transition: .immediate
)
@ -620,10 +839,16 @@ final class SparseItemGridScrollingIndicatorComponent: CombinedComponent {
context.add(rect
.position(CGPoint(x: rectFrame.midX, y: rectFrame.midY))
)
let offset = CGSize(width: textMonth.size.width + 3.0 + textYear.size.width, height: textMonth.size.height).centered(in: rectFrame)
let textFrame = text.size.centered(in: rectFrame)
context.add(text
.position(CGPoint(x: textFrame.midX, y: textFrame.midY))
let monthTextFrame = textMonth.size.leftCentered(in: rectFrame).offsetBy(dx: offset.minX, dy: 0.0)
let yearTextFrame = textYear.size.leftCentered(in: rectFrame).offsetBy(dx: offset.minX + monthTextFrame.width + 3.0, dy: 0.0)
context.add(textMonth
.position(CGPoint(x: monthTextFrame.midX, y: monthTextFrame.midY))
)
context.add(textYear
.position(CGPoint(x: yearTextFrame.midX, y: yearTextFrame.midY))
)
return rect.size
@ -900,6 +1125,8 @@ public final class SparseItemGridScrollingArea: ASDisplayNode {
self.hapticFeedback.tap()
}
private var dateString: String?
public func update(
containerSize: CGSize,
containerInsets: UIEdgeInsets,
@ -912,6 +1139,8 @@ public final class SparseItemGridScrollingArea: ASDisplayNode {
) {
self.containerSize = containerSize
self.theme = theme
let previousDateString = self.dateString
self.dateString = dateString
if self.dateIndicator.alpha.isZero {
let transition: ContainedViewLayoutTransition = .immediate
@ -928,7 +1157,8 @@ public final class SparseItemGridScrollingArea: ASDisplayNode {
backgroundColor: theme.list.itemBlocksBackgroundColor,
shadowColor: .black,
foregroundColor: theme.list.itemPrimaryTextColor,
dateString: dateString
dateString: dateString,
previousDateString: previousDateString
)),
environment: {},
containerSize: containerSize

View File

@ -482,18 +482,15 @@ public final class TelegramMediaFile: Media, Equatable, Codable {
if self.mimeType == "video/webm" {
return true
}
if let _ = self.fileName, self.mimeType == "video/webm" {
if self.mimeType == "video/webm" {
var hasSticker = false
var hasAnimated = false
for attribute in self.attributes {
if case .Sticker = attribute {
hasSticker = true
}
if case .Animated = attribute {
hasAnimated = true
break
}
}
return hasSticker && hasAnimated
return hasSticker
}
return false
}

View File

@ -48,8 +48,7 @@ func _internal_uploadSticker(account: Account, peer: Peer, resource: MediaResour
case let .progress(progress):
return .single(.progress(progress))
case let .inputFile(file):
var flags: Int32 = 0
flags |= (1 << 4)
let flags: Int32 = 0
var attributes: [Api.DocumentAttribute] = []
attributes.append(.documentAttributeSticker(flags: 0, alt: alt, stickerset: .inputStickerSetEmpty, maskCoords: nil))
attributes.append(.documentAttributeImageSize(w: dimensions.width, h: dimensions.height))
@ -134,8 +133,13 @@ func _internal_createStickerSet(account: Account, title: String, shortName: Stri
}
if resources.count == stickers.count {
var flags: Int32 = 0
if case .animation = type {
flags |= (1 << 1)
switch type {
case .animation:
flags |= (1 << 1)
case .video:
flags |= (1 << 4)
default:
break
}
var inputStickers: [Api.InputStickerSetItem] = []
let stickerDocuments = thumbnail != nil ? resources.dropLast() : resources

View File

@ -239,11 +239,7 @@ final class ChatMediaInputMetaSectionItemNode: ListViewItemNode {
} else {
animatedStickerNode = AnimatedStickerNode()
self.animatedStickerNode = animatedStickerNode
// if let placeholderNode = self.placeholderNode {
// self.scalingNode.insertSubnode(animatedStickerNode, belowSubnode: placeholderNode)
// } else {
self.scalingNode.addSubnode(animatedStickerNode)
// }
self.scalingNode.addSubnode(animatedStickerNode)
animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: account, resource: file.resource), width: 128, height: 128, mode: .cached)
}
animatedStickerNode.visibility = self.visibilityStatus && loopAnimatedStickers

View File

@ -88,6 +88,7 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode
private let imageNodeBackground: ASDisplayNode
private let imageNode: TransformImageNode
private var animationNode: AnimatedStickerNode?
private var videoStickerNode: VideoStickerNode?
private var placeholderNode: StickerShimmerEffectNode?
private var videoLayer: (SoftwareVideoThumbnailNode, SoftwareVideoLayerFrameManager, SampleBufferLayer)?
private var currentImageResource: TelegramMediaResource?
@ -416,28 +417,37 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode
animationNode.removeFromSupernode()
}
if let videoStickerNode = strongSelf.videoStickerNode {
strongSelf.videoStickerNode = nil
videoStickerNode.removeFromSupernode()
}
if let animatedStickerFile = animatedStickerFile {
let animationNode: AnimatedStickerNode
if let currentAnimationNode = strongSelf.animationNode {
animationNode = currentAnimationNode
if animatedStickerFile.isVideoSticker {
} else {
animationNode = AnimatedStickerNode()
animationNode.transform = CATransform3DMakeRotation(CGFloat.pi / 2.0, 0.0, 0.0, 1.0)
animationNode.visibility = true
if let placeholderNode = strongSelf.placeholderNode {
strongSelf.insertSubnode(animationNode, belowSubnode: placeholderNode)
let animationNode: AnimatedStickerNode
if let currentAnimationNode = strongSelf.animationNode {
animationNode = currentAnimationNode
} else {
strongSelf.addSubnode(animationNode)
animationNode = AnimatedStickerNode()
animationNode.transform = CATransform3DMakeRotation(CGFloat.pi / 2.0, 0.0, 0.0, 1.0)
animationNode.visibility = true
if let placeholderNode = strongSelf.placeholderNode {
strongSelf.insertSubnode(animationNode, belowSubnode: placeholderNode)
} else {
strongSelf.addSubnode(animationNode)
}
strongSelf.animationNode = animationNode
}
strongSelf.animationNode = animationNode
animationNode.started = { [weak self] in
self?.imageNode.alpha = 0.0
}
let dimensions = animatedStickerFile.dimensions ?? PixelDimensions(width: 512, height: 512)
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))
strongSelf.fetchDisposable.set(freeMediaFileResourceInteractiveFetched(account: item.account, fileReference: stickerPackFileReference(animatedStickerFile), resource: animatedStickerFile.resource).start())
animationNode.setup(source: AnimatedStickerResourceSource(account: item.account, resource: animatedStickerFile.resource), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), mode: .cached)
}
animationNode.started = { [weak self] in
self?.imageNode.alpha = 0.0
}
let dimensions = animatedStickerFile.dimensions ?? PixelDimensions(width: 512, height: 512)
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))
strongSelf.fetchDisposable.set(freeMediaFileResourceInteractiveFetched(account: item.account, fileReference: stickerPackFileReference(animatedStickerFile), resource: animatedStickerFile.resource).start())
animationNode.setup(source: AnimatedStickerResourceSource(account: item.account, resource: animatedStickerFile.resource), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), mode: .cached)
}
}

View File

@ -132,7 +132,9 @@ final class HorizontalStickerGridItemNode: GridItemNode {
func setup(account: Account, item: HorizontalStickerGridItem) {
if self.currentState == nil || self.currentState!.0 !== account || self.currentState!.1.file.id != item.file.id {
if let dimensions = item.file.dimensions {
if item.file.isAnimatedSticker {
if item.file.isVideoSticker {
} else if item.file.isAnimatedSticker {
let animationNode: AnimatedStickerNode
if let currentAnimationNode = self.animationNode {
animationNode = currentAnimationNode

View File

@ -115,7 +115,9 @@ final class TrendingTopItemNode: ASDisplayNode {
self.file = item.file
self.itemSize = itemSize
if item.file.isAnimatedSticker {
if item.file.isVideoSticker {
} else if item.file.isAnimatedSticker {
let animationNode: AnimatedStickerNode
if let currentAnimationNode = self.animationNode {
animationNode = currentAnimationNode

View File

@ -79,7 +79,15 @@ final class PeerInfoGroupsInCommonPaneNode: ASDisplayNode, PeerInfoPaneNode {
}
var status: Signal<PeerInfoStatusData?, NoError> {
return .single(nil)
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
return self.groupsInCommonContext.state
|> map { state in
if let count = state.count {
return PeerInfoStatusData(text: presentationData.strings.SharedMedia_CommonGroupCount(Int32(count)), isActivity: false)
} else {
return nil
}
}
}
var tabBarOffsetUpdated: ((ContainedViewLayoutTransition) -> Void)?

View File

@ -590,6 +590,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
if availablePanes != nil, groupsInCommon != nil, let cachedData = peerView.cachedData as? CachedUserData {
if cachedData.commonGroupCount != 0 {
availablePanes?.append(.groupsInCommon)
} else if hintGroupInCommon != nil {
availablePanes?.append(.groupsInCommon)
}
} else if hintGroupInCommon != nil {
availablePanes = [.groupsInCommon]

View File

@ -468,6 +468,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat
private(set) var currentPaneKey: PeerInfoPaneKey?
var pendingSwitchToPaneKey: PeerInfoPaneKey?
var expandOnSwitch = false
var currentPane: PeerInfoPaneWrapper? {
if let currentPaneKey = self.currentPaneKey {
@ -550,6 +551,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat
}
} else if strongSelf.pendingSwitchToPaneKey != key {
strongSelf.pendingSwitchToPaneKey = key
strongSelf.expandOnSwitch = true
if let (size, sideInset, bottomInset, visibleHeight, expansionFraction, presentationData, data) = strongSelf.currentParams {
strongSelf.update(size: size, sideInset: sideInset, bottomInset: bottomInset, visibleHeight: visibleHeight, expansionFraction: expansionFraction, presentationData: presentationData, data: data, transition: .animated(duration: 0.4, curve: .spring))
@ -967,7 +969,8 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat
}
}
if let previousCurrentPaneKey = previousCurrentPaneKey, self.currentPaneKey != previousCurrentPaneKey {
self.currentPaneUpdated?(true)
self.currentPaneUpdated?(self.expandOnSwitch)
self.expandOnSwitch = false
}
if updateCurrentPaneStatus {
self.currentPaneStatusPromise.set(self.currentPane?.node.status ?? .single(nil))

View File

@ -156,7 +156,9 @@ final class StickerPaneSearchStickerItemNode: GridItemNode {
self.textNode.attributedText = NSAttributedString(string: code ?? "", font: textFont, textColor: .black)
if let dimensions = stickerItem.file.dimensions {
if stickerItem.file.isAnimatedSticker {
if stickerItem.file.isVideoSticker {
} else if stickerItem.file.isAnimatedSticker {
if self.animationNode == nil {
let animationNode = AnimatedStickerNode()
animationNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.imageNodeTap(_:))))

View File

@ -26,6 +26,7 @@ swift_library(
"//submodules/SlotMachineAnimationNode:SlotMachineAnimationNode",
"//submodules/AvatarNode:AvatarNode",
"//submodules/AccountContext:AccountContext",
"//submodules/SoftwareVideo:SoftwareVideo",
],
visibility = [
"//visibility:public",

View File

@ -4,6 +4,7 @@ import AsyncDisplayKit
import Display
import SwiftSignalKit
import TelegramCore
import Postbox
import TelegramPresentationData
import TextFormat
import Markdown
@ -16,6 +17,7 @@ import AnimationUI
import StickerResources
import AvatarNode
import AccountContext
import SoftwareVideo
final class UndoOverlayControllerNode: ViewControllerTracingNode {
private let elevatedLayout: Bool
@ -26,6 +28,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
private let iconCheckNode: RadialStatusNode?
private let animationNode: AnimationNode?
private var animatedStickerNode: AnimatedStickerNode?
private var videoNode: VideoStickerNode?
private var slotMachineNode: SlotMachineAnimationNode?
private var stillStickerNode: TransformImageNode?
private var stickerImageSize: CGSize?
@ -92,6 +95,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = nil
self.animatedStickerNode = nil
self.videoNode = nil
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(14.0), textColor: .white)
displayUndo = true
self.originalRemainingSeconds = 5
@ -112,6 +116,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.animationNode = AnimationNode(animation: "anim_infotip", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
}
self.animatedStickerNode = nil
self.videoNode = nil
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(14.0), textColor: .white)
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(14.0), textColor: .white)
displayUndo = undo
@ -122,6 +127,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: "anim_archiveswipe", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
self.animatedStickerNode = nil
self.videoNode = nil
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(14.0), textColor: .white)
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(14.0), textColor: .white)
displayUndo = undo
@ -132,6 +138,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: "anim_infotip", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
self.animatedStickerNode = nil
self.videoNode = nil
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(14.0), textColor: .white)
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(14.0), textColor: .white)
displayUndo = undo
@ -142,6 +149,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: isOn ? "anim_autoremove_on" : "anim_autoremove_off", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
self.animatedStickerNode = nil
self.videoNode = nil
if let title = title {
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(14.0), textColor: .white)
}
@ -154,6 +162,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: "anim_success", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
self.animatedStickerNode = nil
self.videoNode = nil
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
@ -168,6 +177,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: "anim_infotip", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
self.animatedStickerNode = nil
self.videoNode = nil
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
@ -182,6 +192,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: "anim_success", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
self.animatedStickerNode = nil
self.videoNode = nil
undoTextColor = UIColor(rgb: 0xff7b74)
@ -200,6 +211,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: "anim_linkcopied", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
self.animatedStickerNode = nil
self.videoNode = nil
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
@ -214,6 +226,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: "anim_banned", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
self.animatedStickerNode = nil
self.videoNode = nil
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
@ -231,6 +244,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = nil
self.animatedStickerNode = nil
self.videoNode = nil
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(14.0), textColor: .white)
displayUndo = false
self.originalRemainingSeconds = 5
@ -240,6 +254,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: "anim_success", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
self.animatedStickerNode = nil
self.videoNode = nil
let formattedString = presentationData.strings.ChatList_AddedToFolderTooltip(chatTitle, folderTitle)
@ -257,7 +272,8 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: "anim_success", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
self.animatedStickerNode = nil
self.videoNode = nil
self.videoNode = nil
let formattedString = presentationData.strings.ChatList_RemovedFromFolderTooltip(chatTitle, folderTitle)
let string = NSMutableAttributedString(attributedString: NSAttributedString(string: formattedString.string, font: Font.regular(14.0), textColor: .white))
@ -274,6 +290,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: "anim_payment", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
self.animatedStickerNode = nil
self.videoNode = nil
let formattedString = presentationData.strings.Checkout_SuccessfulTooltip(currencyValue, itemTitle)
@ -291,6 +308,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: isHidden ? "anim_message_hidepin" : "anim_message_unpin", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
self.animatedStickerNode = nil
self.videoNode = nil
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
@ -325,6 +343,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: "anim_swipereply", colors: [:], scale: 1.0)
self.animatedStickerNode = nil
self.videoNode = nil
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(14.0), textColor: .white)
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(14.0), textColor: .white)
self.textNode.maximumNumberOfLines = 2
@ -342,23 +361,22 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
enum StickerPackThumbnailItem {
case still(TelegramMediaImageRepresentation)
case animated(EngineMediaResource)
case animated(EngineMediaResource, Bool)
}
var thumbnailItem: StickerPackThumbnailItem?
var resourceReference: MediaResourceReference?
if let thumbnail = info.thumbnail {
if info.flags.contains(.isAnimated) {
thumbnailItem = .animated(EngineMediaResource(thumbnail.resource))
resourceReference = MediaResourceReference.stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource)
if info.flags.contains(.isAnimated) || info.flags.contains(.isVideo) {
thumbnailItem = .animated(EngineMediaResource(thumbnail.resource), info.flags.contains(.isVideo))
} else {
thumbnailItem = .still(thumbnail)
resourceReference = MediaResourceReference.stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource)
}
resourceReference = MediaResourceReference.stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource)
} else if let item = topItem {
if item.file.isAnimatedSticker {
thumbnailItem = .animated(EngineMediaResource(item.file.resource))
if item.file.isAnimatedSticker || item.file.isVideoSticker {
thumbnailItem = .animated(EngineMediaResource(item.file.resource), item.file.isVideoSticker)
resourceReference = MediaResourceReference.media(media: .standalone(media: item.file), resource: item.file.resource)
} else if let dimensions = item.file.dimensions, let resource = chatMessageStickerResource(file: item.file, small: true) as? TelegramMediaResource {
thumbnailItem = .still(TelegramMediaImageRepresentation(dimensions: dimensions, resource: resource, progressiveSizes: [], immediateThumbnailData: nil))
@ -378,7 +396,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.stickerImageSize = stillImageSize
updatedImageSignal = chatMessageStickerPackThumbnail(postbox: context.account.postbox, resource: representation.resource)
case let .animated(resource):
case let .animated(resource, _):
self.stickerImageSize = imageBoundingSize
updatedImageSignal = chatMessageStickerPackThumbnail(postbox: context.account.postbox, resource: resource._asResource(), animated: true)
@ -416,10 +434,20 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
switch thumbnailItem {
case .still:
break
case let .animated(resource):
let animatedStickerNode = AnimatedStickerNode()
self.animatedStickerNode = animatedStickerNode
animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: context.account, resource: resource._asResource()), width: 80, height: 80, mode: .cached)
case let .animated(resource, isVideo):
if isVideo {
let videoNode = VideoStickerNode()
self.videoNode = videoNode
if let resource = resource._asResource() as? TelegramMediaResource {
let dummyFile = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 1), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/webm", size: resource.size ?? 1, attributes: [.Video(duration: 1, size: PixelDimensions(width: 100, height: 100), flags: [])])
videoNode.update(account: context.account, fileReference: .standalone(media: dummyFile))
}
} else {
let animatedStickerNode = AnimatedStickerNode()
self.animatedStickerNode = animatedStickerNode
animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: context.account, resource: resource._asResource()), width: 80, height: 80, mode: .cached)
}
}
}
case let .dice(dice, context, text, action):
@ -482,6 +510,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: cancelled ? "anim_proximity_cancelled" : "anim_proximity_set", colors: [:], scale: 0.45)
self.animatedStickerNode = nil
self.videoNode = nil
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
@ -500,6 +529,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = nil
self.animatedStickerNode = nil
self.videoNode = nil
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
@ -517,6 +547,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: slowdown ? "anim_voicespeedstop" : "anim_voicespeed", colors: [:], scale: 0.066)
self.animatedStickerNode = nil
self.videoNode = nil
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
@ -532,6 +563,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: savedMessages ? "anim_savedmessages" : "anim_forward", colors: [:], scale: 0.066)
self.animatedStickerNode = nil
self.videoNode = nil
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
@ -547,6 +579,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: "anim_gigagroup", colors: [:], scale: 0.066)
self.animatedStickerNode = nil
self.videoNode = nil
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
@ -562,6 +595,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: "anim_linkrevoked", colors: [:], scale: 0.066)
self.animatedStickerNode = nil
self.videoNode = nil
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
@ -577,6 +611,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: "anim_vcrecord", colors: [:], scale: 0.066)
self.animatedStickerNode = nil
self.videoNode = nil
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
@ -592,6 +627,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: "anim_vcflag", colors: [:], scale: 0.066)
self.animatedStickerNode = nil
self.videoNode = nil
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
@ -607,6 +643,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: "anim_vcspeak", colors: [:], scale: 0.066)
self.animatedStickerNode = nil
self.videoNode = nil
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
@ -704,6 +741,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: "anim_copy", colors: [:], scale: 0.066)
self.animatedStickerNode = nil
self.videoNode = nil
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
@ -739,6 +777,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: "anim_inviterequest", colors: [:], scale: 0.066)
self.animatedStickerNode = nil
self.videoNode = nil
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(14.0), textColor: .white)
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(14.0), textColor: .white)
self.textNode.maximumNumberOfLines = 2
@ -785,6 +824,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.animationNode.flatMap(self.panelWrapperNode.addSubnode)
self.stillStickerNode.flatMap(self.panelWrapperNode.addSubnode)
self.animatedStickerNode.flatMap(self.panelWrapperNode.addSubnode)
self.videoNode.flatMap(self.panelWrapperNode.addSubnode)
self.slotMachineNode.flatMap(self.panelWrapperNode.addSubnode)
self.avatarNode.flatMap(self.panelWrapperNode.addSubnode)
self.panelWrapperNode.addSubnode(self.titleNode)
@ -814,6 +854,9 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.animatedStickerNode?.started = { [weak self] in
self?.stillStickerNode?.isHidden = true
}
self.videoNode?.started = { [weak self] in
self?.stillStickerNode?.isHidden = true
}
}
deinit {
@ -998,12 +1041,20 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
transition.updateFrame(node: stillStickerNode, frame: iconFrame)
}
if let animatedStickerNode = self.animatedStickerNode {
if let videoNode = self.videoNode {
videoNode.updateLayout(size: iconFrame.size)
transition.updateFrame(node: videoNode, frame: iconFrame)
} else if let animatedStickerNode = self.animatedStickerNode {
animatedStickerNode.updateLayout(size: iconFrame.size)
transition.updateFrame(node: animatedStickerNode, frame: iconFrame)
} else if let slotMachineNode = self.slotMachineNode {
transition.updateFrame(node: slotMachineNode, frame: iconFrame)
}
} else if let videoNode = self.videoNode {
let iconSize = CGSize(width: 32.0, height: 32.0)
let iconFrame = CGRect(origin: CGPoint(x: floor((leftInset - iconSize.width) / 2.0), y: floor((contentHeight - iconSize.height) / 2.0)), size: iconSize)
videoNode.updateLayout(size: iconFrame.size)
transition.updateFrame(node: videoNode, frame: iconFrame)
} else if let animatedStickerNode = self.animatedStickerNode {
let iconSize = CGSize(width: 32.0, height: 32.0)
let iconFrame = CGRect(origin: CGPoint(x: floor((leftInset - iconSize.width) / 2.0), y: floor((contentHeight - iconSize.height) / 2.0)), size: iconSize)
@ -1054,6 +1105,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
})
}
self.videoNode?.update(isPlaying: true)
self.animatedStickerNode?.visibility = true
self.checkTimer()