Various improvements

This commit is contained in:
Ilya Laktyushin 2025-04-05 19:18:54 +04:00
parent 13669eee96
commit 88e5ff8f6b
11 changed files with 120 additions and 74 deletions

View File

@ -235,6 +235,13 @@ private func allOpenInOptions(context: AccountContext, item: OpenInItem) -> [Ope
} }
} }
})) }))
options.append(OpenInOption(identifier: "yangoMaps", application: .other(title: "Yango Maps", identifier: 1665672451, scheme: "yangomaps", store: nil), action: {
if let _ = directions {
return .openUrl(url: "yangomaps://build_route_on_map?lat_to=\(lat)&lon_to=\(lon)")
} else {
return .openUrl(url: "yangomaps://maps.yango.com/?pt=\(lon),\(lat)&z=16")
}
}))
options.append(OpenInOption(identifier: "yandexMaps", application: .other(title: "Yandex.Maps", identifier: 313877526, scheme: "yandexmaps", store: nil), action: { options.append(OpenInOption(identifier: "yandexMaps", application: .other(title: "Yandex.Maps", identifier: 313877526, scheme: "yandexmaps", store: nil), action: {
if let _ = directions { if let _ = directions {

View File

@ -264,8 +264,7 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> ([
} else if let _ = media as? TelegramMediaExpiredContent { } else if let _ = media as? TelegramMediaExpiredContent {
result.removeAll() result.removeAll()
result.append((message, ChatMessageActionBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .text, neighborSpacing: .default))) result.append((message, ChatMessageActionBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .text, neighborSpacing: .default)))
needReactions = false break inner
return (result, false, false)
} else if let _ = media as? TelegramMediaPoll { } else if let _ = media as? TelegramMediaPoll {
result.append((message, ChatMessagePollBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .text, neighborSpacing: .default))) result.append((message, ChatMessagePollBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .text, neighborSpacing: .default)))
needReactions = false needReactions = false
@ -2735,6 +2734,8 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
default: default:
centerAligned = true centerAligned = true
} }
} else if let _ = media as? TelegramMediaExpiredContent {
centerAligned = true
} }
break break
} }

View File

@ -299,8 +299,6 @@ public func canAddMessageReactions(message: Message) -> Bool {
if story.isMention { if story.isMention {
return false return false
} }
} else if let _ = media as? TelegramMediaExpiredContent {
return false
} }
} }
return true return true

View File

