no message

This commit is contained in:
Peter
2017-03-03 19:33:19 +04:00
parent 7485eb3a8e
commit 89dce43572
13 changed files with 437 additions and 55 deletions

View File

@@ -240,6 +240,7 @@
D08D452F1D5E340300A7428A /* Display.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D08D452A1D5E340300A7428A /* Display.framework */; };
D08D45301D5E340300A7428A /* Postbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D08D452B1D5E340300A7428A /* Postbox.framework */; };
D08D45311D5E340300A7428A /* SwiftSignalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D08D452C1D5E340300A7428A /* SwiftSignalKit.framework */; };
D099261F1E69791E00D95539 /* GroupsInCommonController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D099261E1E69791E00D95539 /* GroupsInCommonController.swift */; };
D099EA1F1DE7450B001AF5A8 /* HorizontalListContextResultsChatInputContextPanelNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D099EA1E1DE7450B001AF5A8 /* HorizontalListContextResultsChatInputContextPanelNode.swift */; };
D099EA211DE7451D001AF5A8 /* HorizontalListContextResultsChatInputPanelItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D099EA201DE7451D001AF5A8 /* HorizontalListContextResultsChatInputPanelItem.swift */; };
D099EA271DE765DB001AF5A8 /* ManagedMediaId.swift in Sources */ = {isa = PBXBuildFile; fileRef = D099EA261DE765DB001AF5A8 /* ManagedMediaId.swift */; };
@@ -717,6 +718,7 @@
D08D452B1D5E340300A7428A /* Postbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Postbox.framework; path = "../../../../Library/Developer/Xcode/DerivedData/Telegram-iOS-diblohvjozhgaifjcniwdlixlilx/Build/Products/Debug-iphonesimulator/Postbox.framework"; sourceTree = "<group>"; };
D08D452C1D5E340300A7428A /* SwiftSignalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftSignalKit.framework; path = "../../../../Library/Developer/Xcode/DerivedData/Telegram-iOS-diblohvjozhgaifjcniwdlixlilx/Build/Products/Debug-iphonesimulator/SwiftSignalKit.framework"; sourceTree = "<group>"; };
D08D452D1D5E340300A7428A /* TelegramCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TelegramCore.framework; path = "../../../../Library/Developer/Xcode/DerivedData/Telegram-iOS-diblohvjozhgaifjcniwdlixlilx/Build/Products/Debug-iphonesimulator/TelegramCore.framework"; sourceTree = "<group>"; };
D099261E1E69791E00D95539 /* GroupsInCommonController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupsInCommonController.swift; sourceTree = "<group>"; };
D099EA1E1DE7450B001AF5A8 /* HorizontalListContextResultsChatInputContextPanelNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HorizontalListContextResultsChatInputContextPanelNode.swift; sourceTree = "<group>"; };
D099EA201DE7451D001AF5A8 /* HorizontalListContextResultsChatInputPanelItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HorizontalListContextResultsChatInputPanelItem.swift; sourceTree = "<group>"; };
D099EA261DE765DB001AF5A8 /* ManagedMediaId.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedMediaId.swift; sourceTree = "<group>"; };
@@ -1781,6 +1783,7 @@
D0613FD41E6064D200202CDB /* ConvertToSupergroupController.swift */,
D033FEAA1E61BFC100644997 /* GroupAdminsController.swift */,
D0528E621E65BECA00E2FEF5 /* UserInfoController.swift */,
D099261E1E69791E00D95539 /* GroupsInCommonController.swift */,
);
name = Controller;
sourceTree = "<group>";
@@ -2778,6 +2781,7 @@
D0EE971A1D88BCA0006C18E1 /* ChatInfo.swift in Sources */,
D0F69DE31D6B8A420046BCD6 /* ListControllerItem.swift in Sources */,
D0736F211DF41CFD00F2C02A /* ManagedAudioPlaylistPlayer.swift in Sources */,
D099261F1E69791E00D95539 /* GroupsInCommonController.swift in Sources */,
D0177B801DFAE18500A5083A /* MediaPlayerTimeTextNode.swift in Sources */,
D07A7DA31D957671005BCD27 /* ListMessageSnippetItemNode.swift in Sources */,
D0F69E6B1D6B8C160046BCD6 /* MapInputControllerNode.swift in Sources */,

View File

