Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2022-11-29 20:58:07 +04:00
commit 249297b086
14 changed files with 113 additions and 40 deletions

View File

@ -1 +1 @@
4676db79b236dae25073875c1c09a72d
69afbe6d015c96aee8d04108b5ca7a38

View File

@ -891,6 +891,34 @@ public final class AvatarBadgeView: UIImageView {
UIGraphicsPopContext()
}
}
var rSum: Int64 = 0
var gSum: Int64 = 0
var bSum: Int64 = 0
for y in 0 ..< blurredHeight {
let row = blurredContext.bytes.assumingMemoryBound(to: UInt8.self).advanced(by: y * blurredContext.bytesPerRow)
for x in 0 ..< blurredWidth {
let pixel = row.advanced(by: x * 4)
bSum += Int64(pixel.advanced(by: 0).pointee)
gSum += Int64(pixel.advanced(by: 1).pointee)
rSum += Int64(pixel.advanced(by: 2).pointee)
}
}
let colorNorm = CGFloat(blurredWidth * blurredHeight)
let invColorNorm: CGFloat = 1.0 / (255.0 * colorNorm)
let aR = CGFloat(rSum) * invColorNorm
let aG = CGFloat(gSum) * invColorNorm
let aB = CGFloat(bSum) * invColorNorm
let luminance: CGFloat = 0.299 * aR + 0.587 * aG + 0.114 * aB
let isLightImage = luminance > 0.9
var brightness: CGFloat = 1.0
if isLightImage {
brightness = 0.99
} else {
brightness = 0.94
}
var destinationBuffer = vImage_Buffer()
destinationBuffer.width = UInt(blurredWidth)
@ -934,7 +962,6 @@ public final class AvatarBadgeView: UIImageView {
0, 0, 0, 1
]
let brightness: CGFloat = 0.94
let brighnessMatrix: [CGFloat] = [
brightness, 0, 0, 0,
0, brightness, 0, 0,
@ -980,14 +1007,16 @@ public final class AvatarBadgeView: UIImageView {
context.setBlendMode(.normal)
/*context.setFillColor(UIColor(white: 1.0, alpha: 0.08).cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
context.setFillColor(UIColor(white: 0.0, alpha: 0.05).cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))*/
let textColor: UIColor
if isLightImage {
textColor = UIColor(white: 0.7, alpha: 1.0)
} else {
textColor = .white
}
var fontSize: CGFloat = floor(parameters.size.height * 0.48)
while true {
let string = NSAttributedString(string: parameters.text, font: Font.bold(fontSize), textColor: .white)
let string = NSAttributedString(string: parameters.text, font: Font.bold(fontSize), textColor: textColor)
let stringBounds = string.boundingRect(with: CGSize(width: 100.0, height: 100.0), options: .usesLineFragmentOrigin, context: nil)
if stringBounds.width <= size.width - 5.0 * 2.0 || fontSize <= 2.0 {
@ -1002,7 +1031,7 @@ public final class AvatarBadgeView: UIImageView {
let lineInset: CGFloat = 2.0
let lineRadius: CGFloat = size.width * 0.5 - lineInset - lineWidth * 0.5
context.setLineWidth(lineWidth)
context.setStrokeColor(UIColor.white.cgColor)
context.setStrokeColor(textColor.cgColor)
context.setLineCap(.round)
context.addArc(center: CGPoint(x: size.width * 0.5, y: size.height * 0.5), radius: lineRadius, startAngle: CGFloat.pi * 0.5, endAngle: -CGFloat.pi * 0.5, clockwise: false)
@ -1022,6 +1051,12 @@ public final class AvatarBadgeView: UIImageView {
context.strokePath()
}
/*if isLightImage {
context.setLineWidth(UIScreenPixel)
context.setStrokeColor(textColor.withMultipliedAlpha(1.0).cgColor)
context.strokeEllipse(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: UIScreenPixel * 0.5, dy: UIScreenPixel * 0.5))
}*/
UIGraphicsPopContext()
})
}

View File

@ -136,7 +136,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
private let headerContentView = ComponentView<Empty>()
private var primaryContext: ChatListLocationContext?
fileprivate private(set) var primaryContext: ChatListLocationContext?
private let primaryInfoReady = Promise<Bool>()
private var pendingSecondaryContext: ChatListLocationContext?
@ -4744,10 +4744,11 @@ private final class ChatListLocationContext {
self.rightButton = AnyComponentWithIdentity(id: "more", component: AnyComponent(NavigationButtonComponent(
content: .more,
pressed: { [weak parentController] sourceView in
guard let secondaryContext = parentController?.secondaryContext else {
return
if let secondaryContext = parentController?.secondaryContext {
secondaryContext.performMoreAction(sourceView: sourceView)
} else if let primaryContext = parentController?.primaryContext {
primaryContext.performMoreAction(sourceView: sourceView)
}
secondaryContext.performMoreAction(sourceView: sourceView)
},
contextAction: { [weak self] sourceView, gesture in
guard let self, let parentController = self.parentController else {

View File

@ -272,7 +272,7 @@ private final class ChatListShimmerNode: ASDisplayNode {
if !isInlineMode {
if !itemNodes[sampleIndex].avatarNode.isHidden {
context.fillEllipse(in: itemNodes[sampleIndex].avatarNode.frame.offsetBy(dx: 0.0, dy: currentY))
context.fillEllipse(in: itemNodes[sampleIndex].avatarNode.view.convert(itemNodes[sampleIndex].avatarNode.bounds, to: itemNodes[sampleIndex].view).offsetBy(dx: 0.0, dy: currentY))
}
}

View File

@ -924,6 +924,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
private var customAnimationInProgress: Bool = false
private var onlineIsVoiceChat: Bool = false
private var currentOnline: Bool?
override var canBeSelected: Bool {
if self.selectableControlNode != nil || self.item?.editing == true {
@ -2464,6 +2465,12 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
strongSelf.cachedChatListSearchResult = chatListSearchResult
strongSelf.onlineIsVoiceChat = onlineIsVoiceChat
var animateOnline = animateOnline
if let currentOnline = strongSelf.currentOnline, currentOnline == online {
animateOnline = false
}
strongSelf.currentOnline = online
if let currentHiddenOffset = currentItem?.hiddenOffset, item.hiddenOffset, currentHiddenOffset != item.hiddenOffset {
strongSelf.supernode?.insertSubnode(strongSelf, at: 0)
}
@ -2773,6 +2780,9 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
if let autoremoveTimeout = autoremoveTimeout {
let avatarTimerBadge: AvatarBadgeView
var avatarTimerTransition = transition
if !avatarTimerTransition.isAnimated, animateOnline {
avatarTimerTransition = .animated(duration: 0.3, curve: .spring)
}
if let current = strongSelf.avatarTimerBadge {
avatarTimerBadge = current
} else {

View File

@ -193,7 +193,7 @@ func _internal_createForumChannelTopic(account: Account, peerId: PeerId, title:
}
|> castError(CreateForumChannelTopicError.self)
|> mapToSignal { peer -> Signal<Int64, CreateForumChannelTopicError> in
guard let peer else {
guard let peer = peer else {
return .fail(.generic)
}
guard let inputChannel = apiInputChannel(peer) else {

View File

@ -3574,7 +3574,8 @@ func replayFinalState(
updatedIncomingThreadReadStates[threadMessageId] = readMaxId
}
if let channel = transaction.getPeer(threadMessageId.peerId) as? TelegramChannel, case .group = channel.info, channel.flags.contains(.isForum) {
if var data = transaction.getMessageHistoryThreadInfo(peerId: threadMessageId.peerId, threadId: Int64(threadMessageId.id))?.data.get(MessageHistoryThreadData.self) {
let threadId = Int64(threadMessageId.id)
if var data = transaction.getMessageHistoryThreadInfo(peerId: threadMessageId.peerId, threadId: threadId)?.data.get(MessageHistoryThreadData.self) {
if readMaxId > data.maxIncomingReadId {
if let toIndex = transaction.getMessage(MessageId(peerId: threadMessageId.peerId, namespace: threadMessageId.namespace, id: readMaxId))?.index {
if let count = transaction.getThreadMessageCount(peerId: threadMessageId.peerId, threadId: Int64(threadMessageId.id), namespace: threadMessageId.namespace, fromIdExclusive: data.maxIncomingReadId, toIndex: toIndex) {
@ -3582,6 +3583,16 @@ func replayFinalState(
}
}
if let topMessageIndex = transaction.getMessageHistoryThreadTopMessage(peerId: threadMessageId.peerId, threadId: threadId, namespaces: Set([Namespaces.Message.Cloud])) {
if readMaxId >= topMessageIndex.id.id {
let containingHole = transaction.getThreadIndexHole(peerId: threadMessageId.peerId, threadId: threadId, namespace: topMessageIndex.id.namespace, containing: topMessageIndex.id.id)
if let _ = containingHole[.everywhere] {
} else {
data.incomingUnreadCount = 0
}
}
}
data.maxKnownMessageId = max(data.maxKnownMessageId, readMaxId)
data.maxIncomingReadId = max(data.maxIncomingReadId, readMaxId)
@ -4069,14 +4080,18 @@ func replayFinalState(
}
})
}
case let .UpdateAutoremoveTimeout(peer, value):
transaction.updatePeerCachedData(peerIds: Set([peer.peerId]), update: { _, current in
if let current = current as? CachedUserData {
return current.withUpdatedAutoremoveTimeout(.known(value))
} else if let current = current as? CachedGroupData {
return current.withUpdatedAutoremoveTimeout(.known(value))
} else if let current = current as? CachedChannelData {
return current.withUpdatedAutoremoveTimeout(.known(value))
case let .UpdateAutoremoveTimeout(peer, autoremoveValue):
let peerId = peer.peerId
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
if peerId.namespace == Namespaces.Peer.CloudUser {
let current = (current as? CachedUserData) ?? CachedUserData()
return current.withUpdatedAutoremoveTimeout(.known(autoremoveValue))
} else if peerId.namespace == Namespaces.Peer.CloudChannel {
let current = (current as? CachedChannelData) ?? CachedChannelData()
return current.withUpdatedAutoremoveTimeout(.known(autoremoveValue))
} else if peerId.namespace == Namespaces.Peer.CloudGroup {
let current = (current as? CachedGroupData) ?? CachedGroupData()
return current.withUpdatedAutoremoveTimeout(.known(autoremoveValue))
} else {
return current
}

View File

@ -295,7 +295,7 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
}
}
|> mapToSignal { (peer, hash) -> Signal<FetchMessageHistoryHoleResult?, NoError> in
guard let peer else {
guard let peer = peer else {
return .single(FetchMessageHistoryHoleResult(removedIndices: IndexSet(), strictRemovedIndices: IndexSet(), actualPeerId: nil, actualThreadId: nil, ids: []))
}
guard let inputPeer = forceApiInputPeer(peer) else {
@ -820,11 +820,14 @@ func fetchChatListHole(postbox: Postbox, network: Network, accountPeerId: PeerId
for (peerId, autoremoveValue) in fetchedChats.ttlPeriods {
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
if let current = current as? CachedUserData {
if peerId.namespace == Namespaces.Peer.CloudUser {
let current = (current as? CachedUserData) ?? CachedUserData()
return current.withUpdatedAutoremoveTimeout(autoremoveValue)
} else if let current = current as? CachedGroupData {
} else if peerId.namespace == Namespaces.Peer.CloudChannel {
let current = (current as? CachedChannelData) ?? CachedChannelData()
return current.withUpdatedAutoremoveTimeout(autoremoveValue)
} else if let current = current as? CachedChannelData {
} else if peerId.namespace == Namespaces.Peer.CloudGroup {
let current = (current as? CachedGroupData) ?? CachedGroupData()
return current.withUpdatedAutoremoveTimeout(autoremoveValue)
} else {
return current

View File

@ -236,11 +236,14 @@ private func synchronizePinnedChats(transaction: Transaction, postbox: Postbox,
for (peerId, autoremoveValue) in ttlPeriods {
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
if let current = current as? CachedUserData {
if peerId.namespace == Namespaces.Peer.CloudUser {
let current = (current as? CachedUserData) ?? CachedUserData()
return current.withUpdatedAutoremoveTimeout(autoremoveValue)
} else if let current = current as? CachedGroupData {
} else if peerId.namespace == Namespaces.Peer.CloudChannel {
let current = (current as? CachedChannelData) ?? CachedChannelData()
return current.withUpdatedAutoremoveTimeout(autoremoveValue)
} else if let current = current as? CachedChannelData {
} else if peerId.namespace == Namespaces.Peer.CloudGroup {
let current = (current as? CachedGroupData) ?? CachedGroupData()
return current.withUpdatedAutoremoveTimeout(autoremoveValue)
} else {
return current

View File

@ -190,11 +190,14 @@ func _internal_setChatMessageAutoremoveTimeoutInteractively(account: Account, pe
updatedTimeout = .known(nil)
}
if let current = current as? CachedUserData {
if peerId.namespace == Namespaces.Peer.CloudUser {
let current = (current as? CachedUserData) ?? CachedUserData()
return current.withUpdatedAutoremoveTimeout(updatedTimeout)
} else if let current = current as? CachedGroupData {
} else if peerId.namespace == Namespaces.Peer.CloudChannel {
let current = (current as? CachedChannelData) ?? CachedChannelData()
return current.withUpdatedAutoremoveTimeout(updatedTimeout)
} else if let current = current as? CachedChannelData {
} else if peerId.namespace == Namespaces.Peer.CloudGroup {
let current = (current as? CachedGroupData) ?? CachedGroupData()
return current.withUpdatedAutoremoveTimeout(updatedTimeout)
} else {
return current

View File

@ -143,7 +143,7 @@ private class ReplyThreadHistoryContextImpl {
}
|> castError(FetchChannelReplyThreadMessageError.self)
|> mapToSignal { peer -> Signal<DiscussionMessage, FetchChannelReplyThreadMessageError> in
guard let peer else {
guard let peer = peer else {
return .fail(.generic)
}
guard let inputPeer = apiInputPeer(peer) else {
@ -613,7 +613,7 @@ func _internal_fetchChannelReplyThreadMessage(account: Account, messageId: Messa
}
|> castError(FetchChannelReplyThreadMessageError.self)
|> mapToSignal { peer -> Signal<ChatReplyThreadMessage, FetchChannelReplyThreadMessageError> in
guard let peer else {
guard let peer = peer else {
return .fail(.generic)
}
guard let inputPeer = apiInputPeer(peer) else {

View File

@ -807,7 +807,7 @@ public final class SparseMessageCalendar {
return transaction.getPeer(peerId)
}
|> mapToSignal { peer -> Signal<LoadResult, NoError> in
guard let peer else {
guard let peer = peer else {
return .single(LoadResult(messagesByDay: [:], nextOffset: nil, minMessageId: nil, minTimestamp: nil))
}
guard let inputPeer = apiInputPeer(peer) else {

View File

@ -769,11 +769,14 @@ private func loadAndStorePeerChatInfos(accountPeerId: PeerId, postbox: Postbox,
for (peerId, autoremoveValue) in ttlPeriods {
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
if let current = current as? CachedUserData {
if peerId.namespace == Namespaces.Peer.CloudUser {
let current = (current as? CachedUserData) ?? CachedUserData()
return current.withUpdatedAutoremoveTimeout(autoremoveValue)
} else if let current = current as? CachedGroupData {
} else if peerId.namespace == Namespaces.Peer.CloudChannel {
let current = (current as? CachedChannelData) ?? CachedChannelData()
return current.withUpdatedAutoremoveTimeout(autoremoveValue)
} else if let current = current as? CachedChannelData {
} else if peerId.namespace == Namespaces.Peer.CloudGroup {
let current = (current as? CachedGroupData) ?? CachedGroupData()
return current.withUpdatedAutoremoveTimeout(autoremoveValue)
} else {
return current

View File

@ -1963,7 +1963,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
}
var hasReply = replyMessage != nil
if !isInstantVideo, let replyMessage = replyMessage, replyMessage.threadId != nil, case let .peer(peerId) = item.chatLocation, peerId == replyMessage.id.peerId, let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum) {
if !isInstantVideo, let replyMessage = replyMessage, replyMessage.threadId != nil, case let .peer(peerId) = item.chatLocation, peerId == replyMessage.id.peerId, let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum), item.message.associatedThreadInfo != nil {
if let threadId = item.message.threadId, Int64(replyMessage.id.id) == threadId {
hasReply = false
}