@ -24,6 +24,7 @@ swift_library(
"//submodules/AppBundle", "//submodules/AppBundle",
"//submodules/PresentationDataUtils", "//submodules/PresentationDataUtils",
"//submodules/TelegramUI/Components/LottieComponent", "//submodules/TelegramUI/Components/LottieComponent",
"//submodules/TelegramUI/Components/PlainButtonComponent",
"//submodules/AvatarNode", "//submodules/AvatarNode",
], ],
visibility = [ visibility = [

View File

@ -22,22 +22,19 @@ private final class QuickShareScreenComponent: Component {
let context: AccountContext let context: AccountContext
let sourceNode: ASDisplayNode let sourceNode: ASDisplayNode
let gesture: ContextGesture let gesture: ContextGesture
let openPeer: (EnginePeer.Id) -> Void let completion: (EnginePeer, CGRect) -> Void
let completion: (EnginePeer.Id) -> Void
let ready: Promise<Bool> let ready: Promise<Bool>
init( init(
context: AccountContext, context: AccountContext,
sourceNode: ASDisplayNode, sourceNode: ASDisplayNode,
gesture: ContextGesture, gesture: ContextGesture,
openPeer: @escaping (EnginePeer.Id) -> Void, completion: @escaping (EnginePeer, CGRect) -> Void,
completion: @escaping (EnginePeer.Id) -> Void,
ready: Promise<Bool> ready: Promise<Bool>
) { ) {
self.context = context self.context = context
self.sourceNode = sourceNode self.sourceNode = sourceNode
self.gesture = gesture self.gesture = gesture
self.openPeer = openPeer
self.completion = completion self.completion = completion
self.ready = ready self.ready = ready
} }
@ -184,24 +181,9 @@ private final class QuickShareScreenComponent: Component {
func highlightGestureFinished(performAction: Bool) { func highlightGestureFinished(performAction: Bool) {
if let selectedPeerId = self.selectedPeerId, performAction { if let selectedPeerId = self.selectedPeerId, performAction {
if let component = self.component, let peer = self.peers?.first(where: { $0.id == selectedPeerId }), let view = self.items[selectedPeerId]?.view as? ItemComponent.View, let controller = self.environment?.controller() { if let component = self.component, let peer = self.peers?.first(where: { $0.id == selectedPeerId }), let view = self.items[selectedPeerId]?.view as? ItemComponent.View {
controller.window?.forEachController({ controller in component.completion(peer, view.convert(view.bounds, to: nil))
if let controller = controller as? QuickShareToastScreen {
controller.dismiss()
}
})
let toastScreen = QuickShareToastScreen(
context: component.context,
peer: peer,
sourceFrame: view.convert(view.bounds, to: nil),
action: {
component.openPeer(peer.id)
}
)
controller.present(toastScreen, in: .window(.root))
view.avatarNode.isHidden = true view.avatarNode.isHidden = true
component.completion(peer.id)
} }
self.animateOut { self.animateOut {
@ -296,7 +278,7 @@ private final class QuickShareScreenComponent: Component {
if theme.overallDarkAppearance { if theme.overallDarkAppearance {
self.backgroundView.updateColor(color: theme.contextMenu.backgroundColor, forceKeepBlur: true, transition: .immediate) self.backgroundView.updateColor(color: theme.contextMenu.backgroundColor, forceKeepBlur: true, transition: .immediate)
self.backgroundTintView.backgroundColor = UIColor(white: 1.0, alpha: 0.5) self.backgroundTintView.backgroundColor = .clear
} else { } else {
self.backgroundView.updateColor(color: .clear, forceKeepBlur: true, transition: .immediate) self.backgroundView.updateColor(color: .clear, forceKeepBlur: true, transition: .immediate)
self.backgroundTintView.backgroundColor = theme.contextMenu.backgroundColor self.backgroundTintView.backgroundColor = theme.contextMenu.backgroundColor
@ -411,8 +393,7 @@ public class QuickShareScreen: ViewControllerComponentContainer {
context: AccountContext, context: AccountContext,
sourceNode: ASDisplayNode, sourceNode: ASDisplayNode,
gesture: ContextGesture, gesture: ContextGesture,
openPeer: @escaping (EnginePeer.Id) -> Void, completion: @escaping (EnginePeer, CGRect) -> Void
completion: @escaping (EnginePeer.Id) -> Void
) { ) {
let componentReady = Promise<Bool>() let componentReady = Promise<Bool>()
@ -422,7 +403,6 @@ public class QuickShareScreen: ViewControllerComponentContainer {
context: context, context: context,
sourceNode: sourceNode, sourceNode: sourceNode,
gesture: gesture, gesture: gesture,
openPeer: openPeer,
completion: completion, completion: completion,
ready: componentReady ready: componentReady
), ),
@ -528,7 +508,7 @@ private final class ItemComponent: Component {
private weak var state: EmptyComponentState? private weak var state: EmptyComponentState?
override init(frame: CGRect) { override init(frame: CGRect) {
self.avatarNode = AvatarNode(font: avatarPlaceholderFont(size: 14.0)) self.avatarNode = AvatarNode(font: avatarPlaceholderFont(size: 26.0))
self.backgroundNode = NavigationBackgroundNode(color: .clear) self.backgroundNode = NavigationBackgroundNode(color: .clear)
super.init(frame: frame) super.init(frame: frame)

View File

@ -14,18 +14,19 @@ import MultilineTextComponent
import AvatarNode import AvatarNode
import Markdown import Markdown
import LottieComponent import LottieComponent
import PlainButtonComponent
private final class QuickShareToastScreenComponent: Component { private final class QuickShareToastScreenComponent: Component {
let context: AccountContext let context: AccountContext
let peer: EnginePeer let peer: EnginePeer
let sourceFrame: CGRect let sourceFrame: CGRect
let action: () -> Void let action: (QuickShareToastScreen.Action) -> Void
init( init(
context: AccountContext, context: AccountContext,
peer: EnginePeer, peer: EnginePeer,
sourceFrame: CGRect, sourceFrame: CGRect,
action: @escaping () -> Void action: @escaping (QuickShareToastScreen.Action) -> Void
) { ) {
self.context = context self.context = context
self.peer = peer self.peer = peer
@ -51,6 +52,7 @@ private final class QuickShareToastScreenComponent: Component {
private let animation = ComponentView<Empty>() private let animation = ComponentView<Empty>()
private let content = ComponentView<Empty>() private let content = ComponentView<Empty>()
private let actionButton = ComponentView<Empty>()
private var isUpdating: Bool = false private var isUpdating: Bool = false
private var component: QuickShareToastScreenComponent? private var component: QuickShareToastScreenComponent?
@ -93,7 +95,8 @@ private final class QuickShareToastScreenComponent: Component {
guard let component = self.component else { guard let component = self.component else {
return return
} }
component.action() component.action(.info)
self.doneTimer?.invalidate()
self.environment?.controller()?.dismiss() self.environment?.controller()?.dismiss()
} }
@ -187,10 +190,10 @@ private final class QuickShareToastScreenComponent: Component {
if self.component == nil { if self.component == nil {
self.doneTimer = Foundation.Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false, block: { [weak self] _ in self.doneTimer = Foundation.Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false, block: { [weak self] _ in
guard let self else { guard let self, let controller = self.environment?.controller() as? QuickShareToastScreen else {
return return
} }
self.environment?.controller()?.dismiss() controller.dismissWithCommitAction()
}) })
} }
@ -230,6 +233,29 @@ private final class QuickShareToastScreenComponent: Component {
tooltipText = environment.strings.Conversation_ForwardTooltip_Chat_One(component.peer.compactDisplayTitle).string tooltipText = environment.strings.Conversation_ForwardTooltip_Chat_One(component.peer.compactDisplayTitle).string
} }
let actionButtonSize = self.actionButton.update(
transition: .immediate,
component: AnyComponent(PlainButtonComponent(
content: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: "Undo", font: Font.regular(17.0), textColor: environment.theme.list.itemAccentColor.withMultiplied(hue: 0.933, saturation: 0.61, brightness: 1.0)))
)),
effectAlignment: .center,
contentInsets: UIEdgeInsets(top: -8.0, left: -8.0, bottom: -8.0, right: -8.0),
action: { [weak self] in
guard let self, let _ = self.component else {
return
}
self.doneTimer?.invalidate()
self.environment?.controller()?.dismiss()
},
animateAlpha: true,
animateScale: false,
animateContents: false
)),
environment: {},
containerSize: CGSize(width: availableContentSize.width - contentInsets.left - contentInsets.right - spacing - iconSize.width, height: availableContentSize.height)
)
let contentSize = self.content.update( let contentSize = self.content.update(
transition: transition, transition: transition,
component: AnyComponent(MultilineTextComponent(text: .markdown( component: AnyComponent(MultilineTextComponent(text: .markdown(
@ -279,6 +305,13 @@ private final class QuickShareToastScreenComponent: Component {
transition.setFrame(view: contentView, frame: CGRect(origin: CGPoint(x: contentInsets.left + iconSize.width + spacing, y: floor((contentHeight - contentSize.height) * 0.5)), size: contentSize)) transition.setFrame(view: contentView, frame: CGRect(origin: CGPoint(x: contentInsets.left + iconSize.width + spacing, y: floor((contentHeight - contentSize.height) * 0.5)), size: contentSize))
} }
if let actionButtonView = self.actionButton.view {
if actionButtonView.superview == nil {
self.backgroundView.addSubview(actionButtonView)
}
transition.setFrame(view: actionButtonView, frame: CGRect(origin: CGPoint(x: availableContentSize.width - contentInsets.right - 16.0 - actionButtonSize.width, y: floor((contentHeight - actionButtonSize.height) * 0.5)), size: actionButtonSize))
}
let size = CGSize(width: availableContentSize.width, height: contentHeight) let size = CGSize(width: availableContentSize.width, height: contentHeight)
let backgroundFrame = CGRect(origin: CGPoint(x: containerInsets.left, y: availableSize.height - containerInsets.bottom - size.height), size: size) let backgroundFrame = CGRect(origin: CGPoint(x: containerInsets.left, y: availableSize.height - containerInsets.bottom - size.height), size: size)
@ -301,16 +334,24 @@ private final class QuickShareToastScreenComponent: Component {
} }
} }
final class QuickShareToastScreen: ViewControllerComponentContainer { public final class QuickShareToastScreen: ViewControllerComponentContainer {
public enum Action {
case info
case commit
}
private var processedDidAppear: Bool = false private var processedDidAppear: Bool = false
private var processedDidDisappear: Bool = false private var processedDidDisappear: Bool = false
init( private let action: (Action) -> Void
public init(
context: AccountContext, context: AccountContext,
peer: EnginePeer, peer: EnginePeer,
sourceFrame: CGRect, sourceFrame: CGRect,
action: @escaping () -> Void action: @escaping (Action) -> Void
) { ) {
self.action = action
super.init( super.init(
context: context, context: context,
component: QuickShareToastScreenComponent( component: QuickShareToastScreenComponent(
@ -334,11 +375,11 @@ final class QuickShareToastScreen: ViewControllerComponentContainer {
deinit { deinit {
} }
override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { public override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
super.containerLayoutUpdated(layout, transition: transition) super.containerLayoutUpdated(layout, transition: transition)
} }
override func viewDidAppear(_ animated: Bool) { public override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated) super.viewDidAppear(animated)
if !self.processedDidAppear { if !self.processedDidAppear {
@ -353,7 +394,12 @@ final class QuickShareToastScreen: ViewControllerComponentContainer {
super.dismiss() super.dismiss()
} }
override func dismiss(completion: (() -> Void)? = nil) { public func dismissWithCommitAction() {
self.action(.commit)
self.dismiss()
}
public override func dismiss(completion: (() -> Void)? = nil) {
if !self.processedDidDisappear { if !self.processedDidDisappear {
self.processedDidDisappear = true self.processedDidDisappear = true

View File

@ -15,9 +15,9 @@ public func peerMessageAllowedReactions(context: AccountContext, message: Messag
return .single((.all, false)) return .single((.all, false))
} }
if message.containsSecretMedia { // if message.containsSecretMedia {
return .single((AllowedReactions.set(Set()), false)) // return .single((AllowedReactions.set(Set()), false))
} // }
return combineLatest( return combineLatest(
context.engine.data.get( context.engine.data.get(

View File

@ -593,7 +593,6 @@ private final class SheetContent: CombinedComponent {
return return
} }
starsContext.add(balance: StarsAmount(value: stars, nanos: 0)) starsContext.add(balance: StarsAmount(value: stars, nanos: 0))
let _ = (starsContext.onUpdate let _ = (starsContext.onUpdate
|> deliverOnMainQueue).start(next: { |> deliverOnMainQueue).start(next: {
completion() completion()

View File

@ -71,7 +71,8 @@ extension ChatControllerImpl {
guard let self else { guard let self else {
return return
} }
let controller = self.context.sharedContext.makeStarsPurchaseScreen(context: self.context, starsContext: starsContext, options: options, purpose: .sendMessage(peerId: peer.id, requiredStars: totalAmount), completion: { _ in let controller = self.context.sharedContext.makeStarsPurchaseScreen(context: self.context, starsContext: starsContext, options: options, purpose: .sendMessage(peerId: peer.id, requiredStars: totalAmount), completion: { stars in
starsContext.add(balance: StarsAmount(value: stars, nanos: 0))
let _ = (starsContext.onUpdate let _ = (starsContext.onUpdate
|> deliverOnMainQueue).start(next: { |> deliverOnMainQueue).start(next: {
completion(false) completion(false)

View File

@ -12,22 +12,27 @@ extension ChatControllerImpl {
context: self.context, context: self.context,
sourceNode: node, sourceNode: node,
gesture: gesture, gesture: gesture,
openPeer: { [weak self] peerId in completion: { [weak self] peer, sourceFrame in
guard let self else { guard let self else {
return return
} }
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) self.window?.forEachController({ controller in
|> deliverOnMainQueue).start(next: { [weak self] peer in if let controller = controller as? QuickShareToastScreen {
guard let self else { controller.dismissWithCommitAction()
return
} }
self.openPeer(peer: peer, navigation: .chat(textInputState: nil, subject: nil, peekData: nil), fromMessage: nil)
}) })
}, let toastScreen = QuickShareToastScreen(
completion: { [weak self] peerId in context: self.context,
peer: peer,
sourceFrame: sourceFrame,
action: { [weak self] action in
guard let self else { guard let self else {
return return
} }
switch action {
case .info:
self.openPeer(peer: peer, navigation: .chat(textInputState: nil, subject: nil, peekData: nil), fromMessage: nil)
case .commit:
let enqueueMessage = StandaloneSendEnqueueMessage( let enqueueMessage = StandaloneSendEnqueueMessage(
content: .forward(forward: StandaloneSendEnqueueMessage.Forward( content: .forward(forward: StandaloneSendEnqueueMessage.Forward(
sourceId: id, sourceId: id,
@ -41,11 +46,15 @@ extension ChatControllerImpl {
network: self.context.account.network, network: self.context.account.network,
stateManager: self.context.account.stateManager, stateManager: self.context.account.stateManager,
auxiliaryMethods: self.context.account.auxiliaryMethods, auxiliaryMethods: self.context.account.auxiliaryMethods,
peerId: peerId, peerId: peer.id,
threadId: nil, threadId: nil,
messages: [enqueueMessage] messages: [enqueueMessage]
)).startStandalone() )).startStandalone()
} }
}
)
self.present(toastScreen, in: .window(.root))
}
) )
self.presentInGlobalOverlay(controller) self.presentInGlobalOverlay(controller)
} }

View File

@ -134,6 +134,7 @@ import AdsReportScreen
import AdUI import AdUI
import ChatMessagePaymentAlertController import ChatMessagePaymentAlertController
import TelegramCallsUI import TelegramCallsUI
import QuickShareScreen
public enum ChatControllerPeekActions { public enum ChatControllerPeekActions {
case standard case standard
@ -10740,6 +10741,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if let controller = controller as? UndoOverlayController { if let controller = controller as? UndoOverlayController {
controller.dismissWithCommitAction() controller.dismissWithCommitAction()
} }
if let controller = controller as? QuickShareToastScreen {
controller.dismissWithCommitAction()
}
}) })
self.forEachController({ controller in self.forEachController({ controller in
if let controller = controller as? UndoOverlayController { if let controller = controller as? UndoOverlayController {