@@ -38,6 +38,7 @@ public class ChatController: TelegramController {
private var controllerInteraction: ChatControllerInteraction?
private var interfaceInteraction: ChatPanelInterfaceInteraction?
private let messageContextDisposable = MetaDisposable()
private let controllerNavigationDisposable = MetaDisposable()
private let sentMessageEventsDisposable = MetaDisposable()
private let messageActionCallbackDisposable = MetaDisposable()
@@ -55,7 +56,7 @@ public class ChatController: TelegramController {
private var resolveUrlDisposable: MetaDisposable?
private var contextQueryState: (ChatPresentationInputQuery?, Disposable)?
private var urlPreviewQueryState: (URL?, Disposable)?
private var urlPreviewQueryState: (String?, Disposable)?
private var audioRecorderValue: ManagedAudioRecorder?
private var audioRecorderFeedback: HapticFeedback?
@@ -336,7 +337,7 @@ public class ChatController: TelegramController {
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: "")) }
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: "")).withUpdatedComposeDisableUrlPreview(nil) }
})
}
})
@@ -529,6 +530,7 @@ public class ChatController: TelegramController {
self.navigationActionDisposable.dispose()
self.galleryHiddenMesageAndMediaDisposable.dispose()
self.peerDisposable.dispose()
self.messageContextDisposable.dispose()
self.controllerNavigationDisposable.dispose()
self.sentMessageEventsDisposable.dispose()
self.messageActionCallbackDisposable.dispose()
@@ -872,6 +874,18 @@ public class ChatController: TelegramController {
}
}
self.chatDisplayNode.dismissUrlPreview = { [weak self] in
if let strongSelf = self {
if let (link, _) = strongSelf.presentationInterfaceState.urlPreview {
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, {
$0.updatedInterfaceState {
$0.withUpdatedComposeDisableUrlPreview(link)
}
})
}
}
}
self.chatDisplayNode.navigateToLatestButton.tapped = { [weak self] in
if let strongSelf = self, strongSelf.isNodeLoaded {
strongSelf.chatDisplayNode.historyNode.scrollToEndOfHistory()
@@ -901,9 +915,53 @@ public class ChatController: TelegramController {
}, deleteSelectedMessages: { [weak self] in
if let strongSelf = self {
if let messageIds = strongSelf.presentationInterfaceState.interfaceState.selectionState?.selectedIds, !messageIds.isEmpty {
let _ = deleteMessagesInteractively(postbox: strongSelf.account.postbox, messageIds: Array(messageIds), type: .forLocalPeer).start()
strongSelf.messageContextDisposable.set((chatDeleteMessagesOptions(account: strongSelf.account, messageIds: messageIds) |> deliverOnMainQueue).start(next: { options in
if let strongSelf = self, !options.isEmpty {
let actionSheet = ActionSheetController()
var items: [ActionSheetItem] = []
var personalPeerName: String?
var isChannel = false
if let user = strongSelf.presentationInterfaceState.peer as? TelegramUser {
personalPeerName = user.compactDisplayTitle
} else if let channel = strongSelf.presentationInterfaceState.peer as? TelegramChannel, case .broadcast = channel.info {
isChannel = true
}
if options.contains(.globally) {
let globalTitle: String
if isChannel {
globalTitle = "Delete"
} else if let personalPeerName = personalPeerName {
globalTitle = "Delete for me and \(personalPeerName)"
} else {
globalTitle = "Delete for everyone"
}
items.append(ActionSheetButtonItem(title: globalTitle, color: .destructive, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
if let strongSelf = self {
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { $0.updatedInterfaceState { $0.withoutSelectionState() } })
let _ = deleteMessagesInteractively(postbox: strongSelf.account.postbox, messageIds: Array(messageIds), type: .forEveryone).start()
}
}))
}
if options.contains(.locally) {
items.append(ActionSheetButtonItem(title: "Delete for me", color: .destructive, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
if let strongSelf = self {
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { $0.updatedInterfaceState { $0.withoutSelectionState() } })
let _ = deleteMessagesInteractively(postbox: strongSelf.account.postbox, messageIds: Array(messageIds), type: .forLocalPeer).start()
}
}))
}
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: "Cancel", color: .accent, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
})
])])
strongSelf.present(actionSheet, in: .window)
}
}))
}
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { $0.updatedInterfaceState { $0.withoutSelectionState() } })
}
}, forwardSelectedMessages: { [weak self] in
if let strongSelf = self {
@@ -997,7 +1055,7 @@ public class ChatController: TelegramController {
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: "")) }
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: "")).withUpdatedComposeDisableUrlPreview(nil) }
})
}
})
@@ -1039,7 +1097,7 @@ public class ChatController: TelegramController {
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: "")) }
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: "")).withUpdatedComposeDisableUrlPreview(nil) }
})
}
})
@@ -1316,14 +1374,22 @@ public class ChatController: TelegramController {
inScopeResult = result
} else {
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedUrlPreview(result($0.urlPreview))
if let updatedUrlPreviewUrl = updatedUrlPreviewUrl, let webpage = result($0.urlPreview?.1) {
return $0.updatedUrlPreview((updatedUrlPreviewUrl, webpage))
} else {
return $0.updatedUrlPreview(nil)
}
})
}
}
}))
inScope = false
if let inScopeResult = inScopeResult {
updatedChatPresentationInterfaceState = updatedChatPresentationInterfaceState.updatedUrlPreview(inScopeResult(updatedChatPresentationInterfaceState.urlPreview))
if let updatedUrlPreviewUrl = updatedUrlPreviewUrl, let webpage = inScopeResult(updatedChatPresentationInterfaceState.urlPreview?.1) {
updatedChatPresentationInterfaceState = updatedChatPresentationInterfaceState.updatedUrlPreview((updatedUrlPreviewUrl, webpage))
} else {
updatedChatPresentationInterfaceState = updatedChatPresentationInterfaceState.updatedUrlPreview(nil)
}
}
}
@@ -1383,6 +1449,7 @@ public class ChatController: TelegramController {
ActionSheetButtonItem(title: "Delete All Messages", color: .destructive, action: { [weak self, weak actionSheet] in
actionSheet?.dismissAnimated()
if let strongSelf = self {
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { $0.updatedInterfaceState { $0.withoutSelectionState() } })
let _ = clearHistoryInteractively(postbox: strongSelf.account.postbox, peerId: strongSelf.peerId).start()
}
})
@@ -1468,7 +1535,7 @@ public class ChatController: TelegramController {
self.chatDisplayNode.setupSendActionOnViewUpdate({ [weak self] in
if let strongSelf = self {
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: "")) }
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: "")).withUpdatedComposeDisableUrlPreview(nil) }
})
}
})

View File

