mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-04 05:26:48 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/TelegramUI
This commit is contained in:
commit
c9aa4a85da
@ -272,7 +272,7 @@ private struct ChannelAdminControllerState: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
private func stringForRight(strings: PresentationStrings, right: TelegramChatAdminRightsFlags, isGroup: Bool) -> String {
|
||||
private func stringForRight(strings: PresentationStrings, right: TelegramChatAdminRightsFlags, isGroup: Bool, defaultBannedRights: TelegramChatBannedRights?) -> String {
|
||||
if right.contains(.canChangeInfo) {
|
||||
return isGroup ? strings.Group_EditAdmin_PermissionChangeInfo : strings.Channel_EditAdmin_PermissionChangeInfo
|
||||
} else if right.contains(.canPostMessages) {
|
||||
@ -284,7 +284,15 @@ private func stringForRight(strings: PresentationStrings, right: TelegramChatAdm
|
||||
} else if right.contains(.canBanUsers) {
|
||||
return strings.Channel_EditAdmin_PermissionBanUsers
|
||||
} else if right.contains(.canInviteUsers) {
|
||||
return strings.Channel_EditAdmin_PermissionInviteUsers
|
||||
if isGroup {
|
||||
if let defaultBannedRights = defaultBannedRights, defaultBannedRights.flags.contains(.banAddMembers) {
|
||||
return strings.Channel_EditAdmin_PermissionInviteMembers
|
||||
} else {
|
||||
return strings.Channel_EditAdmin_PermissionInviteViaLink
|
||||
}
|
||||
} else {
|
||||
return strings.Channel_EditAdmin_PermissionInviteSubscribers
|
||||
}
|
||||
} else if right.contains(.canChangeInviteLink) {
|
||||
return ""
|
||||
} else if right.contains(.canPinMessages) {
|
||||
@ -408,7 +416,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
|
||||
var index = 0
|
||||
for right in rightsOrder {
|
||||
if accountUserRightsFlags.contains(right) {
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup), right, currentRightsFlags, currentRightsFlags.contains(right), !state.updating))
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, defaultBannedRights: channel.defaultBannedRights), right, currentRightsFlags, currentRightsFlags.contains(right), !state.updating))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
@ -440,7 +448,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
|
||||
} else if let initialParticipant = initialParticipant, case let .member(_, _, maybeAdminInfo, _) = initialParticipant, let adminInfo = maybeAdminInfo {
|
||||
var index = 0
|
||||
for right in rightsOrder {
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup), right, adminInfo.rights.flags, adminInfo.rights.flags.contains(right), false))
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, defaultBannedRights: channel.defaultBannedRights), right, adminInfo.rights.flags, adminInfo.rights.flags.contains(right), false))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
@ -474,7 +482,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
|
||||
var index = 0
|
||||
for right in rightsOrder {
|
||||
if accountUserRightsFlags.contains(right) {
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup), right, currentRightsFlags, currentRightsFlags.contains(right), !state.updating))
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, defaultBannedRights: group.defaultBannedRights), right, currentRightsFlags, currentRightsFlags.contains(right), !state.updating))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
|
||||
@ -769,7 +769,7 @@ public func channelVisibilityController(account: Account, peerId: PeerId, mode:
|
||||
}
|
||||
|
||||
let peersDisablingAddressNameAssignment = Promise<[Peer]?>()
|
||||
peersDisablingAddressNameAssignment.set(.single(nil) |> then(channelAddressNameAssignmentAvailability(account: account, peerId: peerId) |> mapToSignal { result -> Signal<[Peer]?, NoError> in
|
||||
peersDisablingAddressNameAssignment.set(.single(nil) |> then(channelAddressNameAssignmentAvailability(account: account, peerId: peerId.namespace == Namespaces.Peer.CloudChannel ? peerId : nil) |> mapToSignal { result -> Signal<[Peer]?, NoError> in
|
||||
if case .addressNameLimitReached = result {
|
||||
return adminedPublicChannels(account: account)
|
||||
|> map(Optional.init)
|
||||
|
||||
@ -3263,22 +3263,36 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal
|
||||
}
|
||||
|
||||
if self.chatDisplayNode.frameForInputActionButton() != nil, self.presentationInterfaceState.interfaceState.mediaRecordingMode == .audio {
|
||||
let _ = (ApplicationSpecificNotice.getChatMediaMediaRecordingTips(postbox: self.account.postbox)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] counter in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
var canSendMedia = false
|
||||
if let channel = self.presentationInterfaceState.renderedPeer?.peer as? TelegramChannel {
|
||||
if channel.hasBannedPermission(.banSendMedia) == nil {
|
||||
canSendMedia = true
|
||||
}
|
||||
var displayTip = false
|
||||
if counter == 0 {
|
||||
displayTip = true
|
||||
} else if counter < 3 && arc4random_uniform(4) == 1 {
|
||||
displayTip = true
|
||||
} else if let group = self.presentationInterfaceState.renderedPeer?.peer as? TelegramGroup {
|
||||
if !group.hasBannedPermission(.banSendMedia) {
|
||||
canSendMedia = true
|
||||
}
|
||||
if displayTip {
|
||||
let _ = ApplicationSpecificNotice.incrementChatMediaMediaRecordingTips(postbox: strongSelf.account.postbox).start()
|
||||
strongSelf.displayMediaRecordingTip()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
canSendMedia = true
|
||||
}
|
||||
if canSendMedia {
|
||||
let _ = (ApplicationSpecificNotice.getChatMediaMediaRecordingTips(postbox: self.account.postbox)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] counter in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
var displayTip = false
|
||||
if counter == 0 {
|
||||
displayTip = true
|
||||
} else if counter < 3 && arc4random_uniform(4) == 1 {
|
||||
displayTip = true
|
||||
}
|
||||
if displayTip {
|
||||
let _ = ApplicationSpecificNotice.incrementChatMediaMediaRecordingTips(postbox: strongSelf.account.postbox).start()
|
||||
strongSelf.displayMediaRecordingTip()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,7 +134,7 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
|
||||
var isCreator = false
|
||||
if let peer = entry.0.peers[entry.0.id.peerId] as? TelegramGroup, case .creator = peer.role {
|
||||
isCreator = true
|
||||
} else if let peer = entry.0.peers[entry.0.id.peerId] as? TelegramChannel, peer.flags.contains(.isCreator) {
|
||||
} else if let peer = entry.0.peers[entry.0.id.peerId] as? TelegramChannel, case .group = peer.info, peer.flags.contains(.isCreator) {
|
||||
isCreator = true
|
||||
}
|
||||
if isEmptyMedia && isCreator {
|
||||
|
||||
@ -351,7 +351,9 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie
|
||||
if let channel = chatPeer as? TelegramChannel {
|
||||
if case .broadcast = channel.info {
|
||||
canClear = false
|
||||
deleteTitle = strongSelf.presentationData.strings.Channel_LeaveChannel
|
||||
deleteTitle = strongSelf.presentationData.strings.Channel_LeaveChannel
|
||||
} else {
|
||||
deleteTitle = strongSelf.presentationData.strings.Group_LeaveGroup
|
||||
}
|
||||
if let addressName = channel.addressName, !addressName.isEmpty {
|
||||
canClear = false
|
||||
@ -360,7 +362,7 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie
|
||||
canStop = true
|
||||
deleteTitle = strongSelf.presentationData.strings.ChatList_DeleteChat
|
||||
} else if let _ = chatPeer as? TelegramSecretChat {
|
||||
deleteTitle = strongSelf.presentationData.strings.ChatList_DeleteChat
|
||||
deleteTitle = strongSelf.presentationData.strings.ChatList_DeleteSecretChat
|
||||
}
|
||||
items.append(DeleteChatPeerActionSheetItem(account: strongSelf.account, peer: mainPeer, strings: strongSelf.presentationData.strings))
|
||||
if canClear {
|
||||
@ -406,40 +408,7 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.chatListDisplayNode.chatListNode.setCurrentRemovingPeerId(peerId)
|
||||
strongSelf.chatListDisplayNode.chatListNode.updateState({ state in
|
||||
var state = state
|
||||
state.pendingRemovalPeerIds.insert(peer.peerId)
|
||||
return state
|
||||
})
|
||||
strongSelf.chatListDisplayNode.chatListNode.setCurrentRemovingPeerId(nil)
|
||||
strongSelf.present(UndoOverlayController(account: strongSelf.account, text: strongSelf.presentationData.strings.Undo_ChatDeleted, action: { shouldCommit in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if shouldCommit {
|
||||
strongSelf.chatListDisplayNode.chatListNode.setCurrentRemovingPeerId(peerId)
|
||||
let _ = removePeerChat(postbox: strongSelf.account.postbox, peerId: peerId, reportChatSpam: false).start(completed: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.chatListDisplayNode.chatListNode.updateState({ state in
|
||||
var state = state
|
||||
state.pendingRemovalPeerIds.remove(peer.peerId)
|
||||
return state
|
||||
})
|
||||
self?.chatListDisplayNode.chatListNode.setCurrentRemovingPeerId(nil)
|
||||
})
|
||||
} else {
|
||||
strongSelf.chatListDisplayNode.chatListNode.setCurrentRemovingPeerId(peerId)
|
||||
strongSelf.chatListDisplayNode.chatListNode.updateState({ state in
|
||||
var state = state
|
||||
state.pendingRemovalPeerIds.remove(peer.peerId)
|
||||
return state
|
||||
})
|
||||
self?.chatListDisplayNode.chatListNode.setCurrentRemovingPeerId(nil)
|
||||
}
|
||||
}), in: .window(.root))
|
||||
strongSelf.schedulePeerChatRemoval(peer: peer)
|
||||
}))
|
||||
|
||||
if canStop {
|
||||
@ -1081,4 +1050,59 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie
|
||||
self.present(actionSheet, in: .window(.root))
|
||||
}
|
||||
}
|
||||
|
||||
func schedulePeerChatRemoval(peer: RenderedPeer, deleteGloballyIfPossible: Bool = false) {
|
||||
guard let chatPeer = peer.peers[peer.peerId] else {
|
||||
return
|
||||
}
|
||||
let peerId = peer.peerId
|
||||
self.chatListDisplayNode.chatListNode.setCurrentRemovingPeerId(peerId)
|
||||
self.chatListDisplayNode.chatListNode.updateState({ state in
|
||||
var state = state
|
||||
state.pendingRemovalPeerIds.insert(peer.peerId)
|
||||
return state
|
||||
})
|
||||
self.chatListDisplayNode.chatListNode.setCurrentRemovingPeerId(nil)
|
||||
let statusText: String
|
||||
if let channel = chatPeer as? TelegramChannel {
|
||||
if case .broadcast = channel.info {
|
||||
statusText = self.presentationData.strings.Undo_LeftChannel
|
||||
} else {
|
||||
statusText = self.presentationData.strings.Undo_LeftGroup
|
||||
}
|
||||
} else if let _ = chatPeer as? TelegramGroup {
|
||||
statusText = self.presentationData.strings.Undo_LeftGroup
|
||||
} else if let _ = chatPeer as? TelegramSecretChat {
|
||||
statusText = self.presentationData.strings.Undo_SecretChatDeleted
|
||||
} else {
|
||||
statusText = self.presentationData.strings.Undo_ChatDeleted
|
||||
}
|
||||
self.present(UndoOverlayController(account: self.account, text: statusText, action: { [weak self] shouldCommit in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if shouldCommit {
|
||||
strongSelf.chatListDisplayNode.chatListNode.setCurrentRemovingPeerId(peerId)
|
||||
let _ = removePeerChat(postbox: strongSelf.account.postbox, peerId: peerId, reportChatSpam: false, deleteGloballyIfPossible: deleteGloballyIfPossible).start(completed: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.chatListDisplayNode.chatListNode.updateState({ state in
|
||||
var state = state
|
||||
state.pendingRemovalPeerIds.remove(peer.peerId)
|
||||
return state
|
||||
})
|
||||
self?.chatListDisplayNode.chatListNode.setCurrentRemovingPeerId(nil)
|
||||
})
|
||||
} else {
|
||||
strongSelf.chatListDisplayNode.chatListNode.setCurrentRemovingPeerId(peerId)
|
||||
strongSelf.chatListDisplayNode.chatListNode.updateState({ state in
|
||||
var state = state
|
||||
state.pendingRemovalPeerIds.remove(peer.peerId)
|
||||
return state
|
||||
})
|
||||
self?.chatListDisplayNode.chatListNode.setCurrentRemovingPeerId(nil)
|
||||
}
|
||||
}), in: .window(.root))
|
||||
}
|
||||
}
|
||||
|
||||
@ -990,11 +990,11 @@ final class ChatListNode: ListView {
|
||||
strongSelf.didSetReady = true
|
||||
strongSelf._ready.set(true)
|
||||
}
|
||||
|
||||
|
||||
let isEmpty = transition.chatListView.filteredEntries.isEmpty
|
||||
if strongSelf.wasEmpty != isEmpty {
|
||||
strongSelf.wasEmpty = isEmpty
|
||||
strongSelf.isEmptyUpdated?(isEmpty)
|
||||
strongSelf.isEmptyUpdated?(isEmpty)
|
||||
}
|
||||
|
||||
completion()
|
||||
|
||||
@ -214,10 +214,12 @@ func chatListNodeEntriesForView(_ view: ChatListView, state: ChatListNodeState,
|
||||
continue loop
|
||||
}
|
||||
var updatedMessage = message
|
||||
var updatedCombinedReadState = combinedReadState
|
||||
if state.pendingClearHistoryPeerIds.contains(index.messageIndex.id.peerId) {
|
||||
updatedMessage = nil
|
||||
updatedCombinedReadState = nil
|
||||
}
|
||||
result.append(.PeerEntry(index: offsetPinnedIndex(index, offset: pinnedIndexOffset), presentationData: state.presentationData, message: updatedMessage, readState: combinedReadState, notificationSettings: notificationSettings, embeddedInterfaceState: embeddedState, peer: peer, summaryInfo: summaryInfo, editing: state.editing, hasActiveRevealControls: index.messageIndex.id.peerId == state.peerIdWithRevealedOptions, selected: state.selectedPeerIds.contains(index.messageIndex.id.peerId), inputActivities: state.peerInputActivities?.activities[index.messageIndex.id.peerId], isAd: false))
|
||||
result.append(.PeerEntry(index: offsetPinnedIndex(index, offset: pinnedIndexOffset), presentationData: state.presentationData, message: updatedMessage, readState: updatedCombinedReadState, notificationSettings: notificationSettings, embeddedInterfaceState: embeddedState, peer: peer, summaryInfo: summaryInfo, editing: state.editing, hasActiveRevealControls: index.messageIndex.id.peerId == state.peerIdWithRevealedOptions, selected: state.selectedPeerIds.contains(index.messageIndex.id.peerId), inputActivities: state.peerInputActivities?.activities[index.messageIndex.id.peerId], isAd: false))
|
||||
case let .HoleEntry(hole):
|
||||
result.append(.HoleEntry(hole, theme: state.presentationData.theme))
|
||||
case let .GroupReferenceEntry(groupId, index, message, topPeers, counters):
|
||||
@ -246,10 +248,12 @@ func chatListNodeEntriesForView(_ view: ChatListView, state: ChatListNodeState,
|
||||
}
|
||||
}
|
||||
}
|
||||
// if result.count >= 2, case .SearchEntry = result[result.count - 1], case .HoleEntry = result[result.count - 2] {
|
||||
// return []
|
||||
// } else
|
||||
if result.count == 1, case .HoleEntry = result[0] {
|
||||
|
||||
// if result.count == 1, case .HoleEntry = result[0] {
|
||||
|
||||
if result.count >= 1, case .HoleEntry = result[result.count - 1] {
|
||||
return []
|
||||
} else if result.count == 1, case .HoleEntry = result[0] {
|
||||
return []
|
||||
}
|
||||
return result
|
||||
|
||||
@ -18,6 +18,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
private var swipeToReplyFeedback: HapticFeedback?
|
||||
|
||||
private var selectionNode: ChatMessageSelectionNode?
|
||||
private var deliveryFailedNode: ChatMessageDeliveryFailedNode?
|
||||
private var shareButtonNode: HighlightableButtonNode?
|
||||
|
||||
var telegramFile: TelegramMediaFile?
|
||||
@ -154,7 +155,9 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
}
|
||||
|
||||
var needShareButton = false
|
||||
if item.message.id.peerId == item.account.peerId {
|
||||
if item.message.flags.contains(.Failed) {
|
||||
needShareButton = false
|
||||
} else if item.message.id.peerId == item.account.peerId {
|
||||
for attribute in item.content.firstMessage.attributes {
|
||||
if let _ = attribute as? SourceReferenceMessageAttribute {
|
||||
needShareButton = true
|
||||
@ -197,11 +200,16 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
layoutInsets.top += layoutConstants.timestampHeaderHeight
|
||||
}
|
||||
|
||||
var deliveryFailedInset: CGFloat = 0.0
|
||||
if item.content.firstMessage.flags.contains(.Failed) {
|
||||
deliveryFailedInset += 24.0
|
||||
}
|
||||
|
||||
let displayLeftInset = params.leftInset + layoutConstants.bubble.edgeInset + avatarInset
|
||||
|
||||
let innerImageInset: CGFloat = 10.0
|
||||
let innerImageSize = CGSize(width: imageSize.width + innerImageInset * 2.0, height: imageSize.height + innerImageInset * 2.0)
|
||||
let imageFrame = CGRect(origin: CGPoint(x: 0.0 + (incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + avatarInset + layoutConstants.bubble.contentInsets.left) : (params.width - params.rightInset - innerImageSize.width - layoutConstants.bubble.edgeInset - layoutConstants.bubble.contentInsets.left)), y: -innerImageInset), size: innerImageSize)
|
||||
let imageFrame = CGRect(origin: CGPoint(x: 0.0 + (incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + avatarInset + layoutConstants.bubble.contentInsets.left) : (params.width - params.rightInset - innerImageSize.width - layoutConstants.bubble.edgeInset - layoutConstants.bubble.contentInsets.left - deliveryFailedInset)), y: -innerImageInset), size: innerImageSize)
|
||||
|
||||
let arguments = TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets(top: innerImageInset, left: innerImageInset, bottom: innerImageInset, right: innerImageInset))
|
||||
|
||||
@ -330,10 +338,17 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
|
||||
return (ListViewItemNodeLayout(contentSize: layoutSize, insets: layoutInsets), { [weak self] animation, _ in
|
||||
if let strongSelf = self {
|
||||
var transition: ContainedViewLayoutTransition = .immediate
|
||||
if case let .System(duration) = animation {
|
||||
transition = .animated(duration: duration, curve: .spring)
|
||||
}
|
||||
|
||||
let updatedImageFrame = imageFrame.offsetBy(dx: 0.0, dy: floor((contentHeight - imageSize.height) / 2.0))
|
||||
|
||||
strongSelf.imageNode.frame = updatedImageFrame
|
||||
strongSelf.progressNode?.position = strongSelf.imageNode.position
|
||||
transition.updateFrame(node: strongSelf.imageNode, frame: updatedImageFrame)
|
||||
if let progressNode = strongSelf.progressNode {
|
||||
transition.updatePosition(node: progressNode, position: strongSelf.imageNode.position)
|
||||
}
|
||||
imageApply()
|
||||
|
||||
if let updatedShareButtonNode = updatedShareButtonNode {
|
||||
@ -354,11 +369,11 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
}
|
||||
|
||||
if let shareButtonNode = strongSelf.shareButtonNode {
|
||||
shareButtonNode.frame = CGRect(origin: CGPoint(x: updatedImageFrame.maxX + 8.0, y: updatedImageFrame.maxY - 30.0 - 10.0), size: CGSize(width: 29.0, height: 29.0))
|
||||
transition.updateFrame(node: shareButtonNode, frame: CGRect(origin: CGPoint(x: updatedImageFrame.maxX + 8.0, y: updatedImageFrame.maxY - 30.0 - 10.0), size: CGSize(width: 29.0, height: 29.0)))
|
||||
}
|
||||
|
||||
dateAndStatusApply(false)
|
||||
strongSelf.dateAndStatusNode.frame = CGRect(origin: CGPoint(x: max(displayLeftInset, updatedImageFrame.maxX - dateAndStatusSize.width - 4.0), y: updatedImageFrame.maxY - dateAndStatusSize.height - 16.0), size: dateAndStatusSize)
|
||||
transition.updateFrame(node: strongSelf.dateAndStatusNode, frame: CGRect(origin: CGPoint(x: max(displayLeftInset, updatedImageFrame.maxX - dateAndStatusSize.width - 4.0), y: updatedImageFrame.maxY - dateAndStatusSize.height - 16.0), size: dateAndStatusSize))
|
||||
|
||||
if let updatedReplyBackgroundNode = updatedReplyBackgroundNode {
|
||||
if strongSelf.replyBackgroundNode == nil {
|
||||
@ -410,6 +425,37 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
strongSelf.replyInfoNode = nil
|
||||
}
|
||||
|
||||
if item.content.firstMessage.flags.contains(.Failed) {
|
||||
let deliveryFailedNode: ChatMessageDeliveryFailedNode
|
||||
var isAppearing = false
|
||||
if let current = strongSelf.deliveryFailedNode {
|
||||
deliveryFailedNode = current
|
||||
} else {
|
||||
isAppearing = true
|
||||
deliveryFailedNode = ChatMessageDeliveryFailedNode(tapped: {
|
||||
if let item = self?.item {
|
||||
item.controllerInteraction.requestRedeliveryOfFailedMessages(item.content.firstMessage.id)
|
||||
}
|
||||
})
|
||||
strongSelf.deliveryFailedNode = deliveryFailedNode
|
||||
strongSelf.addSubnode(deliveryFailedNode)
|
||||
}
|
||||
let deliveryFailedSize = deliveryFailedNode.updateLayout(theme: item.presentationData.theme.theme)
|
||||
let deliveryFailedFrame = CGRect(origin: CGPoint(x: imageFrame.maxX + deliveryFailedInset - deliveryFailedSize.width, y: imageFrame.maxY - deliveryFailedSize.height - innerImageInset), size: deliveryFailedSize)
|
||||
if isAppearing {
|
||||
deliveryFailedNode.frame = deliveryFailedFrame
|
||||
transition.animatePositionAdditive(node: deliveryFailedNode, offset: CGPoint(x: deliveryFailedInset, y: 0.0))
|
||||
} else {
|
||||
transition.updateFrame(node: deliveryFailedNode, frame: deliveryFailedFrame)
|
||||
}
|
||||
} else if let deliveryFailedNode = strongSelf.deliveryFailedNode {
|
||||
strongSelf.deliveryFailedNode = nil
|
||||
transition.updateAlpha(node: deliveryFailedNode, alpha: 0.0)
|
||||
transition.updateFrame(node: deliveryFailedNode, frame: deliveryFailedNode.frame.offsetBy(dx: 24.0, dy: 0.0), completion: { [weak deliveryFailedNode] _ in
|
||||
deliveryFailedNode?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
|
||||
if let actionButtonsSizeAndApply = actionButtonsSizeAndApply {
|
||||
var animated = false
|
||||
if let _ = strongSelf.actionButtonsNode {
|
||||
|
||||
@ -51,6 +51,8 @@ private final class DeleteChatPeerActionSheetItemNode: ActionSheetItemNode {
|
||||
let text: (String, [(Int, NSRange)])
|
||||
if peer is TelegramGroup || peer is TelegramChannel {
|
||||
text = strings.ChatList_LeaveGroupConfirmation(peer.displayTitle)
|
||||
} else if peer is TelegramSecretChat {
|
||||
text = strings.ChatList_DeleteSecretChatConfirmation(peer.displayTitle)
|
||||
} else {
|
||||
text = strings.ChatList_DeleteChatConfirmation(peer.displayTitle)
|
||||
}
|
||||
|
||||
@ -675,7 +675,6 @@ private func canRemoveParticipant(account: Account, channel: TelegramChannel, pa
|
||||
private func groupInfoEntries(account: Account, presentationData: PresentationData, view: PeerView, channelMembers: [RenderedChannelParticipant], globalNotificationSettings: GlobalNotificationSettings, state: GroupInfoState) -> [GroupInfoEntry] {
|
||||
var entries: [GroupInfoEntry] = []
|
||||
|
||||
var highlightAdmins = false
|
||||
var canEditGroupInfo = false
|
||||
var canEditMembers = false
|
||||
var canAddMembers = false
|
||||
@ -685,7 +684,6 @@ private func groupInfoEntries(account: Account, presentationData: PresentationDa
|
||||
if case .creator = group.role {
|
||||
isCreator = true
|
||||
}
|
||||
highlightAdmins = true
|
||||
switch group.role {
|
||||
case .admin, .creator:
|
||||
canEditGroupInfo = true
|
||||
@ -701,7 +699,6 @@ private func groupInfoEntries(account: Account, presentationData: PresentationDa
|
||||
canAddMembers = true
|
||||
}
|
||||
} else if let channel = view.peers[view.peerId] as? TelegramChannel {
|
||||
highlightAdmins = true
|
||||
isPublic = channel.username != nil
|
||||
isCreator = channel.flags.contains(.isCreator)
|
||||
if channel.hasPermission(.changeInfo) {
|
||||
@ -841,7 +838,7 @@ private func groupInfoEntries(account: Account, presentationData: PresentationDa
|
||||
entries.append(GroupInfoEntry.addMember(presentationData.theme, presentationData.strings.GroupInfo_AddParticipant, editing: state.editingState != nil && canRemoveAnyMember))
|
||||
}
|
||||
|
||||
if let cachedGroupData = view.cachedData as? CachedGroupData, let participants = cachedGroupData.participants {
|
||||
if let group = view.peers[view.peerId] as? TelegramGroup, let cachedGroupData = view.cachedData as? CachedGroupData, let participants = cachedGroupData.participants {
|
||||
var updatedParticipants = participants.participants
|
||||
let existingParticipantIds = Set(updatedParticipants.map { $0.peerId })
|
||||
|
||||
@ -918,17 +915,51 @@ private func groupInfoEntries(account: Account, presentationData: PresentationDa
|
||||
for i in 0 ..< sortedParticipants.count {
|
||||
if let peer = peers[sortedParticipants[i].peerId] {
|
||||
let memberStatus: GroupInfoMemberStatus
|
||||
if highlightAdmins {
|
||||
switch sortedParticipants[i] {
|
||||
case .admin, .creator:
|
||||
memberStatus = .admin
|
||||
case .member:
|
||||
memberStatus = .member
|
||||
}
|
||||
} else {
|
||||
memberStatus = .member
|
||||
let participant: ChannelParticipant
|
||||
switch sortedParticipants[i] {
|
||||
case .creator:
|
||||
participant = .creator(id: sortedParticipants[i].peerId)
|
||||
memberStatus = .admin
|
||||
case .admin:
|
||||
participant = .member(id: sortedParticipants[i].peerId, invitedAt: 0, adminInfo: ChannelParticipantAdminInfo(rights: TelegramChatAdminRights(flags: .groupSpecific), promotedBy: account.peerId, canBeEditedByAccountPeer: true), banInfo: nil)
|
||||
memberStatus = .admin
|
||||
case .member:
|
||||
participant = .member(id: sortedParticipants[i].peerId, invitedAt: 0, adminInfo: nil, banInfo: nil)
|
||||
memberStatus = .member
|
||||
}
|
||||
entries.append(GroupInfoEntry.member(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, index: i, peerId: peer.id, peer: peer, participant: nil, presence: peerPresences[peer.id], memberStatus: memberStatus, editing: ItemListPeerItemEditing(editable: canRemoveParticipant(account: account, isAdmin: canEditMembers, participantId: peer.id, invitedBy: sortedParticipants[i].invitedBy), editing: state.editingState != nil && canRemoveAnyMember, revealed: state.peerIdWithRevealedOptions == peer.id), revealActions: [ParticipantRevealAction(type: .destructive, title: presentationData.strings.Common_Delete, action: .remove)], enabled: !disabledPeerIds.contains(peer.id)))
|
||||
|
||||
var canPromote: Bool
|
||||
var canRestrict: Bool
|
||||
if sortedParticipants[i].peerId == account.peerId {
|
||||
canPromote = false
|
||||
canRestrict = false
|
||||
} else {
|
||||
switch sortedParticipants[i] {
|
||||
case .creator:
|
||||
canPromote = false
|
||||
canRestrict = false
|
||||
case .admin, .member:
|
||||
switch group.role {
|
||||
case .creator:
|
||||
canPromote = true
|
||||
canRestrict = true
|
||||
default:
|
||||
canPromote = false
|
||||
canRestrict = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var peerActions: [ParticipantRevealAction] = []
|
||||
if canPromote {
|
||||
peerActions.append(ParticipantRevealAction(type: .neutral, title: presentationData.strings.GroupInfo_ActionPromote, action: .promote))
|
||||
}
|
||||
if canRestrict {
|
||||
peerActions.append(ParticipantRevealAction(type: .warning, title: presentationData.strings.GroupInfo_ActionRestrict, action: .restrict))
|
||||
peerActions.append(ParticipantRevealAction(type: .destructive, title: presentationData.strings.Common_Delete, action: .remove))
|
||||
}
|
||||
|
||||
entries.append(GroupInfoEntry.member(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, index: i, peerId: peer.id, peer: peer, participant: RenderedChannelParticipant(participant: participant, peer: peer), presence: peerPresences[peer.id], memberStatus: memberStatus, editing: ItemListPeerItemEditing(editable: canRemoveParticipant(account: account, isAdmin: canEditMembers, participantId: peer.id, invitedBy: sortedParticipants[i].invitedBy), editing: state.editingState != nil && canRemoveAnyMember, revealed: state.peerIdWithRevealedOptions == peer.id), revealActions: peerActions, enabled: !disabledPeerIds.contains(peer.id)))
|
||||
}
|
||||
}
|
||||
} else if let channel = view.peers[view.peerId] as? TelegramChannel, let cachedChannelData = view.cachedData as? CachedChannelData, let memberCount = cachedChannelData.participantsSummary.memberCount {
|
||||
@ -992,19 +1023,15 @@ private func groupInfoEntries(account: Account, presentationData: PresentationDa
|
||||
for i in 0 ..< sortedParticipants.count {
|
||||
let participant = sortedParticipants[i]
|
||||
let memberStatus: GroupInfoMemberStatus
|
||||
if highlightAdmins {
|
||||
switch participant.participant {
|
||||
case .creator:
|
||||
switch participant.participant {
|
||||
case .creator:
|
||||
memberStatus = .admin
|
||||
case let .member(_, _, adminInfo, _):
|
||||
if adminInfo != nil {
|
||||
memberStatus = .admin
|
||||
case let .member(_, _, adminInfo, _):
|
||||
if adminInfo != nil {
|
||||
memberStatus = .admin
|
||||
} else {
|
||||
memberStatus = .member
|
||||
}
|
||||
}
|
||||
} else {
|
||||
memberStatus = .member
|
||||
} else {
|
||||
memberStatus = .member
|
||||
}
|
||||
}
|
||||
|
||||
var canPromote: Bool
|
||||
@ -1132,8 +1159,8 @@ public func groupInfoController(account: Account, peerId originalPeerId: PeerId,
|
||||
|
||||
var pushControllerImpl: ((ViewController) -> Void)?
|
||||
var presentControllerImpl: ((ViewController, Any?) -> Void)?
|
||||
var popToRootImpl: (() -> Void)?
|
||||
var endEditingImpl: (() -> Void)?
|
||||
var removePeerChatImpl: ((Peer, Bool) -> Void)?
|
||||
|
||||
let actionsDisposable = DisposableSet()
|
||||
|
||||
@ -1419,8 +1446,11 @@ public func groupInfoController(account: Account, peerId originalPeerId: PeerId,
|
||||
|
||||
var canCreateInviteLink = false
|
||||
if let group = groupPeer as? TelegramGroup {
|
||||
if case .creator = group.role {
|
||||
canCreateInviteLink = true
|
||||
switch group.role {
|
||||
case .creator, .admin:
|
||||
canCreateInviteLink = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
} else if let channel = groupPeer as? TelegramChannel {
|
||||
if channel.hasPermission(.manageInviteLink) {
|
||||
@ -1657,7 +1687,9 @@ public func groupInfoController(account: Account, peerId originalPeerId: PeerId,
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { peerView in
|
||||
presentControllerImpl?(channelAdminController(account: account, peerId: peerView.peerId, adminId: participant.peer.id, initialParticipant: participant.participant, updated: { _ in
|
||||
}, upgradedToSupergroup: { _, f in f() }), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
}, upgradedToSupergroup: { upgradedPeerId, f in
|
||||
upgradedToSupergroupImpl?(upgradedPeerId, f)
|
||||
}), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
})
|
||||
}, restrictPeer: { participant in
|
||||
let _ = (peerView.get()
|
||||
@ -1744,17 +1776,14 @@ public func groupInfoController(account: Account, peerId originalPeerId: PeerId,
|
||||
items.append(ActionSheetTextItem(title: presentationData.strings.ChannelInfo_DeleteGroupConfirmation))
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.ChannelInfo_DeleteGroup, color: .destructive, action: {
|
||||
dismissAction()
|
||||
let _ = (removePeerChat(postbox: account.postbox, peerId: peerView.peerId, reportChatSpam: false, deleteGloballyIfPossible: true)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
popToRootImpl?()
|
||||
})
|
||||
removePeerChatImpl?(channel, true)
|
||||
}))
|
||||
controller.setItemGroups([
|
||||
ActionSheetItemGroup(items: items),
|
||||
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
|
||||
])
|
||||
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
} else {
|
||||
} else if let peer = peerView.peers[peerView.peerId] {
|
||||
let controller = ActionSheetController(presentationTheme: presentationData.theme)
|
||||
let dismissAction: () -> Void = { [weak controller] in
|
||||
controller?.dismissAnimated()
|
||||
@ -1766,10 +1795,7 @@ public func groupInfoController(account: Account, peerId originalPeerId: PeerId,
|
||||
}
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.Group_LeaveGroup, color: .destructive, action: {
|
||||
dismissAction()
|
||||
let _ = (removePeerChat(postbox: account.postbox, peerId: peerView.peerId, reportChatSpam: false)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
popToRootImpl?()
|
||||
})
|
||||
removePeerChatImpl?(peer, false)
|
||||
}))
|
||||
controller.setItemGroups([
|
||||
ActionSheetItemGroup(items: items),
|
||||
@ -2048,8 +2074,20 @@ public func groupInfoController(account: Account, peerId originalPeerId: PeerId,
|
||||
navigationController.setViewControllers(viewControllers, animated: false)
|
||||
})
|
||||
}
|
||||
popToRootImpl = { [weak controller] in
|
||||
(controller?.navigationController as? NavigationController)?.popToRoot(animated: true)
|
||||
removePeerChatImpl = { [weak controller] peer, deleteGloballyIfPossible in
|
||||
guard let controller = controller, let navigationController = controller.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
guard let tabController = navigationController.viewControllers.first as? TabBarController else {
|
||||
return
|
||||
}
|
||||
for childController in tabController.controllers {
|
||||
if let chatListController = childController as? ChatListController {
|
||||
navigationController.popToRoot(animated: true)
|
||||
chatListController.schedulePeerChatRemoval(peer: RenderedPeer(peer: peer), deleteGloballyIfPossible: deleteGloballyIfPossible)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
displayCopyContextMenuImpl = { [weak controller] text, tag in
|
||||
if let strongController = controller {
|
||||
|
||||
@ -119,7 +119,7 @@ func legacyInstantVideoController(theme: PresentationTheme, panelFrame: CGRect,
|
||||
var previewRepresentations: [TelegramMediaImageRepresentation] = []
|
||||
if let previewImage = previewImage {
|
||||
let resource = LocalFileMediaResource(fileId: arc4random64())
|
||||
let thumbnailSize = finalDimensions.aspectFitted(CGSize(width: 90.0, height: 90.0))
|
||||
let thumbnailSize = finalDimensions.aspectFitted(CGSize(width: 320.0, height: 320.0))
|
||||
let thumbnailImage = TGScaleImageToPixelSize(previewImage, thumbnailSize)!
|
||||
if let thumbnailData = UIImageJPEGRepresentation(thumbnailImage, 0.4) {
|
||||
account.postbox.mediaBox.storeResourceData(resource.id, data: thumbnailData)
|
||||
|
||||
@ -212,7 +212,7 @@ func legacyEnqueueGifMessage(account: Account, data: Data) -> Signal<EnqueueMess
|
||||
let dimensions = previewImage.size
|
||||
var previewRepresentations: [TelegramMediaImageRepresentation] = []
|
||||
|
||||
let thumbnailSize = dimensions.aspectFitted(CGSize(width: 90.0, height: 90.0))
|
||||
let thumbnailSize = dimensions.aspectFitted(CGSize(width: 320.0, height: 320.0))
|
||||
let thumbnailImage = TGScaleImageToPixelSize(previewImage, thumbnailSize)!
|
||||
if let thumbnailData = UIImageJPEGRepresentation(thumbnailImage, 0.4) {
|
||||
let resource = LocalFileMediaResource(fileId: arc4random64())
|
||||
@ -260,7 +260,7 @@ func legacyAssetPickerEnqueueMessages(account: Account, signals: [Any]) -> Signa
|
||||
var representations: [TelegramMediaImageRepresentation] = []
|
||||
if let thumbnail = thumbnail {
|
||||
let resource = LocalFileMediaResource(fileId: arc4random64())
|
||||
let thumbnailSize = thumbnail.size.aspectFitted(CGSize(width: 90.0, height: 90.0))
|
||||
let thumbnailSize = thumbnail.size.aspectFitted(CGSize(width: 320.0, height: 320.0))
|
||||
let thumbnailImage = TGScaleImageToPixelSize(thumbnail, thumbnailSize)!
|
||||
if let thumbnailData = UIImageJPEGRepresentation(thumbnailImage, 0.4) {
|
||||
account.postbox.mediaBox.storeResourceData(resource.id, data: thumbnailData)
|
||||
@ -366,7 +366,7 @@ func legacyAssetPickerEnqueueMessages(account: Account, signals: [Any]) -> Signa
|
||||
var previewRepresentations: [TelegramMediaImageRepresentation] = []
|
||||
if let thumbnail = thumbnail {
|
||||
let resource = LocalFileMediaResource(fileId: arc4random64())
|
||||
let thumbnailSize = finalDimensions.aspectFitted(CGSize(width: 90.0, height: 90.0))
|
||||
let thumbnailSize = finalDimensions.aspectFitted(CGSize(width: 320.0, height: 320.0))
|
||||
let thumbnailImage = TGScaleImageToPixelSize(thumbnail, thumbnailSize)!
|
||||
if let thumbnailData = UIImageJPEGRepresentation(thumbnailImage, 0.4) {
|
||||
account.postbox.mediaBox.storeResourceData(resource.id, data: thumbnailData)
|
||||
|
||||
@ -194,40 +194,37 @@ func openResolvedUrl(_ resolvedUrl: ResolvedUrl, account: Account, context: Open
|
||||
}
|
||||
}
|
||||
case let .wallpaper(parameter):
|
||||
// let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
||||
// var controller: OverlayStatusController?
|
||||
//
|
||||
// let wallpaperController = WallpaperListPreviewController(account: account, source: .wallpaper(wallpaper))
|
||||
//
|
||||
//
|
||||
// let signal: Signal<TelegramWallpaper, GetWallpaperError>
|
||||
// switch parameter {
|
||||
// case let .slug(slug):
|
||||
// signal = getWallpaper(account: account, slug: slug)
|
||||
// controller = OverlayStatusController(theme: presentationData.theme, strings: presentationData.strings, type: .loading(cancelled: nil))
|
||||
// present(controller!, nil)
|
||||
// case let .color(color):
|
||||
// signal = .single(.color(Int32(color.rgb)))
|
||||
// }
|
||||
//
|
||||
// let _ = (signal
|
||||
// |> deliverOnMainQueue).start(next: { [weak controller] wallpaper in
|
||||
// controller?.dismiss()
|
||||
// let wallpaperController = WallpaperListPreviewController(account: account, source: .wallpaper(wallpaper))
|
||||
// present(wallpaperController, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
// }, error: { [weak controller] error in
|
||||
// controller?.dismiss()
|
||||
//
|
||||
//// let text: String
|
||||
//// switch error {
|
||||
//// case .limitExceeded:
|
||||
//// text = presentationData.strings.Login_CodeFloodError
|
||||
//// case .generic:
|
||||
//// text = presentationData.strings.Login_UnknownError
|
||||
//// }
|
||||
//// let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
||||
//// present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||
// })
|
||||
let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
||||
var controller: OverlayStatusController?
|
||||
|
||||
let signal: Signal<TelegramWallpaper, GetWallpaperError>
|
||||
switch parameter {
|
||||
case let .slug(slug):
|
||||
signal = getWallpaper(account: account, slug: slug)
|
||||
controller = OverlayStatusController(theme: presentationData.theme, strings: presentationData.strings, type: .loading(cancelled: nil))
|
||||
present(controller!, nil)
|
||||
case let .color(color):
|
||||
signal = .single(.color(Int32(color.rgb)))
|
||||
}
|
||||
|
||||
let _ = (signal
|
||||
|> deliverOnMainQueue).start(next: { [weak controller] wallpaper in
|
||||
controller?.dismiss()
|
||||
let wallpaperController = WallpaperListPreviewController(account: account, source: .wallpaper(wallpaper))
|
||||
present(wallpaperController, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
}, error: { [weak controller] error in
|
||||
controller?.dismiss()
|
||||
|
||||
// let text: String
|
||||
// switch error {
|
||||
// case .limitExceeded:
|
||||
// text = presentationData.strings.Login_CodeFloodError
|
||||
// case .generic:
|
||||
// text = presentationData.strings.Login_UnknownError
|
||||
// }
|
||||
// let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
||||
// present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||
})
|
||||
dismissInput()
|
||||
}
|
||||
}
|
||||
|
||||
@ -284,77 +284,76 @@ private func chatMessageImageFileThumbnailDatas(account: Account, fileReference:
|
||||
}
|
||||
|
||||
private func chatMessageVideoDatas(postbox: Postbox, fileReference: FileMediaReference, thumbnailSize: Bool = false, onlyFullSize: Bool = false) -> Signal<(Data?, (Data, String)?, Bool), NoError> {
|
||||
if let smallestRepresentation = smallestImageRepresentation(fileReference.media.previewRepresentations) {
|
||||
let thumbnailResource = smallestRepresentation.resource
|
||||
let fullSizeResource = fileReference.media.resource
|
||||
|
||||
let maybeFullSize = postbox.mediaBox.cachedResourceRepresentation(fullSizeResource, representation: thumbnailSize ? CachedScaledVideoFirstFrameRepresentation(size: CGSize(width: 160.0, height: 160.0)) : CachedVideoFirstFrameRepresentation(), complete: false, fetch: false)
|
||||
let fetchedFullSize = postbox.mediaBox.cachedResourceRepresentation(fullSizeResource, representation: thumbnailSize ? CachedScaledVideoFirstFrameRepresentation(size: CGSize(width: 160.0, height: 160.0)) : CachedVideoFirstFrameRepresentation(), complete: false, fetch: true)
|
||||
|
||||
let signal = maybeFullSize
|
||||
|> take(1)
|
||||
|> mapToSignal { maybeData -> Signal<(Data?, (Data, String)?, Bool), NoError> in
|
||||
if maybeData.complete {
|
||||
let loadedData: Data? = try? Data(contentsOf: URL(fileURLWithPath: maybeData.path), options: [])
|
||||
|
||||
return .single((nil, loadedData == nil ? nil : (loadedData!, maybeData.path), true))
|
||||
} else {
|
||||
let fetchedThumbnail = fetchedMediaResource(postbox: postbox, reference: fileReference.resourceReference(thumbnailResource), statsCategory: .video)
|
||||
|
||||
let thumbnail: Signal<Data?, NoError>
|
||||
if onlyFullSize {
|
||||
thumbnail = .single(nil)
|
||||
} else {
|
||||
thumbnail = Signal { subscriber in
|
||||
let fetchedDisposable = fetchedThumbnail.start()
|
||||
let thumbnailDisposable = postbox.mediaBox.resourceData(thumbnailResource).start(next: { next in
|
||||
subscriber.putNext(next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []))
|
||||
}, error: subscriber.putError, completed: subscriber.putCompletion)
|
||||
|
||||
return ActionDisposable {
|
||||
fetchedDisposable.dispose()
|
||||
thumbnailDisposable.dispose()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let fullSizeDataAndPath = Signal<MediaResourceData, NoError> { subscriber in
|
||||
let dataDisposable = fetchedFullSize.start(next: { next in
|
||||
subscriber.putNext(next)
|
||||
}, completed: {
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
//let fetchedDisposable = fetchedPartialVideoThumbnailData(postbox: postbox, fileReference: fileReference).start()
|
||||
return ActionDisposable {
|
||||
dataDisposable.dispose()
|
||||
//fetchedDisposable.dispose()
|
||||
}
|
||||
}
|
||||
|> map { next -> ((Data, String)?, Bool) in
|
||||
let data = next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: .mappedIfSafe)
|
||||
return (data == nil ? nil : (data!, next.path), next.complete)
|
||||
}
|
||||
|
||||
return thumbnail
|
||||
|> mapToSignal { thumbnailData in
|
||||
return fullSizeDataAndPath
|
||||
|> map { (dataAndPath, complete) in
|
||||
return (thumbnailData, dataAndPath, complete)
|
||||
}
|
||||
}
|
||||
}
|
||||
} |> filter({
|
||||
let fullSizeResource = fileReference.media.resource
|
||||
|
||||
let thumbnailResource = smallestImageRepresentation(fileReference.media.previewRepresentations)?.resource
|
||||
|
||||
let maybeFullSize = postbox.mediaBox.cachedResourceRepresentation(fullSizeResource, representation: thumbnailSize ? CachedScaledVideoFirstFrameRepresentation(size: CGSize(width: 160.0, height: 160.0)) : CachedVideoFirstFrameRepresentation(), complete: false, fetch: false)
|
||||
let fetchedFullSize = postbox.mediaBox.cachedResourceRepresentation(fullSizeResource, representation: thumbnailSize ? CachedScaledVideoFirstFrameRepresentation(size: CGSize(width: 160.0, height: 160.0)) : CachedVideoFirstFrameRepresentation(), complete: false, fetch: true)
|
||||
|
||||
let signal = maybeFullSize
|
||||
|> take(1)
|
||||
|> mapToSignal { maybeData -> Signal<(Data?, (Data, String)?, Bool), NoError> in
|
||||
if maybeData.complete {
|
||||
let loadedData: Data? = try? Data(contentsOf: URL(fileURLWithPath: maybeData.path), options: [])
|
||||
|
||||
return .single((nil, loadedData == nil ? nil : (loadedData!, maybeData.path), true))
|
||||
} else {
|
||||
let thumbnail: Signal<Data?, NoError>
|
||||
if onlyFullSize {
|
||||
return $0.1 != nil || $0.2
|
||||
thumbnail = .single(nil)
|
||||
} else if let decodedThumbnailData = fileReference.media.immediateThumbnailData.flatMap(decodeTinyThumbnail) {
|
||||
thumbnail = .single(decodedThumbnailData)
|
||||
} else if let thumbnailResource = thumbnailResource {
|
||||
thumbnail = Signal { subscriber in
|
||||
let fetchedDisposable = fetchedMediaResource(postbox: postbox, reference: fileReference.resourceReference(thumbnailResource), statsCategory: .video).start()
|
||||
let thumbnailDisposable = postbox.mediaBox.resourceData(thumbnailResource).start(next: { next in
|
||||
subscriber.putNext(next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []))
|
||||
}, error: subscriber.putError, completed: subscriber.putCompletion)
|
||||
|
||||
return ActionDisposable {
|
||||
fetchedDisposable.dispose()
|
||||
thumbnailDisposable.dispose()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true//$0.0 != nil || $0.1 != nil || $0.2
|
||||
thumbnail = .single(nil)
|
||||
}
|
||||
})
|
||||
|
||||
return signal
|
||||
} else {
|
||||
return .single((nil, nil, true))
|
||||
}
|
||||
|
||||
let fullSizeDataAndPath = Signal<MediaResourceData, NoError> { subscriber in
|
||||
let dataDisposable = fetchedFullSize.start(next: { next in
|
||||
subscriber.putNext(next)
|
||||
}, completed: {
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
//let fetchedDisposable = fetchedPartialVideoThumbnailData(postbox: postbox, fileReference: fileReference).start()
|
||||
return ActionDisposable {
|
||||
dataDisposable.dispose()
|
||||
//fetchedDisposable.dispose()
|
||||
}
|
||||
}
|
||||
|> map { next -> ((Data, String)?, Bool) in
|
||||
let data = next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: .mappedIfSafe)
|
||||
return (data == nil ? nil : (data!, next.path), next.complete)
|
||||
}
|
||||
|
||||
return thumbnail
|
||||
|> mapToSignal { thumbnailData in
|
||||
return fullSizeDataAndPath
|
||||
|> map { (dataAndPath, complete) in
|
||||
return (thumbnailData, dataAndPath, complete)
|
||||
}
|
||||
}
|
||||
}
|
||||
} |> filter({
|
||||
if onlyFullSize {
|
||||
return $0.1 != nil || $0.2
|
||||
} else {
|
||||
return true//$0.0 != nil || $0.1 != nil || $0.2
|
||||
}
|
||||
})
|
||||
|
||||
return signal
|
||||
}
|
||||
|
||||
private enum Corner: Hashable {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -42,7 +42,7 @@ public func transformOutgoingMessageMedia(postbox: Postbox, network: Network, me
|
||||
|
||||
let image = UIImage(cgImage: cgImage, scale: 1.0, orientation: imageOrientation)
|
||||
|
||||
if let scaledImage = generateImage(image.size.fitted(CGSize(width: 90.0, height: 90.0)), contextGenerator: { size, context in
|
||||
if let scaledImage = generateImage(image.size.fitted(CGSize(width: 320.0, height: 320.0)), contextGenerator: { size, context in
|
||||
context.setBlendMode(.copy)
|
||||
drawImage(context: context, image: image.cgImage!, orientation: image.imageOrientation, in: CGRect(origin: CGPoint(), size: size))
|
||||
}, scale: 1.0), let thumbnailData = UIImageJPEGRepresentation(scaledImage, 0.6) {
|
||||
@ -94,7 +94,7 @@ public func transformOutgoingMessageMedia(postbox: Postbox, network: Network, me
|
||||
} |> runOn(opportunistic ? Queue.mainQueue() : Queue.concurrentDefaultQueue())
|
||||
} else if file.mimeType.hasPrefix("video/") {
|
||||
return Signal { subscriber in
|
||||
if let scaledImage = generateVideoFirstFrame(data.path, maxDimensions: CGSize(width: 90.0, height: 90.0)), let thumbnailData = UIImageJPEGRepresentation(scaledImage, 0.6) {
|
||||
if let scaledImage = generateVideoFirstFrame(data.path, maxDimensions: CGSize(width: 320.0, height: 320.0)), let thumbnailData = UIImageJPEGRepresentation(scaledImage, 0.6) {
|
||||
let thumbnailResource = LocalFileMediaResource(fileId: arc4random64())
|
||||
postbox.mediaBox.storeResourceData(thumbnailResource.id, data: thumbnailData)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user