mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-02 00:17:02 +00:00
Merge commit 'fd63e83d6e5471546fc0922d97508fa4d921d13c'
This commit is contained in:
commit
807608a44a
@ -12653,5 +12653,6 @@ Sorry for the inconvenience.";
|
|||||||
"Story.Cover" = "Story Cover";
|
"Story.Cover" = "Story Cover";
|
||||||
"Story.SaveCover" = "Save Cover";
|
"Story.SaveCover" = "Save Cover";
|
||||||
|
|
||||||
|
"WebBrowser.CopyLink" = "Copy Link";
|
||||||
"WebBrowser.DeleteBookmark" = "Delete Bookmark";
|
"WebBrowser.DeleteBookmark" = "Delete Bookmark";
|
||||||
"WebBrowser.RemoveRecent" = "Remove from Recent";
|
"WebBrowser.RemoveRecent" = "Remove from Recent";
|
||||||
|
@ -9,6 +9,7 @@ import TelegramCore
|
|||||||
import AccountContext
|
import AccountContext
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
import ContextUI
|
import ContextUI
|
||||||
|
import UndoUI
|
||||||
|
|
||||||
final class BrowserAddressListComponent: Component {
|
final class BrowserAddressListComponent: Component {
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
@ -336,13 +337,23 @@ final class BrowserAddressListComponent: Component {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
contextAction: { [weak self] webPage, message, sourceView, gesture in
|
contextAction: { [weak self] webPage, message, sourceView, gesture in
|
||||||
guard let self, let component = self.component else {
|
guard let self, let component = self.component, let url = webPage.content.url else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
var itemList: [ContextMenuItem] = []
|
var itemList: [ContextMenuItem] = []
|
||||||
|
itemList.append(.action(ContextMenuActionItem(text: presentationData.strings.WebBrowser_CopyLink, icon: { theme in
|
||||||
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor)
|
||||||
|
}, action: { [weak self] _, f in
|
||||||
|
f(.default)
|
||||||
|
|
||||||
|
UIPasteboard.general.string = url
|
||||||
|
if let self, let component = self.component {
|
||||||
|
component.presentInGlobalOverlay(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }))
|
||||||
|
}
|
||||||
|
})))
|
||||||
|
|
||||||
if let message {
|
if let message {
|
||||||
itemList.append(.action(ContextMenuActionItem(text: presentationData.strings.WebBrowser_DeleteBookmark, textColor: .destructive, icon: { theme in
|
itemList.append(.action(ContextMenuActionItem(text: presentationData.strings.WebBrowser_DeleteBookmark, textColor: .destructive, icon: { theme in
|
||||||
|
@ -186,6 +186,7 @@ final class BrowserAddressListItemComponent: Component {
|
|||||||
}
|
}
|
||||||
address = address.replacingOccurrences(of: "https://www.", with: "")
|
address = address.replacingOccurrences(of: "https://www.", with: "")
|
||||||
address = address.replacingOccurrences(of: "https://", with: "")
|
address = address.replacingOccurrences(of: "https://", with: "")
|
||||||
|
address = address.replacingOccurrences(of: "tonsite://", with: "")
|
||||||
address = address.trimmingCharacters(in: CharacterSet(charactersIn: "/"))
|
address = address.trimmingCharacters(in: CharacterSet(charactersIn: "/"))
|
||||||
subtitle = address
|
subtitle = address
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@ import UrlWhitelist
|
|||||||
import SearchUI
|
import SearchUI
|
||||||
import SearchBarNode
|
import SearchBarNode
|
||||||
import ChatHistorySearchContainerNode
|
import ChatHistorySearchContainerNode
|
||||||
|
import ContextUI
|
||||||
|
import UndoUI
|
||||||
|
|
||||||
public final class BrowserBookmarksScreen: ViewController {
|
public final class BrowserBookmarksScreen: ViewController {
|
||||||
final class Node: ViewControllerTracingNode, ASScrollViewDelegate {
|
final class Node: ViewControllerTracingNode, ASScrollViewDelegate {
|
||||||
@ -39,6 +41,7 @@ public final class BrowserBookmarksScreen: ViewController {
|
|||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
|
|
||||||
var openMessageImpl: ((Message) -> Bool)?
|
var openMessageImpl: ((Message) -> Bool)?
|
||||||
|
var openContextMenuImpl: ((Message, ASDisplayNode, CGRect, UIGestureRecognizer?) -> Void)?
|
||||||
self.controllerInteraction = ChatControllerInteraction(openMessage: { message, _ in
|
self.controllerInteraction = ChatControllerInteraction(openMessage: { message, _ in
|
||||||
if let openMessageImpl = openMessageImpl {
|
if let openMessageImpl = openMessageImpl {
|
||||||
return openMessageImpl(message)
|
return openMessageImpl(message)
|
||||||
@ -47,7 +50,8 @@ public final class BrowserBookmarksScreen: ViewController {
|
|||||||
}
|
}
|
||||||
}, openPeer: { _, _, _, _ in
|
}, openPeer: { _, _, _, _ in
|
||||||
}, openPeerMention: { _, _ in
|
}, openPeerMention: { _, _ in
|
||||||
}, openMessageContextMenu: { _, _, _, _, _, _ in
|
}, openMessageContextMenu: { message, _, sourceView, rect, gesture, _ in
|
||||||
|
openContextMenuImpl?(message, sourceView, rect, gesture)
|
||||||
}, openMessageReactionContextMenu: { _, _, _, _ in
|
}, openMessageReactionContextMenu: { _, _, _, _ in
|
||||||
}, updateMessageReaction: { _, _, _, _ in
|
}, updateMessageReaction: { _, _, _, _ in
|
||||||
}, activateMessagePinch: { _ in
|
}, activateMessagePinch: { _ in
|
||||||
@ -220,6 +224,47 @@ public final class BrowserBookmarksScreen: ViewController {
|
|||||||
self.containerLayoutUpdated(layout: layout, navigationBarHeight: navigationBarHeight, actualNavigationBarHeight: actualNavigationBarHeight, transition: .animated(duration: 0.4, curve: .spring))
|
self.containerLayoutUpdated(layout: layout, navigationBarHeight: navigationBarHeight, actualNavigationBarHeight: actualNavigationBarHeight, transition: .animated(duration: 0.4, curve: .spring))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openContextMenuImpl = { [weak self] message, sourceNode, rect, gesture in
|
||||||
|
guard let self, let sourceNode = sourceNode as? ContextExtractedContentContainingNode else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
|
var itemList: [ContextMenuItem] = []
|
||||||
|
if let webPage = message.media.first(where: { $0 is TelegramMediaWebpage }) as? TelegramMediaWebpage, let url = webPage.content.url {
|
||||||
|
itemList.append(.action(ContextMenuActionItem(text: presentationData.strings.WebBrowser_CopyLink, icon: { theme in
|
||||||
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor)
|
||||||
|
}, action: { [weak self] _, f in
|
||||||
|
f(.default)
|
||||||
|
|
||||||
|
UIPasteboard.general.string = url
|
||||||
|
if let self {
|
||||||
|
self.controller?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||||
|
}
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
itemList.append(.action(ContextMenuActionItem(text: presentationData.strings.WebBrowser_DeleteBookmark, textColor: .destructive, icon: { theme in
|
||||||
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor)
|
||||||
|
}, action: { [weak self] _, f in
|
||||||
|
f(.dismissWithoutContent)
|
||||||
|
|
||||||
|
if let self {
|
||||||
|
let _ = self.context.engine.messages.deleteMessagesInteractively(messageIds: [message.id], type: .forEveryone).startStandalone()
|
||||||
|
}
|
||||||
|
})))
|
||||||
|
|
||||||
|
let items = ContextController.Items(content: .list(itemList))
|
||||||
|
let controller = ContextController(
|
||||||
|
presentationData: presentationData,
|
||||||
|
source: .extracted(BrowserBookmarksContextExtractedContentSource(contentNode: sourceNode)),
|
||||||
|
items: .single(items),
|
||||||
|
recognizer: nil,
|
||||||
|
gesture: gesture as? ContextGesture
|
||||||
|
)
|
||||||
|
self.controller?.presentInGlobalOverlay(controller)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func activateSearch(placeholderNode: SearchBarPlaceholderNode) {
|
func activateSearch(placeholderNode: SearchBarPlaceholderNode) {
|
||||||
@ -515,3 +560,23 @@ private class BottomPanelNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
final class BrowserBookmarksContextExtractedContentSource: ContextExtractedContentSource {
|
||||||
|
let keepInPlace: Bool = false
|
||||||
|
let ignoreContentTouches: Bool = false
|
||||||
|
let blurBackground: Bool = true
|
||||||
|
|
||||||
|
private let contentNode: ContextExtractedContentContainingNode
|
||||||
|
|
||||||
|
init(contentNode: ContextExtractedContentContainingNode) {
|
||||||
|
self.contentNode = contentNode
|
||||||
|
}
|
||||||
|
|
||||||
|
func takeView() -> ContextControllerTakeViewInfo? {
|
||||||
|
return ContextControllerTakeViewInfo(containingItem: .node(self.contentNode), contentAreaInScreenSpace: UIScreen.main.bounds)
|
||||||
|
}
|
||||||
|
|
||||||
|
func putBack() -> ContextControllerPutBackViewInfo? {
|
||||||
|
return ContextControllerPutBackViewInfo(contentAreaInScreenSpace: UIScreen.main.bounds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -261,6 +261,8 @@ final class BrowserNavigationBarComponent: CombinedComponent {
|
|||||||
availableWidth -= itemSpacing * CGFloat(max(0, leftItemList.count - 1)) + itemSpacing * CGFloat(max(0, rightItemList.count - 1)) + 30.0
|
availableWidth -= itemSpacing * CGFloat(max(0, leftItemList.count - 1)) + itemSpacing * CGFloat(max(0, rightItemList.count - 1)) + 30.0
|
||||||
}
|
}
|
||||||
availableWidth -= context.component.sideInset * 2.0
|
availableWidth -= context.component.sideInset * 2.0
|
||||||
|
|
||||||
|
let canCenter = availableWidth > 660.0
|
||||||
availableWidth = min(660.0, availableWidth)
|
availableWidth = min(660.0, availableWidth)
|
||||||
|
|
||||||
let environment = BrowserNavigationBarEnvironment(fraction: context.component.collapseFraction)
|
let environment = BrowserNavigationBarEnvironment(fraction: context.component.collapseFraction)
|
||||||
@ -276,7 +278,11 @@ final class BrowserNavigationBarComponent: CombinedComponent {
|
|||||||
|
|
||||||
var centerX = maxCenterInset + (context.availableSize.width - maxCenterInset * 2.0) / 2.0
|
var centerX = maxCenterInset + (context.availableSize.width - maxCenterInset * 2.0) / 2.0
|
||||||
if "".isEmpty {
|
if "".isEmpty {
|
||||||
centerX = centerLeftInset + (context.availableSize.width - centerLeftInset - centerRightInset) / 2.0
|
if canCenter {
|
||||||
|
centerX = context.availableSize.width / 2.0
|
||||||
|
} else {
|
||||||
|
centerX = centerLeftInset + (context.availableSize.width - centerLeftInset - centerRightInset) / 2.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if let centerItem = centerItem {
|
if let centerItem = centerItem {
|
||||||
let centerItemPosition = CGPoint(x: centerX, y: context.component.topInset + contentHeight / 2.0 + verticalOffset)
|
let centerItemPosition = CGPoint(x: centerX, y: context.component.topInset + contentHeight / 2.0 + verticalOffset)
|
||||||
|
@ -153,24 +153,24 @@ private final class BrowserScreenComponent: CombinedComponent {
|
|||||||
]
|
]
|
||||||
|
|
||||||
if isTablet {
|
if isTablet {
|
||||||
navigationLeftItems.append(
|
// navigationLeftItems.append(
|
||||||
AnyComponentWithIdentity(
|
// AnyComponentWithIdentity(
|
||||||
id: "minimize",
|
// id: "minimize",
|
||||||
component: AnyComponent(
|
// component: AnyComponent(
|
||||||
Button(
|
// Button(
|
||||||
content: AnyComponent(
|
// content: AnyComponent(
|
||||||
BundleIconComponent(
|
// BundleIconComponent(
|
||||||
name: "Media Gallery/PictureInPictureButton",
|
// name: "Media Gallery/PictureInPictureButton",
|
||||||
tintColor: environment.theme.rootController.navigationBar.accentTextColor
|
// tintColor: environment.theme.rootController.navigationBar.accentTextColor
|
||||||
)
|
// )
|
||||||
),
|
// ),
|
||||||
action: {
|
// action: {
|
||||||
performAction.invoke(.close)
|
// performAction.invoke(.close)
|
||||||
}
|
// }
|
||||||
)
|
// )
|
||||||
)
|
// )
|
||||||
)
|
// )
|
||||||
)
|
// )
|
||||||
|
|
||||||
let canGoBack = context.component.contentState?.canGoBack ?? false
|
let canGoBack = context.component.contentState?.canGoBack ?? false
|
||||||
let canGoForward = context.component.contentState?.canGoForward ?? false
|
let canGoForward = context.component.contentState?.canGoForward ?? false
|
||||||
|
@ -348,7 +348,7 @@ public final class ListMessageSnippetItemNode: ListMessageNode {
|
|||||||
}
|
}
|
||||||
address = address.trimmingCharacters(in: CharacterSet(charactersIn: "/"))
|
address = address.trimmingCharacters(in: CharacterSet(charactersIn: "/"))
|
||||||
|
|
||||||
let plainUrlString = NSAttributedString(string: address.replacingOccurrences(of: "https://", with: ""), font: descriptionFont, textColor: item.presentationData.theme.theme.list.itemAccentColor)
|
let plainUrlString = NSAttributedString(string: address.replacingOccurrences(of: "https://", with: "").replacingOccurrences(of: "tonsite://", with: ""), font: descriptionFont, textColor: item.presentationData.theme.theme.list.itemAccentColor)
|
||||||
let urlString = NSMutableAttributedString()
|
let urlString = NSMutableAttributedString()
|
||||||
urlString.append(plainUrlString)
|
urlString.append(plainUrlString)
|
||||||
urlString.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.URL), value: content.url, range: NSMakeRange(0, urlString.length))
|
urlString.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.URL), value: content.url, range: NSMakeRange(0, urlString.length))
|
||||||
@ -412,8 +412,13 @@ public final class ListMessageSnippetItemNode: ListMessageNode {
|
|||||||
let rawUrlString = urlString
|
let rawUrlString = urlString
|
||||||
var parsedUrl = URL(string: urlString)
|
var parsedUrl = URL(string: urlString)
|
||||||
if (parsedUrl == nil || parsedUrl!.host == nil || parsedUrl!.host!.isEmpty) && !urlString.contains("@") {
|
if (parsedUrl == nil || parsedUrl!.host == nil || parsedUrl!.host!.isEmpty) && !urlString.contains("@") {
|
||||||
urlString = "http://" + urlString
|
if let mappedURL = URL(string: "https://\(urlString)"), let host = mappedURL.host, host.lowercased().hasSuffix(".ton") {
|
||||||
parsedUrl = URL(string: urlString)
|
urlString = "tonsite://" + urlString
|
||||||
|
parsedUrl = URL(string: urlString)
|
||||||
|
} else {
|
||||||
|
urlString = "http://" + urlString
|
||||||
|
parsedUrl = URL(string: urlString)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var host: String? = concealed ? urlString : parsedUrl?.host
|
var host: String? = concealed ? urlString : parsedUrl?.host
|
||||||
if host == nil {
|
if host == nil {
|
||||||
@ -463,7 +468,7 @@ public final class ListMessageSnippetItemNode: ListMessageNode {
|
|||||||
urlString = address
|
urlString = address
|
||||||
|
|
||||||
let urlAttributedString = NSMutableAttributedString()
|
let urlAttributedString = NSMutableAttributedString()
|
||||||
urlAttributedString.append(NSAttributedString(string: urlString.replacingOccurrences(of: "https://", with: ""), font: descriptionFont, textColor: item.presentationData.theme.theme.list.itemAccentColor))
|
urlAttributedString.append(NSAttributedString(string: urlString.replacingOccurrences(of: "https://", with: "").replacingOccurrences(of: "tonsite://", with: ""), font: descriptionFont, textColor: item.presentationData.theme.theme.list.itemAccentColor))
|
||||||
if item.presentationData.theme.theme.list.itemAccentColor.isEqual(item.presentationData.theme.theme.list.itemPrimaryTextColor) {
|
if item.presentationData.theme.theme.list.itemAccentColor.isEqual(item.presentationData.theme.theme.list.itemPrimaryTextColor) {
|
||||||
urlAttributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue as NSNumber, range: NSMakeRange(0, urlAttributedString.length))
|
urlAttributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue as NSNumber, range: NSMakeRange(0, urlAttributedString.length))
|
||||||
}
|
}
|
||||||
@ -495,8 +500,13 @@ public final class ListMessageSnippetItemNode: ListMessageNode {
|
|||||||
let rawUrlString = urlString
|
let rawUrlString = urlString
|
||||||
var parsedUrl = URL(string: urlString)
|
var parsedUrl = URL(string: urlString)
|
||||||
if (parsedUrl == nil || parsedUrl!.host == nil || parsedUrl!.host!.isEmpty) && !urlString.contains("@") {
|
if (parsedUrl == nil || parsedUrl!.host == nil || parsedUrl!.host!.isEmpty) && !urlString.contains("@") {
|
||||||
urlString = "http://" + urlString
|
if let mappedURL = URL(string: "https://\(urlString)"), let host = mappedURL.host, host.lowercased().hasSuffix(".ton") {
|
||||||
parsedUrl = URL(string: urlString)
|
urlString = "tonsite://" + urlString
|
||||||
|
parsedUrl = URL(string: urlString)
|
||||||
|
} else {
|
||||||
|
urlString = "http://" + urlString
|
||||||
|
parsedUrl = URL(string: urlString)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let host: String? = concealed ? urlString : parsedUrl?.host
|
let host: String? = concealed ? urlString : parsedUrl?.host
|
||||||
if let url = parsedUrl, let host = host {
|
if let url = parsedUrl, let host = host {
|
||||||
@ -533,7 +543,7 @@ public final class ListMessageSnippetItemNode: ListMessageNode {
|
|||||||
urlString = address
|
urlString = address
|
||||||
|
|
||||||
let urlAttributedString = NSMutableAttributedString()
|
let urlAttributedString = NSMutableAttributedString()
|
||||||
urlAttributedString.append(NSAttributedString(string: urlString.replacingOccurrences(of: "https://", with: ""), font: descriptionFont, textColor: item.presentationData.theme.theme.list.itemAccentColor))
|
urlAttributedString.append(NSAttributedString(string: urlString.replacingOccurrences(of: "https://", with: "").replacingOccurrences(of: "tonsite://", with: ""), font: descriptionFont, textColor: item.presentationData.theme.theme.list.itemAccentColor))
|
||||||
if item.presentationData.theme.theme.list.itemAccentColor.isEqual(item.presentationData.theme.theme.list.itemPrimaryTextColor) {
|
if item.presentationData.theme.theme.list.itemAccentColor.isEqual(item.presentationData.theme.theme.list.itemPrimaryTextColor) {
|
||||||
urlAttributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue as NSNumber, range: NSMakeRange(0, urlAttributedString.length))
|
urlAttributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue as NSNumber, range: NSMakeRange(0, urlAttributedString.length))
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user