@@ -44,6 +44,7 @@ class ChatControllerNode: ASDisplayNode {
var requestUpdateChatInterfaceState: (Bool, (ChatInterfaceState) -> ChatInterfaceState) -> Void = { _ in }
var displayAttachmentMenu: () -> Void = { }
var updateTypingActivity: () -> Void = { }
var dismissUrlPreview: () -> Void = { }
var setupSendActionOnViewUpdate: (@escaping () -> Void) -> Void = { _ in }
var requestLayout: (ContainedViewLayoutTransition) -> Void = { _ in }
@@ -131,7 +132,7 @@ class ChatControllerNode: ASDisplayNode {
if let strongSelf = strongSelf, let textInputPanelNode = strongSelf.inputPanelNode as? ChatTextInputPanelNode {
strongSelf.ignoreUpdateHeight = true
textInputPanelNode.text = ""
strongSelf.requestUpdateChatInterfaceState(false, { $0.withUpdatedReplyMessageId(nil).withUpdatedForwardMessageIds(nil) })
strongSelf.requestUpdateChatInterfaceState(false, { $0.withUpdatedReplyMessageId(nil).withUpdatedForwardMessageIds(nil).withUpdatedComposeDisableUrlPreview(nil) })
strongSelf.ignoreUpdateHeight = false
}
})
@@ -143,7 +144,11 @@ class ChatControllerNode: ASDisplayNode {
if !entities.isEmpty {
attributes.append(TextEntitiesMessageAttribute(entities: entities))
}
messages.append(.message(text: text, attributes: attributes, media: nil, replyToMessageId: strongSelf.chatPresentationInterfaceState.interfaceState.replyMessageId))
if strongSelf.chatPresentationInterfaceState.interfaceState.composeDisableUrlPreview != nil {
attributes.append(OutgoingContentInfoMessageAttribute(flags: [.disableLinkPreviews]))
}
let webpage = strongSelf.chatPresentationInterfaceState.urlPreview?.1
messages.append(.message(text: text, attributes: attributes, media: webpage, replyToMessageId: strongSelf.chatPresentationInterfaceState.interfaceState.replyMessageId))
}
if let forwardMessageIds = strongSelf.chatPresentationInterfaceState.interfaceState.forwardMessageIds {
for id in forwardMessageIds {
@@ -316,7 +321,7 @@ class ChatControllerNode: ASDisplayNode {
} else if let _ = accessoryPanelNode as? EditAccessoryPanelNode {
strongSelf.requestUpdateChatInterfaceState(true, { $0.withUpdatedEditMessage(nil) })
} else if let _ = accessoryPanelNode as? WebpagePreviewAccessoryPanelNode {
strongSelf.dismissUrlPreview()
}
}
}

View File

@@ -218,6 +218,7 @@ struct ChatInterfaceMessageActionsState: Coding, Equatable {
final class ChatInterfaceState: PeerChatInterfaceState, Equatable {
let timestamp: Int32
let composeInputState: ChatTextInputState
let composeDisableUrlPreview: String?
let replyMessageId: MessageId?
let forwardMessageIds: [MessageId]?
let editMessage: ChatEditMessageState?
@@ -243,6 +244,7 @@ final class ChatInterfaceState: PeerChatInterfaceState, Equatable {
init() {
self.timestamp = 0
self.composeInputState = ChatTextInputState()
self.composeDisableUrlPreview = nil
self.replyMessageId = nil
self.forwardMessageIds = nil
self.editMessage = nil
@@ -250,9 +252,10 @@ final class ChatInterfaceState: PeerChatInterfaceState, Equatable {
self.messageActionsState = ChatInterfaceMessageActionsState()
}
init(timestamp: Int32, composeInputState: ChatTextInputState, replyMessageId: MessageId?, forwardMessageIds: [MessageId]?, editMessage: ChatEditMessageState?, selectionState: ChatInterfaceSelectionState?, messageActionsState: ChatInterfaceMessageActionsState) {
init(timestamp: Int32, composeInputState: ChatTextInputState, composeDisableUrlPreview: String?, replyMessageId: MessageId?, forwardMessageIds: [MessageId]?, editMessage: ChatEditMessageState?, selectionState: ChatInterfaceSelectionState?, messageActionsState: ChatInterfaceMessageActionsState) {
self.timestamp = timestamp
self.composeInputState = composeInputState
self.composeDisableUrlPreview = composeDisableUrlPreview
self.replyMessageId = replyMessageId
self.forwardMessageIds = forwardMessageIds
self.editMessage = editMessage
@@ -267,6 +270,11 @@ final class ChatInterfaceState: PeerChatInterfaceState, Equatable {
} else {
self.composeInputState = ChatTextInputState()
}
if let composeDisableUrlPreview = decoder.decodeStringForKey("dup") as String? {
self.composeDisableUrlPreview = composeDisableUrlPreview
} else {
self.composeDisableUrlPreview = nil
}
let replyMessageIdPeerId: Int64? = decoder.decodeInt64ForKey("r.p")
let replyMessageIdNamespace: Int32? = decoder.decodeInt32ForKey("r.n")
let replyMessageIdId: Int32? = decoder.decodeInt32ForKey("r.i")
@@ -301,6 +309,11 @@ final class ChatInterfaceState: PeerChatInterfaceState, Equatable {
func encode(_ encoder: Encoder) {
encoder.encodeInt32(self.timestamp, forKey: "ts")
encoder.encodeObject(self.composeInputState, forKey: "is")
if let composeDisableUrlPreview = self.composeDisableUrlPreview {
encoder.encodeString(composeDisableUrlPreview, forKey: "dup")
} else {
encoder.encodeNil(forKey: "dup")
}
if let replyMessageId = self.replyMessageId {
encoder.encodeInt64(replyMessageId.peerId.toInt64(), forKey: "r.p")
encoder.encodeInt32(replyMessageId.namespace, forKey: "r.n")
@@ -343,6 +356,9 @@ final class ChatInterfaceState: PeerChatInterfaceState, Equatable {
}
static func ==(lhs: ChatInterfaceState, rhs: ChatInterfaceState) -> Bool {
if lhs.composeDisableUrlPreview != rhs.composeDisableUrlPreview {
return false
}
if let lhsForwardMessageIds = lhs.forwardMessageIds, let rhsForwardMessageIds = rhs.forwardMessageIds {
if lhsForwardMessageIds != rhsForwardMessageIds {
return false
@@ -359,7 +375,11 @@ final class ChatInterfaceState: PeerChatInterfaceState, Equatable {
func withUpdatedComposeInputState(_ inputState: ChatTextInputState) -> ChatInterfaceState {
let updatedComposeInputState = inputState
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: updatedComposeInputState, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState)
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: updatedComposeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState)
}
func withUpdatedComposeDisableUrlPreview(_ disableUrlPreview: String?) -> ChatInterfaceState {
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: disableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState)
}
func withUpdatedEffectiveInputState(_ inputState: ChatTextInputState) -> ChatInterfaceState {
@@ -371,15 +391,15 @@ final class ChatInterfaceState: PeerChatInterfaceState, Equatable {
updatedComposeInputState = inputState
}
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: updatedComposeInputState, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: updatedEditMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState)
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: updatedComposeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: updatedEditMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState)
}
func withUpdatedReplyMessageId(_ replyMessageId: MessageId?) -> ChatInterfaceState {
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, replyMessageId: replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState)
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState)
}
func withUpdatedForwardMessageIds(_ forwardMessageIds: [MessageId]?) -> ChatInterfaceState {
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, replyMessageId: self.replyMessageId, forwardMessageIds: forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState)
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState)
}
func withUpdatedSelectedMessage(_ messageId: MessageId) -> ChatInterfaceState {
@@ -388,7 +408,7 @@ final class ChatInterfaceState: PeerChatInterfaceState, Equatable {
selectedIds.formUnion(selectionState.selectedIds)
}
selectedIds.insert(messageId)
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds), messageActionsState: self.messageActionsState)
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds), messageActionsState: self.messageActionsState)
}
func withToggledSelectedMessage(_ messageId: MessageId) -> ChatInterfaceState {
@@ -401,22 +421,22 @@ final class ChatInterfaceState: PeerChatInterfaceState, Equatable {
} else {
selectedIds.insert(messageId)
}
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds), messageActionsState: self.messageActionsState)
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds), messageActionsState: self.messageActionsState)
}
func withoutSelectionState() -> ChatInterfaceState {
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: nil, messageActionsState: self.messageActionsState)
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: nil, messageActionsState: self.messageActionsState)
}
func withUpdatedTimestamp(_ timestamp: Int32) -> ChatInterfaceState {
return ChatInterfaceState(timestamp: timestamp, composeInputState: self.composeInputState, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState)
return ChatInterfaceState(timestamp: timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState)
}
func withUpdatedEditMessage(_ editMessage: ChatEditMessageState?) -> ChatInterfaceState {
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState)
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState)
}
func withUpdatedMessageActionsState(_ f: (ChatInterfaceMessageActionsState) -> ChatInterfaceMessageActionsState) -> ChatInterfaceState {
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: f(self.messageActionsState))
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: f(self.messageActionsState))
}
}

