mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-29 03:21:29 +00:00
Voice Chat fixes
This commit is contained in:
parent
73657fc155
commit
67ac8b10c3
@ -6263,3 +6263,6 @@ Sorry for the inconvenience.";
|
|||||||
"VoiceChat.CancelSpeakRequest" = "Cancel Request to Speak";
|
"VoiceChat.CancelSpeakRequest" = "Cancel Request to Speak";
|
||||||
|
|
||||||
"VoiceChat.RemovePeerConfirmationChannel" = "Are you sure you want to remove %@ from the channel?";
|
"VoiceChat.RemovePeerConfirmationChannel" = "Are you sure you want to remove %@ from the channel?";
|
||||||
|
"VoiceChat.RemoveAndBanPeerConfirmation" = "“Do you want to remove %1$@ from the voice chat and ban them in %2$@?";
|
||||||
|
|
||||||
|
"Notification.VoiceChatStartedChannel" = "Voice chat started";
|
||||||
|
|||||||
21
submodules/CameraUI/Sources/CameraModeNode.swift
Normal file
21
submodules/CameraUI/Sources/CameraModeNode.swift
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import Display
|
||||||
|
import SwiftSignalKit
|
||||||
|
|
||||||
|
final class CameraModeNode: ASDisplayNode {
|
||||||
|
enum Mode {
|
||||||
|
case photo
|
||||||
|
case video
|
||||||
|
case scan
|
||||||
|
}
|
||||||
|
|
||||||
|
override init() {
|
||||||
|
super.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(mode: Mode, transition: ContainedViewLayoutTransition) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1339,17 +1339,21 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func viewWillDisappear(_ animated: Bool) {
|
func dismissAllUndoControllers() {
|
||||||
super.viewWillDisappear(animated)
|
|
||||||
|
|
||||||
self.chatListDisplayNode.containerNode.updateEnableAdjacentFilterLoading(false)
|
|
||||||
|
|
||||||
self.forEachController({ controller in
|
self.forEachController({ controller in
|
||||||
if let controller = controller as? UndoOverlayController {
|
if let controller = controller as? UndoOverlayController {
|
||||||
controller.dismissWithCommitAction()
|
controller.dismissWithCommitAction()
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func viewWillDisappear(_ animated: Bool) {
|
||||||
|
super.viewWillDisappear(animated)
|
||||||
|
|
||||||
|
self.chatListDisplayNode.containerNode.updateEnableAdjacentFilterLoading(false)
|
||||||
|
|
||||||
|
self.dismissAllUndoControllers()
|
||||||
|
|
||||||
self.featuredFiltersDisposable.set(nil)
|
self.featuredFiltersDisposable.set(nil)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -403,6 +403,8 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
private let filterBecameEmpty: (ChatListFilter?) -> Void
|
private let filterBecameEmpty: (ChatListFilter?) -> Void
|
||||||
private let filterEmptyAction: (ChatListFilter?) -> Void
|
private let filterEmptyAction: (ChatListFilter?) -> Void
|
||||||
|
|
||||||
|
fileprivate var onFilterSwitch: (() -> Void)?
|
||||||
|
|
||||||
private var presentationData: PresentationData
|
private var presentationData: PresentationData
|
||||||
|
|
||||||
private var itemNodes: [ChatListFilterTabEntryId: ChatListContainerItemNode] = [:]
|
private var itemNodes: [ChatListFilterTabEntryId: ChatListContainerItemNode] = [:]
|
||||||
@ -607,6 +609,8 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
@objc private func panGesture(_ recognizer: UIPanGestureRecognizer) {
|
@objc private func panGesture(_ recognizer: UIPanGestureRecognizer) {
|
||||||
switch recognizer.state {
|
switch recognizer.state {
|
||||||
case .began:
|
case .began:
|
||||||
|
self.onFilterSwitch?()
|
||||||
|
|
||||||
self.transitionFractionOffset = 0.0
|
self.transitionFractionOffset = 0.0
|
||||||
if let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, isReorderingFilters, isEditing) = self.validLayout, let itemNode = self.itemNodes[self.selectedId] {
|
if let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, isReorderingFilters, isEditing) = self.validLayout, let itemNode = self.itemNodes[self.selectedId] {
|
||||||
for (id, itemNode) in self.itemNodes {
|
for (id, itemNode) in self.itemNodes {
|
||||||
@ -792,6 +796,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
guard let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, isReorderingFilters, isEditing) = self.validLayout else {
|
guard let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, isReorderingFilters, isEditing) = self.validLayout else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
self.onFilterSwitch?()
|
||||||
if id != self.selectedId, let index = self.availableFilters.firstIndex(where: { $0.id == id }) {
|
if id != self.selectedId, let index = self.availableFilters.firstIndex(where: { $0.id == id }) {
|
||||||
if let itemNode = self.itemNodes[id] {
|
if let itemNode = self.itemNodes[id] {
|
||||||
self.selectedId = id
|
self.selectedId = id
|
||||||
@ -1057,6 +1062,12 @@ final class ChatListControllerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
strongSelf.emptyListAction?()
|
strongSelf.emptyListAction?()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.containerNode.onFilterSwitch = { [weak self] in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.controller?.dismissAllUndoControllers()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func didLoad() {
|
override func didLoad() {
|
||||||
|
|||||||
@ -142,14 +142,14 @@ private final class DeleteChatPeerActionSheetItemNode: ActionSheetItemNode {
|
|||||||
text?.0 += "\n\n\(strings.Conversation_AlsoClearCacheTitle)"
|
text?.0 += "\n\n\(strings.Conversation_AlsoClearCacheTitle)"
|
||||||
}
|
}
|
||||||
case .removeFromGroup:
|
case .removeFromGroup:
|
||||||
text = strings.VoiceChat_RemovePeerConfirmation(peer.displayTitle(strings: strings, displayOrder: nameOrder))
|
text = strings.VoiceChat_RemoveAndBanPeerConfirmation(peer.displayTitle(strings: strings, displayOrder: nameOrder), chatPeer.displayTitle(strings: strings, displayOrder: nameOrder))
|
||||||
case .removeFromChannel:
|
case .removeFromChannel:
|
||||||
text = strings.VoiceChat_RemovePeerConfirmationChannel(peer.displayTitle(strings: strings, displayOrder: nameOrder))
|
text = strings.VoiceChat_RemovePeerConfirmationChannel(peer.displayTitle(strings: strings, displayOrder: nameOrder))
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if let text = text {
|
if let text = text {
|
||||||
var formattedAttributedText = NSMutableAttributedString(attributedString: NSAttributedString(string: text.0, font: textFont, textColor: theme.primaryTextColor))
|
let formattedAttributedText = NSMutableAttributedString(attributedString: NSAttributedString(string: text.0, font: textFont, textColor: theme.primaryTextColor))
|
||||||
for (_, range) in text.1 {
|
for (_, range) in text.1 {
|
||||||
formattedAttributedText.addAttribute(.font, value: boldFont, range: range)
|
formattedAttributedText.addAttribute(.font, value: boldFont, range: range)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -346,7 +346,13 @@ final class JoinLinkPreviewControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var animatingOut = false
|
||||||
func animateOut(completion: (() -> Void)? = nil) {
|
func animateOut(completion: (() -> Void)? = nil) {
|
||||||
|
guard !self.animatingOut else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.animatingOut = true
|
||||||
|
|
||||||
if self.contentNode != nil {
|
if self.contentNode != nil {
|
||||||
var dimCompleted = false
|
var dimCompleted = false
|
||||||
var offsetCompleted = false
|
var offsetCompleted = false
|
||||||
@ -354,6 +360,7 @@ final class JoinLinkPreviewControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
let internalCompletion: () -> Void = { [weak self] in
|
let internalCompletion: () -> Void = { [weak self] in
|
||||||
if let strongSelf = self, dimCompleted && offsetCompleted {
|
if let strongSelf = self, dimCompleted && offsetCompleted {
|
||||||
strongSelf.dismiss?()
|
strongSelf.dismiss?()
|
||||||
|
strongSelf.animatingOut = true
|
||||||
}
|
}
|
||||||
completion?()
|
completion?()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -639,7 +639,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var animatingOut = false
|
private var animatingOut = false
|
||||||
var outCompletion: (() -> Void)?
|
var outCompletion: (() -> Void)?
|
||||||
func animateOut(shared: Bool, completion: @escaping () -> Void) {
|
func animateOut(shared: Bool, completion: @escaping () -> Void) {
|
||||||
guard !self.animatingOut else {
|
guard !self.animatingOut else {
|
||||||
|
|||||||
@ -445,6 +445,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||||||
private var markedAsCanBeRemoved = false
|
private var markedAsCanBeRemoved = false
|
||||||
|
|
||||||
private let wasRemoved = Promise<Bool>(false)
|
private let wasRemoved = Promise<Bool>(false)
|
||||||
|
private var leaving = false
|
||||||
|
|
||||||
private var stateValue: PresentationGroupCallState {
|
private var stateValue: PresentationGroupCallState {
|
||||||
didSet {
|
didSet {
|
||||||
@ -1391,7 +1392,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !participants.contains(where: { $0.peer.id == myPeerId }) {
|
if !participants.contains(where: { $0.peer.id == myPeerId }) && !strongSelf.leaving {
|
||||||
if let (myPeer, cachedData) = myPeerAndCachedData {
|
if let (myPeer, cachedData) = myPeerAndCachedData {
|
||||||
let about: String?
|
let about: String?
|
||||||
if let cachedData = cachedData as? CachedUserData {
|
if let cachedData = cachedData as? CachedUserData {
|
||||||
@ -1436,7 +1437,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||||||
strongSelf.stateValue.raisedHand = participant.raiseHandRating != nil
|
strongSelf.stateValue.raisedHand = participant.raiseHandRating != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if let muteState = participant.muteState, muteState.canUnmute && previousRaisedHand {
|
if let muteState = participant.muteState, muteState.canUnmute && previousRaisedHand {
|
||||||
let _ = (strongSelf.accountContext.sharedContext.hasGroupCallOnScreen
|
let _ = (strongSelf.accountContext.sharedContext.hasGroupCallOnScreen
|
||||||
|> take(1)
|
|> take(1)
|
||||||
|> deliverOnMainQueue).start(next: { hasGroupCallOnScreen in
|
|> deliverOnMainQueue).start(next: { hasGroupCallOnScreen in
|
||||||
@ -1444,17 +1445,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
let presentationData = strongSelf.accountContext.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = strongSelf.accountContext.sharedContext.currentPresentationData.with { $0 }
|
||||||
if hasGroupCallOnScreen, let groupCallController = strongSelf.accountContext.sharedContext.currentGroupCallController {
|
if !hasGroupCallOnScreen {
|
||||||
var animateInAsReplacement = false
|
|
||||||
groupCallController.forEachController { c in
|
|
||||||
if let c = c as? UndoOverlayController {
|
|
||||||
animateInAsReplacement = true
|
|
||||||
c.dismiss()
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
groupCallController.present(UndoOverlayController(presentationData: presentationData, content: .voiceChatCanSpeak(text: presentationData.strings.VoiceChat_YouCanNowSpeak), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { _ in return true }), in: .current)
|
|
||||||
} else {
|
|
||||||
let title: String?
|
let title: String?
|
||||||
if let voiceChatTitle = strongSelf.stateValue.title {
|
if let voiceChatTitle = strongSelf.stateValue.title {
|
||||||
title = voiceChatTitle
|
title = voiceChatTitle
|
||||||
@ -1760,6 +1751,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func leave(terminateIfPossible: Bool) -> Signal<Bool, NoError> {
|
public func leave(terminateIfPossible: Bool) -> Signal<Bool, NoError> {
|
||||||
|
self.leaving = true
|
||||||
if let callInfo = self.internalState.callInfo, let localSsrc = self.currentLocalSsrc {
|
if let callInfo = self.internalState.callInfo, let localSsrc = self.currentLocalSsrc {
|
||||||
if terminateIfPossible {
|
if terminateIfPossible {
|
||||||
self.leaveDisposable.set((stopGroupCall(account: self.account, peerId: self.peerId, callId: callInfo.id, accessHash: callInfo.accessHash)
|
self.leaveDisposable.set((stopGroupCall(account: self.account, peerId: self.peerId, callId: callInfo.id, accessHash: callInfo.accessHash)
|
||||||
|
|||||||
@ -1410,7 +1410,17 @@ final class VoiceChatActionButtonIconNode: ManagedAnimationNode {
|
|||||||
|
|
||||||
func playRandomAnimation() {
|
func playRandomAnimation() {
|
||||||
if case .hand = self.iconState {
|
if case .hand = self.iconState {
|
||||||
if let animationName = ["VoiceHand_1", "VoiceHand_2", "VoiceHand_3", "VoiceHand_4", "VoiceHand_5", "VoiceHand_6", "VoiceHand_7"].randomElement() {
|
var useTiredAnimation = false
|
||||||
|
let val = Float.random(in: 0.0..<1.0)
|
||||||
|
if val <= 0.01 {
|
||||||
|
useTiredAnimation = true
|
||||||
|
}
|
||||||
|
|
||||||
|
let normalAnimations = ["VoiceHand_1", "VoiceHand_2", "VoiceHand_3", "VoiceHand_4", "VoiceHand_7"]
|
||||||
|
let tiredAnimations = ["VoiceHand_5", "VoiceHand_6"]
|
||||||
|
let animations = useTiredAnimation ? tiredAnimations : normalAnimations
|
||||||
|
|
||||||
|
if let animationName = animations.randomElement() {
|
||||||
self.trackTo(item: ManagedAnimationItem(source: .local(animationName)))
|
self.trackTo(item: ManagedAnimationItem(source: .local(animationName)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1270,12 +1270,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData.withUpdated(theme: strongSelf.darkTheme))
|
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData.withUpdated(theme: strongSelf.darkTheme))
|
||||||
var items: [ActionSheetItem] = []
|
var items: [ActionSheetItem] = []
|
||||||
|
|
||||||
var action: DeleteChatPeerAction = .removeFromGroup
|
items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: peer, chatPeer: chatPeer, action: .removeFromGroup, strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder))
|
||||||
if let chatPeer = chatPeer as? TelegramChannel, case .broadcast = chatPeer.info {
|
|
||||||
action = .removeFromChannel
|
|
||||||
}
|
|
||||||
|
|
||||||
items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: peer, chatPeer: peer, action: action, strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder))
|
|
||||||
|
|
||||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.VoiceChat_RemovePeerRemove, color: .destructive, action: { [weak actionSheet] in
|
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.VoiceChat_RemovePeerRemove, color: .destructive, action: { [weak actionSheet] in
|
||||||
actionSheet?.dismissAnimated()
|
actionSheet?.dismissAnimated()
|
||||||
|
|||||||
@ -95,17 +95,45 @@ public final class VoiceChatJoinScreen: ViewController {
|
|||||||
return transaction.getPeerCachedData(peerId: peerId)
|
return transaction.getPeerCachedData(peerId: peerId)
|
||||||
}
|
}
|
||||||
|> castError(GetCurrentGroupCallError.self)
|
|> castError(GetCurrentGroupCallError.self)
|
||||||
|
|
||||||
|
let currentGroupCallId: Signal<Int64?, GetCurrentGroupCallError>
|
||||||
|
if let callManager = context.sharedContext.callManager {
|
||||||
|
currentGroupCallId = callManager.currentGroupCallSignal
|
||||||
|
|> castError(GetCurrentGroupCallError.self)
|
||||||
|
|> mapToSignal { call -> Signal<Int64?, GetCurrentGroupCallError> in
|
||||||
|
if let call = call {
|
||||||
|
return call.summaryState
|
||||||
|
|> castError(GetCurrentGroupCallError.self)
|
||||||
|
|> map { state -> Int64? in
|
||||||
|
return state?.info?.id
|
||||||
|
}
|
||||||
|
|> filter { id in
|
||||||
|
return id != nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return .single(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> take(1)
|
||||||
|
} else {
|
||||||
|
currentGroupCallId = .single(nil)
|
||||||
|
}
|
||||||
|
|
||||||
self.disposable.set(combineLatest(queue: Queue.mainQueue(), signal, cachedGroupCallDisplayAsAvailablePeers(account: context.account, peerId: peerId) |> castError(GetCurrentGroupCallError.self), cachedData).start(next: { [weak self] peerAndCall, availablePeers, cachedData in
|
self.disposable.set(combineLatest(queue: Queue.mainQueue(), signal, cachedGroupCallDisplayAsAvailablePeers(account: context.account, peerId: peerId) |> castError(GetCurrentGroupCallError.self), cachedData, currentGroupCallId).start(next: { [weak self] peerAndCall, availablePeers, cachedData, currentGroupCallId in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if let (peer, call) = peerAndCall {
|
if let (peer, call) = peerAndCall {
|
||||||
|
if call.info.id == currentGroupCallId {
|
||||||
|
strongSelf.context.sharedContext.navigateToCurrentCall()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var defaultJoinAsPeerId: PeerId?
|
var defaultJoinAsPeerId: PeerId?
|
||||||
if let cachedData = cachedData as? CachedChannelData {
|
if let cachedData = cachedData as? CachedChannelData {
|
||||||
defaultJoinAsPeerId = cachedData.callJoinPeerId
|
defaultJoinAsPeerId = cachedData.callJoinPeerId
|
||||||
} else if let cachedData = cachedData as? CachedGroupData {
|
} else if let cachedData = cachedData as? CachedGroupData {
|
||||||
defaultJoinAsPeerId = cachedData.callJoinPeerId
|
defaultJoinAsPeerId = cachedData.callJoinPeerId
|
||||||
}
|
}
|
||||||
|
|
||||||
let activeCall = CachedChannelData.ActiveCall(id: call.info.id, accessHash: call.info.accessHash, title: call.info.title)
|
let activeCall = CachedChannelData.ActiveCall(id: call.info.id, accessHash: call.info.accessHash, title: call.info.title)
|
||||||
if availablePeers.count > 0 && defaultJoinAsPeerId == nil {
|
if availablePeers.count > 0 && defaultJoinAsPeerId == nil {
|
||||||
strongSelf.dismiss()
|
strongSelf.dismiss()
|
||||||
@ -481,13 +509,20 @@ public final class VoiceChatJoinScreen: ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var animatingOut = false
|
||||||
func animateOut(completion: (() -> Void)? = nil) {
|
func animateOut(completion: (() -> Void)? = nil) {
|
||||||
|
guard !self.animatingOut else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.animatingOut = true
|
||||||
|
|
||||||
if self.contentNode != nil {
|
if self.contentNode != nil {
|
||||||
var dimCompleted = false
|
var dimCompleted = false
|
||||||
var offsetCompleted = false
|
var offsetCompleted = false
|
||||||
|
|
||||||
let internalCompletion: () -> Void = { [weak self] in
|
let internalCompletion: () -> Void = { [weak self] in
|
||||||
if let strongSelf = self, dimCompleted && offsetCompleted {
|
if let strongSelf = self, dimCompleted && offsetCompleted {
|
||||||
|
strongSelf.animatingOut = false
|
||||||
strongSelf.dismiss?()
|
strongSelf.dismiss?()
|
||||||
}
|
}
|
||||||
completion?()
|
completion?()
|
||||||
|
|||||||
@ -243,7 +243,6 @@ private func installRemoteStickerPacks(network: Network, infos: [StickerPackColl
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func removeRemoteStickerPacks(network: Network, infos: [StickerPackCollectionInfo]) -> Signal<Void, NoError> {
|
private func removeRemoteStickerPacks(network: Network, infos: [StickerPackCollectionInfo]) -> Signal<Void, NoError> {
|
||||||
var signals: [Signal<Void, NoError>] = []
|
|
||||||
if infos.count > 0 {
|
if infos.count > 0 {
|
||||||
if infos.count > 1 {
|
if infos.count > 1 {
|
||||||
return network.request(Api.functions.messages.toggleStickerSets(flags: 1 << 0, stickersets: infos.map { .inputStickerSetID(id: $0.id.id, accessHash: $0.accessHash) }))
|
return network.request(Api.functions.messages.toggleStickerSets(flags: 1 << 0, stickersets: infos.map { .inputStickerSetID(id: $0.id.id, accessHash: $0.accessHash) }))
|
||||||
@ -267,7 +266,6 @@ private func removeRemoteStickerPacks(network: Network, infos: [StickerPackColle
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func archiveRemoteStickerPacks(network: Network, infos: [StickerPackCollectionInfo]) -> Signal<Void, NoError> {
|
private func archiveRemoteStickerPacks(network: Network, infos: [StickerPackCollectionInfo]) -> Signal<Void, NoError> {
|
||||||
var signals: [Signal<Void, NoError>] = []
|
|
||||||
if infos.count > 0 {
|
if infos.count > 0 {
|
||||||
if infos.count > 1 {
|
if infos.count > 1 {
|
||||||
return network.request(Api.functions.messages.toggleStickerSets(flags: 1 << 1, stickersets: infos.map { .inputStickerSetID(id: $0.id.id, accessHash: $0.accessHash) }))
|
return network.request(Api.functions.messages.toggleStickerSets(flags: 1 << 1, stickersets: infos.map { .inputStickerSetID(id: $0.id.id, accessHash: $0.accessHash) }))
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -451,9 +451,14 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
|||||||
let titleString = strings.Notification_VoiceChatEnded(callDurationString(strings: strings, value: duration)).0
|
let titleString = strings.Notification_VoiceChatEnded(callDurationString(strings: strings, value: duration)).0
|
||||||
attributedString = NSAttributedString(string: titleString, font: titleFont, textColor: primaryTextColor)
|
attributedString = NSAttributedString(string: titleString, font: titleFont, textColor: primaryTextColor)
|
||||||
} else {
|
} else {
|
||||||
let attributePeerIds: [(Int, PeerId?)] = [(0, message.author?.id)]
|
if message.author?.id.namespace == Namespaces.Peer.CloudChannel {
|
||||||
let titleString = strings.Notification_VoiceChatStarted(authorName)
|
let titleString = strings.Notification_VoiceChatStartedChannel
|
||||||
attributedString = addAttributesToStringWithRanges(titleString, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: attributePeerIds))
|
attributedString = NSAttributedString(string: titleString, font: titleFont, textColor: primaryTextColor)
|
||||||
|
} else {
|
||||||
|
let attributePeerIds: [(Int, PeerId?)] = [(0, message.author?.id)]
|
||||||
|
let titleString = strings.Notification_VoiceChatStarted(authorName)
|
||||||
|
attributedString = addAttributesToStringWithRanges(titleString, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: attributePeerIds))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case let .customText(text, entities):
|
case let .customText(text, entities):
|
||||||
attributedString = stringWithAppliedEntities(text, entities: entities, baseColor: primaryTextColor, linkColor: primaryTextColor, baseFont: titleFont, linkFont: titleBoldFont, boldFont: titleBoldFont, italicFont: titleFont, boldItalicFont: titleBoldFont, fixedFont: titleFont, blockQuoteFont: titleFont, underlineLinks: false)
|
attributedString = stringWithAppliedEntities(text, entities: entities, baseColor: primaryTextColor, linkColor: primaryTextColor, baseFont: titleFont, linkFont: titleBoldFont, boldFont: titleBoldFont, italicFont: titleFont, boldItalicFont: titleBoldFont, fixedFont: titleFont, blockQuoteFont: titleFont, underlineLinks: false)
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -70,7 +70,7 @@ private class ChatHistoryListSelectionRecognizer: UIPanGestureRecognizer {
|
|||||||
let dy = v1.y - v2.y
|
let dy = v1.y - v2.y
|
||||||
return sqrt(dx * dx + dy * dy)
|
return sqrt(dx * dx + dy * dy)
|
||||||
}
|
}
|
||||||
if distance(firstLocation, secondLocation) > 100 {
|
if distance(firstLocation, secondLocation) > 70 {
|
||||||
self.state = .failed
|
self.state = .failed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1388,6 +1388,15 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
|||||||
overrideImage = AvatarNodeImageOverride.none
|
overrideImage = AvatarNodeImageOverride.none
|
||||||
item = nil
|
item = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let _ = overrideImage {
|
||||||
|
self.containerNode.isGestureEnabled = false
|
||||||
|
} else if peer.profileImageRepresentations.isEmpty {
|
||||||
|
self.containerNode.isGestureEnabled = false
|
||||||
|
} else {
|
||||||
|
self.containerNode.isGestureEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
self.avatarNode.setPeer(context: self.context, theme: theme, peer: peer, overrideImage: overrideImage, synchronousLoad: self.isFirstAvatarLoading, displayDimensions: CGSize(width: avatarSize, height: avatarSize), storeUnrounded: true)
|
self.avatarNode.setPeer(context: self.context, theme: theme, peer: peer, overrideImage: overrideImage, synchronousLoad: self.isFirstAvatarLoading, displayDimensions: CGSize(width: avatarSize, height: avatarSize), storeUnrounded: true)
|
||||||
self.isFirstAvatarLoading = false
|
self.isFirstAvatarLoading = false
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user