mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-07-19 09:41:29 +00:00
Various improvements
This commit is contained in:
parent
0a1be88185
commit
4fdbe44825
@ -14383,7 +14383,7 @@ Sorry for the inconvenience.";
|
||||
"ChannelMessages.PriceSectionTitle" = "PRICE FOR EACH MESSAGE";
|
||||
"ChannelMessages.PriceSectionFooter" = "You will receive 85% of the selected fee for each incoming message.";
|
||||
|
||||
"ChatList.MonoforumLabel" = "MESSAGES";
|
||||
"ChatList.MonoforumLabel" = "DIRECT";
|
||||
"ChatList.MonoforumEmptyText" = "No messages here yet...";
|
||||
|
||||
"Chat.InlineTopicMenu.Reorder" = "Reorder";
|
||||
@ -14400,6 +14400,7 @@ Sorry for the inconvenience.";
|
||||
|
||||
"Chat.EmptyStateMonoforum.Text" = "Send a direct message to the administrator of **%@**.";
|
||||
"Chat.EmptyStateMonoforumPaid.Text" = "**%1$@** charges **%2$@**\nper message to its admin.";
|
||||
"Chat.Monoforum.Subtitle" = "Direct messages";
|
||||
|
||||
"Monoforum.NameFormat" = "%@ Messages";
|
||||
|
||||
|
@ -97,22 +97,14 @@ open class TransformImageNode: ASDisplayNode {
|
||||
self.disposable.set((result |> deliverOnMainQueue).start(next: { [weak self] next in
|
||||
let apply: () -> Void = {
|
||||
if let strongSelf = self {
|
||||
var animateFromContents: Any?
|
||||
|
||||
if strongSelf.contents == nil {
|
||||
if strongSelf.contentAnimations.contains(.firstUpdate) && !attemptSynchronously {
|
||||
strongSelf.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15)
|
||||
}
|
||||
} else if strongSelf.contentAnimations.contains(.subsequentUpdates) {
|
||||
let tempLayer = CALayer()
|
||||
if strongSelf.captureProtected {
|
||||
setLayerDisableScreenshots(tempLayer, strongSelf.captureProtected)
|
||||
}
|
||||
tempLayer.frame = strongSelf.bounds
|
||||
tempLayer.contentsGravity = strongSelf.layer.contentsGravity
|
||||
tempLayer.contents = strongSelf.contents
|
||||
strongSelf.layer.addSublayer(tempLayer)
|
||||
tempLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false, completion: { [weak tempLayer] _ in
|
||||
tempLayer?.removeFromSuperlayer()
|
||||
})
|
||||
animateFromContents = strongSelf.contents
|
||||
}
|
||||
|
||||
var imageUpdate: UIImage?
|
||||
@ -129,6 +121,23 @@ open class TransformImageNode: ASDisplayNode {
|
||||
if let imageUpdated = strongSelf.imageUpdated {
|
||||
imageUpdated(imageUpdate)
|
||||
}
|
||||
|
||||
if let animateFromContents {
|
||||
let transition: ContainedViewLayoutTransition = .animated(duration: 0.2, curve: .linear)
|
||||
transition.animateContents(layer: strongSelf.layer, from: animateFromContents)
|
||||
|
||||
/*let tempLayer = CALayer()
|
||||
if strongSelf.captureProtected {
|
||||
setLayerDisableScreenshots(tempLayer, strongSelf.captureProtected)
|
||||
}
|
||||
tempLayer.frame = strongSelf.bounds
|
||||
tempLayer.contentsGravity = strongSelf.layer.contentsGravity
|
||||
tempLayer.contents = animateFromContents
|
||||
strongSelf.layer.addSublayer(tempLayer)
|
||||
tempLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false, completion: { [weak tempLayer] _ in
|
||||
tempLayer?.removeFromSuperlayer()
|
||||
})*/
|
||||
}
|
||||
}
|
||||
}
|
||||
if dispatchOnDisplayLink && !attemptSynchronously {
|
||||
@ -168,6 +177,34 @@ open class TransformImageNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
public func asyncLayoutWithAnimation() -> (TransformImageArguments) -> ((ListViewItemUpdateAnimation) -> Void) {
|
||||
let currentTransform = self.currentTransform
|
||||
let currentArguments = self.currentArguments
|
||||
return { [weak self] arguments in
|
||||
let updatedImage: UIImage?
|
||||
|
||||
if currentArguments != arguments {
|
||||
updatedImage = currentTransform?(arguments)?.generateImage()
|
||||
} else {
|
||||
updatedImage = nil
|
||||
}
|
||||
return { animation in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if let image = updatedImage {
|
||||
self.contents = image.cgImage
|
||||
self.image = image
|
||||
self.currentArguments = arguments
|
||||
if let _ = self.overlayColor {
|
||||
self.applyOverlayColor(animated: false)
|
||||
}
|
||||
}
|
||||
self.argumentsPromise.set(arguments)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class func asyncLayout(_ maybeNode: TransformImageNode?) -> (TransformImageArguments) -> (() -> TransformImageNode) {
|
||||
return { arguments in
|
||||
let node: TransformImageNode
|
||||
|
@ -402,7 +402,7 @@ public final class MediaPlayerNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
private func updateLayout() {
|
||||
public func updateLayout() {
|
||||
let bounds = self.bounds
|
||||
if bounds.isEmpty {
|
||||
return
|
||||
|
@ -858,7 +858,7 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
public func asyncLayout() -> (_ context: AccountContext, _ presentationData: ChatPresentationData, _ dateTimeFormat: PresentationDateTimeFormat, _ message: Message, _ associatedData: ChatMessageItemAssociatedData, _ attributes: ChatMessageEntryAttributes, _ media: Media, _ mediaIndex: Int?, _ dateAndStatus: ChatMessageDateAndStatus?, _ automaticDownload: InteractiveMediaNodeAutodownloadMode, _ peerType: MediaAutoDownloadPeerType, _ peerId: EnginePeer.Id?, _ sizeCalculation: InteractiveMediaNodeSizeCalculation, _ layoutConstants: ChatMessageItemLayoutConstants, _ contentMode: InteractiveMediaNodeContentMode, _ presentationContext: ChatPresentationContext) -> (CGSize, CGFloat, (CGSize, Bool, Bool, ImageCorners) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))) {
|
||||
let currentMessage = self.message
|
||||
let currentMedia = self.media
|
||||
let imageLayout = self.imageNode.asyncLayout()
|
||||
let imageLayout = self.imageNode.asyncLayoutWithAnimation()
|
||||
let statusLayout = self.dateAndStatusNode.asyncLayout()
|
||||
|
||||
let currentVideoNode = self.videoNode
|
||||
@ -1894,7 +1894,7 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
timestampMaskView.image = strongSelf.generateTimestampMaskImage(corners: arguments.corners)
|
||||
}
|
||||
strongSelf.currentImageArguments = arguments
|
||||
imageApply()
|
||||
imageApply(transition)
|
||||
|
||||
if let statusApply = statusApply {
|
||||
let dateAndStatusFrame = CGRect(origin: CGPoint(x: cleanImageFrame.width - layoutConstants.image.statusInsets.right - statusSize.width, y: cleanImageFrame.height - layoutConstants.image.statusInsets.bottom - statusSize.height), size: statusSize)
|
||||
@ -2084,8 +2084,13 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
strongSelf.imageNode.cornerRadius = 0.0
|
||||
}
|
||||
|
||||
videoNode.updateLayout(size: arguments.drawingSize, transition: .immediate)
|
||||
videoNode.frame = CGRect(origin: CGPoint(), size: imageFrame.size)
|
||||
if videoNode.bounds.isEmpty {
|
||||
videoNode.updateLayout(size: arguments.drawingSize, transition: .immediate)
|
||||
videoNode.frame = CGRect(origin: CGPoint(), size: imageFrame.size)
|
||||
} else {
|
||||
videoNode.updateLayout(size: arguments.drawingSize, transition: transition.transition)
|
||||
transition.animator.updateFrame(layer: videoNode.layer, frame: CGRect(origin: CGPoint(), size: imageFrame.size), completion: nil)
|
||||
}
|
||||
|
||||
if strongSelf.visibility && strongSelf.internallyVisible && !presentationData.isPreview {
|
||||
if !videoNode.canAttachContent {
|
||||
|
@ -1359,7 +1359,7 @@ public final class ChatSideTopicsPanel: Component {
|
||||
maximumNumberOfLines: 2
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: 200.0, height: 200.0)
|
||||
containerSize: CGSize(width: 400.0, height: 200.0)
|
||||
)
|
||||
|
||||
let contentSize: CGFloat = leftInset + rightInset + titleSize.height
|
||||
|
@ -68,6 +68,8 @@ public enum ChatTitleContent: Equatable {
|
||||
return false
|
||||
}
|
||||
if lhs.peerPresences.count != rhs.peerPresences.count {
|
||||
return false
|
||||
} else {
|
||||
for (key, value) in lhs.peerPresences {
|
||||
if let rhsValue = rhs.peerPresences[key] {
|
||||
if !value.isEqual(to: rhsValue) {
|
||||
|
@ -397,21 +397,30 @@ extension ChatControllerImpl {
|
||||
self.navigationActionDisposable.set((peerView.get()
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).startStrict(next: { [weak self] peerView in
|
||||
if let strongSelf = self, let peer = peerView.peers[peerView.peerId], peer.restrictionText(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with { $0 }) == nil && !strongSelf.presentationInterfaceState.isNotAccessible {
|
||||
|
||||
if peer.id == strongSelf.context.account.peerId {
|
||||
if let peer = strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer, let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: true, requestsContext: nil) {
|
||||
strongSelf.effectiveNavigationController?.pushViewController(infoController)
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
guard var peer = peerView.peers[peerView.peerId] else {
|
||||
return
|
||||
}
|
||||
if let channel = peer as? TelegramChannel, channel.isMonoForum, let linkedMonoforumId = channel.linkedMonoforumId, let mainPeer = peerView.peers[linkedMonoforumId] {
|
||||
peer = mainPeer
|
||||
}
|
||||
|
||||
if peer.restrictionText(platform: "ios", contentSettings: self.context.currentContentSettings.with { $0 }) == nil && !self.presentationInterfaceState.isNotAccessible {
|
||||
if peer.id == self.context.account.peerId {
|
||||
if let peer = self.presentationInterfaceState.renderedPeer?.chatMainPeer, let infoController = self.context.sharedContext.makePeerInfoController(context: self.context, updatedPresentationData: self.updatedPresentationData, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: true, requestsContext: nil) {
|
||||
self.effectiveNavigationController?.pushViewController(infoController)
|
||||
}
|
||||
} else {
|
||||
var expandAvatar = expandAvatar
|
||||
if peer.smallProfileImage == nil {
|
||||
expandAvatar = false
|
||||
}
|
||||
if let validLayout = strongSelf.validLayout, validLayout.deviceMetrics.type == .tablet {
|
||||
if let validLayout = self.validLayout, validLayout.deviceMetrics.type == .tablet {
|
||||
expandAvatar = false
|
||||
}
|
||||
let mode: PeerInfoControllerMode
|
||||
let mode: PeerInfoControllerMode
|
||||
switch section {
|
||||
case .groupsInCommon:
|
||||
mode = .groupsInCommon
|
||||
@ -420,12 +429,12 @@ extension ChatControllerImpl {
|
||||
default:
|
||||
mode = .generic
|
||||
}
|
||||
if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: peer, mode: mode, avatarInitiallyExpanded: expandAvatar, fromChat: true, requestsContext: strongSelf.contentData?.inviteRequestsContext) {
|
||||
strongSelf.effectiveNavigationController?.pushViewController(infoController)
|
||||
if let infoController = self.context.sharedContext.makePeerInfoController(context: self.context, updatedPresentationData: self.updatedPresentationData, peer: peer, mode: mode, avatarInitiallyExpanded: expandAvatar, fromChat: true, requestsContext: self.contentData?.inviteRequestsContext) {
|
||||
self.effectiveNavigationController?.pushViewController(infoController)
|
||||
}
|
||||
}
|
||||
|
||||
let _ = strongSelf.dismissPreviewing?(false)
|
||||
let _ = self.dismissPreviewing?(false)
|
||||
}
|
||||
}))
|
||||
case .replyThread:
|
||||
|
@ -548,9 +548,9 @@ extension ChatControllerImpl {
|
||||
strongSelf.state.chatTitleContent = .custom(strings.Chat_TitlePinnedMessages(Int32(displayedCount ?? 1)), nil, false)
|
||||
} else if let channel = peer as? TelegramChannel, channel.isMonoForum {
|
||||
if let linkedMonoforumId = channel.linkedMonoforumId, let mainPeer = peerView.peers[linkedMonoforumId] {
|
||||
strongSelf.state.chatTitleContent = .custom(mainPeer.debugDisplayTitle, "Direct messages", false)
|
||||
strongSelf.state.chatTitleContent = .custom(mainPeer.debugDisplayTitle, strings.Chat_Monoforum_Subtitle, true)
|
||||
} else {
|
||||
strongSelf.state.chatTitleContent = .custom(channel.debugDisplayTitle, nil, false)
|
||||
strongSelf.state.chatTitleContent = .custom(channel.debugDisplayTitle, nil, true)
|
||||
}
|
||||
} else {
|
||||
strongSelf.state.chatTitleContent = .peer(peerView: ChatTitleContent.PeerData(peerView: peerView), customTitle: nil, onlineMemberCount: onlineMemberCount, isScheduledMessages: isScheduledMessages, isMuted: nil, customMessageCount: nil, isEnabled: hasPeerInfo)
|
||||
|
@ -2552,17 +2552,9 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
if self.leftPanel != nil || dismissedLeftPanel != nil {
|
||||
titleTopicsAccessoryPanelNode.updateGlobalOffset(globalOffset: -titleTopicsAccessoryPanelFrame.height, transition: .immediate)
|
||||
}
|
||||
|
||||
let topPanelTransition = ComponentTransition(transition)
|
||||
/*switch topPanelTransition.animation {
|
||||
case let .curve(duration, _):
|
||||
topPanelTransition = topPanelTransition.withAnimation(.curve(duration: duration, curve: ComponentTransition.Animation.Curve(ChatMessageTransitionNodeImpl.verticalAnimationCurve)))
|
||||
default:
|
||||
break
|
||||
}*/
|
||||
|
||||
topPanelTransition.setFrame(view: titleTopicsAccessoryPanelNode.view, frame: titleTopicsAccessoryPanelFrame)
|
||||
titleTopicsAccessoryPanelNode.updateGlobalOffset(globalOffset: 0.0, transition: topPanelTransition)
|
||||
ComponentTransition(transition).setFrame(view: titleTopicsAccessoryPanelNode.view, frame: titleTopicsAccessoryPanelFrame)
|
||||
titleTopicsAccessoryPanelNode.updateGlobalOffset(globalOffset: 0.0, transition: ComponentTransition(transition))
|
||||
} else {
|
||||
let previousFrame = titleTopicsAccessoryPanelNode.frame
|
||||
titleTopicsAccessoryPanelNode.frame = titleTopicsAccessoryPanelFrame
|
||||
|
@ -681,6 +681,7 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
||||
|
||||
private var loadedMessagesFromCachedDataDisposable: Disposable?
|
||||
|
||||
private var isSettingTopReplyThreadMessageShown: Bool = false
|
||||
let isTopReplyThreadMessageShown = ValuePromise<Bool>(false, ignoreRepeated: true)
|
||||
|
||||
private var topVisibleMessageRangeValueInitialized: Bool = false
|
||||
@ -3178,8 +3179,15 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
self.isTopReplyThreadMessageShown.set(isTopReplyThreadMessageShownValue)
|
||||
if !self.isSettingTopReplyThreadMessageShown {
|
||||
self.isSettingTopReplyThreadMessageShown = true
|
||||
self.isTopReplyThreadMessageShown.set(isTopReplyThreadMessageShownValue)
|
||||
self.isSettingTopReplyThreadMessageShown = false
|
||||
} else {
|
||||
#if DEBUG
|
||||
print("Ignore repeated isTopReplyThreadMessageShown update")
|
||||
#endif
|
||||
}
|
||||
self.updateTopVisibleMessageRange(topVisibleMessageRange)
|
||||
let _ = self.visibleMessageRange.swap(topVisibleMessageRange.flatMap { range in
|
||||
return VisibleMessageRange(lowerBound: range.lowerBound, upperBound: range.upperBound)
|
||||
|
@ -1591,7 +1591,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
}
|
||||
}
|
||||
|
||||
if let message = messages.first, message.id.namespace == Namespaces.Message.Cloud, let channel = message.peers[message.id.peerId] as? TelegramChannel, !(message.media.first is TelegramMediaAction), !isReplyThreadHead, !isMigrated {
|
||||
if let message = messages.first, message.id.namespace == Namespaces.Message.Cloud, let channel = message.peers[message.id.peerId] as? TelegramChannel, !channel.isMonoForum, !(message.media.first is TelegramMediaAction), !isReplyThreadHead, !isMigrated {
|
||||
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextMenuCopyLink, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Link"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { _, f in
|
||||
@ -1893,8 +1893,8 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
|
||||
var canViewStats = false
|
||||
var canViewAuthor = false
|
||||
if let channel = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramChannel, channel.isMonoForum {
|
||||
if message.effectivelyIncoming(context.account.peerId) {
|
||||
if let channel = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramChannel, channel.isMonoForum, let associatedPeerId = channel.associatedPeerId {
|
||||
if message.effectivelyIncoming(context.account.peerId), message.author?.id == associatedPeerId {
|
||||
canViewAuthor = true
|
||||
}
|
||||
} else if let messageReadStatsAreHidden = infoSummaryData.messageReadStatsAreHidden, !messageReadStatsAreHidden {
|
||||
|
@ -690,22 +690,34 @@ private final class NativeVideoContentNode: ASDisplayNode, UniversalVideoContent
|
||||
|
||||
if let dimensions = self.dimensions {
|
||||
let imageSize = CGSize(width: floor(dimensions.width / 2.0), height: floor(dimensions.height / 2.0))
|
||||
let makeLayout = self.imageNode.asyncLayout()
|
||||
let makeLayout = self.imageNode.asyncLayoutWithAnimation()
|
||||
let applyLayout = makeLayout(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets(), emptyColor: self.fileReference.media.isInstantVideo ? .clear : self.placeholderColor))
|
||||
applyLayout()
|
||||
let mappedAnimation: ListViewItemUpdateAnimation
|
||||
if case let .animated(duration, curve) = transition {
|
||||
mappedAnimation = .System(duration: duration, transition: ControlledTransition(duration: duration, curve: curve, interactive: false))
|
||||
} else {
|
||||
mappedAnimation = .None
|
||||
}
|
||||
applyLayout(mappedAnimation)
|
||||
}
|
||||
|
||||
transition.updateFrame(node: self.imageNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
let fromFrame = self.playerNode.frame
|
||||
let toFrame = CGRect(origin: CGPoint(), size: size).insetBy(dx: -1.0, dy: -1.0)
|
||||
if case let .animated(duration, curve) = transition, fromFrame != toFrame, !fromFrame.width.isZero, !fromFrame.height.isZero, !toFrame.width.isZero, !toFrame.height.isZero {
|
||||
self.playerNode.frame = toFrame
|
||||
transition.animatePosition(node: self.playerNode, from: CGPoint(x: fromFrame.center.x - toFrame.center.x, y: fromFrame.center.y - toFrame.center.y))
|
||||
let _ = duration
|
||||
let _ = curve
|
||||
self.playerNode.position = toFrame.center
|
||||
self.playerNode.bounds = CGRect(origin: CGPoint(), size: toFrame.size)
|
||||
self.playerNode.updateLayout()
|
||||
transition.animatePosition(node: self.playerNode, from: CGPoint(x: fromFrame.center.x, y: fromFrame.center.y))
|
||||
|
||||
let transform = CATransform3DScale(CATransform3DIdentity, fromFrame.width / toFrame.width, fromFrame.height / toFrame.height, 1.0)
|
||||
self.playerNode.layer.animate(from: NSValue(caTransform3D: transform), to: NSValue(caTransform3D: CATransform3DIdentity), keyPath: "transform", timingFunction: curve.timingFunction, duration: duration)
|
||||
} else {
|
||||
transition.updateFrame(node: self.playerNode, frame: toFrame)
|
||||
transition.updatePosition(node: self.playerNode, position: toFrame.center)
|
||||
transition.updateBounds(node: self.playerNode, bounds: CGRect(origin: CGPoint(), size: toFrame.size))
|
||||
self.playerNode.updateLayout()
|
||||
}
|
||||
if let thumbnailNode = self.thumbnailNode {
|
||||
transition.updateFrame(node: thumbnailNode, frame: CGRect(origin: CGPoint(), size: size).insetBy(dx: -1.0, dy: -1.0))
|
||||
|
Loading…
x
Reference in New Issue
Block a user