View File

@@ -34,12 +34,12 @@ func accessoryPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceS
panelNode.interfaceInteraction = interfaceInteraction
return panelNode
}
} else if let urlPreview = chatPresentationInterfaceState.urlPreview {
if let previewPanelNode = currentPanel as? WebpagePreviewAccessoryPanelNode, previewPanelNode.webpage.id == urlPreview.id {
} else if let urlPreview = chatPresentationInterfaceState.urlPreview, chatPresentationInterfaceState.interfaceState.composeDisableUrlPreview != urlPreview.0 {
if let previewPanelNode = currentPanel as? WebpagePreviewAccessoryPanelNode, previewPanelNode.webpage.id == urlPreview.1.id {
previewPanelNode.interfaceInteraction = interfaceInteraction
return previewPanelNode
} else {
let panelNode = WebpagePreviewAccessoryPanelNode(account: account, webpage: urlPreview)
let panelNode = WebpagePreviewAccessoryPanelNode(account: account, webpage: urlPreview.1)
panelNode.interfaceInteraction = interfaceInteraction
return panelNode
}

View File

@@ -3,6 +3,7 @@ import Postbox
import TelegramCore
import Display
import UIKit
import SwiftSignalKit
func contextMenuForChatPresentationIntefaceState(_ chatPresentationInterfaceState: ChatPresentationInterfaceState, account: Account, message: Message, interfaceInteraction: ChatPanelInterfaceInteraction?) -> ContextMenuController? {
guard let peer = chatPresentationInterfaceState.peer, let interfaceInteraction = interfaceInteraction else {
@@ -23,6 +24,7 @@ func contextMenuForChatPresentationIntefaceState(_ chatPresentationInterfaceStat
canReply = false
}
case .group:
canReply = true
switch channel.role {
case .creator, .editor, .moderator:
canPin = true
@@ -94,3 +96,83 @@ func contextMenuForChatPresentationIntefaceState(_ chatPresentationInterfaceStat
return nil
}
}
struct ChatDeleteMessagesOptions: OptionSet {
var rawValue: Int32
init(rawValue: Int32) {
self.rawValue = rawValue
}
init() {
self.rawValue = 0
}
static let locally = ChatDeleteMessagesOptions(rawValue: 1 << 0)
static let globally = ChatDeleteMessagesOptions(rawValue: 1 << 1)
}
func chatDeleteMessagesOptions(account: Account, messageIds: Set<MessageId>) -> Signal<ChatDeleteMessagesOptions, NoError> {
return account.postbox.modify { modifier -> ChatDeleteMessagesOptions in
var optionsMap: [MessageId: ChatDeleteMessagesOptions] = [:]
for id in messageIds {
if let peer = modifier.getPeer(id.peerId), let message = modifier.getMessage(id) {
if let channel = peer as? TelegramChannel {
var options: ChatDeleteMessagesOptions = []
if !message.flags.contains(.Incoming) {
options.insert(.globally)
} else {
switch channel.role {
case .creator:
options.insert(.globally)
case .moderator, .editor:
options.insert(.globally)
case .member:
break
}
}
optionsMap[message.id] = options
} else if let group = peer as? TelegramGroup {
var options: ChatDeleteMessagesOptions = []
options.insert(.locally)
if !message.flags.contains(.Incoming) {
options.insert(.globally)
} else {
switch group.role {
case .creator, .admin:
options.insert(.globally)
case .member:
break
}
}
optionsMap[message.id] = options
} else if let _ = peer as? TelegramUser {
var options: ChatDeleteMessagesOptions = []
options.insert(.locally)
if !message.flags.contains(.Incoming) {
options.insert(.globally)
}
optionsMap[message.id] = options
} else if let _ = peer as? TelegramSecretChat {
var options: ChatDeleteMessagesOptions = []
options.insert(.globally)
optionsMap[message.id] = options
} else {
assertionFailure()
}
} else {
optionsMap[id] = [.locally]
}
}
if !optionsMap.isEmpty {
var reducedOptions = optionsMap.values.first!
for value in optionsMap.values {
reducedOptions.formIntersection(value)
}
return reducedOptions
} else {
return []
}
}
}

View File

@@ -182,22 +182,22 @@ func contextQueryResultStateForChatInterfacePresentationState(_ chatPresentation
private let dataDetector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType([.link]).rawValue)
func urlPreviewStateForChatInterfacePresentationState(_ chatPresentationInterfaceState: ChatPresentationInterfaceState, account: Account, currentQuery: URL?) -> (URL?, Signal<(TelegramMediaWebpage?) -> TelegramMediaWebpage?, NoError>)? {
func urlPreviewStateForChatInterfacePresentationState(_ chatPresentationInterfaceState: ChatPresentationInterfaceState, account: Account, currentQuery: String?) -> (String?, Signal<(TelegramMediaWebpage?) -> TelegramMediaWebpage?, NoError>)? {
if let dataDetector = dataDetector {
let text = chatPresentationInterfaceState.interfaceState.composeInputState.inputText
let utf16 = text.utf16
var detectedUrl: URL?
var detectedUrl: String?
let matches = dataDetector.matches(in: text, options: [], range: NSRange(location: 0, length: utf16.count))
if let match = matches.first {
let urlText = (text as NSString).substring(with: match.range)
detectedUrl = URL(string: urlText)
detectedUrl = urlText
}
if detectedUrl != currentQuery {
if let detectedUrl = detectedUrl {
return (detectedUrl, webpagePreview(account: account, url: detectedUrl.absoluteString) |> map { value in
return (detectedUrl, webpagePreview(account: account, url: detectedUrl) |> map { value in
return { _ in return value }
})
} else {

View File

@@ -596,13 +596,13 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
let contentRect = rawContentRect.offsetBy(dx: editingOffset + 78.0 + revealOffset, dy: 0.0)
transition.updateFrame(node: strongSelf.dateNode, frame: CGRect(origin: CGPoint(x: contentRect.origin.x + contentRect.size.width - dateLayout.size.width, y: contentRect.origin.y + 2.0), size: dateLayout.size))
strongSelf.dateNode.frame = CGRect(origin: CGPoint(x: contentRect.origin.x + contentRect.size.width - dateLayout.size.width, y: contentRect.origin.y + 2.0), size: dateLayout.size)
if let statusImage = statusImage {
strongSelf.statusNode.image = statusImage
strongSelf.statusNode.isHidden = false
let statusSize = statusImage.size
transition.updateFrame(node: strongSelf.statusNode, frame: CGRect(origin: CGPoint(x: contentRect.origin.x + contentRect.size.width - dateLayout.size.width - 2.0 - statusSize.width, y: contentRect.origin.y + 5.0), size: statusSize))
strongSelf.statusNode.frame = CGRect(origin: CGPoint(x: contentRect.origin.x + contentRect.size.width - dateLayout.size.width - 2.0 - statusSize.width, y: contentRect.origin.y + 5.0), size: statusSize)
} else {
strongSelf.statusNode.image = nil
strongSelf.statusNode.isHidden = true
@@ -616,8 +616,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
let badgeBackgroundFrame = CGRect(x: contentRect.maxX - badgeBackgroundWidth, y: contentRect.maxY - currentBadgeBackgroundImage.size.height - 2.0, width: badgeBackgroundWidth, height: currentBadgeBackgroundImage.size.height)
let badgeTextFrame = CGRect(origin: CGPoint(x: badgeBackgroundFrame.midX - badgeLayout.size.width / 2.0, y: badgeBackgroundFrame.minY + 1.0), size: badgeLayout.size)
transition.updateFrame(node: strongSelf.badgeTextNode, frame: badgeTextFrame)
transition.updateFrame(node: strongSelf.badgeBackgroundNode, frame: badgeBackgroundFrame)
strongSelf.badgeTextNode.frame = badgeTextFrame
strongSelf.badgeBackgroundNode.frame = badgeBackgroundFrame
} else {
strongSelf.badgeBackgroundNode.image = nil
strongSelf.badgeBackgroundNode.isHidden = true
@@ -632,9 +632,17 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
strongSelf.mutedIconNode.isHidden = true
}
transition.updateFrame(node: strongSelf.titleNode, frame: CGRect(origin: CGPoint(x: contentRect.origin.x, y: contentRect.origin.y), size: titleLayout.size))
let contentDeltaX = contentRect.origin.x - strongSelf.titleNode.frame.minX
strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: contentRect.origin.x, y: contentRect.origin.y), size: titleLayout.size)
strongSelf.textNode.frame = CGRect(origin: CGPoint(x: contentRect.origin.x, y: contentRect.maxY - textLayout.size.height - 1.0), size: textLayout.size)
transition.updateFrame(node: strongSelf.textNode, frame: CGRect(origin: CGPoint(x: contentRect.origin.x, y: contentRect.maxY - textLayout.size.height - 1.0), size: textLayout.size))
if !contentDeltaX.isZero {
let titlePosition = strongSelf.titleNode.position
transition.animatePosition(node: strongSelf.titleNode, from: CGPoint(x: titlePosition.x - contentDeltaX, y: titlePosition.y))
let textPosition = strongSelf.textNode.position
transition.animatePosition(node: strongSelf.textNode, from: CGPoint(x: textPosition.x - contentDeltaX, y: textPosition.y))
}
let separatorInset: CGFloat
if !nextIsPinned && item.index.pinningIndex != nil {
@@ -663,7 +671,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -separatorHeight - topNegativeInset), size: CGSize(width: layout.contentSize.width, height: layout.contentSize.height + separatorHeight + topNegativeInset))
/*if crossfadeContent && animated {
if let contents = strongSelf.contentNode.contents {
if let contents = strongSelf.titleNode.contents {
let tempNode = ASDisplayNode()
tempNode.isLayerBacked = true
tempNode.contents = contents
@@ -674,9 +682,6 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
tempNode?.removeFromSupernode()
})
}
}
if updateContentNode {
strongSelf.contentNode.setNeedsDisplay()
}*/
strongSelf.setRevealOptions(peerRevealOptions)

View File

@@ -107,7 +107,7 @@ private func chatMediaInputGridEntries(view: ItemCollectionsView, recentStickers
}
if let recentStickers = recentStickers, !recentStickers.items.isEmpty {
let packInfo = StickerPackCollectionInfo(id: ItemCollectionId(namespace: Namespaces.ItemCollection.CloudRecentStickers, id: 0), accessHash: 0, title: "FREQUENTLY USED", shortName: "", hash: 0)
let packInfo = StickerPackCollectionInfo(id: ItemCollectionId(namespace: Namespaces.ItemCollection.CloudRecentStickers, id: 0), flags: [], accessHash: 0, title: "FREQUENTLY USED", shortName: "", hash: 0)
for i in 0 ..< min(20, recentStickers.items.count) {
if let item = recentStickers.items[i].contents as? RecentMediaItem, let file = item.media as? TelegramMediaFile, let mediaId = item.media.id {
let index = ItemCollectionItemIndex(index: Int32(i), id: mediaId.id)

View File

@@ -179,7 +179,7 @@ struct ChatPresentationInterfaceState: Equatable {
let canReportPeer: Bool
let chatHistoryState: ChatHistoryNodeHistoryState?
let botStartPayload: String?
let urlPreview: TelegramMediaWebpage?
let urlPreview: (String, TelegramMediaWebpage)?
init() {
self.interfaceState = ChatInterfaceState()
@@ -197,7 +197,7 @@ struct ChatPresentationInterfaceState: Equatable {
self.urlPreview = nil
}
init(interfaceState: ChatInterfaceState, peer: Peer?, inputTextPanelState: ChatTextInputPanelState, inputQueryResult: ChatPresentationInputQueryResult?, inputMode: ChatInputMode, titlePanelContexts: [ChatTitlePanelContext], keyboardButtonsMessage: Message?, pinnedMessageId: MessageId?, peerIsBlocked: Bool, canReportPeer: Bool, chatHistoryState: ChatHistoryNodeHistoryState?, botStartPayload: String?, urlPreview: TelegramMediaWebpage?) {
init(interfaceState: ChatInterfaceState, peer: Peer?, inputTextPanelState: ChatTextInputPanelState, inputQueryResult: ChatPresentationInputQueryResult?, inputMode: ChatInputMode, titlePanelContexts: [ChatTitlePanelContext], keyboardButtonsMessage: Message?, pinnedMessageId: MessageId?, peerIsBlocked: Bool, canReportPeer: Bool, chatHistoryState: ChatHistoryNodeHistoryState?, botStartPayload: String?, urlPreview: (String, TelegramMediaWebpage)?) {
self.interfaceState = interfaceState
self.peer = peer
self.inputTextPanelState = inputTextPanelState
@@ -273,7 +273,10 @@ struct ChatPresentationInterfaceState: Equatable {
}
if let lhsUrlPreview = lhs.urlPreview, let rhsUrlPreview = rhs.urlPreview {
if !lhsUrlPreview.isEqual(rhsUrlPreview) {
if lhsUrlPreview.0 != rhsUrlPreview.0 {
return false
}
if !lhsUrlPreview.1.isEqual(rhsUrlPreview.1) {
return false
}
} else if (lhs.urlPreview != nil) != (rhs.urlPreview != nil) {
@@ -331,7 +334,7 @@ struct ChatPresentationInterfaceState: Equatable {
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, peer: self.peer, inputTextPanelState: self.inputTextPanelState, inputQueryResult: self.inputQueryResult, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, peerIsBlocked: self.peerIsBlocked, canReportPeer: self.canReportPeer, chatHistoryState: chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview)
}
func updatedUrlPreview(_ urlPreview: TelegramMediaWebpage?) -> ChatPresentationInterfaceState {
func updatedUrlPreview(_ urlPreview: (String, TelegramMediaWebpage)?) -> ChatPresentationInterfaceState {
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, peer: self.peer, inputTextPanelState: self.inputTextPanelState, inputQueryResult: self.inputQueryResult, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, peerIsBlocked: self.peerIsBlocked, canReportPeer: self.canReportPeer, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: urlPreview)
}
}

View File

@@ -0,0 +1,181 @@
import Foundation
import Display
import SwiftSignalKit
import Postbox
import TelegramCore
private final class GroupsInCommonControllerArguments {
let account: Account
let openPeer: (PeerId) -> Void
init(account: Account, openPeer: @escaping (PeerId) -> Void) {
self.account = account
self.openPeer = openPeer
}
}
private enum GroupsInCommonSection: Int32 {
case peers
}
private enum GroupsInCommonEntryStableId: Hashable {
case peer(PeerId)
var hashValue: Int {
switch self {
case let .peer(peerId):
return peerId.hashValue
}
}
static func ==(lhs: GroupsInCommonEntryStableId, rhs: GroupsInCommonEntryStableId) -> Bool {
switch lhs {
case let .peer(peerId):
if case .peer(peerId) = rhs {
return true
} else {
return false
}
}
}
}
private enum GroupsInCommonEntry: ItemListNodeEntry {
case peerItem(Int32, Peer)
var section: ItemListSectionId {
switch self {
case .peerItem:
return GroupsInCommonSection.peers.rawValue
}
}
var stableId: GroupsInCommonEntryStableId {
switch self {
case let .peerItem(_, peer):
return .peer(peer.id)
}
}
static func ==(lhs: GroupsInCommonEntry, rhs: GroupsInCommonEntry) -> Bool {
switch lhs {
case let .peerItem(lhsIndex, lhsPeer):
if case let .peerItem(rhsIndex, rhsPeer) = rhs {
if lhsIndex != rhsIndex {
return false
}
if !lhsPeer.isEqual(rhsPeer) {
return false
}
return true
} else {
return false
}
}
}
static func <(lhs: GroupsInCommonEntry, rhs: GroupsInCommonEntry) -> Bool {
switch lhs {
case let .peerItem(index, _):
switch rhs {
case let .peerItem(rhsIndex, _):
return index < rhsIndex
}
}
}
func item(_ arguments: GroupsInCommonControllerArguments) -> ListViewItem {
switch self {
case let .peerItem(_, peer):
return ItemListPeerItem(account: arguments.account, peer: peer, presence: nil, text: .none, label: nil, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: nil, enabled: true, sectionId: self.section, action: {
arguments.openPeer(peer.id)
}, setPeerIdWithRevealedOptions: { _ in
}, removePeer: { _ in
})
}
}
}
private struct GroupsInCommonControllerState: Equatable {
static func ==(lhs: GroupsInCommonControllerState, rhs: GroupsInCommonControllerState) -> Bool {
return true
}
}
private func groupsInCommonControllerEntries(state: GroupsInCommonControllerState, peers: [Peer]?) -> [GroupsInCommonEntry] {
var entries: [GroupsInCommonEntry] = []
if let peers = peers {
var index: Int32 = 0
for peer in peers {
entries.append(.peerItem(index, peer))
index += 1
}
}
return entries
}
public func groupsInCommonController(account: Account, peerId: PeerId) -> ViewController {
let statePromise = ValuePromise(GroupsInCommonControllerState(), ignoreRepeated: true)
let stateValue = Atomic(value: GroupsInCommonControllerState())
let updateState: ((GroupsInCommonControllerState) -> GroupsInCommonControllerState) -> Void = { f in
statePromise.set(stateValue.modify { f($0) })
}
let actionsDisposable = DisposableSet()
let peersPromise = Promise<[Peer]?>(nil)
var pushControllerImpl: ((ViewController) -> Void)?
let arguments = GroupsInCommonControllerArguments(account: account, openPeer: { memberId in
pushControllerImpl?(ChatController(account: account, peerId: memberId))
})
let peersSignal: Signal<[Peer]?, NoError> = .single(nil) |> then(groupsInCommon(account: account, peerId: peerId) |> mapToSignal { peerIds -> Signal<[Peer], NoError> in
return account.postbox.modify { modifier -> [Peer] in
var result: [Peer] = []
for id in peerIds {
if let peer = modifier.getPeer(id) {
result.append(peer)
}
}
return result
}
}
|> map { Optional($0) })
peersPromise.set(peersSignal)
var previousPeers: [Peer]?
let signal = combineLatest(statePromise.get(), peersPromise.get())
|> deliverOnMainQueue
|> map { state, peers -> (ItemListControllerState, (ItemListNodeState<GroupsInCommonEntry>, GroupsInCommonEntry.ItemGenerationArguments)) in
var emptyStateItem: ItemListControllerEmptyStateItem?
if peers == nil {
emptyStateItem = ItemListLoadingIndicatorEmptyStateItem()
}
let previous = previousPeers
previousPeers = peers
let controllerState = ItemListControllerState(title: "Groups in Common", leftNavigationButton: nil, rightNavigationButton: nil, animateChanges: false)
let listState = ItemListNodeState(entries: groupsInCommonControllerEntries(state: state, peers: peers), style: .blocks, emptyStateItem: emptyStateItem, animateChanges: previous != nil && peers != nil && previous!.count >= peers!.count)
return (controllerState, (listState, arguments))
} |> afterDisposed {
actionsDisposable.dispose()
}
let controller = ItemListController(signal)
pushControllerImpl = { [weak controller] c in
if let controller = controller {
(controller.navigationController as? NavigationController)?.pushViewController(c)
}
}
controller.navigationItem.backBarButtonItem = UIBarButtonItem(title: "Back", style: .plain, target: nil, action: nil)
return controller
}

View File

@@ -34,7 +34,7 @@ public func transformOutgoingMessageMedia(postbox: Postbox, network: Network, me
if data.complete {
if file.mimeType.hasPrefix("image/") {
return Signal { subscriber in
if let image = UIImage(contentsOfFile: data.path), let scaledImage = generateImage(image.size.fitted(CGSize(width: 90.0, height: 90.0)), context: { size, context in
if let image = UIImage(contentsOfFile: data.path), let scaledImage = generateImage(image.size.fitted(CGSize(width: 90.0, height: 90.0)), contextGenerator: { size, context in
context.setBlendMode(.copy)
context.draw(image.cgImage!, in: CGRect(origin: CGPoint(), size: size))
}), let thumbnailData = UIImageJPEGRepresentation(scaledImage, 0.6) {

View File

@@ -9,14 +9,16 @@ private final class UserInfoControllerArguments {
let updateEditingName: (ItemListAvatarAndNameInfoItemName) -> Void
let changeNotificationMuteSettings: () -> Void
let openSharedMedia: () -> Void
let openGroupsInCommon: () -> Void
let updatePeerBlocked: (Bool) -> Void
let deleteContact: () -> Void
init(account: Account, updateEditingName: @escaping (ItemListAvatarAndNameInfoItemName) -> Void, changeNotificationMuteSettings: @escaping () -> Void, openSharedMedia: @escaping () -> Void, updatePeerBlocked: @escaping (Bool) -> Void, deleteContact: @escaping () -> Void) {
init(account: Account, updateEditingName: @escaping (ItemListAvatarAndNameInfoItemName) -> Void, changeNotificationMuteSettings: @escaping () -> Void, openSharedMedia: @escaping () -> Void, openGroupsInCommon: @escaping () -> Void, updatePeerBlocked: @escaping (Bool) -> Void, deleteContact: @escaping () -> Void) {
self.account = account
self.updateEditingName = updateEditingName
self.changeNotificationMuteSettings = changeNotificationMuteSettings
self.openSharedMedia = openSharedMedia
self.openGroupsInCommon = openGroupsInCommon
self.updatePeerBlocked = updatePeerBlocked
self.deleteContact = deleteContact
}
@@ -40,6 +42,7 @@ private enum UserInfoEntry: ItemListNodeEntry {
case sharedMedia
case notifications(settings: PeerNotificationSettings?)
case notificationSound(settings: PeerNotificationSettings?)
case groupsInCommon(Int32)
case secretEncryptionKey(SecretChatKeyFingerprint)
case block(action: DestructiveUserInfoAction)
@@ -49,7 +52,7 @@ private enum UserInfoEntry: ItemListNodeEntry {
return UserInfoSection.info.rawValue
case .sendMessage, .shareContact, .startSecretChat:
return UserInfoSection.actions.rawValue
case .sharedMedia, .notifications, .notificationSound, .secretEncryptionKey:
case .sharedMedia, .notifications, .notificationSound, .secretEncryptionKey, .groupsInCommon:
return UserInfoSection.sharedMediaAndNotifications.rawValue
case .block:
return UserInfoSection.block.rawValue
@@ -166,6 +169,12 @@ private enum UserInfoEntry: ItemListNodeEntry {
default:
return false
}
case let .groupsInCommon(count):
if case .groupsInCommon(count) = rhs {
return true
} else {
return false
}
case let .secretEncryptionKey(fingerprint):
if case .secretEncryptionKey(fingerprint) = rhs {
return true
@@ -204,10 +213,12 @@ private enum UserInfoEntry: ItemListNodeEntry {
return 1005
case .notificationSound:
return 1006
case .secretEncryptionKey:
case .groupsInCommon:
return 1007
case .block:
case .secretEncryptionKey:
return 1008
case .block:
return 1009
}
}
@@ -258,6 +269,10 @@ private enum UserInfoEntry: ItemListNodeEntry {
label = "Default"
return ItemListDisclosureItem(title: "Sound", label: label, sectionId: self.section, style: .plain, action: {
})
case let .groupsInCommon(count):
return ItemListDisclosureItem(title: "Groups in Common", label: "\(count)", sectionId: self.section, style: .plain, action: {
arguments.openGroupsInCommon()
})
case let .secretEncryptionKey(fingerprint):
return ItemListDisclosureItem(title: "Encryption Key", label: "", sectionId: self.section, style: .plain, action: {
})
@@ -360,11 +375,6 @@ private func userInfoEntries(account: Account, view: PeerView, state: UserInfoSt
}
}
var editable = true
if peer is TelegramSecretChat {
editable = false
}
if let phoneNumber = user.phone, !phoneNumber.isEmpty {
entries.append(UserInfoEntry.phoneNumber(index: 0, value: PhoneNumberWithLabel(label: "home", number: phoneNumber)))
}
@@ -384,6 +394,9 @@ private func userInfoEntries(account: Account, view: PeerView, state: UserInfoSt
entries.append(UserInfoEntry.sharedMedia)
}
entries.append(UserInfoEntry.notifications(settings: view.notificationSettings))
if let groupsInCommon = (view.cachedData as? CachedUserData)?.commonGroupCount, !isEditing {
entries.append(UserInfoEntry.groupsInCommon(groupsInCommon))
}
if let _ = peer as? TelegramSecretChat {
entries.append(UserInfoEntry.secretEncryptionKey(SecretChatKeyFingerprint(k0: 0, k1: 0, k2: 0, k3: 0)))
@@ -486,6 +499,8 @@ public func userInfoController(account: Account, peerId: PeerId) -> ViewControll
if let controller = peerSharedMediaController(account: account, peerId: peerId) {
pushControllerImpl?(controller)
}
}, openGroupsInCommon: {
pushControllerImpl?(groupsInCommonController(account: account, peerId: peerId))
}, updatePeerBlocked: { value in
updatePeerBlockedDisposable.set(requestUpdatePeerIsBlocked(account: account, peerId: peerId, isBlocked: value).start())
}, deleteContact: {