mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-04 21:41:45 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
115c896a96
2
Makefile
2
Makefile
@ -3,7 +3,7 @@
|
|||||||
include Utils.makefile
|
include Utils.makefile
|
||||||
|
|
||||||
|
|
||||||
APP_VERSION="6.1"
|
APP_VERSION="6.1.1"
|
||||||
CORE_COUNT=$(shell sysctl -n hw.logicalcpu)
|
CORE_COUNT=$(shell sysctl -n hw.logicalcpu)
|
||||||
CORE_COUNT_MINUS_ONE=$(shell expr ${CORE_COUNT} \- 1)
|
CORE_COUNT_MINUS_ONE=$(shell expr ${CORE_COUNT} \- 1)
|
||||||
|
|
||||||
|
|||||||
@ -1521,7 +1521,6 @@
|
|||||||
|
|
||||||
"Channel.UpdatePhotoItem" = "Set Channel Photo";
|
"Channel.UpdatePhotoItem" = "Set Channel Photo";
|
||||||
|
|
||||||
"Channel.AboutItem" = "about";
|
|
||||||
"Channel.LinkItem" = "share link";
|
"Channel.LinkItem" = "share link";
|
||||||
"Channel.Edit.AboutItem" = "Description";
|
"Channel.Edit.AboutItem" = "Description";
|
||||||
"Channel.Edit.LinkItem" = "Link";
|
"Channel.Edit.LinkItem" = "Link";
|
||||||
@ -5495,3 +5494,6 @@ Any member of this group will be able to see messages in the channel.";
|
|||||||
|
|
||||||
"Message.GenericForwardedPsa" = "Public Service Announcement\nFrom: %@";
|
"Message.GenericForwardedPsa" = "Public Service Announcement\nFrom: %@";
|
||||||
"Message.ForwardedPsa.covid" = "Covid-19 Notification\nFrom: %@";
|
"Message.ForwardedPsa.covid" = "Covid-19 Notification\nFrom: %@";
|
||||||
|
|
||||||
|
"Channel.AboutItem" = "about";
|
||||||
|
"PeerInfo.GroupAboutItem" = "about";
|
||||||
|
|||||||
@ -1216,7 +1216,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
if item.enableContextActions {
|
if item.enableContextActions {
|
||||||
if case .psa = promoInfo {
|
if case .psa = promoInfo {
|
||||||
peerRevealOptions = [
|
peerRevealOptions = [
|
||||||
ItemListRevealOption(key: RevealOptionKey.hidePsa.rawValue, title: item.presentationData.strings.ChatList_HideAction, icon: hideIcon, color: item.presentationData.theme.list.itemDisclosureActions.inactive.fillColor, textColor: item.presentationData.theme.list.itemDisclosureActions.neutral1.foregroundColor)
|
ItemListRevealOption(key: RevealOptionKey.hidePsa.rawValue, title: item.presentationData.strings.ChatList_HideAction, icon: deleteIcon, color: item.presentationData.theme.list.itemDisclosureActions.inactive.fillColor, textColor: item.presentationData.theme.list.itemDisclosureActions.neutral1.foregroundColor)
|
||||||
]
|
]
|
||||||
peerLeftRevealOptions = []
|
peerLeftRevealOptions = []
|
||||||
} else if promoInfo == nil {
|
} else if promoInfo == nil {
|
||||||
|
|||||||
@ -156,7 +156,11 @@ public struct MessageIndex: Comparable, Hashable {
|
|||||||
return lhs.id.namespace < rhs.id.namespace
|
return lhs.id.namespace < rhs.id.namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
return lhs.id.id < rhs.id.id
|
if lhs.id.id != rhs.id.id {
|
||||||
|
return lhs.id.id < rhs.id.id
|
||||||
|
}
|
||||||
|
|
||||||
|
return lhs.id.peerId.toInt64() < rhs.id.peerId.toInt64()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1879,13 +1879,16 @@ final class MessageHistoryTable: Table {
|
|||||||
if let forwardInfo = message.forwardInfo {
|
if let forwardInfo = message.forwardInfo {
|
||||||
var forwardInfoFlags: Int8 = 1
|
var forwardInfoFlags: Int8 = 1
|
||||||
if forwardInfo.sourceId != nil {
|
if forwardInfo.sourceId != nil {
|
||||||
forwardInfoFlags |= 2
|
forwardInfoFlags |= 1 << 1
|
||||||
}
|
}
|
||||||
if forwardInfo.sourceMessageId != nil {
|
if forwardInfo.sourceMessageId != nil {
|
||||||
forwardInfoFlags |= 4
|
forwardInfoFlags |= 1 << 2
|
||||||
}
|
}
|
||||||
if forwardInfo.authorSignature != nil {
|
if forwardInfo.authorSignature != nil {
|
||||||
forwardInfoFlags |= 8
|
forwardInfoFlags |= 1 << 3
|
||||||
|
}
|
||||||
|
if forwardInfo.psaType != nil {
|
||||||
|
forwardInfoFlags |= 1 << 4
|
||||||
}
|
}
|
||||||
sharedBuffer.write(&forwardInfoFlags, offset: 0, length: 1)
|
sharedBuffer.write(&forwardInfoFlags, offset: 0, length: 1)
|
||||||
var forwardAuthorId: Int64 = forwardInfo.authorId?.toInt64() ?? 0
|
var forwardAuthorId: Int64 = forwardInfo.authorId?.toInt64() ?? 0
|
||||||
@ -1917,6 +1920,17 @@ final class MessageHistoryTable: Table {
|
|||||||
sharedBuffer.write(&length, offset: 0, length: 4)
|
sharedBuffer.write(&length, offset: 0, length: 4)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let psaType = forwardInfo.psaType {
|
||||||
|
if let data = psaType.data(using: .utf8, allowLossyConversion: true) {
|
||||||
|
var length: Int32 = Int32(data.count)
|
||||||
|
sharedBuffer.write(&length, offset: 0, length: 4)
|
||||||
|
sharedBuffer.write(data)
|
||||||
|
} else {
|
||||||
|
var length: Int32 = 0
|
||||||
|
sharedBuffer.write(&length, offset: 0, length: 4)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
var forwardInfoFlags: Int8 = 0
|
var forwardInfoFlags: Int8 = 0
|
||||||
sharedBuffer.write(&forwardInfoFlags, offset: 0, length: 1)
|
sharedBuffer.write(&forwardInfoFlags, offset: 0, length: 1)
|
||||||
|
|||||||
@ -296,6 +296,7 @@ public final class AccountStateManager {
|
|||||||
var collectedPollCompletionSubscribers: [(Int32, ([MessageId]) -> Void)] = []
|
var collectedPollCompletionSubscribers: [(Int32, ([MessageId]) -> Void)] = []
|
||||||
var collectedReplayAsynchronouslyBuiltFinalState: [(AccountFinalState, () -> Void)] = []
|
var collectedReplayAsynchronouslyBuiltFinalState: [(AccountFinalState, () -> Void)] = []
|
||||||
var processEvents: [(Int32, AccountFinalStateEvents)] = []
|
var processEvents: [(Int32, AccountFinalStateEvents)] = []
|
||||||
|
var customOperations: [(Int32, Signal<Void, NoError>)] = []
|
||||||
|
|
||||||
var replacedOperations: [AccountStateManagerOperation] = []
|
var replacedOperations: [AccountStateManagerOperation] = []
|
||||||
|
|
||||||
@ -313,6 +314,8 @@ public final class AccountStateManager {
|
|||||||
collectedReplayAsynchronouslyBuiltFinalState.append((finalState, completion))
|
collectedReplayAsynchronouslyBuiltFinalState.append((finalState, completion))
|
||||||
case let .processEvents(operationId, events):
|
case let .processEvents(operationId, events):
|
||||||
processEvents.append((operationId, events))
|
processEvents.append((operationId, events))
|
||||||
|
case let .custom(operationId, customSignal):
|
||||||
|
customOperations.append((operationId, customSignal))
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -335,6 +338,10 @@ public final class AccountStateManager {
|
|||||||
replacedOperations.append(AccountStateManagerOperation(content: .processEvents(operationId, events)))
|
replacedOperations.append(AccountStateManagerOperation(content: .processEvents(operationId, events)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (operationId, customSignal) in customOperations {
|
||||||
|
replacedOperations.append(AccountStateManagerOperation(content: .custom(operationId, customSignal)))
|
||||||
|
}
|
||||||
|
|
||||||
self.operations.removeAll()
|
self.operations.removeAll()
|
||||||
self.operations.append(contentsOf: replacedOperations)
|
self.operations.append(contentsOf: replacedOperations)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,40 +60,6 @@ private func dialogTopMessage(network: Network, postbox: Postbox, peerId: PeerId
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchPeerCloudReadState(network: Network, postbox: Postbox, peerId: PeerId, inputPeer: Api.InputPeer) -> Signal<PeerReadState?, NoError> {
|
|
||||||
return network.request(Api.functions.messages.getPeerDialogs(peers: [.inputDialogPeer(peer: inputPeer)]))
|
|
||||||
|> map { result -> PeerReadState? in
|
|
||||||
switch result {
|
|
||||||
case let .peerDialogs(dialogs, _, _, _, _):
|
|
||||||
if let dialog = dialogs.filter({ $0.peerId == peerId }).first {
|
|
||||||
let apiTopMessage: Int32
|
|
||||||
let apiReadInboxMaxId: Int32
|
|
||||||
let apiReadOutboxMaxId: Int32
|
|
||||||
let apiUnreadCount: Int32
|
|
||||||
let apiMarkedUnread: Bool
|
|
||||||
switch dialog {
|
|
||||||
case let .dialog(flags, _, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, _, _, _, _, _):
|
|
||||||
apiTopMessage = topMessage
|
|
||||||
apiReadInboxMaxId = readInboxMaxId
|
|
||||||
apiReadOutboxMaxId = readOutboxMaxId
|
|
||||||
apiUnreadCount = unreadCount
|
|
||||||
apiMarkedUnread = (flags & (1 << 3)) != 0
|
|
||||||
case .dialogFolder:
|
|
||||||
assertionFailure()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return .idBased(maxIncomingReadId: apiReadInboxMaxId, maxOutgoingReadId: apiReadOutboxMaxId, maxKnownId: apiTopMessage, count: apiUnreadCount, markedUnread: apiMarkedUnread)
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|> `catch` { _ -> Signal<PeerReadState?, NoError> in
|
|
||||||
return .single(nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func dialogReadState(network: Network, postbox: Postbox, peerId: PeerId) -> Signal<(PeerReadState, PeerReadStateMarker), PeerReadStateValidationError> {
|
private func dialogReadState(network: Network, postbox: Postbox, peerId: PeerId) -> Signal<(PeerReadState, PeerReadStateMarker), PeerReadStateValidationError> {
|
||||||
return dialogTopMessage(network: network, postbox: postbox, peerId: peerId)
|
return dialogTopMessage(network: network, postbox: postbox, peerId: peerId)
|
||||||
|> mapToSignal { topMessage -> Signal<(PeerReadState, PeerReadStateMarker), PeerReadStateValidationError> in
|
|> mapToSignal { topMessage -> Signal<(PeerReadState, PeerReadStateMarker), PeerReadStateValidationError> in
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -6482,7 +6482,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let tooltipScreen = TooltipScreen(text: psaText, textEntities: psaEntities, icon: .info, location: .top, shouldDismissOnTouch: { point in
|
let tooltipScreen = TooltipScreen(text: psaText, textEntities: psaEntities, icon: .info, location: .top, displayDuration: .custom(10.0), shouldDismissOnTouch: { point in
|
||||||
return .ignore
|
return .ignore
|
||||||
}, openActiveTextItem: { [weak self] item, action in
|
}, openActiveTextItem: { [weak self] item, action in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
@ -6492,7 +6492,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
case let .url(url, concealed):
|
case let .url(url, concealed):
|
||||||
switch action {
|
switch action {
|
||||||
case .tap:
|
case .tap:
|
||||||
strongSelf.openUrl(url, concealed: false)
|
strongSelf.openUrl(url, concealed: concealed)
|
||||||
case .longTap:
|
case .longTap:
|
||||||
strongSelf.controllerInteraction?.longTap(.url(url), nil)
|
strongSelf.controllerInteraction?.longTap(.url(url), nil)
|
||||||
}
|
}
|
||||||
@ -6560,18 +6560,34 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
|
|
||||||
let psaEntities: [MessageTextEntity] = generateTextEntities(psaText, enabledTypes: .url)
|
let psaEntities: [MessageTextEntity] = generateTextEntities(psaText, enabledTypes: .url)
|
||||||
|
|
||||||
|
let messageId = item.message.id
|
||||||
|
|
||||||
var found = false
|
var found = false
|
||||||
self.forEachController({ controller in
|
self.forEachController({ controller in
|
||||||
if let controller = controller as? TooltipScreen {
|
if let controller = controller as? TooltipScreen {
|
||||||
if controller.text == psaText {
|
if controller.text == psaText {
|
||||||
found = true
|
found = true
|
||||||
controller.dismiss()
|
controller.resetDismissTimeout()
|
||||||
|
|
||||||
|
controller.willBecomeDismissed = { [weak self] tooltipScreen in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if strongSelf.controllerInteraction?.currentPsaMessageWithTooltip == messageId {
|
||||||
|
strongSelf.controllerInteraction?.currentPsaMessageWithTooltip = nil
|
||||||
|
strongSelf.updatePollTooltipMessageState(animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
if found {
|
if found {
|
||||||
|
self.controllerInteraction?.currentPsaMessageWithTooltip = messageId
|
||||||
|
self.updatePollTooltipMessageState(animated: !isAutomatic)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6585,7 +6601,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
case let .url(url, concealed):
|
case let .url(url, concealed):
|
||||||
switch action {
|
switch action {
|
||||||
case .tap:
|
case .tap:
|
||||||
strongSelf.openUrl(url, concealed: false)
|
strongSelf.openUrl(url, concealed: concealed)
|
||||||
case .longTap:
|
case .longTap:
|
||||||
strongSelf.controllerInteraction?.longTap(.url(url), nil)
|
strongSelf.controllerInteraction?.longTap(.url(url), nil)
|
||||||
}
|
}
|
||||||
@ -6620,7 +6636,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
let messageId = item.message.id
|
|
||||||
self.controllerInteraction?.currentPsaMessageWithTooltip = messageId
|
self.controllerInteraction?.currentPsaMessageWithTooltip = messageId
|
||||||
self.updatePollTooltipMessageState(animated: !isAutomatic)
|
self.updatePollTooltipMessageState(animated: !isAutomatic)
|
||||||
|
|
||||||
|
|||||||
@ -784,7 +784,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
|||||||
|
|
||||||
var effectiveAuthor: Peer?
|
var effectiveAuthor: Peer?
|
||||||
var ignoreForward = false
|
var ignoreForward = false
|
||||||
let displayAuthorInfo: Bool
|
var displayAuthorInfo: Bool
|
||||||
|
|
||||||
let avatarInset: CGFloat
|
let avatarInset: CGFloat
|
||||||
var hasAvatar = false
|
var hasAvatar = false
|
||||||
@ -809,7 +809,10 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
|||||||
displayAuthorInfo = !mergedTop.merged && incoming && effectiveAuthor != nil
|
displayAuthorInfo = !mergedTop.merged && incoming && effectiveAuthor != nil
|
||||||
} else {
|
} else {
|
||||||
effectiveAuthor = firstMessage.author
|
effectiveAuthor = firstMessage.author
|
||||||
displayAuthorInfo = !mergedTop.merged && incoming && peerId.isGroupOrChannel && effectiveAuthor != nil
|
displayAuthorInfo = !mergedTop.merged && incoming && peerId.isGroupOrChannel && effectiveAuthor != nil
|
||||||
|
if let forwardInfo = firstMessage.forwardInfo, forwardInfo.psaType != nil {
|
||||||
|
displayAuthorInfo = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if peerId != item.context.account.peerId {
|
if peerId != item.context.account.peerId {
|
||||||
@ -827,10 +830,6 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
|||||||
} else if incoming {
|
} else if incoming {
|
||||||
hasAvatar = true
|
hasAvatar = true
|
||||||
}
|
}
|
||||||
/*case .group:
|
|
||||||
allowFullWidth = true
|
|
||||||
hasAvatar = true
|
|
||||||
displayAuthorInfo = true*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let forwardInfo = item.content.firstMessage.forwardInfo, forwardInfo.source == nil, forwardInfo.author?.id.namespace == Namespaces.Peer.CloudUser {
|
if let forwardInfo = item.content.firstMessage.forwardInfo, forwardInfo.source == nil, forwardInfo.author?.id.namespace == Namespaces.Peer.CloudUser {
|
||||||
@ -987,6 +986,10 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let forwardInfo = firstMessage.forwardInfo, forwardInfo.psaType != nil {
|
||||||
|
inlineBotNameString = nil
|
||||||
|
}
|
||||||
|
|
||||||
var contentPropertiesAndLayouts: [(CGSize?, ChatMessageBubbleContentProperties, ChatMessageBubblePreparePosition, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void)))] = []
|
var contentPropertiesAndLayouts: [(CGSize?, ChatMessageBubbleContentProperties, ChatMessageBubblePreparePosition, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void)))] = []
|
||||||
|
|
||||||
let topNodeMergeStatus: ChatMessageBubbleMergeStatus = mergedTop.merged ? (incoming ? .Left : .Right) : .None(incoming ? .Incoming : .Outgoing)
|
let topNodeMergeStatus: ChatMessageBubbleMergeStatus = mergedTop.merged ? (incoming ? .Left : .Right) : .None(incoming ? .Incoming : .Outgoing)
|
||||||
@ -1877,19 +1880,19 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
|||||||
|
|
||||||
if let forwardInfoNode = forwardInfoSizeApply.1(bubbleContentWidth) {
|
if let forwardInfoNode = forwardInfoSizeApply.1(bubbleContentWidth) {
|
||||||
strongSelf.forwardInfoNode = forwardInfoNode
|
strongSelf.forwardInfoNode = forwardInfoNode
|
||||||
forwardInfoNode.openPsa = { [weak strongSelf] type, sourceNode in
|
|
||||||
guard let strongSelf = strongSelf, let item = strongSelf.item else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
item.controllerInteraction.displayPsa(type, sourceNode)
|
|
||||||
}
|
|
||||||
var animateFrame = true
|
var animateFrame = true
|
||||||
if forwardInfoNode.supernode == nil {
|
if forwardInfoNode.supernode == nil {
|
||||||
strongSelf.contextSourceNode.contentNode.addSubnode(forwardInfoNode)
|
strongSelf.contextSourceNode.contentNode.addSubnode(forwardInfoNode)
|
||||||
animateFrame = false
|
animateFrame = false
|
||||||
|
forwardInfoNode.openPsa = { [weak strongSelf] type, sourceNode in
|
||||||
|
guard let strongSelf = strongSelf, let item = strongSelf.item else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
item.controllerInteraction.displayPsa(type, sourceNode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let previousForwardInfoNodeFrame = forwardInfoNode.frame
|
let previousForwardInfoNodeFrame = forwardInfoNode.frame
|
||||||
forwardInfoNode.frame = CGRect(origin: CGPoint(x: contentOrigin.x + layoutConstants.text.bubbleInsets.left, y: layoutConstants.bubble.contentInsets.top + forwardInfoOriginY), size: forwardInfoSizeApply.0)
|
forwardInfoNode.frame = CGRect(origin: CGPoint(x: contentOrigin.x + layoutConstants.text.bubbleInsets.left, y: layoutConstants.bubble.contentInsets.top + forwardInfoOriginY), size: CGSize(width: bubbleContentWidth, height: forwardInfoSizeApply.0.height))
|
||||||
if case let .System(duration) = animation {
|
if case let .System(duration) = animation {
|
||||||
if animateFrame {
|
if animateFrame {
|
||||||
forwardInfoNode.layer.animateFrame(from: previousForwardInfoNodeFrame, to: forwardInfoNode.frame, duration: duration, timingFunction: kCAMediaTimingFunctionSpring)
|
forwardInfoNode.layer.animateFrame(from: previousForwardInfoNodeFrame, to: forwardInfoNode.frame, duration: duration, timingFunction: kCAMediaTimingFunctionSpring)
|
||||||
|
|||||||
@ -154,7 +154,32 @@ class ChatMessageForwardInfoNode: ASDisplayNode {
|
|||||||
case .standalone:
|
case .standalone:
|
||||||
let serviceColor = serviceMessageColorComponents(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
|
let serviceColor = serviceMessageColorComponents(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
|
||||||
titleColor = serviceColor.primaryText
|
titleColor = serviceColor.primaryText
|
||||||
completeSourceString = strings.Message_ForwardedMessageShort(peerString)
|
|
||||||
|
if let psaType = psaType {
|
||||||
|
var customFormat: String?
|
||||||
|
let key = "Message.ForwardedPsa.\(psaType)"
|
||||||
|
if let string = presentationData.strings.primaryComponent.dict[key] {
|
||||||
|
customFormat = string
|
||||||
|
} else if let string = presentationData.strings.secondaryComponent?.dict[key] {
|
||||||
|
customFormat = string
|
||||||
|
}
|
||||||
|
|
||||||
|
if let customFormat = customFormat {
|
||||||
|
if let range = customFormat.range(of: "%@") {
|
||||||
|
let leftPart = String(customFormat[customFormat.startIndex ..< range.lowerBound])
|
||||||
|
let rightPart = String(customFormat[range.upperBound...])
|
||||||
|
|
||||||
|
let formattedText = leftPart + peerString + rightPart
|
||||||
|
completeSourceString = (formattedText, [(0, NSRange(location: leftPart.count, length: peerString.count))])
|
||||||
|
} else {
|
||||||
|
completeSourceString = (customFormat, [])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
completeSourceString = strings.Message_GenericForwardedPsa(peerString)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
completeSourceString = strings.Message_ForwardedMessageShort(peerString)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentCredibilityIconImage: UIImage?
|
var currentCredibilityIconImage: UIImage?
|
||||||
|
|||||||
@ -122,6 +122,10 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
|||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if let shareButtonNode = strongSelf.shareButtonNode, shareButtonNode.frame.contains(point) {
|
if let shareButtonNode = strongSelf.shareButtonNode, shareButtonNode.frame.contains(point) {
|
||||||
return .fail
|
return .fail
|
||||||
|
} else if let forwardInfoNode = strongSelf.forwardInfoNode, forwardInfoNode.frame.contains(point) {
|
||||||
|
if forwardInfoNode.hasAction(at: strongSelf.view.convert(point, to: forwardInfoNode.view)) {
|
||||||
|
return .fail
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return .waitForSingleTap
|
return .waitForSingleTap
|
||||||
@ -572,6 +576,12 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
|||||||
if strongSelf.forwardInfoNode == nil {
|
if strongSelf.forwardInfoNode == nil {
|
||||||
strongSelf.forwardInfoNode = forwardInfoNode
|
strongSelf.forwardInfoNode = forwardInfoNode
|
||||||
strongSelf.addSubnode(forwardInfoNode)
|
strongSelf.addSubnode(forwardInfoNode)
|
||||||
|
forwardInfoNode.openPsa = { [weak strongSelf] type, sourceNode in
|
||||||
|
guard let strongSelf = strongSelf, let item = strongSelf.item else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
item.controllerInteraction.displayPsa(type, sourceNode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let forwardInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 12.0) : (params.width - params.rightInset - forwardInfoSize.width - layoutConstants.bubble.edgeInset - 12.0)), y: 8.0), size: forwardInfoSize)
|
let forwardInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 12.0) : (params.width - params.rightInset - forwardInfoSize.width - layoutConstants.bubble.edgeInset - 12.0)), y: 8.0), size: forwardInfoSize)
|
||||||
forwardInfoNode.frame = forwardInfoFrame
|
forwardInfoNode.frame = forwardInfoFrame
|
||||||
@ -696,26 +706,28 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
|||||||
|
|
||||||
if let forwardInfoNode = self.forwardInfoNode, forwardInfoNode.frame.contains(location) {
|
if let forwardInfoNode = self.forwardInfoNode, forwardInfoNode.frame.contains(location) {
|
||||||
if let item = self.item, let forwardInfo = item.message.forwardInfo {
|
if let item = self.item, let forwardInfo = item.message.forwardInfo {
|
||||||
if let sourceMessageId = forwardInfo.sourceMessageId {
|
let performAction: () -> Void = {
|
||||||
if let channel = forwardInfo.author as? TelegramChannel, channel.username == nil {
|
if let sourceMessageId = forwardInfo.sourceMessageId {
|
||||||
if case .member = channel.participationStatus {
|
if let channel = forwardInfo.author as? TelegramChannel, channel.username == nil {
|
||||||
} else {
|
if case let .broadcast(info) = channel.info, info.flags.contains(.hasDiscussionGroup) {
|
||||||
return .optionalAction({
|
} else if case .member = channel.participationStatus {
|
||||||
|
} else {
|
||||||
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_PrivateChannelTooltip, forwardInfoNode, nil)
|
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_PrivateChannelTooltip, forwardInfoNode, nil)
|
||||||
})
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return .optionalAction({
|
|
||||||
item.controllerInteraction.navigateToMessage(item.message.id, sourceMessageId)
|
item.controllerInteraction.navigateToMessage(item.message.id, sourceMessageId)
|
||||||
})
|
} else if let id = forwardInfo.source?.id ?? forwardInfo.author?.id {
|
||||||
} else if let id = forwardInfo.source?.id ?? forwardInfo.author?.id {
|
item.controllerInteraction.openPeer(id, .info, nil)
|
||||||
return .optionalAction({
|
} else if let _ = forwardInfo.authorSignature {
|
||||||
item.controllerInteraction.openPeer(id, .chat(textInputState: nil, subject: nil), nil)
|
|
||||||
})
|
|
||||||
} else if let _ = forwardInfo.authorSignature {
|
|
||||||
return .optionalAction({
|
|
||||||
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, forwardInfoNode, nil)
|
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, forwardInfoNode, nil)
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if forwardInfoNode.hasAction(at: self.view.convert(location, to: forwardInfoNode.view)) {
|
||||||
|
return .action({})
|
||||||
|
} else {
|
||||||
|
return .optionalAction(performAction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -609,11 +609,11 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
|||||||
}
|
}
|
||||||
if let cachedData = data.cachedData as? CachedUserData {
|
if let cachedData = data.cachedData as? CachedUserData {
|
||||||
if user.isScam {
|
if user.isScam {
|
||||||
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: user.botInfo == nil ? presentationData.strings.Profile_About : presentationData.strings.Channel_AboutItem, text: user.botInfo != nil ? presentationData.strings.UserInfo_ScamBotWarning : presentationData.strings.UserInfo_ScamUserWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: user.botInfo != nil ? enabledBioEntities : []), action: nil, requestLayout: {
|
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: user.botInfo == nil ? presentationData.strings.Profile_About : presentationData.strings.Profile_BotInfo, text: user.botInfo != nil ? presentationData.strings.UserInfo_ScamBotWarning : presentationData.strings.UserInfo_ScamUserWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: user.botInfo != nil ? enabledBioEntities : []), action: nil, requestLayout: {
|
||||||
interaction.requestLayout()
|
interaction.requestLayout()
|
||||||
}))
|
}))
|
||||||
} else if let about = cachedData.about, !about.isEmpty {
|
} else if let about = cachedData.about, !about.isEmpty {
|
||||||
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: user.botInfo == nil ? presentationData.strings.Profile_About : presentationData.strings.Channel_AboutItem, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: []), action: nil, longTapAction: bioContextAction, linkItemAction: bioLinkAction, requestLayout: {
|
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: user.botInfo == nil ? presentationData.strings.Profile_About : presentationData.strings.Profile_BotInfo, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: []), action: nil, longTapAction: bioContextAction, linkItemAction: bioLinkAction, requestLayout: {
|
||||||
interaction.requestLayout()
|
interaction.requestLayout()
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -733,11 +733,11 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
|||||||
} else if let group = data.peer as? TelegramGroup {
|
} else if let group = data.peer as? TelegramGroup {
|
||||||
if let cachedData = data.cachedData as? CachedGroupData {
|
if let cachedData = data.cachedData as? CachedGroupData {
|
||||||
if group.isScam {
|
if group.isScam {
|
||||||
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Channel_AboutItem, text: presentationData.strings.GroupInfo_ScamGroupWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledBioEntities), action: nil, requestLayout: {
|
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.PeerInfo_GroupAboutItem, text: presentationData.strings.GroupInfo_ScamGroupWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledBioEntities), action: nil, requestLayout: {
|
||||||
interaction.requestLayout()
|
interaction.requestLayout()
|
||||||
}))
|
}))
|
||||||
} else if let about = cachedData.about, !about.isEmpty {
|
} else if let about = cachedData.about, !about.isEmpty {
|
||||||
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Channel_AboutItem, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledBioEntities), action: nil, longTapAction: bioContextAction, linkItemAction: bioLinkAction, requestLayout: {
|
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.PeerInfo_GroupAboutItem, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledBioEntities), action: nil, longTapAction: bioContextAction, linkItemAction: bioLinkAction, requestLayout: {
|
||||||
interaction.requestLayout()
|
interaction.requestLayout()
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -391,6 +391,8 @@ public final class TooltipScreen: ViewController {
|
|||||||
public var willBecomeDismissed: ((TooltipScreen) -> Void)?
|
public var willBecomeDismissed: ((TooltipScreen) -> Void)?
|
||||||
public var becameDismissed: ((TooltipScreen) -> Void)?
|
public var becameDismissed: ((TooltipScreen) -> Void)?
|
||||||
|
|
||||||
|
private var dismissTimer: Foundation.Timer?
|
||||||
|
|
||||||
public init(text: String, textEntities: [MessageTextEntity] = [], icon: TooltipScreen.Icon?, location: TooltipScreen.Location, displayDuration: DisplayDuration = .default, shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch, openActiveTextItem: @escaping (TooltipActiveTextItem, TooltipActiveTextAction) -> Void = { _, _ in }) {
|
public init(text: String, textEntities: [MessageTextEntity] = [], icon: TooltipScreen.Icon?, location: TooltipScreen.Location, displayDuration: DisplayDuration = .default, shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch, openActiveTextItem: @escaping (TooltipActiveTextItem, TooltipActiveTextAction) -> Void = { _, _ in }) {
|
||||||
self.text = text
|
self.text = text
|
||||||
self.textEntities = textEntities
|
self.textEntities = textEntities
|
||||||
@ -409,22 +411,47 @@ public final class TooltipScreen: ViewController {
|
|||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
self.dismissTimer?.invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
override public func viewDidAppear(_ animated: Bool) {
|
override public func viewDidAppear(_ animated: Bool) {
|
||||||
super.viewDidAppear(animated)
|
super.viewDidAppear(animated)
|
||||||
|
|
||||||
self.controllerNode.animateIn()
|
self.controllerNode.animateIn()
|
||||||
|
self.resetDismissTimeout(duration: self.displayDuration)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func resetDismissTimeout(duration: TooltipScreen.DisplayDuration? = nil) {
|
||||||
|
self.dismissTimer?.invalidate()
|
||||||
|
|
||||||
let timeout: Double
|
let timeout: Double
|
||||||
switch self.displayDuration {
|
switch duration ?? self.displayDuration {
|
||||||
case .default:
|
case .default:
|
||||||
timeout = 5.0
|
timeout = 5.0
|
||||||
case let .custom(value):
|
case let .custom(value):
|
||||||
timeout = value
|
timeout = value
|
||||||
}
|
}
|
||||||
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + timeout, execute: { [weak self] in
|
final class TimerTarget: NSObject {
|
||||||
self?.dismiss()
|
private let f: () -> Void
|
||||||
})
|
|
||||||
|
init(_ f: @escaping () -> Void) {
|
||||||
|
self.f = f
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func timerEvent() {
|
||||||
|
self.f()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let dismissTimer = Foundation.Timer(timeInterval: timeout, target: TimerTarget { [weak self] in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strongSelf.dismiss()
|
||||||
|
}, selector: #selector(TimerTarget.timerEvent), userInfo: nil, repeats: false)
|
||||||
|
self.dismissTimer = dismissTimer
|
||||||
|
RunLoop.main.add(dismissTimer, forMode: .common)
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func loadDisplayNode() {
|
override public func loadDisplayNode() {
|
||||||
|
|||||||
Binary file not shown.
@ -449,12 +449,12 @@ public final class WalletStrings: Equatable {
|
|||||||
public var Wallet_SecureStorageReset_Title: String { return self._s[219]! }
|
public var Wallet_SecureStorageReset_Title: String { return self._s[219]! }
|
||||||
public var Wallet_Receive_CommentHeader: String { return self._s[220]! }
|
public var Wallet_Receive_CommentHeader: String { return self._s[220]! }
|
||||||
public var Wallet_Info_ReceiveGrams: String { return self._s[221]! }
|
public var Wallet_Info_ReceiveGrams: String { return self._s[221]! }
|
||||||
public func Wallet_Updated_HoursAgo(_ value: Int32) -> String {
|
public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String {
|
||||||
let form = getPluralizationForm(self.lc, value)
|
let form = getPluralizationForm(self.lc, value)
|
||||||
let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator)
|
let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator)
|
||||||
return String(format: self._ps[0 * 6 + Int(form.rawValue)]!, stringValue)
|
return String(format: self._ps[0 * 6 + Int(form.rawValue)]!, stringValue)
|
||||||
}
|
}
|
||||||
public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String {
|
public func Wallet_Updated_HoursAgo(_ value: Int32) -> String {
|
||||||
let form = getPluralizationForm(self.lc, value)
|
let form = getPluralizationForm(self.lc, value)
|
||||||
let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator)
|
let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator)
|
||||||
return String(format: self._ps[1 * 6 + Int(form.rawValue)]!, stringValue)
|
return String(format: self._ps[1 * 6 + Int(form.rawValue)]!, stringValue)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user