mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 17:30:12 +00:00
Various improvements
This commit is contained in:
parent
10275ad968
commit
ad3bed0a9f
@ -12217,6 +12217,17 @@ Sorry for the inconvenience.";
|
|||||||
"Chat.Context.Phone.NotOnTelegram" = "This number is not on Telegram.";
|
"Chat.Context.Phone.NotOnTelegram" = "This number is not on Telegram.";
|
||||||
"Chat.Context.Phone.ViewProfile" = "View Profile";
|
"Chat.Context.Phone.ViewProfile" = "View Profile";
|
||||||
|
|
||||||
|
"Chat.Context.Username.SendMessage" = "Send Message";
|
||||||
|
"Chat.Context.Username.OpenGroup" = "Open Group";
|
||||||
|
"Chat.Context.Username.OpenChannel" = "Open Channel";
|
||||||
|
"Chat.Context.Username.Copy" = "Copy Username";
|
||||||
|
"Chat.Context.Username.NotOnTelegram" = "This user doesn't exist on Telegram.";
|
||||||
|
|
||||||
|
"Chat.Context.Hashtag.Search" = "View Profile";
|
||||||
|
"Chat.Context.Hashtag.Copy" = "Copy Hashtag";
|
||||||
|
|
||||||
|
"Chat.Context.Card.Copy" = "Copy Card Number";
|
||||||
|
|
||||||
"Message.FactCheck" = "Fact Check";
|
"Message.FactCheck" = "Fact Check";
|
||||||
"Message.FactCheck.WhatIsThis" = "what's this?";
|
"Message.FactCheck.WhatIsThis" = "what's this?";
|
||||||
|
|
||||||
|
|||||||
@ -110,7 +110,7 @@ public final class DrawingLinkEntityView: DrawingEntityView, UITextViewDelegate
|
|||||||
|
|
||||||
private var textSize: CGSize = .zero
|
private var textSize: CGSize = .zero
|
||||||
public override func sizeThatFits(_ size: CGSize) -> CGSize {
|
public override func sizeThatFits(_ size: CGSize) -> CGSize {
|
||||||
if self.linkEntity.webpage != nil, let image = self.linkEntity.renderImage {
|
if self.linkEntity.webpage != nil, let image = self.linkEntity.whiteImage {
|
||||||
self.imageView.frame = CGRect(origin: .zero, size: image.size)
|
self.imageView.frame = CGRect(origin: .zero, size: image.size)
|
||||||
return image.size
|
return image.size
|
||||||
} else {
|
} else {
|
||||||
@ -118,7 +118,7 @@ public final class DrawingLinkEntityView: DrawingEntityView, UITextViewDelegate
|
|||||||
self.textSize = result
|
self.textSize = result
|
||||||
|
|
||||||
let widthExtension = result.height * 0.65
|
let widthExtension = result.height * 0.65
|
||||||
result.width = floorToScreenPixels(max(224.0, ceil(result.width) + 20.0) + widthExtension)
|
result.width = floorToScreenPixels(max(104.0, ceil(result.width) + 20.0) + widthExtension)
|
||||||
result.height = ceil(result.height * 1.2);
|
result.height = ceil(result.height * 1.2);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -260,7 +260,11 @@ public final class DrawingLinkEntityView: DrawingEntityView, UITextViewDelegate
|
|||||||
self.blurredBackgroundView.isHidden = true
|
self.blurredBackgroundView.isHidden = true
|
||||||
self.iconView.isHidden = true
|
self.iconView.isHidden = true
|
||||||
|
|
||||||
self.imageView.image = self.linkEntity.style == .white ? self.linkEntity.renderImage : self.linkEntity.secondaryRenderImage
|
if self.linkEntity.style == .white && self.imageView.image !== self.linkEntity.whiteImage {
|
||||||
|
self.imageView.image = self.linkEntity.whiteImage
|
||||||
|
} else if self.linkEntity.style == .black && self.imageView.image !== self.linkEntity.blackImage {
|
||||||
|
self.imageView.image = self.linkEntity.blackImage
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.textView.isHidden = false
|
self.textView.isHidden = false
|
||||||
self.textView.frameInsets = UIEdgeInsets(top: 0.15, left: 0.0, bottom: 0.15, right: 0.0)
|
self.textView.frameInsets = UIEdgeInsets(top: 0.15, left: 0.0, bottom: 0.15, right: 0.0)
|
||||||
|
|||||||
@ -2467,42 +2467,41 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
if selectionCount > 1 {
|
if selectionCount > 1 {
|
||||||
items.append(.action(ContextMenuActionItem(text: "Send Without Grouping", icon: { theme in
|
// items.append(.action(ContextMenuActionItem(text: "Send Without Grouping", icon: { theme in
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Media Grid/GroupingOff"), color: theme.contextMenu.primaryColor)
|
// return generateTintedImage(image: UIImage(bundleImageName: "Media Grid/GroupingOff"), color: theme.contextMenu.primaryColor)
|
||||||
}, action: { [weak self] _, f in
|
|
||||||
f(.default)
|
|
||||||
|
|
||||||
self?.groupedValue = false
|
|
||||||
self?.controllerNode.send(asFile: false, silently: false, scheduleTime: nil, animated: true, parameters: nil, completion: {})
|
|
||||||
})))
|
|
||||||
|
|
||||||
// if !items.isEmpty {
|
|
||||||
// items.append(.separator)
|
|
||||||
// }
|
|
||||||
// items.append(.action(ContextMenuActionItem(text: strings.Attachment_Grouped, icon: { theme in
|
|
||||||
// if !grouped {
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
// return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
|
||||||
// }, action: { [weak self] _, f in
|
|
||||||
// f(.default)
|
|
||||||
//
|
|
||||||
// self?.groupedValue = true
|
|
||||||
// })))
|
|
||||||
// items.append(.action(ContextMenuActionItem(text: strings.Attachment_Ungrouped, icon: { theme in
|
|
||||||
// if grouped {
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
// return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
|
||||||
// }, action: { [weak self] _, f in
|
// }, action: { [weak self] _, f in
|
||||||
// f(.default)
|
// f(.default)
|
||||||
//
|
//
|
||||||
// self?.groupedValue = false
|
// self?.groupedValue = false
|
||||||
|
// self?.controllerNode.send(asFile: false, silently: false, scheduleTime: nil, animated: true, parameters: nil, completion: {})
|
||||||
// })))
|
// })))
|
||||||
|
|
||||||
|
if !items.isEmpty {
|
||||||
|
items.append(.separator)
|
||||||
|
}
|
||||||
|
items.append(.action(ContextMenuActionItem(text: strings.Attachment_Grouped, icon: { theme in
|
||||||
|
if !grouped {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||||
|
}, action: { [weak self] _, f in
|
||||||
|
f(.default)
|
||||||
|
|
||||||
|
self?.groupedValue = true
|
||||||
|
})))
|
||||||
|
items.append(.action(ContextMenuActionItem(text: strings.Attachment_Ungrouped, icon: { theme in
|
||||||
|
if grouped {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||||
|
}, action: { [weak self] _, f in
|
||||||
|
f(.default)
|
||||||
|
|
||||||
|
self?.groupedValue = false
|
||||||
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
let isPaidAvailable = true
|
let isPaidAvailable = !"".isEmpty
|
||||||
|
|
||||||
if isSpoilerAvailable || isPaidAvailable || (selectionCount > 0 && isCaptionAboveMediaAvailable) {
|
if isSpoilerAvailable || isPaidAvailable || (selectionCount > 0 && isCaptionAboveMediaAvailable) {
|
||||||
if !items.isEmpty {
|
if !items.isEmpty {
|
||||||
items.append(.separator)
|
items.append(.separator)
|
||||||
|
|||||||
@ -23,6 +23,7 @@ public struct UserLimitsConfiguration: Equatable {
|
|||||||
public var maxStoriesWeeklyCount: Int32
|
public var maxStoriesWeeklyCount: Int32
|
||||||
public var maxStoriesMonthlyCount: Int32
|
public var maxStoriesMonthlyCount: Int32
|
||||||
public var maxStoriesSuggestedReactions: Int32
|
public var maxStoriesSuggestedReactions: Int32
|
||||||
|
public var maxStoriesLinksCount: Int32
|
||||||
public var maxGiveawayChannelsCount: Int32
|
public var maxGiveawayChannelsCount: Int32
|
||||||
public var maxGiveawayCountriesCount: Int32
|
public var maxGiveawayCountriesCount: Int32
|
||||||
public var maxGiveawayPeriodSeconds: Int32
|
public var maxGiveawayPeriodSeconds: Int32
|
||||||
@ -51,6 +52,7 @@ public struct UserLimitsConfiguration: Equatable {
|
|||||||
maxStoriesWeeklyCount: 7,
|
maxStoriesWeeklyCount: 7,
|
||||||
maxStoriesMonthlyCount: 30,
|
maxStoriesMonthlyCount: 30,
|
||||||
maxStoriesSuggestedReactions: 1,
|
maxStoriesSuggestedReactions: 1,
|
||||||
|
maxStoriesLinksCount: 3,
|
||||||
maxGiveawayChannelsCount: 10,
|
maxGiveawayChannelsCount: 10,
|
||||||
maxGiveawayCountriesCount: 10,
|
maxGiveawayCountriesCount: 10,
|
||||||
maxGiveawayPeriodSeconds: 86400 * 31,
|
maxGiveawayPeriodSeconds: 86400 * 31,
|
||||||
@ -80,6 +82,7 @@ public struct UserLimitsConfiguration: Equatable {
|
|||||||
maxStoriesWeeklyCount: Int32,
|
maxStoriesWeeklyCount: Int32,
|
||||||
maxStoriesMonthlyCount: Int32,
|
maxStoriesMonthlyCount: Int32,
|
||||||
maxStoriesSuggestedReactions: Int32,
|
maxStoriesSuggestedReactions: Int32,
|
||||||
|
maxStoriesLinksCount: Int32,
|
||||||
maxGiveawayChannelsCount: Int32,
|
maxGiveawayChannelsCount: Int32,
|
||||||
maxGiveawayCountriesCount: Int32,
|
maxGiveawayCountriesCount: Int32,
|
||||||
maxGiveawayPeriodSeconds: Int32,
|
maxGiveawayPeriodSeconds: Int32,
|
||||||
@ -106,6 +109,7 @@ public struct UserLimitsConfiguration: Equatable {
|
|||||||
self.maxStoriesWeeklyCount = maxStoriesWeeklyCount
|
self.maxStoriesWeeklyCount = maxStoriesWeeklyCount
|
||||||
self.maxStoriesMonthlyCount = maxStoriesMonthlyCount
|
self.maxStoriesMonthlyCount = maxStoriesMonthlyCount
|
||||||
self.maxStoriesSuggestedReactions = maxStoriesSuggestedReactions
|
self.maxStoriesSuggestedReactions = maxStoriesSuggestedReactions
|
||||||
|
self.maxStoriesLinksCount = maxStoriesLinksCount
|
||||||
self.maxGiveawayChannelsCount = maxGiveawayChannelsCount
|
self.maxGiveawayChannelsCount = maxGiveawayChannelsCount
|
||||||
self.maxGiveawayCountriesCount = maxGiveawayCountriesCount
|
self.maxGiveawayCountriesCount = maxGiveawayCountriesCount
|
||||||
self.maxGiveawayPeriodSeconds = maxGiveawayPeriodSeconds
|
self.maxGiveawayPeriodSeconds = maxGiveawayPeriodSeconds
|
||||||
@ -158,6 +162,7 @@ extension UserLimitsConfiguration {
|
|||||||
self.maxStoriesWeeklyCount = getValue("stories_sent_weekly_limit", orElse: defaultValue.maxStoriesWeeklyCount)
|
self.maxStoriesWeeklyCount = getValue("stories_sent_weekly_limit", orElse: defaultValue.maxStoriesWeeklyCount)
|
||||||
self.maxStoriesMonthlyCount = getValue("stories_sent_monthly_limit", orElse: defaultValue.maxStoriesMonthlyCount)
|
self.maxStoriesMonthlyCount = getValue("stories_sent_monthly_limit", orElse: defaultValue.maxStoriesMonthlyCount)
|
||||||
self.maxStoriesSuggestedReactions = getValue("stories_suggested_reactions_limit", orElse: defaultValue.maxStoriesMonthlyCount)
|
self.maxStoriesSuggestedReactions = getValue("stories_suggested_reactions_limit", orElse: defaultValue.maxStoriesMonthlyCount)
|
||||||
|
self.maxStoriesLinksCount = getGeneralValue("stories_area_url_max", orElse: defaultValue.maxStoriesLinksCount)
|
||||||
self.maxGiveawayChannelsCount = getGeneralValue("giveaway_add_peers_max", orElse: defaultValue.maxGiveawayChannelsCount)
|
self.maxGiveawayChannelsCount = getGeneralValue("giveaway_add_peers_max", orElse: defaultValue.maxGiveawayChannelsCount)
|
||||||
self.maxGiveawayCountriesCount = getGeneralValue("giveaway_countries_max", orElse: defaultValue.maxGiveawayCountriesCount)
|
self.maxGiveawayCountriesCount = getGeneralValue("giveaway_countries_max", orElse: defaultValue.maxGiveawayCountriesCount)
|
||||||
self.maxGiveawayPeriodSeconds = getGeneralValue("giveaway_period_max", orElse: defaultValue.maxGiveawayPeriodSeconds)
|
self.maxGiveawayPeriodSeconds = getGeneralValue("giveaway_period_max", orElse: defaultValue.maxGiveawayPeriodSeconds)
|
||||||
|
|||||||
@ -57,6 +57,7 @@ public enum EngineConfiguration {
|
|||||||
public let maxStoriesWeeklyCount: Int32
|
public let maxStoriesWeeklyCount: Int32
|
||||||
public let maxStoriesMonthlyCount: Int32
|
public let maxStoriesMonthlyCount: Int32
|
||||||
public let maxStoriesSuggestedReactions: Int32
|
public let maxStoriesSuggestedReactions: Int32
|
||||||
|
public let maxStoriesLinksCount: Int32
|
||||||
public let maxGiveawayChannelsCount: Int32
|
public let maxGiveawayChannelsCount: Int32
|
||||||
public let maxGiveawayCountriesCount: Int32
|
public let maxGiveawayCountriesCount: Int32
|
||||||
public let maxGiveawayPeriodSeconds: Int32
|
public let maxGiveawayPeriodSeconds: Int32
|
||||||
@ -88,6 +89,7 @@ public enum EngineConfiguration {
|
|||||||
maxStoriesWeeklyCount: Int32,
|
maxStoriesWeeklyCount: Int32,
|
||||||
maxStoriesMonthlyCount: Int32,
|
maxStoriesMonthlyCount: Int32,
|
||||||
maxStoriesSuggestedReactions: Int32,
|
maxStoriesSuggestedReactions: Int32,
|
||||||
|
maxStoriesLinksCount: Int32,
|
||||||
maxGiveawayChannelsCount: Int32,
|
maxGiveawayChannelsCount: Int32,
|
||||||
maxGiveawayCountriesCount: Int32,
|
maxGiveawayCountriesCount: Int32,
|
||||||
maxGiveawayPeriodSeconds: Int32,
|
maxGiveawayPeriodSeconds: Int32,
|
||||||
@ -114,6 +116,7 @@ public enum EngineConfiguration {
|
|||||||
self.maxStoriesWeeklyCount = maxStoriesWeeklyCount
|
self.maxStoriesWeeklyCount = maxStoriesWeeklyCount
|
||||||
self.maxStoriesMonthlyCount = maxStoriesMonthlyCount
|
self.maxStoriesMonthlyCount = maxStoriesMonthlyCount
|
||||||
self.maxStoriesSuggestedReactions = maxStoriesSuggestedReactions
|
self.maxStoriesSuggestedReactions = maxStoriesSuggestedReactions
|
||||||
|
self.maxStoriesLinksCount = maxStoriesLinksCount
|
||||||
self.maxGiveawayChannelsCount = maxGiveawayChannelsCount
|
self.maxGiveawayChannelsCount = maxGiveawayChannelsCount
|
||||||
self.maxGiveawayCountriesCount = maxGiveawayCountriesCount
|
self.maxGiveawayCountriesCount = maxGiveawayCountriesCount
|
||||||
self.maxGiveawayPeriodSeconds = maxGiveawayPeriodSeconds
|
self.maxGiveawayPeriodSeconds = maxGiveawayPeriodSeconds
|
||||||
@ -176,6 +179,7 @@ public extension EngineConfiguration.UserLimits {
|
|||||||
maxStoriesWeeklyCount: userLimitsConfiguration.maxStoriesWeeklyCount,
|
maxStoriesWeeklyCount: userLimitsConfiguration.maxStoriesWeeklyCount,
|
||||||
maxStoriesMonthlyCount: userLimitsConfiguration.maxStoriesMonthlyCount,
|
maxStoriesMonthlyCount: userLimitsConfiguration.maxStoriesMonthlyCount,
|
||||||
maxStoriesSuggestedReactions: userLimitsConfiguration.maxStoriesSuggestedReactions,
|
maxStoriesSuggestedReactions: userLimitsConfiguration.maxStoriesSuggestedReactions,
|
||||||
|
maxStoriesLinksCount: userLimitsConfiguration.maxStoriesLinksCount,
|
||||||
maxGiveawayChannelsCount: userLimitsConfiguration.maxGiveawayChannelsCount,
|
maxGiveawayChannelsCount: userLimitsConfiguration.maxGiveawayChannelsCount,
|
||||||
maxGiveawayCountriesCount: userLimitsConfiguration.maxGiveawayCountriesCount,
|
maxGiveawayCountriesCount: userLimitsConfiguration.maxGiveawayCountriesCount,
|
||||||
maxGiveawayPeriodSeconds: userLimitsConfiguration.maxGiveawayPeriodSeconds,
|
maxGiveawayPeriodSeconds: userLimitsConfiguration.maxGiveawayPeriodSeconds,
|
||||||
|
|||||||
@ -107,15 +107,15 @@ public class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
if selectedMedia == nil {
|
if selectedMedia == nil {
|
||||||
for media in item.message.media {
|
for media in item.message.media {
|
||||||
if let telegramImage = media as? TelegramMediaImage {
|
if let telegramImage = media as? TelegramMediaImage {
|
||||||
#if DEBUG
|
// #if DEBUG
|
||||||
if item.message.text == "#" {
|
// if item.message.text == "#" {
|
||||||
selectedMedia = TelegramMediaInvoice(title: "", description: "", photo: nil, receiptMessageId: nil, currency: "XTR", totalAmount: 100, startParam: "", extendedMedia: .preview(dimensions: telegramImage.representations.first?.dimensions ?? PixelDimensions(width: 1, height: 1), immediateThumbnailData: telegramImage.immediateThumbnailData, videoDuration: nil), flags: [], version: 0)
|
// selectedMedia = TelegramMediaInvoice(title: "", description: "", photo: nil, receiptMessageId: nil, currency: "XTR", totalAmount: 100, startParam: "", extendedMedia: .preview(dimensions: telegramImage.representations.first?.dimensions ?? PixelDimensions(width: 1, height: 1), immediateThumbnailData: telegramImage.immediateThumbnailData, videoDuration: nil), flags: [], version: 0)
|
||||||
} else {
|
// } else {
|
||||||
|
// selectedMedia = telegramImage
|
||||||
|
// }
|
||||||
|
// #else
|
||||||
selectedMedia = telegramImage
|
selectedMedia = telegramImage
|
||||||
}
|
// #endif
|
||||||
#else
|
|
||||||
selectedMedia = telegramImage
|
|
||||||
#endif
|
|
||||||
if shouldDownloadMediaAutomatically(settings: item.controllerInteraction.automaticMediaDownloadSettings, peerType: item.associatedData.automaticDownloadPeerType, networkType: item.associatedData.automaticDownloadNetworkType, authorPeerId: item.message.author?.id, contactsPeerIds: item.associatedData.contactsPeerIds, media: telegramImage) {
|
if shouldDownloadMediaAutomatically(settings: item.controllerInteraction.automaticMediaDownloadSettings, peerType: item.associatedData.automaticDownloadPeerType, networkType: item.associatedData.automaticDownloadNetworkType, authorPeerId: item.message.author?.id, contactsPeerIds: item.associatedData.contactsPeerIds, media: telegramImage) {
|
||||||
automaticDownload = .full
|
automaticDownload = .full
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,6 +24,8 @@ public final class DrawingLinkEntity: DrawingEntity, Codable {
|
|||||||
case scale
|
case scale
|
||||||
case rotation
|
case rotation
|
||||||
case renderImage
|
case renderImage
|
||||||
|
case whiteImage
|
||||||
|
case blackImage
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Style: Codable, Equatable {
|
public enum Style: Codable, Equatable {
|
||||||
@ -75,9 +77,10 @@ public final class DrawingLinkEntity: DrawingEntity, Codable {
|
|||||||
return self.position
|
return self.position
|
||||||
}
|
}
|
||||||
|
|
||||||
public var renderImage: UIImage?
|
public var whiteImage: UIImage?
|
||||||
public var secondaryRenderImage: UIImage?
|
public var blackImage: UIImage?
|
||||||
|
|
||||||
|
public var renderImage: UIImage?
|
||||||
public var renderSubEntities: [DrawingEntity]?
|
public var renderSubEntities: [DrawingEntity]?
|
||||||
|
|
||||||
public var isMedia: Bool {
|
public var isMedia: Bool {
|
||||||
@ -131,6 +134,15 @@ public final class DrawingLinkEntity: DrawingEntity, Codable {
|
|||||||
self.width = try container.decode(CGFloat.self, forKey: .width)
|
self.width = try container.decode(CGFloat.self, forKey: .width)
|
||||||
self.scale = try container.decode(CGFloat.self, forKey: .scale)
|
self.scale = try container.decode(CGFloat.self, forKey: .scale)
|
||||||
self.rotation = try container.decode(CGFloat.self, forKey: .rotation)
|
self.rotation = try container.decode(CGFloat.self, forKey: .rotation)
|
||||||
|
|
||||||
|
if let imagePath = try container.decodeIfPresent(String.self, forKey: .whiteImage), let image = UIImage(contentsOfFile: fullEntityMediaPath(imagePath)) {
|
||||||
|
self.whiteImage = image
|
||||||
|
}
|
||||||
|
|
||||||
|
if let imagePath = try container.decodeIfPresent(String.self, forKey: .blackImage), let image = UIImage(contentsOfFile: fullEntityMediaPath(imagePath)) {
|
||||||
|
self.blackImage = image
|
||||||
|
}
|
||||||
|
|
||||||
if let renderImageData = try? container.decodeIfPresent(Data.self, forKey: .renderImage) {
|
if let renderImageData = try? container.decodeIfPresent(Data.self, forKey: .renderImage) {
|
||||||
self.renderImage = UIImage(data: renderImageData)
|
self.renderImage = UIImage(data: renderImageData)
|
||||||
}
|
}
|
||||||
@ -162,7 +174,28 @@ public final class DrawingLinkEntity: DrawingEntity, Codable {
|
|||||||
try container.encode(self.width, forKey: .width)
|
try container.encode(self.width, forKey: .width)
|
||||||
try container.encode(self.scale, forKey: .scale)
|
try container.encode(self.scale, forKey: .scale)
|
||||||
try container.encode(self.rotation, forKey: .rotation)
|
try container.encode(self.rotation, forKey: .rotation)
|
||||||
if let renderImage, let data = renderImage.pngData() {
|
|
||||||
|
if let image = self.whiteImage {
|
||||||
|
let imagePath = "\(self.uuid)_white.png"
|
||||||
|
let fullImagePath = fullEntityMediaPath(imagePath)
|
||||||
|
if let imageData = image.pngData() {
|
||||||
|
try? FileManager.default.createDirectory(atPath: entitiesPath(), withIntermediateDirectories: true)
|
||||||
|
try? imageData.write(to: URL(fileURLWithPath: fullImagePath))
|
||||||
|
try container.encodeIfPresent(imagePath, forKey: .whiteImage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let image = self.blackImage {
|
||||||
|
let imagePath = "\(self.uuid)black.png"
|
||||||
|
let fullImagePath = fullEntityMediaPath(imagePath)
|
||||||
|
if let imageData = image.pngData() {
|
||||||
|
try? FileManager.default.createDirectory(atPath: entitiesPath(), withIntermediateDirectories: true)
|
||||||
|
try? imageData.write(to: URL(fileURLWithPath: fullImagePath))
|
||||||
|
try container.encodeIfPresent(imagePath, forKey: .blackImage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let renderImage = self.renderImage, let data = renderImage.pngData() {
|
||||||
try container.encode(data, forKey: .renderImage)
|
try container.encode(data, forKey: .renderImage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,6 +210,8 @@ public final class DrawingLinkEntity: DrawingEntity, Codable {
|
|||||||
newEntity.width = self.width
|
newEntity.width = self.width
|
||||||
newEntity.scale = self.scale
|
newEntity.scale = self.scale
|
||||||
newEntity.rotation = self.rotation
|
newEntity.rotation = self.rotation
|
||||||
|
newEntity.whiteImage = self.whiteImage
|
||||||
|
newEntity.blackImage = self.blackImage
|
||||||
return newEntity
|
return newEntity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,11 +5,11 @@ import AccountContext
|
|||||||
import Postbox
|
import Postbox
|
||||||
import TelegramCore
|
import TelegramCore
|
||||||
|
|
||||||
private func entitiesPath() -> String {
|
func entitiesPath() -> String {
|
||||||
return NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] + "/mediaEntities"
|
return NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] + "/mediaEntities"
|
||||||
}
|
}
|
||||||
|
|
||||||
private func fullEntityMediaPath(_ path: String) -> String {
|
func fullEntityMediaPath(_ path: String) -> String {
|
||||||
return NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] + "/mediaEntities/" + path
|
return NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] + "/mediaEntities/" + path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -343,7 +343,7 @@ public final class DrawingMessageRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func render(completion: @escaping (Result) -> Void) {
|
public func render(completion: @escaping (Result) -> Void) {
|
||||||
Queue.mainQueue().after(0.066) {
|
Queue.mainQueue().after(0.12) {
|
||||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
let defaultPresentationData = defaultPresentationData()
|
let defaultPresentationData = defaultPresentationData()
|
||||||
|
|
||||||
|
|||||||
@ -23,6 +23,7 @@ import MediaEditor
|
|||||||
import UrlEscaping
|
import UrlEscaping
|
||||||
|
|
||||||
private let linkTag = GenericComponentViewTag()
|
private let linkTag = GenericComponentViewTag()
|
||||||
|
private let nameTag = GenericComponentViewTag()
|
||||||
|
|
||||||
private final class SheetContent: CombinedComponent {
|
private final class SheetContent: CombinedComponent {
|
||||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||||
@ -130,16 +131,17 @@ private final class SheetContent: CombinedComponent {
|
|||||||
Text(
|
Text(
|
||||||
text: strings.Common_Done,
|
text: strings.Common_Done,
|
||||||
font: Font.bold(17.0),
|
font: Font.bold(17.0),
|
||||||
color: state.link.isEmpty ? theme.actionSheet.secondaryTextColor : theme.actionSheet.controlAccentColor
|
color: isValidLink ? theme.actionSheet.controlAccentColor : theme.actionSheet.secondaryTextColor
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
isEnabled: isValidLink,
|
isEnabled: isValidLink,
|
||||||
action: { [weak state] in
|
action: { [weak state] in
|
||||||
if let controller = controller() as? CreateLinkScreen {
|
if let controller = controller() as? CreateLinkScreen, let state {
|
||||||
state?.complete(controller: controller)
|
if state.complete(controller: controller) {
|
||||||
}
|
|
||||||
component.dismiss()
|
component.dismiss()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
),
|
),
|
||||||
availableSize: context.availableSize,
|
availableSize: context.availableSize,
|
||||||
transition: .immediate
|
transition: .immediate
|
||||||
@ -198,6 +200,11 @@ private final class SheetContent: CombinedComponent {
|
|||||||
state?.link = text
|
state?.link = text
|
||||||
state?.updated()
|
state?.updated()
|
||||||
},
|
},
|
||||||
|
textReturned: { [weak state] in
|
||||||
|
if let controller = controller() as? CreateLinkScreen {
|
||||||
|
state?.switchToNextField(controller: controller)
|
||||||
|
}
|
||||||
|
},
|
||||||
tag: linkTag
|
tag: linkTag
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -263,7 +270,15 @@ private final class SheetContent: CombinedComponent {
|
|||||||
placeholderText: strings.MediaEditor_Link_LinkName_Placeholder,
|
placeholderText: strings.MediaEditor_Link_LinkName_Placeholder,
|
||||||
textUpdated: { [weak state] text in
|
textUpdated: { [weak state] text in
|
||||||
state?.name = text
|
state?.name = text
|
||||||
|
},
|
||||||
|
textReturned: { [weak state] in
|
||||||
|
if let controller = controller() as? CreateLinkScreen, let state {
|
||||||
|
if state.complete(controller: controller) {
|
||||||
|
component.dismiss()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tag: nameTag
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -433,7 +448,21 @@ private final class CreateLinkSheetComponent: CombinedComponent {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func complete(controller: CreateLinkScreen) {
|
func switchToNextField(controller: CreateLinkScreen) {
|
||||||
|
if let view = controller.node.hostView.findTaggedView(tag: nameTag) as? LinkFieldComponent.View {
|
||||||
|
view.activateInput()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func complete(controller: CreateLinkScreen) -> Bool {
|
||||||
|
let explicitLink = explicitUrl(self.link)
|
||||||
|
if !isValidUrl(explicitLink) {
|
||||||
|
if let view = controller.node.hostView.findTaggedView(tag: linkTag) as? LinkFieldComponent.View {
|
||||||
|
view.animateError()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
let text = !self.name.isEmpty ? self.name : self.link
|
let text = !self.name.isEmpty ? self.name : self.link
|
||||||
|
|
||||||
var effectiveMedia: TelegramMediaWebpage?
|
var effectiveMedia: TelegramMediaWebpage?
|
||||||
@ -466,6 +495,7 @@ private final class CreateLinkSheetComponent: CombinedComponent {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -638,6 +668,7 @@ private final class LinkFieldComponent: Component {
|
|||||||
let link: Bool
|
let link: Bool
|
||||||
let placeholderText: String
|
let placeholderText: String
|
||||||
let textUpdated: (String) -> Void
|
let textUpdated: (String) -> Void
|
||||||
|
let textReturned: () -> Void
|
||||||
let tag: AnyObject?
|
let tag: AnyObject?
|
||||||
|
|
||||||
init(
|
init(
|
||||||
@ -647,6 +678,7 @@ private final class LinkFieldComponent: Component {
|
|||||||
link: Bool,
|
link: Bool,
|
||||||
placeholderText: String,
|
placeholderText: String,
|
||||||
textUpdated: @escaping (String) -> Void,
|
textUpdated: @escaping (String) -> Void,
|
||||||
|
textReturned: @escaping () -> Void,
|
||||||
tag: AnyObject? = nil
|
tag: AnyObject? = nil
|
||||||
) {
|
) {
|
||||||
self.textColor = textColor
|
self.textColor = textColor
|
||||||
@ -655,6 +687,7 @@ private final class LinkFieldComponent: Component {
|
|||||||
self.link = link
|
self.link = link
|
||||||
self.placeholderText = placeholderText
|
self.placeholderText = placeholderText
|
||||||
self.textUpdated = textUpdated
|
self.textUpdated = textUpdated
|
||||||
|
self.textReturned = textReturned
|
||||||
self.tag = tag
|
self.tag = tag
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -714,14 +747,14 @@ private final class LinkFieldComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
|
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
|
||||||
|
if string == "\n" {
|
||||||
|
self.component?.textReturned()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
let newText = ((textField.text ?? "") as NSString).replacingCharacters(in: range, with: string)
|
let newText = ((textField.text ?? "") as NSString).replacingCharacters(in: range, with: string)
|
||||||
if let component = self.component, !component.link && newText.count > 48 {
|
if let component = self.component, !component.link && newText.count > 48 {
|
||||||
textField.layer.addShakeAnimation()
|
self.animateError()
|
||||||
let hapticFeedback = HapticFeedback()
|
|
||||||
hapticFeedback.error()
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.0, execute: {
|
|
||||||
let _ = hapticFeedback
|
|
||||||
})
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@ -735,6 +768,15 @@ private final class LinkFieldComponent: Component {
|
|||||||
self.textField.selectAll(nil)
|
self.textField.selectAll(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func animateError() {
|
||||||
|
self.textField.layer.addShakeAnimation()
|
||||||
|
let hapticFeedback = HapticFeedback()
|
||||||
|
hapticFeedback.error()
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.0, execute: {
|
||||||
|
let _ = hapticFeedback
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func update(component: LinkFieldComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
|
func update(component: LinkFieldComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
|
||||||
self.textField.textColor = component.textColor
|
self.textField.textColor = component.textColor
|
||||||
self.textField.text = component.text
|
self.textField.text = component.text
|
||||||
@ -747,6 +789,8 @@ private final class LinkFieldComponent: Component {
|
|||||||
self.textField.autocorrectionType = .no
|
self.textField.autocorrectionType = .no
|
||||||
self.textField.autocapitalizationType = .none
|
self.textField.autocapitalizationType = .none
|
||||||
self.textField.textContentType = .URL
|
self.textField.textContentType = .URL
|
||||||
|
} else {
|
||||||
|
self.textField.returnKeyType = .done
|
||||||
}
|
}
|
||||||
|
|
||||||
self.component = component
|
self.component = component
|
||||||
|
|||||||
@ -4486,7 +4486,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
}
|
}
|
||||||
|
|
||||||
if existingEntity == nil {
|
if existingEntity == nil {
|
||||||
let maxLinkCount = 3
|
let maxLinkCount = self.context.userLimits.maxStoriesLinksCount
|
||||||
var currentLinkCount = 0
|
var currentLinkCount = 0
|
||||||
self.entitiesView.eachView { entityView in
|
self.entitiesView.eachView { entityView in
|
||||||
if entityView.entity is DrawingLinkEntity {
|
if entityView.entity is DrawingLinkEntity {
|
||||||
@ -4528,8 +4528,8 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
}
|
}
|
||||||
|
|
||||||
let entity = DrawingLinkEntity(url: result.url, name: result.name, webpage: result.webpage, positionBelowText: result.positionBelowText, largeMedia: result.largeMedia, style: style)
|
let entity = DrawingLinkEntity(url: result.url, name: result.name, webpage: result.webpage, positionBelowText: result.positionBelowText, largeMedia: result.largeMedia, style: style)
|
||||||
entity.renderImage = result.image
|
entity.whiteImage = result.image
|
||||||
entity.secondaryRenderImage = result.nightImage
|
entity.blackImage = result.nightImage
|
||||||
|
|
||||||
if let existingEntity {
|
if let existingEntity {
|
||||||
self.entitiesView.remove(uuid: existingEntity.uuid, animated: true)
|
self.entitiesView.remove(uuid: existingEntity.uuid, animated: true)
|
||||||
|
|||||||
@ -2565,7 +2565,7 @@ final class StoryStickersContentView: UIView, EmojiCustomContentView {
|
|||||||
InteractiveStickerButtonContent(
|
InteractiveStickerButtonContent(
|
||||||
theme: theme,
|
theme: theme,
|
||||||
title: strings.MediaEditor_AddLink,
|
title: strings.MediaEditor_AddLink,
|
||||||
iconName: "Premium/Link",
|
iconName: self.isPremium ? "Media Editor/Link" : "Media Editor/LinkLocked",
|
||||||
useOpaqueTheme: useOpaqueTheme,
|
useOpaqueTheme: useOpaqueTheme,
|
||||||
tintContainerView: self.tintContainerView
|
tintContainerView: self.tintContainerView
|
||||||
)
|
)
|
||||||
|
|||||||
12
submodules/TelegramUI/Images.xcassets/Media Editor/Link.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Media Editor/Link.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "link.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
submodules/TelegramUI/Images.xcassets/Media Editor/Link.imageset/link.pdf
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Media Editor/Link.imageset/link.pdf
vendored
Normal file
Binary file not shown.
12
submodules/TelegramUI/Images.xcassets/Media Editor/LinkLocked.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Media Editor/LinkLocked.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "linklocked.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
submodules/TelegramUI/Images.xcassets/Media Editor/LinkLocked.imageset/linklocked.pdf
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Media Editor/LinkLocked.imageset/linklocked.pdf
vendored
Normal file
Binary file not shown.
@ -52,26 +52,8 @@ extension ChatControllerImpl {
|
|||||||
|
|
||||||
var items: [ContextMenuItem] = []
|
var items: [ContextMenuItem] = []
|
||||||
|
|
||||||
if let info {
|
|
||||||
for url in info.urls {
|
|
||||||
items.append(
|
items.append(
|
||||||
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_AddToContacts, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Card_Copy, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||||
guard let self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
f(.default)
|
|
||||||
self.controllerInteraction?.openUrl(ChatControllerInteraction.OpenUrl(url: url.url, concealed: false, external: false, message: message))
|
|
||||||
}))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !items.isEmpty {
|
|
||||||
items.append(.separator)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
items.append(
|
|
||||||
.action(ContextMenuActionItem(text: "Copy Card Number", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
|
||||||
f(.default)
|
f(.default)
|
||||||
|
|
||||||
guard let self else {
|
guard let self else {
|
||||||
|
|||||||
@ -44,7 +44,7 @@ extension ChatControllerImpl {
|
|||||||
var items: [ContextMenuItem] = []
|
var items: [ContextMenuItem] = []
|
||||||
|
|
||||||
items.append(
|
items.append(
|
||||||
.action(ContextMenuActionItem(text: "Search", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Search"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Hashtag_Search, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Search"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -54,7 +54,7 @@ extension ChatControllerImpl {
|
|||||||
)
|
)
|
||||||
|
|
||||||
items.append(
|
items.append(
|
||||||
.action(ContextMenuActionItem(text: "Copy Hashtag", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Hashtag_Copy, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||||
f(.default)
|
f(.default)
|
||||||
|
|
||||||
guard let self else {
|
guard let self else {
|
||||||
|
|||||||
@ -80,7 +80,7 @@ extension ChatControllerImpl {
|
|||||||
|
|
||||||
if canAddToReadingList {
|
if canAddToReadingList {
|
||||||
items.append(
|
items.append(
|
||||||
.action(ContextMenuActionItem(text: "Add to Reading List", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Add"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
.action(ContextMenuActionItem(text: self.presentationData.strings.Conversation_AddToReadingList, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Add"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||||
f(.default)
|
f(.default)
|
||||||
|
|
||||||
if let link = URL(string: url) {
|
if let link = URL(string: url) {
|
||||||
@ -88,16 +88,10 @@ extension ChatControllerImpl {
|
|||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
// / items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_AddToReadingList, color: .accent, action: { [weak actionSheet] in
|
|
||||||
// // actionSheet?.dismissAnimated()
|
|
||||||
// // if let link = URL(string: url) {
|
|
||||||
// // let _ = try? SSReadingList.default()?.addItem(with: link, title: nil, previewText: nil)
|
|
||||||
// // }
|
|
||||||
// // }))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
items.append(
|
items.append(
|
||||||
.action(ContextMenuActionItem(text: "Copy Link", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
.action(ContextMenuActionItem(text: self.presentationData.strings.Conversation_ContextMenuCopyLink, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||||
f(.default)
|
f(.default)
|
||||||
|
|
||||||
guard let self else {
|
guard let self else {
|
||||||
|
|||||||
@ -68,8 +68,34 @@ extension ChatControllerImpl {
|
|||||||
|
|
||||||
var items: [ContextMenuItem] = []
|
var items: [ContextMenuItem] = []
|
||||||
if let peer {
|
if let peer {
|
||||||
|
if case .user = peer {
|
||||||
items.append(
|
items.append(
|
||||||
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_SendMessage, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MessageBubble"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Username_SendMessage, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MessageBubble"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||||
|
f(.default)
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.openPeer(peer: peer, navigation: .chat(textInputState: nil, subject: nil, peekData: nil), fromMessage: nil)
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
var isGroup = true
|
||||||
|
if case let .channel(channel) = peer, case .broadcast = channel.info {
|
||||||
|
isGroup = false
|
||||||
|
}
|
||||||
|
|
||||||
|
let openTitle: String
|
||||||
|
let openIcon: UIImage?
|
||||||
|
|
||||||
|
if isGroup {
|
||||||
|
openTitle = self.presentationData.strings.Chat_Context_Username_OpenGroup
|
||||||
|
openIcon = UIImage(bundleImageName: "Chat/Context Menu/Groups")
|
||||||
|
} else {
|
||||||
|
openTitle = self.presentationData.strings.Chat_Context_Username_OpenChannel
|
||||||
|
openIcon = UIImage(bundleImageName: "Chat/Context Menu/Channels")
|
||||||
|
}
|
||||||
|
items.append(
|
||||||
|
.action(ContextMenuActionItem(text: openTitle, icon: { theme in return generateTintedImage(image: openIcon, color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||||
f(.default)
|
f(.default)
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
@ -78,9 +104,10 @@ extension ChatControllerImpl {
|
|||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
items.append(
|
items.append(
|
||||||
.action(ContextMenuActionItem(text: "Copy Username", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Username_Copy, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||||
f(.default)
|
f(.default)
|
||||||
|
|
||||||
guard let self else {
|
guard let self else {
|
||||||
@ -117,7 +144,7 @@ extension ChatControllerImpl {
|
|||||||
} else {
|
} else {
|
||||||
let emptyAction: ((ContextMenuActionItem.Action) -> Void)? = nil
|
let emptyAction: ((ContextMenuActionItem.Action) -> Void)? = nil
|
||||||
items.append(
|
items.append(
|
||||||
.action(ContextMenuActionItem(text: "This user doesn't exist on Telegram.", textLayout: .multiline, textFont: .small, icon: { _ in return nil }, action: emptyAction))
|
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Username_NotOnTelegram, textLayout: .multiline, textFont: .small, icon: { _ in return nil }, action: emptyAction))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -902,40 +902,40 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
// #if DEBUG
|
||||||
if message.text == "#", let telegramImage = message.media.first(where: { $0 is TelegramMediaImage }) as? TelegramMediaImage {
|
// if message.text == "#", let telegramImage = message.media.first(where: { $0 is TelegramMediaImage }) as? TelegramMediaImage {
|
||||||
let invoice = TelegramMediaInvoice(title: "", description: "", photo: nil, receiptMessageId: nil, currency: "XTR", totalAmount: 100, startParam: "", extendedMedia: .preview(dimensions: telegramImage.representations.first?.dimensions ?? PixelDimensions(width: 1, height: 1), immediateThumbnailData: telegramImage.immediateThumbnailData, videoDuration: nil), flags: [], version: 0)
|
// let invoice = TelegramMediaInvoice(title: "", description: "", photo: nil, receiptMessageId: nil, currency: "XTR", totalAmount: 100, startParam: "", extendedMedia: .preview(dimensions: telegramImage.representations.first?.dimensions ?? PixelDimensions(width: 1, height: 1), immediateThumbnailData: telegramImage.immediateThumbnailData, videoDuration: nil), flags: [], version: 0)
|
||||||
|
//
|
||||||
let inputData = Promise<BotCheckoutController.InputData?>()
|
// let inputData = Promise<BotCheckoutController.InputData?>()
|
||||||
inputData.set(.single(
|
// inputData.set(.single(
|
||||||
BotCheckoutController.InputData(
|
// BotCheckoutController.InputData(
|
||||||
form: BotPaymentForm(id: 123, canSaveCredentials: false, passwordMissing: false, invoice: BotPaymentInvoice(isTest: false, requestedFields: [], currency: "XTR", prices: [BotPaymentPrice(label: "", amount: 100)], tip: nil, termsInfo: nil), paymentBotId: message.id.peerId, providerId: nil, url: nil, nativeProvider: nil, savedInfo: nil, savedCredentials: [], additionalPaymentMethods: []),
|
// form: BotPaymentForm(id: 123, canSaveCredentials: false, passwordMissing: false, invoice: BotPaymentInvoice(isTest: false, requestedFields: [], currency: "XTR", prices: [BotPaymentPrice(label: "", amount: 100)], tip: nil, termsInfo: nil), paymentBotId: message.id.peerId, providerId: nil, url: nil, nativeProvider: nil, savedInfo: nil, savedCredentials: [], additionalPaymentMethods: []),
|
||||||
validatedFormInfo: nil,
|
// validatedFormInfo: nil,
|
||||||
botPeer: nil
|
// botPeer: nil
|
||||||
)))
|
// )))
|
||||||
if invoice.currency == "XTR", let starsContext = strongSelf.context.starsContext {
|
// if invoice.currency == "XTR", let starsContext = strongSelf.context.starsContext {
|
||||||
let starsInputData = combineLatest(
|
// let starsInputData = combineLatest(
|
||||||
inputData.get(),
|
// inputData.get(),
|
||||||
starsContext.state
|
// starsContext.state
|
||||||
)
|
// )
|
||||||
|> map { data, state -> (StarsContext.State, BotPaymentForm, EnginePeer?)? in
|
// |> map { data, state -> (StarsContext.State, BotPaymentForm, EnginePeer?)? in
|
||||||
if let data, let state {
|
// if let data, let state {
|
||||||
return (state, data.form, data.botPeer)
|
// return (state, data.form, data.botPeer)
|
||||||
} else {
|
// } else {
|
||||||
return nil
|
// return nil
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
let _ = (starsInputData |> filter { $0 != nil } |> take(1) |> deliverOnMainQueue).start(next: { [weak self] _ in
|
// let _ = (starsInputData |> filter { $0 != nil } |> take(1) |> deliverOnMainQueue).start(next: { [weak self] _ in
|
||||||
guard let strongSelf = self else {
|
// guard let strongSelf = self else {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
let controller = strongSelf.context.sharedContext.makeStarsTransferScreen(context: strongSelf.context, starsContext: starsContext, invoice: invoice, source: .message(message.id), inputData: starsInputData, completion: { _ in })
|
// let controller = strongSelf.context.sharedContext.makeStarsTransferScreen(context: strongSelf.context, starsContext: starsContext, invoice: invoice, source: .message(message.id), inputData: starsInputData, completion: { _ in })
|
||||||
strongSelf.push(controller)
|
// strongSelf.push(controller)
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
return true
|
// return true
|
||||||
}
|
// }
|
||||||
#endif
|
// #endif
|
||||||
|
|
||||||
if let invoice = media as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia {
|
if let invoice = media as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia {
|
||||||
switch extendedMedia {
|
switch extendedMedia {
|
||||||
|
|||||||
@ -26,7 +26,7 @@ public func isValidUrl(_ url: String, validSchemes: [String: Bool] = ["http": tr
|
|||||||
if let escapedUrl = url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let url = URL(string: escapedUrl), let scheme = url.scheme?.lowercased(), let requiresTopLevelDomain = validSchemes[scheme], let host = url.host, (!requiresTopLevelDomain || host.contains(".")) && url.user == nil {
|
if let escapedUrl = url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let url = URL(string: escapedUrl), let scheme = url.scheme?.lowercased(), let requiresTopLevelDomain = validSchemes[scheme], let host = url.host, (!requiresTopLevelDomain || host.contains(".")) && url.user == nil {
|
||||||
if requiresTopLevelDomain {
|
if requiresTopLevelDomain {
|
||||||
let components = host.components(separatedBy: ".")
|
let components = host.components(separatedBy: ".")
|
||||||
let domain = (components.first ?? "")
|
let domain = (components.last ?? "")
|
||||||
if domain.isEmpty {
|
if domain.isEmpty {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user