Merge commit '313505ae6b9ebfd7fa9f862284cb3edcccea027a'

This commit is contained in:
Peter 2019-06-26 22:02:34 +03:00
commit aa87d2695a
30 changed files with 2817 additions and 2740 deletions

View File

@ -4328,6 +4328,8 @@ Any member of this group will be able to see messages in the channel.";
"Conversation.OpenBotLinkOpen" = "Open";
"TextFormat.Link" = "Link";
"TextFormat.Strikethrough" = "Strikethrough";
"TextFormat.Underline" = "Underline";
"TextFormat.AddLinkTitle" = "Add Link";
"TextFormat.AddLinkText" = "The link will be displayed as \"%@\".";
@ -4458,3 +4460,7 @@ Any member of this group will be able to see messages in the channel.";
"Activity.RemindAboutGroup" = "Send message to %@";
"Activity.RemindAboutUser" = "Send message to %@";
"Activity.RemindAboutChannel" = "Read %@";
"CreateGroup.ChannelsTooMuch" = "Sorry, you are a member of too many groups and channels. Please leave some before creating a new one.";
"Join.ChannelsTooMuch" = "Sorry, you are a member of too many groups and channels. Please leave some before joining one.";
"Invite.ChannelsTooMuch" = "Sorry, the target user is a member of too many groups and channels. Please ask them to leave some first.";

View File

@ -75,6 +75,7 @@ public enum AddChannelMemberError {
case generic
case restricted
case limitExceeded
case tooMuchJoined
case bot(PeerId)
}
@ -97,6 +98,8 @@ public func addChannelMember(account: Account, peerId: PeerId, memberId: PeerId)
|> map { [$0] }
|> `catch` { error -> Signal<[Api.Updates], AddChannelMemberError> in
switch error.errorDescription {
case "CHANNELS_TOO_MUCH":
return .fail(.tooMuchJoined)
case "USERS_TOO_MUCH":
return .fail(.limitExceeded)
case "USER_PRIVACY_RESTRICTED":
@ -190,6 +193,8 @@ public func addChannelMembers(account: Account, peerId: PeerId, memberIds: [Peer
let signal = account.network.request(Api.functions.channels.inviteToChannel(channel: inputChannel, users: inputUsers))
|> mapError { error -> AddChannelMemberError in
switch error.errorDescription {
case "CHANNELS_TOO_MUCH":
return .tooMuchJoined
case "USER_PRIVACY_RESTRICTED":
return .restricted
case "USERS_TOO_MUCH":

View File

@ -18,6 +18,7 @@ import Foundation
public enum CreateChannelError {
case generic
case restricted
case tooMuchJoined
case tooMuchLocationBasedGroups
case serverProvided(String)
}
@ -43,6 +44,8 @@ private func createChannel(account: Account, title: String, description: String?
|> mapError { error -> CreateChannelError in
if error.errorCode == 406 {
return .serverProvided(error.errorDescription)
} else if error.errorDescription == "CHANNELS_TOO_MUCH" {
return .tooMuchJoined
} else if error.errorDescription == "CHANNELS_ADMIN_LOCATED_TOO_MUCH" {
return .tooMuchLocationBasedGroups
} else if error.errorDescription == "USER_RESTRICTED" {

View File

@ -21,6 +21,7 @@ public enum ChannelOwnershipTransferError {
case adminsTooMuch
case userPublicChannelsTooMuch
case userLocatedGroupsTooMuch
case tooMuchJoined
case restricted
case userBlocked
}
@ -64,6 +65,8 @@ public func checkOwnershipTranfserAvailability(postbox: Postbox, network: Networ
return .restricted
} else if error.errorDescription == "USER_BLOCKED" {
return .userBlocked
} else if error.errorDescription == "CHANNELS_TOO_MUCH" {
return .tooMuchJoined
}
return .generic
}

View File

@ -19,6 +19,7 @@ public enum CreateGroupError {
case generic
case privacy
case restricted
case tooMuchJoined
case tooMuchLocationBasedGroups
case serverProvided(String)
}

View File

@ -11,6 +11,7 @@ import Foundation
public enum JoinChannelError {
case generic
case tooMuchJoined
}
public func joinChannel(account: Account, peerId: PeerId) -> Signal<RenderedChannelParticipant?, JoinChannelError> {
@ -20,8 +21,12 @@ public func joinChannel(account: Account, peerId: PeerId) -> Signal<RenderedChan
|> mapToSignal { peer -> Signal<RenderedChannelParticipant?, JoinChannelError> in
if let inputChannel = apiInputChannel(peer) {
return account.network.request(Api.functions.channels.joinChannel(channel: inputChannel))
|> mapError { _ -> JoinChannelError in
return .generic
|> mapError { error -> JoinChannelError in
if error.errorDescription == "CHANNELS_TOO_MUCH" {
return .tooMuchJoined
} else {
return .generic
}
}
|> mapToSignal { updates -> Signal<RenderedChannelParticipant?, JoinChannelError> in
account.stateManager.addUpdates(updates)

View File

@ -14,6 +14,11 @@
#endif
#endif
public enum JoinLinkError {
case generic
case tooMuchJoined
}
func apiUpdatesGroups(_ updates: Api.Updates) -> [Api.Chat] {
switch updates {
case let .updates( _, _, chats, _, _):
@ -31,31 +36,31 @@ public enum ExternalJoiningChatState {
case invalidHash
}
public func joinChatInteractively(with hash: String, account: Account) -> Signal <PeerId?, NoError> {
public func joinChatInteractively(with hash: String, account: Account) -> Signal <PeerId?, JoinLinkError> {
return account.network.request(Api.functions.messages.importChatInvite(hash: hash))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.Updates?, NoError> in
return .single(nil)
}
|> mapToSignal { updates -> Signal<PeerId?, NoError> in
if let updates = updates {
account.stateManager.addUpdates(updates)
if let peerId = apiUpdatesGroups(updates).first?.peerId {
return account.postbox.multiplePeersView([peerId])
|> filter { view in
return view.peers[peerId] != nil
}
|> take(1)
|> map { _ in
return peerId
}
|> timeout(5.0, queue: Queue.concurrentDefaultQueue(), alternate: .single(nil))
}
return .single(nil)
|> mapError { error -> JoinLinkError in
if error.errorDescription == "CHANNELS_TOO_MUCH" {
return .tooMuchJoined
} else {
return .single(nil)
return .generic
}
}
|> mapToSignal { updates -> Signal<PeerId?, JoinLinkError> in
account.stateManager.addUpdates(updates)
if let peerId = apiUpdatesGroups(updates).first?.peerId {
return account.postbox.multiplePeersView([peerId])
|> introduceError(JoinLinkError.self)
|> filter { view in
return view.peers[peerId] != nil
}
|> take(1)
|> map { _ in
return peerId
}
|> timeout(5.0, queue: Queue.concurrentDefaultQueue(), alternate: .single(nil) |> introduceError(JoinLinkError.self))
}
return .single(nil)
}
}
public func joinLinkInformation(_ hash: String, account: Account) -> Signal<ExternalJoiningChatState, NoError> {

View File

@ -237,11 +237,11 @@ func processSecretChatIncomingDecryptedOperations(mediaBox: MediaBox, transactio
} else if layerSupport >= 73 {
let sequenceBasedLayerState = SecretChatSequenceBasedLayerState(layerNegotiationState: SecretChatLayerNegotiationState(activeLayer: .layer73, locallyRequestedLayer: 73, remotelyRequestedLayer: layerSupport), rekeyState: nil, baseIncomingOperationIndex: entry.tagLocalIndex, baseOutgoingOperationIndex: transaction.operationLogGetNextEntryLocalIndex(peerId: peerId, tag: OperationLogTags.SecretOutgoing), topProcessedCanonicalIncomingOperationIndex: nil)
updatedState = updatedState.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceBasedLayerState))
updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: peerId, operation: .reportLayerSupport(layer: .layer73, actionGloballyUniqueId: arc4random64(), layerSupport: 73), state: updatedState)
updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: peerId, operation: .reportLayerSupport(layer: .layer73, actionGloballyUniqueId: arc4random64(), layerSupport: 101), state: updatedState)
} else if layerSupport >= 46 {
let sequenceBasedLayerState = SecretChatSequenceBasedLayerState(layerNegotiationState: SecretChatLayerNegotiationState(activeLayer: .layer46, locallyRequestedLayer: 46, remotelyRequestedLayer: layerSupport), rekeyState: nil, baseIncomingOperationIndex: entry.tagLocalIndex, baseOutgoingOperationIndex: transaction.operationLogGetNextEntryLocalIndex(peerId: peerId, tag: OperationLogTags.SecretOutgoing), topProcessedCanonicalIncomingOperationIndex: nil)
updatedState = updatedState.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceBasedLayerState))
updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: peerId, operation: .reportLayerSupport(layer: .layer46, actionGloballyUniqueId: arc4random64(), layerSupport: 73), state: updatedState)
updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: peerId, operation: .reportLayerSupport(layer: .layer46, actionGloballyUniqueId: arc4random64(), layerSupport: 101), state: updatedState)
} else {
throw MessageParsingError.contentParsingError
}

View File

@ -216,7 +216,7 @@ public class BoxedMessage: NSObject {
public class Serialization: NSObject, MTSerialization {
public func currentLayer() -> UInt {
return 102
return 101
}
public func parseMessage(_ data: Data!) -> Any! {

View File

@ -34,7 +34,7 @@ private final class CallRatingAlertContentNode: AlertContentNode {
self.apply = apply
self.titleNode = ASTextNode()
self.titleNode.maximumNumberOfLines = 2
self.titleNode.maximumNumberOfLines = 3
var starNodes: [ASButtonNode] = []
for _ in 0 ..< 5 {
@ -110,7 +110,7 @@ private final class CallRatingAlertContentNode: AlertContentNode {
}
override func updateTheme(_ theme: AlertControllerTheme) {
self.titleNode.attributedText = NSAttributedString(string: strings.Calls_RatingTitle, font: Font.bold(17.0), textColor: theme.primaryColor, paragraphAlignment: .center)
self.titleNode.attributedText = NSAttributedString(string: self.strings.Calls_RatingTitle, font: Font.bold(17.0), textColor: theme.primaryColor, paragraphAlignment: .center)
for node in self.starNodes {
node.setImage(generateTintedImage(image: UIImage(bundleImageName: "Call/Star"), color: theme.accentColor), for: [])
@ -140,7 +140,7 @@ private final class CallRatingAlertContentNode: AlertContentNode {
var origin: CGPoint = CGPoint(x: 0.0, y: 20.0)
let titleSize = self.titleNode.measure(size)
let titleSize = self.titleNode.measure(CGSize(width: size.width - 32.0, height: size.height))
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - titleSize.width) / 2.0), y: origin.y), size: titleSize))
origin.y += titleSize.height + 13.0
@ -156,10 +156,10 @@ private final class CallRatingAlertContentNode: AlertContentNode {
effectiveActionLayout = .vertical
}
switch effectiveActionLayout {
case .horizontal:
minActionsWidth += actionTitleSize.width + actionTitleInsets
case .vertical:
minActionsWidth = max(minActionsWidth, actionTitleSize.width + actionTitleInsets)
case .horizontal:
minActionsWidth += actionTitleSize.width + actionTitleInsets
case .vertical:
minActionsWidth = max(minActionsWidth, actionTitleSize.width + actionTitleInsets)
}
}
@ -198,24 +198,24 @@ private final class CallRatingAlertContentNode: AlertContentNode {
if separatorIndex >= 0 {
let separatorNode = self.actionVerticalSeparators[separatorIndex]
switch effectiveActionLayout {
case .horizontal:
transition.updateFrame(node: separatorNode, frame: CGRect(origin: CGPoint(x: actionOffset - UIScreenPixel, y: resultSize.height - actionsHeight), size: CGSize(width: UIScreenPixel, height: actionsHeight - UIScreenPixel)))
case .vertical:
transition.updateFrame(node: separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight + actionOffset - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel)))
case .horizontal:
transition.updateFrame(node: separatorNode, frame: CGRect(origin: CGPoint(x: actionOffset - UIScreenPixel, y: resultSize.height - actionsHeight), size: CGSize(width: UIScreenPixel, height: actionsHeight - UIScreenPixel)))
case .vertical:
transition.updateFrame(node: separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight + actionOffset - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel)))
}
}
separatorIndex += 1
let currentActionWidth: CGFloat
switch effectiveActionLayout {
case .horizontal:
if nodeIndex == self.actionNodes.count - 1 {
currentActionWidth = resultSize.width - actionOffset
} else {
currentActionWidth = actionWidth
}
case .vertical:
currentActionWidth = resultSize.width
case .horizontal:
if nodeIndex == self.actionNodes.count - 1 {
currentActionWidth = resultSize.width - actionOffset
} else {
currentActionWidth = actionWidth
}
case .vertical:
currentActionWidth = resultSize.width
}
let actionNodeFrame: CGRect

View File

@ -376,6 +376,8 @@ public func channelMembersController(context: AccountContext, peerId: PeerId) ->
switch error {
case .limitExceeded:
text = presentationData.strings.Channel_ErrorAddTooMuch
case .tooMuchJoined:
text = presentationData.strings.Invite_ChannelsTooMuch
case .generic:
text = presentationData.strings.Login_UnknownError
case .restricted:

View File

@ -126,15 +126,20 @@ final class ChatChannelSubscriberInputPanelNode: ChatInputPanelNode {
strongSelf.activityIndicator.stopAnimating()
}
}
}).start(error: { [weak self] _ in
}).start(error: { [weak self] error in
guard let strongSelf = self, let presentationInterfaceState = strongSelf.presentationInterfaceState, let peer = presentationInterfaceState.renderedPeer?.peer else {
return
}
let text: String
if let channel = peer as? TelegramChannel, case .broadcast = channel.info {
text = presentationInterfaceState.strings.Channel_ErrorAccessDenied
} else {
text = presentationInterfaceState.strings.Group_ErrorAccessDenied
switch error {
case .tooMuchJoined:
text = presentationInterfaceState.strings.Join_ChannelsTooMuch
default:
if let channel = peer as? TelegramChannel, case .broadcast = channel.info {
text = presentationInterfaceState.strings.Channel_ErrorAccessDenied
} else {
text = presentationInterfaceState.strings.Group_ErrorAccessDenied
}
}
strongSelf.interfaceInteraction?.presentController(textAlertController(context: context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationInterfaceState.strings.Common_OK, action: {})]), nil)
}))

View File

@ -97,10 +97,11 @@ public class ChatListController: TelegramController, UIViewControllerPreviewingD
private var searchContentNode: NavigationBarSearchContentNode?
public override func updateNavigationCustomData(_ data: Any?, progress: CGFloat, transition: ContainedViewLayoutTransition) {
self.chatListDisplayNode.chatListNode.updateSelectedChatLocation(data as? ChatLocation, progress: progress, transition: transition)
if self.isNodeLoaded {
self.chatListDisplayNode.chatListNode.updateSelectedChatLocation(data as? ChatLocation, progress: progress, transition: transition)
}
}
public init(context: AccountContext, groupId: PeerGroupId, controlsHistoryPreload: Bool, hideNetworkActivityStatus: Bool = false) {
self.context = context
self.controlsHistoryPreload = controlsHistoryPreload

View File

@ -534,7 +534,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
}
} else {
if self.highlightedBackgroundNode.supernode != nil {
transition.updateAlpha(layer: self.highlightedBackgroundNode.layer, alpha: highlightProgress, completion: { [weak self] completed in
transition.updateAlpha(layer: self.highlightedBackgroundNode.layer, alpha: 1.0 - highlightProgress, completion: { [weak self] completed in
if let strongSelf = self {
if completed {
strongSelf.highlightedBackgroundNode.removeFromSupernode()

View File

@ -13,6 +13,8 @@ final class ChatTextInputMenu {
private var stringItalic: String = "Italic"
private var stringMonospace: String = "Monospace"
private var stringLink: String = "Link"
private var stringStrikethrough: String = "Strikethrough"
private var stringUnderline: String = "Underline"
private(set) var state: ChatTextInputMenuState = .inactive {
didSet {
@ -27,7 +29,9 @@ final class ChatTextInputMenu {
UIMenuItem(title: self.stringBold, action: Selector(("formatAttributesBold:"))),
UIMenuItem(title: self.stringItalic, action: Selector(("formatAttributesItalic:"))),
UIMenuItem(title: self.stringMonospace, action: Selector(("formatAttributesMonospace:"))),
UIMenuItem(title: self.stringLink, action: Selector(("formatAttributesLink:")))
UIMenuItem(title: self.stringLink, action: Selector(("formatAttributesLink:"))),
UIMenuItem(title: self.stringStrikethrough, action: Selector(("formatAttributesStrikethrough:"))),
UIMenuItem(title: self.stringUnderline, action: Selector(("formatAttributesUnderline:")))
]
UIMenuController.shared.isMenuVisible = true
UIMenuController.shared.update()
@ -56,6 +60,8 @@ final class ChatTextInputMenu {
self.stringItalic = strings.TextFormat_Italic
self.stringMonospace = strings.TextFormat_Monospace
self.stringLink = strings.TextFormat_Link
self.stringStrikethrough = strings.TextFormat_Strikethrough
self.stringUnderline = strings.TextFormat_Underline
}
func activate() {

View File

@ -230,6 +230,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
private var currentPlaceholder: String?
private var presentationInterfaceState: ChatPresentationInterfaceState?
private var initializedPlaceholder = false
private var keepSendButtonEnabled = false
private var extendedSearchLayout = false
@ -684,7 +685,9 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
}
}
if let peer = interfaceState.renderedPeer?.peer, previousState?.renderedPeer?.peer == nil || !peer.isEqual(previousState!.renderedPeer!.peer!) || previousState?.interfaceState.silentPosting != interfaceState.interfaceState.silentPosting || themeUpdated {
if let peer = interfaceState.renderedPeer?.peer, previousState?.renderedPeer?.peer == nil || !peer.isEqual(previousState!.renderedPeer!.peer!) || previousState?.interfaceState.silentPosting != interfaceState.interfaceState.silentPosting || themeUpdated || !self.initializedPlaceholder {
self.initializedPlaceholder = true
let placeholder: String
if let channel = peer as? TelegramChannel, case .broadcast = channel.info {
if interfaceState.interfaceState.silentPosting {
@ -1342,7 +1345,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
} else {
return ASEditableTextNodeTargetForAction(target: nil)
}
} else if action == #selector(self.formatAttributesBold(_:)) || action == #selector(self.formatAttributesItalic(_:)) || action == #selector(self.formatAttributesMonospace(_:)) || action == #selector(self.formatAttributesLink(_:)) {
} else if action == #selector(self.formatAttributesBold(_:)) || action == #selector(self.formatAttributesItalic(_:)) || action == #selector(self.formatAttributesMonospace(_:)) || action == #selector(self.formatAttributesLink(_:)) || action == #selector(self.formatAttributesStrikethrough(_:)) || action == #selector(self.formatAttributesUnderline(_:)) {
if case .format = self.inputMenu.state {
return ASEditableTextNodeTargetForAction(target: self)
} else {
@ -1385,6 +1388,20 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
self.interfaceInteraction?.openLinkEditing()
}
@objc func formatAttributesStrikethrough(_ sender: Any) {
self.inputMenu.back()
self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in
return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.strikethrough), inputMode)
}
}
@objc func formatAttributesUnderline(_ sender: Any) {
self.inputMenu.back()
self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in
return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.underline), inputMode)
}
}
@objc func editableTextNode(_ editableTextNode: ASEditableTextNode, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
self.updateActivity()
var cleanText = text

View File

@ -77,12 +77,12 @@ public class ContactsController: ViewController {
var switchToChatsController: (() -> Void)?
public override func updateNavigationCustomData(_ data: Any?, progress: CGFloat, transition: ContainedViewLayoutTransition) {
self.contactsNode.contactListNode.updateSelectedChatLocation(data as? ChatLocation, progress: progress, transition: transition)
if self.isNodeLoaded {
self.contactsNode.contactListNode.updateSelectedChatLocation(data as? ChatLocation, progress: progress, transition: transition)
}
}
public init(context: AccountContext) {
self.context = context

View File

@ -424,7 +424,7 @@ class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
transition.updateAlpha(layer: self.highlightedBackgroundNode.layer, alpha: highlightProgress)
} else {
if self.highlightedBackgroundNode.supernode != nil {
transition.updateAlpha(layer: self.highlightedBackgroundNode.layer, alpha: highlightProgress, completion: { [weak self] completed in
transition.updateAlpha(layer: self.highlightedBackgroundNode.layer, alpha: 1.0 - highlightProgress, completion: { [weak self] completed in
if let strongSelf = self {
if completed {
strongSelf.highlightedBackgroundNode.removeFromSupernode()

View File

@ -262,6 +262,8 @@ public func createChannelController(context: AccountContext) -> ViewController {
switch error {
case .generic, .tooMuchLocationBasedGroups:
text = presentationData.strings.Login_UnknownError
case .tooMuchJoined:
text = presentationData.strings.CreateGroup_ChannelsTooMuch
case .restricted:
text = presentationData.strings.Common_ActionNotAllowedError
default:

View File

@ -356,6 +356,8 @@ public func createGroupController(context: AccountContext, peerIds: [PeerId], in
return .generic
case .restricted:
return .restricted
case .tooMuchJoined:
return .tooMuchJoined
case .tooMuchLocationBasedGroups:
return .tooMuchLocationBasedGroups
case let .serverProvided(error):
@ -381,6 +383,8 @@ public func createGroupController(context: AccountContext, peerIds: [PeerId], in
return .generic
case .restricted:
return .restricted
case .tooMuchJoined:
return .tooMuchJoined
case .tooMuchLocationBasedGroups:
return .tooMuchLocationBasedGroups
case let .serverProvided(error):
@ -448,6 +452,8 @@ public func createGroupController(context: AccountContext, peerIds: [PeerId], in
text = presentationData.strings.Login_UnknownError
case .restricted:
text = presentationData.strings.Common_ActionNotAllowedError
case .tooMuchJoined:
text = presentationData.strings.CreateGroup_ChannelsTooMuch
case .tooMuchLocationBasedGroups:
text = presentationData.strings.CreateGroup_ErrorLocatedGroupsTooMuch
default:

View File

@ -54,7 +54,7 @@ final class DeviceLocationManager: NSObject, CLLocationManagerDelegate {
}
self.manager.delegate = self
self.manager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
self.manager.distanceFilter = 20.0
self.manager.distanceFilter = 10.0
self.manager.activityType = .other
self.manager.pausesLocationUpdatesAutomatically = false
}

View File

@ -1815,13 +1815,13 @@ public func groupInfoController(context: AccountContext, peerId originalPeerId:
|> deliverOnMainQueue).start(error: { error in
if peers.count == 1, case .restricted = error {
switch peers[0] {
case let .peer(peerId):
let _ = (context.account.postbox.loadedPeerWithId(peerId)
|> deliverOnMainQueue).start(next: { peer in
presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(peer.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), nil)
})
default:
break
case let .peer(peerId):
let _ = (context.account.postbox.loadedPeerWithId(peerId)
|> deliverOnMainQueue).start(next: { peer in
presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(peer.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), nil)
})
default:
break
}
}

View File

@ -105,6 +105,13 @@ public final class JoinLinkPreviewController: ViewController {
strongSelf.dismiss()
}
}
}, error: { [weak self] error in
if let strongSelf = self {
if case .tooMuchJoined = error {
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: strongSelf.presentationData.strings.Join_ChannelsTooMuch, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
strongSelf.dismiss()
}
}
}))
}
}

View File

@ -32,7 +32,7 @@ final class LocationBroadcastNavigationAccessoryPanel: ASDisplayNode {
private let separatorNode: ASDisplayNode
private var validLayout: (CGSize, CGFloat, CGFloat)?
private var peersAndMode: ([Peer], LocationBroadcastNavigationAccessoryPanelMode)?
private var peersAndMode: ([Peer], LocationBroadcastNavigationAccessoryPanelMode, Bool)?
init(accountPeerId: PeerId, theme: PresentationTheme, strings: PresentationStrings, tapAction: @escaping () -> Void, close: @escaping () -> Void) {
self.accountPeerId = accountPeerId
@ -108,7 +108,7 @@ final class LocationBroadcastNavigationAccessoryPanel: ASDisplayNode {
let titleString = NSAttributedString(string: self.strings.Conversation_LiveLocation, font: titleFont, textColor: self.theme.rootController.navigationBar.primaryTextColor)
var subtitleString: NSAttributedString?
if let (peers, mode) = self.peersAndMode {
if let (peers, mode, canClose) = self.peersAndMode {
switch mode {
case .summary:
let text: String
@ -119,6 +119,7 @@ final class LocationBroadcastNavigationAccessoryPanel: ASDisplayNode {
}
subtitleString = NSAttributedString(string: text, font: subtitleFont, textColor: self.theme.rootController.navigationBar.secondaryTextColor)
case .peer:
self.closeButton.isHidden = !canClose
let filteredPeers = peers.filter {
$0.id != self.accountPeerId
}
@ -172,8 +173,8 @@ final class LocationBroadcastNavigationAccessoryPanel: ASDisplayNode {
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: size.height - UIScreenPixel), size: CGSize(width: size.width, height: UIScreenPixel)))
}
func update(peers: [Peer], mode: LocationBroadcastNavigationAccessoryPanelMode) {
self.peersAndMode = (peers, mode)
func update(peers: [Peer], mode: LocationBroadcastNavigationAccessoryPanelMode, canClose: Bool) {
self.peersAndMode = (peers, mode, canClose)
if let layout = validLayout {
self.updateLayout(size: layout.0, leftInset: layout.1, rightInset: layout.2, transition: .immediate)
}

View File

@ -327,23 +327,6 @@ final class PeerChannelMemberCategoriesContextsManager {
|> mapToSignal { _ -> Signal<Void, AddChannelMemberError> in
return .complete()
}
/*return addChannelMembers(account: account, peerId: peerId, memberIds: memberIds)
|> deliverOnMainQueue
|> beforeNext { [weak self] result in
if let strongSelf = self {
strongSelf.impl.with { impl in
for (contextPeerId, context) in impl.contexts {
if peerId == contextPeerId {
context.reset(.recent)
}
}
}
}
}
|> mapToSignal { _ -> Signal<Void, AddChannelMemberError> in
return .single(Void())
}*/
}
func recentOnline(postbox: Postbox, network: Network, accountPeerId: PeerId, peerId: PeerId) -> Signal<Int32, NoError> {

View File

@ -1347,15 +1347,9 @@ public func settingsController(context: AccountContext, accountManager: AccountM
context.sharedContext.switchToAccount(id: id)
})
}
var didAppear = false
controller.didAppear = { [weak controller] _ in
controller.didAppear = { _ in
updatePassport()
updateNotifyExceptions()
if !didAppear {
(controller?.displayNode as? ItemListControllerNode<SettingsEntry>)?.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: ListViewScrollToItem(index: 0, position: .top(-navigationBarSearchContentHeight), animated: false, curve: .Default(duration: 0.0), directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
didAppear = true
}
}
controller.previewItemWithTag = { tag in
if let tag = tag as? SettingsEntryTag, case let .account(id) = tag {

View File

@ -184,24 +184,24 @@ public class TelegramController: ViewController, KeyShortcutResponder {
peers?.append(author)
}
}
return (peers, nil)
return (peers, outgoingMessages)
}
default:
self.locationBroadcastMode = .summary
signal = liveLocationManager.summaryManager.broadcastingToMessages()
|> map { messages -> ([Peer]?, [MessageId: Message]?) in
if messages.isEmpty {
return (nil, nil)
} else {
var peers: [Peer] = []
for message in messages.values.sorted(by: { $0.index < $1.index }) {
if let peer = message.peers[message.id.peerId] {
peers.append(peer)
}
|> map { messages -> ([Peer]?, [MessageId: Message]?) in
if messages.isEmpty {
return (nil, nil)
} else {
var peers: [Peer] = []
for message in messages.values.sorted(by: { $0.index < $1.index }) {
if let peer = message.peers[message.id.peerId] {
peers.append(peer)
}
return (peers, messages)
}
return (peers, messages)
}
}
}
@ -223,7 +223,16 @@ public class TelegramController: ViewController, KeyShortcutResponder {
if wasEmpty != (peers == nil) {
strongSelf.requestLayout(transition: .animated(duration: 0.4, curve: .spring))
} else if let peers = peers, let locationBroadcastMode = strongSelf.locationBroadcastMode {
strongSelf.locationBroadcastAccessoryPanel?.update(peers: peers, mode: locationBroadcastMode)
var canClose = true
if case let .peer(peerId) = strongSelf.locationBroadcastPanelSource, let messages = messages {
canClose = false
for messageId in messages.keys {
if messageId.peerId == peerId {
canClose = true
}
}
}
strongSelf.locationBroadcastAccessoryPanel?.update(peers: peers, mode: locationBroadcastMode, canClose: canClose)
}
}
}
@ -401,7 +410,18 @@ public class TelegramController: ViewController, KeyShortcutResponder {
}
self.locationBroadcastAccessoryPanel = locationBroadcastAccessoryPanel
locationBroadcastAccessoryPanel.frame = panelFrame
locationBroadcastAccessoryPanel.update(peers: locationBroadcastPeers, mode: locationBroadcastMode)
var canClose = true
if case let .peer(peerId) = self.locationBroadcastPanelSource, let messages = self.locationBroadcastMessages {
canClose = false
for messageId in messages.keys {
if messageId.peerId == peerId {
canClose = true
}
}
}
locationBroadcastAccessoryPanel.update(peers: locationBroadcastPeers, mode: locationBroadcastMode, canClose: canClose)
locationBroadcastAccessoryPanel.updateLayout(size: panelFrame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, transition: .immediate)
if transition.isAnimated {
locationBroadcastAccessoryPanel.animateIn(transition)

View File

@ -890,7 +890,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
transformedSuperFrame = transformedSuperFrame.offsetBy(dx: videoNode.position.x - previousFrame.center.x, dy: videoNode.position.y - previousFrame.center.y)
}
let initialScale = min(videoNode.layer.bounds.width / node.0.view.bounds.width, videoNode.layer.bounds.height / node.0.view.bounds.height)
let initialScale: CGFloat = 1.0 //min(videoNode.layer.bounds.width / node.0.view.bounds.width, videoNode.layer.bounds.height / node.0.view.bounds.height)
let targetScale = max(transformedFrame.size.width / videoNode.layer.bounds.size.width, transformedFrame.size.height / videoNode.layer.bounds.size.height)
videoNode.backgroundColor = .clear