mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-05 05:51:42 +00:00
Various fixes
This commit is contained in:
parent
d3d3932595
commit
a1c3217083
@ -6,16 +6,26 @@ import SwiftSignalKit
|
||||
import AsyncDisplayKit
|
||||
import TelegramCore
|
||||
|
||||
enum AvatarGalleryEntry: Equatable {
|
||||
case topImage([TelegramMediaImageRepresentation], GalleryItemIndexData?)
|
||||
case image(TelegramMediaImage, Peer, Int32, GalleryItemIndexData?)
|
||||
public struct ImageRepresentationWithReference: Equatable {
|
||||
public let representation: TelegramMediaImageRepresentation
|
||||
public let reference: MediaResourceReference
|
||||
|
||||
var representations: [TelegramMediaImageRepresentation] {
|
||||
public init(representation: TelegramMediaImageRepresentation, reference: MediaResourceReference) {
|
||||
self.representation = representation
|
||||
self.reference = reference
|
||||
}
|
||||
}
|
||||
|
||||
enum AvatarGalleryEntry: Equatable {
|
||||
case topImage([ImageRepresentationWithReference], GalleryItemIndexData?)
|
||||
case image(TelegramMediaImageReference?, [ImageRepresentationWithReference], Peer, Int32, GalleryItemIndexData?)
|
||||
|
||||
var representations: [ImageRepresentationWithReference] {
|
||||
switch self {
|
||||
case let .topImage(representations, _):
|
||||
return representations
|
||||
case let .image(image, _, _, _):
|
||||
return image.representations
|
||||
case let .image(_, representations, _, _, _):
|
||||
return representations
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,7 +33,7 @@ enum AvatarGalleryEntry: Equatable {
|
||||
switch self {
|
||||
case let .topImage(_, indexData):
|
||||
return indexData
|
||||
case let .image(_, _, _, indexData):
|
||||
case let .image(_, _, _, _, indexData):
|
||||
return indexData
|
||||
}
|
||||
}
|
||||
@ -36,8 +46,8 @@ enum AvatarGalleryEntry: Equatable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .image(lhsImage, lhsPeer, lhsDate, lhsIndexData):
|
||||
if case let .image(rhsImage, rhsPeer, rhsDate, rhsIndexData) = rhs, lhsImage.isEqual(to: rhsImage), arePeersEqual(lhsPeer, rhsPeer), lhsDate == rhsDate, lhsIndexData == rhsIndexData {
|
||||
case let .image(lhsImageReference, lhsRepresentations, lhsPeer, lhsDate, lhsIndexData):
|
||||
if case let .image(rhsImageReference, rhsRepresentations, rhsPeer, rhsDate, rhsIndexData) = rhs, lhsImageReference == rhsImageReference, lhsRepresentations == rhsRepresentations, arePeersEqual(lhsPeer, rhsPeer), lhsDate == rhsDate, lhsIndexData == rhsIndexData {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -58,12 +68,8 @@ final class AvatarGalleryControllerPresentationArguments {
|
||||
|
||||
private func initialAvatarGalleryEntries(peer: Peer) -> [AvatarGalleryEntry]{
|
||||
var initialEntries: [AvatarGalleryEntry] = []
|
||||
if let user = peer as? TelegramUser, !user.photo.isEmpty {
|
||||
initialEntries.append(.topImage(user.photo, nil))
|
||||
} else if let group = peer as? TelegramGroup {
|
||||
initialEntries.append(.topImage(group.photo, nil))
|
||||
} else if let channel = peer as? TelegramChannel {
|
||||
initialEntries.append(.topImage(channel.photo, nil))
|
||||
if !peer.profileImageRepresentations.isEmpty, let peerReference = PeerReference(peer) {
|
||||
initialEntries.append(.topImage(peer.profileImageRepresentations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatar(peer: peerReference, resource: $0.resource)) }), nil))
|
||||
}
|
||||
return initialEntries
|
||||
}
|
||||
@ -79,10 +85,9 @@ func fetchedAvatarGalleryEntries(account: Account, peer: Peer) -> Signal<[Avatar
|
||||
for photo in photos {
|
||||
let indexData = GalleryItemIndexData(position: index, totalCount: Int32(photos.count))
|
||||
if result.isEmpty, let first = initialEntries.first {
|
||||
let image = TelegramMediaImage(imageId: photo.image.imageId, representations: first.representations, reference: photo.reference, partialReference: nil)
|
||||
result.append(.image(image, peer, photo.date, indexData))
|
||||
result.append(.image(photo.image.reference, first.representations, peer, photo.date, indexData))
|
||||
} else {
|
||||
result.append(.image(photo.image, peer, photo.date, indexData))
|
||||
result.append(.image(photo.image.reference, photo.image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.standalone(resource: $0.resource)) }), peer, photo.date, indexData))
|
||||
}
|
||||
index += 1
|
||||
}
|
||||
@ -387,8 +392,8 @@ class AvatarGalleryController: ViewController {
|
||||
switch entry {
|
||||
case .topImage:
|
||||
break
|
||||
case let .image(image, _, _, _):
|
||||
if let reference = image.reference {
|
||||
case let .image(reference, _, _, _, _):
|
||||
if let reference = reference {
|
||||
let _ = removeAccountPhoto(network: self.account.network, reference: reference).start()
|
||||
}
|
||||
if entry == self.entries.first {
|
||||
|
||||
@ -74,7 +74,7 @@ final class AvatarGalleryItemFooterContentNode: GalleryFooterContentNode {
|
||||
var nameText: String?
|
||||
var dateText: String?
|
||||
switch entry {
|
||||
case let .image(_, peer, date, _):
|
||||
case let .image(_, _, peer, date, _):
|
||||
nameText = peer.displayTitle
|
||||
dateText = humanReadableStringForTimestamp(strings: self.strings, dateTimeFormat: self.dateTimeFormat, timestamp: date)
|
||||
default:
|
||||
|
||||
@ -151,7 +151,7 @@ final class CallControllerNode: ASDisplayNode {
|
||||
if !arePeersEqual(self.peer, peer) {
|
||||
self.peer = peer
|
||||
if let peerReference = PeerReference(peer), !peer.profileImageRepresentations.isEmpty {
|
||||
let representations: [(TelegramMediaImageRepresentation, MediaResourceReference)] = peer.profileImageRepresentations.map({ ($0, .avatar(peer: peerReference, resource: $0.resource)) })
|
||||
let representations: [ImageRepresentationWithReference] = peer.profileImageRepresentations.map({ ImageRepresentationWithReference(representation: $0, reference: .avatar(peer: peerReference, resource: $0.resource)) })
|
||||
self.imageNode.setSignal(chatAvatarGalleryPhoto(account: self.account, representations: representations, autoFetchFullSize: true))
|
||||
self.dimNode.isHidden = false
|
||||
} else {
|
||||
|
||||
@ -620,7 +620,7 @@ public func channelInfoController(account: Account, peerId: PeerId) -> ViewContr
|
||||
|
||||
})
|
||||
hiddenAvatarRepresentationDisposable.set((galleryController.hiddenMedia |> deliverOnMainQueue).start(next: { entry in
|
||||
avatarAndNameInfoContext.hiddenAvatarRepresentation = entry?.representations.first
|
||||
avatarAndNameInfoContext.hiddenAvatarRepresentation = entry?.representations.first?.representation
|
||||
updateHiddenAvatarImpl?()
|
||||
}))
|
||||
presentControllerImpl?(galleryController, AvatarGalleryControllerPresentationArguments(transitionArguments: { entry in
|
||||
|
||||
@ -154,6 +154,7 @@ public final class ChatController: TelegramController, KeyShortcutResponder, UID
|
||||
private var audioRecorderValue: ManagedAudioRecorder?
|
||||
private var audioRecorder = Promise<ManagedAudioRecorder?>()
|
||||
private var audioRecorderDisposable: Disposable?
|
||||
private var audioRecorderStatusDisposable: Disposable?
|
||||
|
||||
private var videoRecorderValue: InstantVideoController?
|
||||
private var tempVideoRecorderValue: InstantVideoController?
|
||||
@ -207,6 +208,7 @@ public final class ChatController: TelegramController, KeyShortcutResponder, UID
|
||||
private let chatAdditionalDataDisposable = MetaDisposable()
|
||||
|
||||
private var beginMediaRecordingRequestId: Int = 0
|
||||
private var lockMediaRecordingRequestId: Int?
|
||||
|
||||
var purposefulAction: (() -> Void)?
|
||||
|
||||
@ -1319,7 +1321,8 @@ public final class ChatController: TelegramController, KeyShortcutResponder, UID
|
||||
}
|
||||
})
|
||||
|
||||
self.audioRecorderDisposable = (self.audioRecorder.get() |> deliverOnMainQueue).start(next: { [weak self] audioRecorder in
|
||||
self.audioRecorderDisposable = (self.audioRecorder.get()
|
||||
|> deliverOnMainQueue).start(next: { [weak self] audioRecorder in
|
||||
if let strongSelf = self {
|
||||
if strongSelf.audioRecorderValue !== audioRecorder {
|
||||
strongSelf.audioRecorderValue = audioRecorder
|
||||
@ -1329,7 +1332,7 @@ public final class ChatController: TelegramController, KeyShortcutResponder, UID
|
||||
$0.updatedInputTextPanelState { panelState in
|
||||
if let audioRecorder = audioRecorder {
|
||||
if panelState.mediaRecordingState == nil {
|
||||
return panelState.withUpdatedMediaRecordingState(.audio(recorder: audioRecorder, isLocked: false))
|
||||
return panelState.withUpdatedMediaRecordingState(.audio(recorder: audioRecorder, isLocked: strongSelf.lockMediaRecordingRequestId == strongSelf.beginMediaRecordingRequestId))
|
||||
}
|
||||
} else {
|
||||
return panelState.withUpdatedMediaRecordingState(nil)
|
||||
@ -1337,12 +1340,21 @@ public final class ChatController: TelegramController, KeyShortcutResponder, UID
|
||||
return panelState
|
||||
}
|
||||
})
|
||||
strongSelf.audioRecorderStatusDisposable?.dispose()
|
||||
|
||||
if let audioRecorder = audioRecorder {
|
||||
if !audioRecorder.beginWithTone {
|
||||
strongSelf.recorderFeedback?.impact(.light)
|
||||
}
|
||||
audioRecorder.start()
|
||||
strongSelf.audioRecorderStatusDisposable = (audioRecorder.recordingState
|
||||
|> deliverOnMainQueue).start(next: { value in
|
||||
if case .stopped = value {
|
||||
self?.stopMediaRecorder()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
strongSelf.audioRecorderStatusDisposable = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1386,6 +1398,10 @@ public final class ChatController: TelegramController, KeyShortcutResponder, UID
|
||||
}
|
||||
}
|
||||
strongSelf.present(videoRecorder, in: .window(.root))
|
||||
|
||||
if strongSelf.lockMediaRecordingRequestId == strongSelf.beginMediaRecordingRequestId {
|
||||
videoRecorder.lockVideo()
|
||||
}
|
||||
}
|
||||
|
||||
if let previousVideoRecorderValue = previousVideoRecorderValue {
|
||||
@ -1513,6 +1529,7 @@ public final class ChatController: TelegramController, KeyShortcutResponder, UID
|
||||
}
|
||||
self.urlPreviewQueryState?.1.dispose()
|
||||
self.audioRecorderDisposable?.dispose()
|
||||
self.audioRecorderStatusDisposable?.dispose()
|
||||
self.videoRecorderDisposable?.dispose()
|
||||
self.buttonKeyboardMessageDisposable?.dispose()
|
||||
self.cachedDataDisposable?.dispose()
|
||||
@ -2449,9 +2466,14 @@ public final class ChatController: TelegramController, KeyShortcutResponder, UID
|
||||
return
|
||||
}
|
||||
strongSelf.beginMediaRecordingRequestId += 1
|
||||
self?.stopMediaRecorder()
|
||||
strongSelf.lockMediaRecordingRequestId = nil
|
||||
strongSelf.stopMediaRecorder()
|
||||
}, lockMediaRecording: { [weak self] in
|
||||
self?.lockMediaRecorder()
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.lockMediaRecordingRequestId = strongSelf.beginMediaRecordingRequestId
|
||||
strongSelf.lockMediaRecorder()
|
||||
}, deleteRecordedMedia: { [weak self] in
|
||||
self?.deleteMediaRecording()
|
||||
}, sendRecordedMedia: { [weak self] in
|
||||
|
||||
@ -92,6 +92,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
private var overlayContextPanelNode: ChatInputContextPanelNode?
|
||||
|
||||
private var inputNode: ChatInputNode?
|
||||
private var disappearingNode: ChatInputNode?
|
||||
|
||||
private var textInputPanelNode: ChatTextInputPanelNode?
|
||||
private var inputMediaNode: ChatMediaInputNode?
|
||||
@ -1222,7 +1223,17 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
})
|
||||
}
|
||||
|
||||
if let disappearingNode = self.disappearingNode {
|
||||
let targetY: CGFloat
|
||||
if cleanInsets.bottom.isLess(than: insets.bottom) {
|
||||
targetY = layout.size.height - insets.bottom
|
||||
} else {
|
||||
targetY = layout.size.height
|
||||
}
|
||||
transition.updateFrame(node: disappearingNode, frame: CGRect(origin: CGPoint(x: 0.0, y: targetY), size: CGSize(width: layout.size.width, height: max(insets.bottom, disappearingNode.bounds.size.height))))
|
||||
}
|
||||
if let dismissedInputNode = dismissedInputNode {
|
||||
self.disappearingNode = dismissedInputNode
|
||||
let targetY: CGFloat
|
||||
if cleanInsets.bottom.isLess(than: insets.bottom) {
|
||||
targetY = layout.size.height - insets.bottom
|
||||
@ -1230,8 +1241,11 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
targetY = layout.size.height
|
||||
}
|
||||
transition.updateFrame(node: dismissedInputNode, frame: CGRect(origin: CGPoint(x: 0.0, y: targetY), size: CGSize(width: layout.size.width, height: max(insets.bottom, dismissedInputNode.bounds.size.height))), force: true, completion: { [weak self, weak dismissedInputNode] completed in
|
||||
if completed, let dismissedInputNode = dismissedInputNode {
|
||||
if let dismissedInputNode = dismissedInputNode {
|
||||
if let strongSelf = self {
|
||||
if strongSelf.disappearingNode === dismissedInputNode {
|
||||
strongSelf.disappearingNode = nil
|
||||
}
|
||||
if strongSelf.inputNode !== dismissedInputNode {
|
||||
dismissedInputNode.alpha = 0.0
|
||||
dismissedInputNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak dismissedInputNode] completed in
|
||||
|
||||
@ -702,7 +702,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode {
|
||||
var subject: ShareControllerSubject = ShareControllerSubject.messages(messages)
|
||||
for m in messages[0].media {
|
||||
if let image = m as? TelegramMediaImage {
|
||||
subject = .image(image.representations)
|
||||
subject = .image(image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: .media(media: .message(message: MessageReference(messages[0]), media: m), resource: $0.resource)) }))
|
||||
} else if let webpage = m as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content {
|
||||
if content.embedType == "iframe" {
|
||||
let item = OpenInItem.url(url: content.url)
|
||||
|
||||
@ -328,7 +328,10 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
if let strongSelf = self {
|
||||
let _ = removePeerChat(postbox: strongSelf.account.postbox, peerId: peerId, reportChatSpam: false).start()
|
||||
strongSelf.chatListDisplayNode.chatListNode.setCurrentRemovingPeerId(peerId)
|
||||
let _ = removePeerChat(postbox: strongSelf.account.postbox, peerId: peerId, reportChatSpam: false).start(completed: {
|
||||
self?.chatListDisplayNode.chatListNode.setCurrentRemovingPeerId(nil)
|
||||
})
|
||||
}
|
||||
}))
|
||||
|
||||
@ -337,7 +340,10 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
if let strongSelf = self {
|
||||
let _ = removePeerChat(postbox: strongSelf.account.postbox, peerId: peerId, reportChatSpam: false).start()
|
||||
strongSelf.chatListDisplayNode.chatListNode.setCurrentRemovingPeerId(peerId)
|
||||
let _ = removePeerChat(postbox: strongSelf.account.postbox, peerId: peerId, reportChatSpam: false).start(completed: {
|
||||
self?.chatListDisplayNode.chatListNode.setCurrentRemovingPeerId(peerId)
|
||||
})
|
||||
let _ = requestUpdatePeerIsBlocked(account: strongSelf.account, peerId: peer.id, isBlocked: true).start()
|
||||
}
|
||||
}))
|
||||
|
||||
@ -336,6 +336,11 @@ final class ChatListNode: ListView {
|
||||
var isEmptyUpdated: ((Bool) -> Void)?
|
||||
private var wasEmpty: Bool?
|
||||
|
||||
private let currentRemovingPeerId = Atomic<PeerId?>(value: nil)
|
||||
func setCurrentRemovingPeerId(_ peerId: PeerId?) {
|
||||
let _ = self.currentRemovingPeerId.swap(peerId)
|
||||
}
|
||||
|
||||
init(account: Account, groupId: PeerGroupId?, controlsHistoryPreload: Bool, mode: ChatListNodeMode, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, disableAnimations: Bool) {
|
||||
self.account = account
|
||||
self.controlsHistoryPreload = controlsHistoryPreload
|
||||
@ -438,6 +443,7 @@ final class ChatListNode: ListView {
|
||||
|
||||
let previousState = Atomic<ChatListNodeState>(value: self.currentState)
|
||||
let previousView = Atomic<ChatListNodeView?>(value: nil)
|
||||
let currentRemovingPeerId = self.currentRemovingPeerId
|
||||
|
||||
let savedMessagesPeer: Signal<Peer?, NoError>
|
||||
if case let .peers(filter) = mode, filter == [.onlyWriteable] {
|
||||
@ -453,7 +459,6 @@ final class ChatListNode: ListView {
|
||||
let entries = chatListNodeEntriesForView(update.view, state: state, savedMessagesPeer: savedMessagesPeer, mode: mode).filter { entry in
|
||||
switch entry {
|
||||
case let .PeerEntry(_, _, _, _, _, _, peer, _, _, _, _, _, _):
|
||||
//ChatListNodePeersFilter
|
||||
switch mode {
|
||||
case .chatList:
|
||||
return true
|
||||
@ -533,26 +538,36 @@ final class ChatListNode: ListView {
|
||||
}
|
||||
}
|
||||
|
||||
let removingPeerId = currentRemovingPeerId.with { $0 }
|
||||
|
||||
var disableAnimations = state.presentationData.disableAnimations
|
||||
if previousState.editing != state.editing {
|
||||
disableAnimations = false
|
||||
} else {
|
||||
var previousPinnedCount = 0
|
||||
var updatedPinnedCount = 0
|
||||
var didIncludeRemovingPeerId = false
|
||||
if let previous = previousView {
|
||||
for entry in previous.filteredEntries {
|
||||
if case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _) = entry {
|
||||
if index.pinningIndex != nil {
|
||||
previousPinnedCount += 1
|
||||
}
|
||||
if index.messageIndex.id.peerId == removingPeerId {
|
||||
didIncludeRemovingPeerId = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var doesIncludeRemovingPeerId = false
|
||||
for entry in processedView.filteredEntries {
|
||||
if case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _) = entry {
|
||||
if index.pinningIndex != nil {
|
||||
updatedPinnedCount += 1
|
||||
}
|
||||
if index.messageIndex.id.peerId == removingPeerId {
|
||||
doesIncludeRemovingPeerId = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if previousPinnedCount != updatedPinnedCount {
|
||||
@ -561,9 +576,17 @@ final class ChatListNode: ListView {
|
||||
if previousState.selectedPeerIds != state.selectedPeerIds {
|
||||
disableAnimations = false
|
||||
}
|
||||
if !doesIncludeRemovingPeerId, didIncludeRemovingPeerId {
|
||||
disableAnimations = false
|
||||
}
|
||||
}
|
||||
|
||||
return preparedChatListNodeViewTransition(from: previousView, to: processedView, reason: reason, disableAnimations: disableAnimations, account: account, scrollPosition: updatedScrollPosition)
|
||||
var searchMode = false
|
||||
if case .chatList = mode {
|
||||
searchMode = true
|
||||
}
|
||||
|
||||
return preparedChatListNodeViewTransition(from: previousView, to: processedView, reason: reason, disableAnimations: disableAnimations, account: account, scrollPosition: updatedScrollPosition, searchMode: searchMode)
|
||||
|> map({ mappedChatListNodeViewListTransition(account: account, nodeInteraction: nodeInteraction, peerGroupId: groupId, mode: mode, transition: $0) })
|
||||
|> runOn(prepareOnMainQueue ? Queue.mainQueue() : viewProcessingQueue)
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ enum ChatListNodeViewScrollPosition {
|
||||
case index(index: ChatListIndex, position: ListViewScrollPosition, directionHint: ListViewScrollToItemDirectionHint, animated: Bool)
|
||||
}
|
||||
|
||||
func preparedChatListNodeViewTransition(from fromView: ChatListNodeView?, to toView: ChatListNodeView, reason: ChatListNodeViewTransitionReason, disableAnimations: Bool, account: Account, scrollPosition: ChatListNodeViewScrollPosition?) -> Signal<ChatListNodeViewTransition, NoError> {
|
||||
func preparedChatListNodeViewTransition(from fromView: ChatListNodeView?, to toView: ChatListNodeView, reason: ChatListNodeViewTransitionReason, disableAnimations: Bool, account: Account, scrollPosition: ChatListNodeViewScrollPosition?, searchMode: Bool) -> Signal<ChatListNodeViewTransition, NoError> {
|
||||
return Signal { subscriber in
|
||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromView?.filteredEntries ?? [], rightList: toView.filteredEntries)
|
||||
|
||||
@ -194,7 +194,7 @@ func preparedChatListNodeViewTransition(from fromView: ChatListNodeView?, to toV
|
||||
fromEmptyView = true
|
||||
}
|
||||
|
||||
if fromEmptyView && scrollToItem == nil && toView.filteredEntries.count >= 2 {
|
||||
if !searchMode && fromEmptyView && scrollToItem == nil && toView.filteredEntries.count >= 2 {
|
||||
if case .SearchEntry = toView.filteredEntries[toView.filteredEntries.count - 1] {
|
||||
scrollToItem = ListViewScrollToItem(index: 1, position: .top(0.0), animated: false, curve: .Default(duration: 0.0), directionHint: .Up)
|
||||
}
|
||||
|
||||
@ -38,6 +38,8 @@ final class ChatTextInputAudioRecordingTimeNode: ASDisplayNode {
|
||||
strongSelf.timestamp = duration
|
||||
case let .recording(duration, _):
|
||||
strongSelf.timestamp = duration
|
||||
case .stopped:
|
||||
break
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
@ -350,7 +350,7 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto
|
||||
func micButtonInteractionCancelled(_ velocity: CGPoint) {
|
||||
//print("\(CFAbsoluteTimeGetCurrent()) cancelled")
|
||||
self.modeTimeoutTimer?.invalidate()
|
||||
self.endRecording(false)
|
||||
self.stopRecording()
|
||||
}
|
||||
|
||||
func micButtonInteractionCompleted(_ velocity: CGPoint) {
|
||||
|
||||
@ -52,7 +52,7 @@ public class ExternalMusicAlbumArtResource: TelegramMediaResource {
|
||||
return ExternalMusicAlbumArtResourceId(title: self.title, performer: self.performer, isThumbnail: self.isThumbnail)
|
||||
}
|
||||
|
||||
public func isEqual(to: TelegramMediaResource) -> Bool {
|
||||
public func isEqual(to: MediaResource) -> Bool {
|
||||
if let to = to as? ExternalMusicAlbumArtResource {
|
||||
return self.title == to.title && self.performer == to.performer && self.isThumbnail == to.isThumbnail
|
||||
} else {
|
||||
|
||||
@ -1088,7 +1088,11 @@ private func groupInfoEntries(account: Account, presentationData: PresentationDa
|
||||
if case .creator = group.role, state.editingState != nil {
|
||||
entries.append(.convertToSupergroup(presentationData.theme, presentationData.strings.GroupInfo_ConvertToSupergroup))
|
||||
}
|
||||
if case .creator = group.role {
|
||||
entries.append(.leave(presentationData.theme, presentationData.strings.GroupInfo_DeleteAndExit))
|
||||
} else {
|
||||
entries.append(.leave(presentationData.theme, presentationData.strings.Group_LeaveGroup))
|
||||
}
|
||||
}
|
||||
} else if let channel = view.peers[view.peerId] as? TelegramChannel {
|
||||
if case .member = channel.participationStatus, let cachedChannelData = view.cachedData as? CachedChannelData, let memberCount = cachedChannelData.participantsSummary.memberCount, memberCount <= 200 {
|
||||
@ -1192,7 +1196,7 @@ public func groupInfoController(account: Account, peerId: PeerId) -> ViewControl
|
||||
|
||||
})
|
||||
hiddenAvatarRepresentationDisposable.set((galleryController.hiddenMedia |> deliverOnMainQueue).start(next: { entry in
|
||||
avatarAndNameInfoContext.hiddenAvatarRepresentation = entry?.representations.first
|
||||
avatarAndNameInfoContext.hiddenAvatarRepresentation = entry?.representations.first?.representation
|
||||
updateHiddenAvatarImpl?()
|
||||
}))
|
||||
presentControllerImpl?(galleryController, AvatarGalleryControllerPresentationArguments(transitionArguments: { entry in
|
||||
|
||||
@ -42,7 +42,7 @@ public class ICloudFileResource: TelegramMediaResource {
|
||||
return ICloudFileResourceId(urlData: self.urlData)
|
||||
}
|
||||
|
||||
public func isEqual(to: TelegramMediaResource) -> Bool {
|
||||
public func isEqual(to: MediaResource) -> Bool {
|
||||
if let to = to as? ICloudFileResource {
|
||||
if self.urlData != to.urlData {
|
||||
return false
|
||||
|
||||
@ -135,6 +135,8 @@ final class InstantPageMediaPlaylist: SharedMediaPlaylist {
|
||||
return InstantPagePlaylistLocation(webpageId: self.webPage.webpageId)
|
||||
}
|
||||
|
||||
var currentItemDisappeared: (() -> Void)?
|
||||
|
||||
private var currentItem: InstantPageMedia?
|
||||
private var playedToEnd: Bool = false
|
||||
private var order: MusicPlaybackSettingsOrder = .regular
|
||||
|
||||
@ -263,7 +263,7 @@ func legacyAssetPickerEnqueueMessages(account: Account, signals: [Any]) -> Signa
|
||||
var randomId: Int64 = 0
|
||||
arc4random_buf(&randomId, 8)
|
||||
let tempFilePath = NSTemporaryDirectory() + "\(randomId).jpeg"
|
||||
let scaledSize = image.size.aspectFitted(CGSize(width: 1280.0, height: 1280.0))
|
||||
let scaledSize = image.size.aspectFittedOrSmaller(CGSize(width: 1280.0, height: 1280.0))
|
||||
if let scaledImage = TGScaleImageToPixelSize(image, scaledSize) {
|
||||
if let scaledImageData = compressImageToJPEG(scaledImage, quality: 0.6) {
|
||||
let _ = try? scaledImageData.write(to: URL(fileURLWithPath: tempFilePath))
|
||||
@ -299,7 +299,7 @@ func legacyAssetPickerEnqueueMessages(account: Account, signals: [Any]) -> Signa
|
||||
var randomId: Int64 = 0
|
||||
arc4random_buf(&randomId, 8)
|
||||
let size = CGSize(width: CGFloat(asset.pixelWidth), height: CGFloat(asset.pixelHeight))
|
||||
let scaledSize = size.aspectFitted(CGSize(width: 1280.0, height: 1280.0))
|
||||
let scaledSize = size.aspectFittedOrSmaller(CGSize(width: 1280.0, height: 1280.0))
|
||||
let resource = PhotoLibraryMediaResource(localIdentifier: asset.localIdentifier, uniqueId: arc4random64())
|
||||
representations.append(TelegramMediaImageRepresentation(dimensions: scaledSize, resource: resource))
|
||||
|
||||
|
||||
@ -53,7 +53,7 @@ private enum LanguageListEntry: Comparable, Identifiable {
|
||||
openSearch()
|
||||
})
|
||||
case let .localization(_, info, type, selected, activity, revealed, editing):
|
||||
return LocalizationListItem(theme: theme, strings: strings, id: info.languageCode, title: info.title, subtitle: info.localizedTitle, checked: selected, activity: activity, editing: LocalizationListItemEditing(editable: !searchMode && !info.isOfficial, editing: editing, revealed: revealed, reorderable: false), sectionId: type == .official ? LanguageListSection.official.rawValue : LanguageListSection.unofficial.rawValue, alwaysPlain: searchMode, action: {
|
||||
return LocalizationListItem(theme: theme, strings: strings, id: info.languageCode, title: info.title, subtitle: info.localizedTitle, checked: selected, activity: activity, editing: LocalizationListItemEditing(editable: !selected && !searchMode && !info.isOfficial, editing: editing, revealed: !selected && revealed, reorderable: false), sectionId: type == .official ? LanguageListSection.official.rawValue : LanguageListSection.unofficial.rawValue, alwaysPlain: searchMode, action: {
|
||||
selectLocalization(info)
|
||||
}, setItemWithRevealedOptions: setItemWithRevealedOptions, removeItem: removeItem)
|
||||
}
|
||||
|
||||
@ -175,9 +175,9 @@ final class ManagedAudioRecorderContext {
|
||||
private var hasAudioSession = false
|
||||
private var audioSessionDisposable: Disposable?
|
||||
|
||||
private var tonePlayer: TonePlayer?
|
||||
//private var toneRenderer: MediaPlayerAudioRenderer?
|
||||
//private var toneRendererAudioSession: MediaPlayerAudioSessionCustomControl?
|
||||
//private var tonePlayer: TonePlayer?
|
||||
private var toneRenderer: MediaPlayerAudioRenderer?
|
||||
private var toneRendererAudioSession: MediaPlayerAudioSessionCustomControl?
|
||||
private var toneRendererAudioSessionActivated = false
|
||||
|
||||
private var processSamples = false
|
||||
@ -200,7 +200,7 @@ final class ManagedAudioRecorderContext {
|
||||
self.dataItem = TGDataItem()
|
||||
self.oggWriter = TGOggOpusWriter()
|
||||
|
||||
/*if false, let toneData = audioRecordingToneData {
|
||||
if beginWithTone, let toneData = audioRecordingToneData {
|
||||
self.processSamples = false
|
||||
let toneRenderer = MediaPlayerAudioRenderer(audioSession: .custom({ [weak self] control in
|
||||
queue.async {
|
||||
@ -286,9 +286,9 @@ final class ManagedAudioRecorderContext {
|
||||
toneTimer.start()
|
||||
} else {
|
||||
self.processSamples = true
|
||||
}*/
|
||||
}
|
||||
|
||||
if beginWithTone, let beginToneData = beginToneData {
|
||||
/*if beginWithTone, let beginToneData = beginToneData {
|
||||
self.tonePlayer = TonePlayer()
|
||||
self.tonePlayer?.play(data: beginToneData, completed: { [weak self] in
|
||||
queue.async {
|
||||
@ -307,7 +307,7 @@ final class ManagedAudioRecorderContext {
|
||||
})
|
||||
} else {
|
||||
self.processSamples = true
|
||||
}
|
||||
}*/
|
||||
|
||||
addAudioRecorderContext(self.id, self)
|
||||
addAudioUnitHolder(self.id, queue, self.audioUnit)
|
||||
@ -331,7 +331,7 @@ final class ManagedAudioRecorderContext {
|
||||
|
||||
self.audioSessionDisposable?.dispose()
|
||||
|
||||
//self.toneRenderer?.stop()
|
||||
self.toneRenderer?.stop()
|
||||
self.toneTimer?.invalidate()
|
||||
}
|
||||
|
||||
@ -396,7 +396,7 @@ final class ManagedAudioRecorderContext {
|
||||
|
||||
if self.audioSessionDisposable == nil {
|
||||
let queue = self.queue
|
||||
self.audioSessionDisposable = self.mediaManager.audioSession.push(audioSessionType: .record, activate: { [weak self] state in
|
||||
self.audioSessionDisposable = self.mediaManager.audioSession.push(audioSessionType: .record(speaker: self.beginWithTone), activate: { [weak self] state in
|
||||
queue.async {
|
||||
if let strongSelf = self, !strongSelf.paused {
|
||||
strongSelf.hasAudioSession = true
|
||||
@ -409,6 +409,7 @@ final class ManagedAudioRecorderContext {
|
||||
if let strongSelf = self {
|
||||
strongSelf.hasAudioSession = false
|
||||
strongSelf.stop()
|
||||
strongSelf.recordingState.set(.stopped)
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
}
|
||||
@ -420,12 +421,13 @@ final class ManagedAudioRecorderContext {
|
||||
}
|
||||
|
||||
func audioSessionAcquired(headset: Bool) {
|
||||
if let tonePlayer = self.tonePlayer, headset || self.beginWithTone {
|
||||
if let toneRenderer = self.toneRenderer, headset || self.beginWithTone {
|
||||
self.beganWithTone(true)
|
||||
if !self.toneRendererAudioSessionActivated {
|
||||
self.toneRendererAudioSessionActivated = true
|
||||
tonePlayer.start()
|
||||
self.toneRendererAudioSession?.activate()
|
||||
}
|
||||
toneRenderer.setRate(1.0)
|
||||
} else {
|
||||
self.processSamples = true
|
||||
self.beganWithTone(false)
|
||||
@ -463,9 +465,9 @@ final class ManagedAudioRecorderContext {
|
||||
}
|
||||
}
|
||||
|
||||
if let tonePlayer = self.tonePlayer, self.toneRendererAudioSessionActivated {
|
||||
if let toneRenderer = self.toneRenderer, self.toneRendererAudioSessionActivated {
|
||||
self.toneRendererAudioSessionActivated = false
|
||||
tonePlayer.stop()
|
||||
toneRenderer.stop()
|
||||
}
|
||||
|
||||
let audioSessionDisposable = self.audioSessionDisposable
|
||||
@ -647,23 +649,7 @@ final class ManagedAudioRecorderContext {
|
||||
enum AudioRecordingState: Equatable {
|
||||
case paused(duration: Double)
|
||||
case recording(duration: Double, durationMediaTimestamp: Double)
|
||||
|
||||
static func ==(lhs: AudioRecordingState, rhs: AudioRecordingState) -> Bool {
|
||||
switch lhs {
|
||||
case let .paused(duration):
|
||||
if case .paused(duration) = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .recording(duration, durationMediaTimestamp):
|
||||
if case .recording(duration, durationMediaTimestamp) = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
case stopped
|
||||
}
|
||||
|
||||
final class ManagedAudioRecorder {
|
||||
|
||||
@ -3,10 +3,10 @@ import SwiftSignalKit
|
||||
import AVFoundation
|
||||
import UIKit
|
||||
|
||||
enum ManagedAudioSessionType {
|
||||
enum ManagedAudioSessionType: Equatable {
|
||||
case play
|
||||
case playWithPossiblePortOverride
|
||||
case record
|
||||
case record(speaker: Bool)
|
||||
case voiceCall
|
||||
}
|
||||
|
||||
@ -544,7 +544,17 @@ public final class ManagedAudioSession {
|
||||
private func applyNoneDelayed() {
|
||||
self.deactivateTimer?.invalidate()
|
||||
|
||||
if self.currentTypeAndOutputMode?.0 == .voiceCall || self.currentTypeAndOutputMode?.0 == .record {
|
||||
var immediately = false
|
||||
if let mode = self.currentTypeAndOutputMode?.0 {
|
||||
switch mode {
|
||||
case .voiceCall, .record:
|
||||
immediately = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if immediately {
|
||||
self.applyNone()
|
||||
} else {
|
||||
let deactivateTimer = SwiftSignalKit.Timer(timeout: 1.0, repeat: false, completion: { [weak self] in
|
||||
@ -696,13 +706,13 @@ public final class ManagedAudioSession {
|
||||
}
|
||||
}
|
||||
if resetToBuiltin {
|
||||
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none)
|
||||
switch type {
|
||||
case .voiceCall, .playWithPossiblePortOverride, .record:
|
||||
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none)
|
||||
if let routes = AVAudioSession.sharedInstance().availableInputs {
|
||||
for route in routes {
|
||||
if route.portType == AVAudioSessionPortBuiltInMic {
|
||||
if type == .record && self.isHeadsetPluggedInValue {
|
||||
if case .record = type, self.isHeadsetPluggedInValue {
|
||||
} else {
|
||||
let _ = try? AVAudioSession.sharedInstance().setPreferredInput(route)
|
||||
}
|
||||
@ -711,7 +721,7 @@ public final class ManagedAudioSession {
|
||||
}
|
||||
}
|
||||
default:
|
||||
break
|
||||
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,7 +58,7 @@ public class MapSnapshotMediaResource: TelegramMediaResource {
|
||||
return MapSnapshotMediaResourceId(latitude: self.latitude, longitude: self.longitude, width: self.width, height: self.height)
|
||||
}
|
||||
|
||||
public func isEqual(to: TelegramMediaResource) -> Bool {
|
||||
public func isEqual(to: MediaResource) -> Bool {
|
||||
if let to = to as? MapSnapshotMediaResource {
|
||||
return self.latitude == to.latitude && self.longitude == to.longitude && self.width == to.width && self.height == to.height
|
||||
} else {
|
||||
|
||||
@ -450,6 +450,13 @@ public final class MediaManager: NSObject {
|
||||
strongSelf.voiceMediaPlayer = voiceMediaPlayer
|
||||
voiceMediaPlayer.playedToEnd = { [weak voiceMediaPlayer] in
|
||||
if let strongSelf = self, let voiceMediaPlayer = voiceMediaPlayer, voiceMediaPlayer === strongSelf.voiceMediaPlayer {
|
||||
voiceMediaPlayer.stop()
|
||||
strongSelf.voiceMediaPlayer = nil
|
||||
}
|
||||
}
|
||||
voiceMediaPlayer.cancelled = { [weak voiceMediaPlayer] in
|
||||
if let strongSelf = self, let voiceMediaPlayer = voiceMediaPlayer, voiceMediaPlayer === strongSelf.voiceMediaPlayer {
|
||||
voiceMediaPlayer.stop()
|
||||
strongSelf.voiceMediaPlayer = nil
|
||||
}
|
||||
}
|
||||
@ -461,7 +468,14 @@ public final class MediaManager: NSObject {
|
||||
strongSelf.musicMediaPlayer?.stop()
|
||||
strongSelf.voiceMediaPlayer?.control(.playback(.pause))
|
||||
if let playlist = playlist {
|
||||
strongSelf.musicMediaPlayer = SharedMediaPlayer(mediaManager: strongSelf, inForeground: strongSelf.inForeground, postbox: strongSelf.postbox, audioSession: strongSelf.audioSession, overlayMediaManager: strongSelf.overlayMediaManager, playlist: playlist, initialOrder: settings.order, initialLooping: settings.looping, initialPlaybackRate: .x1, playerIndex: nextPlayerIndex, controlPlaybackWithProximity: false)
|
||||
let musicMediaPlayer = SharedMediaPlayer(mediaManager: strongSelf, inForeground: strongSelf.inForeground, postbox: strongSelf.postbox, audioSession: strongSelf.audioSession, overlayMediaManager: strongSelf.overlayMediaManager, playlist: playlist, initialOrder: settings.order, initialLooping: settings.looping, initialPlaybackRate: .x1, playerIndex: nextPlayerIndex, controlPlaybackWithProximity: false)
|
||||
strongSelf.musicMediaPlayer = musicMediaPlayer
|
||||
musicMediaPlayer.cancelled = { [weak musicMediaPlayer] in
|
||||
if let strongSelf = self, let musicMediaPlayer = musicMediaPlayer, musicMediaPlayer === strongSelf.musicMediaPlayer {
|
||||
musicMediaPlayer.stop()
|
||||
strongSelf.musicMediaPlayer = nil
|
||||
}
|
||||
}
|
||||
strongSelf.musicMediaPlayer?.control(.playback(.play))
|
||||
} else {
|
||||
strongSelf.musicMediaPlayer = nil
|
||||
|
||||
@ -132,7 +132,7 @@ public final class VideoLibraryMediaResource: TelegramMediaResource {
|
||||
return VideoLibraryMediaResourceId(localIdentifier: self.localIdentifier, adjustmentsDigest: adjustmentsDigest)
|
||||
}
|
||||
|
||||
public func isEqual(to: TelegramMediaResource) -> Bool {
|
||||
public func isEqual(to: MediaResource) -> Bool {
|
||||
if let to = to as? VideoLibraryMediaResource {
|
||||
return self.localIdentifier == to.localIdentifier && self.conversion == to.conversion
|
||||
} else {
|
||||
@ -196,7 +196,7 @@ public final class LocalFileVideoMediaResource: TelegramMediaResource {
|
||||
return LocalFileVideoMediaResourceId(randomId: self.randomId)
|
||||
}
|
||||
|
||||
public func isEqual(to: TelegramMediaResource) -> Bool {
|
||||
public func isEqual(to: MediaResource) -> Bool {
|
||||
if let to = to as? LocalFileVideoMediaResource {
|
||||
return self.randomId == to.randomId && self.path == to.path && self.adjustments == to.adjustments
|
||||
} else {
|
||||
@ -253,7 +253,7 @@ public class PhotoLibraryMediaResource: TelegramMediaResource {
|
||||
return PhotoLibraryMediaResourceId(localIdentifier: self.localIdentifier, resourceId: self.uniqueId)
|
||||
}
|
||||
|
||||
public func isEqual(to: TelegramMediaResource) -> Bool {
|
||||
public func isEqual(to: MediaResource) -> Bool {
|
||||
if let to = to as? PhotoLibraryMediaResource {
|
||||
return self.localIdentifier == to.localIdentifier && self.uniqueId == to.uniqueId
|
||||
} else {
|
||||
@ -309,7 +309,7 @@ public final class LocalFileGifMediaResource: TelegramMediaResource {
|
||||
return LocalFileGifMediaResourceId(randomId: self.randomId)
|
||||
}
|
||||
|
||||
public func isEqual(to: TelegramMediaResource) -> Bool {
|
||||
public func isEqual(to: MediaResource) -> Bool {
|
||||
if let to = to as? LocalFileGifMediaResource {
|
||||
return self.randomId == to.randomId && self.path == to.path
|
||||
} else {
|
||||
|
||||
@ -29,7 +29,7 @@ private func chatMessageGalleryControllerData(account: Account, message: Message
|
||||
switch action.action {
|
||||
case let .photoUpdated(image):
|
||||
if let peer = messageMainPeer(message), let image = image {
|
||||
let promise: Promise<[AvatarGalleryEntry]> = Promise([AvatarGalleryEntry.image(image, peer, message.timestamp, nil)])
|
||||
let promise: Promise<[AvatarGalleryEntry]> = Promise([AvatarGalleryEntry.image(image.reference, image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: .media(media: .message(message: MessageReference(message), media: media), resource: $0.resource)) }), peer, message.timestamp, nil)])
|
||||
let galleryController = AvatarGalleryController(account: account, peer: peer, remoteEntries: promise, replaceRootController: { controller, ready in
|
||||
|
||||
})
|
||||
|
||||
@ -42,7 +42,7 @@ public class OpenInAppIconResource: TelegramMediaResource {
|
||||
return OpenInAppIconResourceId(appStoreId: self.appStoreId)
|
||||
}
|
||||
|
||||
public func isEqual(to: TelegramMediaResource) -> Bool {
|
||||
public func isEqual(to: MediaResource) -> Bool {
|
||||
if let to = to as? OpenInAppIconResource {
|
||||
return self.appStoreId == to.appStoreId
|
||||
} else {
|
||||
|
||||
@ -5,39 +5,20 @@ import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
|
||||
private enum PeerAvatarImageGalleryThumbnailContent: Equatable {
|
||||
case avatar(PeerReference, [TelegramMediaImageRepresentation])
|
||||
case standaloneImage([TelegramMediaImageRepresentation])
|
||||
|
||||
var representations: [TelegramMediaImageRepresentation] {
|
||||
switch self {
|
||||
case let .avatar(_, representations):
|
||||
return representations
|
||||
case let .standaloneImage(representations):
|
||||
return representations
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct PeerAvatarImageGalleryThumbnailItem: GalleryThumbnailItem {
|
||||
let account: Account
|
||||
let peer: Peer
|
||||
let content: PeerAvatarImageGalleryThumbnailContent
|
||||
let content: [ImageRepresentationWithReference]
|
||||
|
||||
init(account: Account, peer: Peer, content: PeerAvatarImageGalleryThumbnailContent) {
|
||||
init(account: Account, peer: Peer, content: [ImageRepresentationWithReference]) {
|
||||
self.account = account
|
||||
self.peer = peer
|
||||
self.content = content
|
||||
}
|
||||
|
||||
var image: (Signal<(TransformImageArguments) -> DrawingContext?, NoError>, CGSize) {
|
||||
if let representation = largestImageRepresentation(self.content.representations) {
|
||||
switch self.content {
|
||||
case let .avatar(peer, representations):
|
||||
return (avatarGalleryThumbnailPhoto(account: self.account, representations: representations.map({ ($0, .avatar(peer: peer, resource: $0.resource)) })), representation.dimensions)
|
||||
case let .standaloneImage(representations):
|
||||
return (avatarGalleryThumbnailPhoto(account: self.account, representations: representations.map({ ($0, .standalone(resource: $0.resource)) })), representation.dimensions)
|
||||
}
|
||||
if let representation = largestImageRepresentation(self.content.map({ $0.representation })) {
|
||||
return (avatarGalleryThumbnailPhoto(account: self.account, representations: self.content), representation.dimensions)
|
||||
} else {
|
||||
return (.single({ _ in return nil }), CGSize(width: 128.0, height: 128.0))
|
||||
}
|
||||
@ -92,16 +73,12 @@ class PeerAvatarImageGalleryItem: GalleryItem {
|
||||
}
|
||||
|
||||
func thumbnailItem() -> (Int64, GalleryThumbnailItem)? {
|
||||
let content: PeerAvatarImageGalleryThumbnailContent
|
||||
let content: [ImageRepresentationWithReference]
|
||||
switch self.entry {
|
||||
case let .topImage(representations, _):
|
||||
if let peerReference = PeerReference(self.peer) {
|
||||
content = .avatar(peerReference, representations)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
case let .image(image, _, _, _):
|
||||
content = .standaloneImage(image.representations)
|
||||
content = representations
|
||||
case let .image(_, representations, _, _, _):
|
||||
content = representations
|
||||
}
|
||||
|
||||
return (0, PeerAvatarImageGalleryThumbnailItem(account: self.account, peer: self.peer, content: content))
|
||||
@ -182,28 +159,20 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
|
||||
self.footerContentNode.setEntry(entry)
|
||||
|
||||
if let largestSize = largestImageRepresentation(entry.representations) {
|
||||
if let largestSize = largestImageRepresentation(entry.representations.map({ $0.representation })) {
|
||||
let displaySize = largestSize.dimensions.fitted(CGSize(width: 1280.0, height: 1280.0)).dividedByScreenScale().integralFloor
|
||||
self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: displaySize, boundingSize: displaySize, intrinsicInsets: UIEdgeInsets()))()
|
||||
let representations: [(TelegramMediaImageRepresentation, MediaResourceReference)]
|
||||
let representations: [ImageRepresentationWithReference]
|
||||
switch entry {
|
||||
case let .topImage(topRepresentations, _):
|
||||
if let peerReference = PeerReference(self.peer) {
|
||||
representations = topRepresentations.map { representation in
|
||||
return (representation, .avatar(peer: peerReference, resource: representation.resource))
|
||||
}
|
||||
} else {
|
||||
representations = []
|
||||
}
|
||||
case let .image(image, _, _, _):
|
||||
representations = image.representations.map { representation in
|
||||
return (representation, .standalone(resource: representation.resource))
|
||||
}
|
||||
representations = topRepresentations
|
||||
case let .image(_, imageRepresentations, _, _, _):
|
||||
representations = imageRepresentations
|
||||
}
|
||||
self.imageNode.setSignal(chatAvatarGalleryPhoto(account: account, representations: representations), dispatchOnDisplayLink: false)
|
||||
self.zoomableContent = (largestSize.dimensions, self.imageNode)
|
||||
if let largestIndex = representations.index(where: { $0.0 == largestSize }) {
|
||||
self.fetchDisposable.set(fetchedMediaResource(postbox: self.account.postbox, reference: representations[largestIndex].1).start())
|
||||
if let largestIndex = representations.index(where: { $0.representation == largestSize }) {
|
||||
self.fetchDisposable.set(fetchedMediaResource(postbox: self.account.postbox, reference: representations[largestIndex].reference).start())
|
||||
}
|
||||
|
||||
self.statusDisposable.set((account.postbox.mediaBox.resourceStatus(largestSize.resource)
|
||||
@ -359,29 +328,21 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
}
|
||||
|
||||
@objc func statusPressed() {
|
||||
if let entry = self.entry, let largestSize = largestImageRepresentation(entry.representations), let status = self.status {
|
||||
if let entry = self.entry, let largestSize = largestImageRepresentation(entry.representations.map({ $0.representation })), let status = self.status {
|
||||
switch status {
|
||||
case .Fetching:
|
||||
self.account.postbox.mediaBox.cancelInteractiveResourceFetch(largestSize.resource)
|
||||
case .Remote:
|
||||
let representations: [(TelegramMediaImageRepresentation, MediaResourceReference)]
|
||||
let representations: [ImageRepresentationWithReference]
|
||||
switch entry {
|
||||
case let .topImage(topRepresentations, _):
|
||||
if let peerReference = PeerReference(self.peer) {
|
||||
representations = topRepresentations.map { representation in
|
||||
return (representation, .avatar(peer: peerReference, resource: representation.resource))
|
||||
}
|
||||
} else {
|
||||
representations = []
|
||||
}
|
||||
case let .image(image, _, _, _):
|
||||
representations = image.representations.map { representation in
|
||||
return (representation, .standalone(resource: representation.resource))
|
||||
}
|
||||
representations = topRepresentations
|
||||
case let .image(_, imageRepresentations, _, _, _):
|
||||
representations = imageRepresentations
|
||||
}
|
||||
|
||||
if let largestIndex = representations.index(where: { $0.0 == largestSize }) {
|
||||
self.fetchDisposable.set(fetchedMediaResource(postbox: self.account.postbox, reference: representations[largestIndex].1).start())
|
||||
if let largestIndex = representations.index(where: { $0.representation == largestSize }) {
|
||||
self.fetchDisposable.set(fetchedMediaResource(postbox: self.account.postbox, reference: representations[largestIndex].reference).start())
|
||||
}
|
||||
default:
|
||||
break
|
||||
|
||||
@ -360,11 +360,15 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist {
|
||||
return self.messagesLocation
|
||||
}
|
||||
|
||||
var currentItemDisappeared: (() -> Void)?
|
||||
|
||||
private let navigationDisposable = MetaDisposable()
|
||||
|
||||
private var playbackStack = PlaybackStack()
|
||||
|
||||
private var currentItem: (current: Message, around: [Message])?
|
||||
private var currentlyObservedMessageId: MessageId?
|
||||
private let currentlyObservedMessageDisposable = MetaDisposable()
|
||||
private var loadingItem: Bool = false
|
||||
private var playedToEnd: Bool = false
|
||||
private var order: MusicPlaybackSettingsOrder = .regular
|
||||
@ -400,6 +404,7 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist {
|
||||
|
||||
deinit {
|
||||
self.navigationDisposable.dispose()
|
||||
self.currentlyObservedMessageDisposable.dispose()
|
||||
}
|
||||
|
||||
func control(_ action: SharedMediaPlaylistControlAction) {
|
||||
@ -481,6 +486,27 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist {
|
||||
}
|
||||
}
|
||||
self.stateValue.set(.single(SharedMediaPlaylistState(loading: self.loadingItem, playedToEnd: self.playedToEnd, item: item, nextItem: nextItem, previousItem: previousItem, order: self.order, looping: self.looping)))
|
||||
if item?.message.id != self.currentlyObservedMessageId {
|
||||
self.currentlyObservedMessageId = item?.message.id
|
||||
if let id = item?.message.id {
|
||||
let key: PostboxViewKey = .messages(Set([id]))
|
||||
self.currentlyObservedMessageDisposable.set((self.postbox.combinedView(keys: [key])
|
||||
|> filter { views in
|
||||
if let view = views.views[key] as? MessagesView {
|
||||
if !view.messages.isEmpty {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] _ in
|
||||
self?.currentItemDisappeared?()
|
||||
}))
|
||||
} else {
|
||||
self.currentlyObservedMessageDisposable.set(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func loadItem(anchor: PeerMessagesMediaPlaylistLoadAnchor, navigation: PeerMessagesMediaPlaylistNavigation) {
|
||||
|
||||
@ -1110,18 +1110,19 @@ func chatSecretPhoto(account: Account, photoReference: ImageMediaReference) -> S
|
||||
}
|
||||
}
|
||||
|
||||
private func avatarGalleryThumbnailDatas(postbox: Postbox, representations: [(TelegramMediaImageRepresentation, MediaResourceReference)], fullRepresentationSize: CGSize = CGSize(width: 1280.0, height: 1280.0), autoFetchFullSize: Bool = false) -> Signal<(Data?, Data?, Bool), NoError> {
|
||||
if let smallestRepresentation = smallestImageRepresentation(representations.map({ $0.0 })), let largestRepresentation = imageRepresentationLargerThan(representations.map({ $0.0 }), size: fullRepresentationSize), let smallestIndex = representations.index(where: { $0.0 == smallestRepresentation }), let largestIndex = representations.index(where: { $0.0 == largestRepresentation }) {
|
||||
|
||||
private func avatarGalleryThumbnailDatas(postbox: Postbox, representations: [ImageRepresentationWithReference], fullRepresentationSize: CGSize = CGSize(width: 1280.0, height: 1280.0), autoFetchFullSize: Bool = false) -> Signal<(Data?, Data?, Bool), NoError> {
|
||||
if let smallestRepresentation = smallestImageRepresentation(representations.map({ $0.representation })), let largestRepresentation = imageRepresentationLargerThan(representations.map({ $0.representation }), size: fullRepresentationSize), let smallestIndex = representations.index(where: { $0.representation == smallestRepresentation }), let largestIndex = representations.index(where: { $0.representation == largestRepresentation }) {
|
||||
let maybeFullSize = postbox.mediaBox.resourceData(largestRepresentation.resource)
|
||||
|
||||
let signal = maybeFullSize |> take(1) |> mapToSignal { maybeData -> Signal<(Data?, Data?, Bool), NoError> in
|
||||
let signal = maybeFullSize
|
||||
|> take(1)
|
||||
|> mapToSignal { maybeData -> Signal<(Data?, Data?, Bool), NoError> in
|
||||
if maybeData.complete {
|
||||
let loadedData: Data? = try? Data(contentsOf: URL(fileURLWithPath: maybeData.path), options: [])
|
||||
return .single((nil, loadedData, true))
|
||||
} else {
|
||||
let fetchedThumbnail = fetchedMediaResource(postbox: postbox, reference: representations[smallestIndex].1, statsCategory: .image)
|
||||
let fetchedFullSize = fetchedMediaResource(postbox: postbox, reference: representations[largestIndex].1, statsCategory: .image)
|
||||
let fetchedThumbnail = fetchedMediaResource(postbox: postbox, reference: representations[smallestIndex].reference, statsCategory: .image)
|
||||
let fetchedFullSize = fetchedMediaResource(postbox: postbox, reference: representations[largestIndex].reference, statsCategory: .image)
|
||||
|
||||
let thumbnail = Signal<Data?, NoError> { subscriber in
|
||||
let fetchedDisposable = fetchedThumbnail.start()
|
||||
@ -1177,7 +1178,7 @@ private func avatarGalleryThumbnailDatas(postbox: Postbox, representations: [(Te
|
||||
}
|
||||
}
|
||||
|
||||
func avatarGalleryThumbnailPhoto(account: Account, representations: [(TelegramMediaImageRepresentation, MediaResourceReference)]) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||
func avatarGalleryThumbnailPhoto(account: Account, representations: [ImageRepresentationWithReference]) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||
let signal = avatarGalleryThumbnailDatas(postbox: account.postbox, representations: representations, fullRepresentationSize: CGSize(width: 127.0, height: 127.0), autoFetchFullSize: true)
|
||||
|
||||
return signal |> map { (thumbnailData, fullSizeData, fullSizeComplete) in
|
||||
@ -2129,8 +2130,8 @@ func instantPageImageFile(account: Account, fileReference: FileMediaReference, f
|
||||
}
|
||||
}
|
||||
|
||||
private func avatarGalleryPhotoDatas(account: Account, representations: [(TelegramMediaImageRepresentation, MediaResourceReference)], autoFetchFullSize: Bool = false) -> Signal<(Data?, Data?, Bool), NoError> {
|
||||
if let smallestRepresentation = smallestImageRepresentation(representations.map({ $0.0 })), let largestRepresentation = largestImageRepresentation(representations.map({ $0.0 })), let smallestIndex = representations.index(where: { $0.0 == smallestRepresentation }), let largestIndex = representations.index(where: { $0.0 == largestRepresentation }) {
|
||||
private func avatarGalleryPhotoDatas(account: Account, representations: [ImageRepresentationWithReference], autoFetchFullSize: Bool = false) -> Signal<(Data?, Data?, Bool), NoError> {
|
||||
if let smallestRepresentation = smallestImageRepresentation(representations.map({ $0.representation })), let largestRepresentation = largestImageRepresentation(representations.map({ $0.representation })), let smallestIndex = representations.index(where: { $0.representation == smallestRepresentation }), let largestIndex = representations.index(where: { $0.representation == largestRepresentation }) {
|
||||
let maybeFullSize = account.postbox.mediaBox.resourceData(largestRepresentation.resource)
|
||||
|
||||
let signal = maybeFullSize
|
||||
@ -2140,8 +2141,8 @@ private func avatarGalleryPhotoDatas(account: Account, representations: [(Telegr
|
||||
let loadedData: Data? = try? Data(contentsOf: URL(fileURLWithPath: maybeData.path), options: [])
|
||||
return .single((nil, loadedData, true))
|
||||
} else {
|
||||
let fetchedThumbnail = fetchedMediaResource(postbox: account.postbox, reference: representations[smallestIndex].1)
|
||||
let fetchedFullSize = fetchedMediaResource(postbox: account.postbox, reference: representations[largestIndex].1)
|
||||
let fetchedThumbnail = fetchedMediaResource(postbox: account.postbox, reference: representations[smallestIndex].reference)
|
||||
let fetchedFullSize = fetchedMediaResource(postbox: account.postbox, reference: representations[largestIndex].reference)
|
||||
|
||||
let thumbnail = Signal<Data?, NoError> { subscriber in
|
||||
let fetchedDisposable = fetchedThumbnail.start()
|
||||
@ -2191,7 +2192,7 @@ private func avatarGalleryPhotoDatas(account: Account, representations: [(Telegr
|
||||
}
|
||||
}
|
||||
|
||||
func chatAvatarGalleryPhoto(account: Account, representations: [(TelegramMediaImageRepresentation, MediaResourceReference)], autoFetchFullSize: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||
func chatAvatarGalleryPhoto(account: Account, representations: [ImageRepresentationWithReference], autoFetchFullSize: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||
let signal = avatarGalleryPhotoDatas(account: account, representations: representations, autoFetchFullSize: autoFetchFullSize)
|
||||
|
||||
return signal
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -270,8 +270,12 @@ public final class SecretMediaPreviewController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
if let _ = media as? TelegramMediaFile {
|
||||
if let file = media as? TelegramMediaFile {
|
||||
if file.isAnimated {
|
||||
strongSelf.title = strongSelf.presentationData.strings.Message_Animation
|
||||
} else {
|
||||
strongSelf.title = strongSelf.presentationData.strings.Message_Video
|
||||
}
|
||||
} else {
|
||||
strongSelf.title = strongSelf.presentationData.strings.Message_Photo
|
||||
}
|
||||
@ -289,8 +293,12 @@ public final class SecretMediaPreviewController: ViewController {
|
||||
let contentNode = SecretMediaPreviewFooterContentNode()
|
||||
let peerTitle = messageMainPeer(message)?.compactDisplayTitle ?? ""
|
||||
let text: String
|
||||
if let _ = media as? TelegramMediaFile {
|
||||
if let file = media as? TelegramMediaFile {
|
||||
if file.isAnimated {
|
||||
text = strongSelf.presentationData.strings.SecretGIF_NotViewedYet(peerTitle).0
|
||||
} else {
|
||||
text = strongSelf.presentationData.strings.SecretVideo_NotViewedYet(peerTitle).0
|
||||
}
|
||||
} else {
|
||||
text = strongSelf.presentationData.strings.SecretImage_NotViewedYet(peerTitle).0
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ public class SecureIdLocalImageResource: TelegramMediaResource {
|
||||
return SecureIdLocalImageResourceId(id: self.localId)
|
||||
}
|
||||
|
||||
public func isEqual(to: TelegramMediaResource) -> Bool {
|
||||
public func isEqual(to: MediaResource) -> Bool {
|
||||
if let to = to as? SecureIdLocalImageResource {
|
||||
return self.localId == to.localId && self.source.isEqual(to:to.source)
|
||||
} else {
|
||||
|
||||
@ -497,7 +497,7 @@ public func settingsController(account: Account, accountManager: AccountManager)
|
||||
|
||||
})
|
||||
hiddenAvatarRepresentationDisposable.set((galleryController.hiddenMedia |> deliverOnMainQueue).start(next: { entry in
|
||||
avatarAndNameInfoContext.hiddenAvatarRepresentation = entry?.representations.first
|
||||
avatarAndNameInfoContext.hiddenAvatarRepresentation = entry?.representations.first?.representation
|
||||
updateHiddenAvatarImpl?()
|
||||
}))
|
||||
presentControllerImpl?(galleryController, AvatarGalleryControllerPresentationArguments(transitionArguments: { entry in
|
||||
|
||||
@ -47,7 +47,7 @@ final class SettingsThemeWallpaperNode: ASDisplayNode {
|
||||
self.imageNode.isHidden = false
|
||||
self.backgroundNode.isHidden = true
|
||||
|
||||
let convertedRepresentations: [(TelegramMediaImageRepresentation, MediaResourceReference)] = representations.map({ ($0, .wallpaper(resource: $0.resource)) })
|
||||
let convertedRepresentations: [ImageRepresentationWithReference] = representations.map({ ImageRepresentationWithReference(representation: $0, reference: .wallpaper(resource: $0.resource)) })
|
||||
self.imageNode.setSignal(chatAvatarGalleryPhoto(account: account, representations: convertedRepresentations, autoFetchFullSize: true))
|
||||
let apply = self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: largestImageRepresentation(representations)!.dimensions.aspectFilled(size), boundingSize: size, intrinsicInsets: UIEdgeInsets()))
|
||||
apply()
|
||||
|
||||
@ -27,7 +27,7 @@ public enum ShareControllerSubject {
|
||||
case text(String)
|
||||
case quote(text: String, url: String)
|
||||
case messages([Message])
|
||||
case image([TelegramMediaImageRepresentation])
|
||||
case image([ImageRepresentationWithReference])
|
||||
case media(AnyMediaReference)
|
||||
case mapMedia(TelegramMediaMap)
|
||||
case fromExternal(([PeerId], String) -> Signal<ShareControllerExternalStatus, NoError>)
|
||||
@ -220,7 +220,7 @@ public final class ShareController: ViewController {
|
||||
case let .image(representations):
|
||||
if case .saveToCameraRoll = preferredAction {
|
||||
self.defaultAction = ShareControllerAction(title: self.presentationData.strings.Preview_SaveToCameraRoll, action: { [weak self] in
|
||||
self?.saveToCameraRoll(image: representations)
|
||||
self?.saveToCameraRoll(representations: representations)
|
||||
})
|
||||
}
|
||||
case let .media(mediaReference):
|
||||
@ -358,7 +358,7 @@ public final class ShareController: ViewController {
|
||||
if !text.isEmpty {
|
||||
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
|
||||
}
|
||||
messages.append(.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64()), representations: representations, reference: nil, partialReference: nil)), replyToMessageId: nil, localGroupingKey: nil))
|
||||
messages.append(.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64()), representations: representations.map({ $0.representation }), reference: nil, partialReference: nil)), replyToMessageId: nil, localGroupingKey: nil))
|
||||
let _ = enqueueMessages(account: strongSelf.account, peerId: peerId, messages: messages).start()
|
||||
}
|
||||
return .complete()
|
||||
@ -421,7 +421,7 @@ public final class ShareController: ViewController {
|
||||
case let .quote(text, url):
|
||||
collectableItems.append(CollectableExternalShareItem(url: "", text: "\"\(text)\"\n\n\(url)", mediaReference: nil))
|
||||
case let .image(representations):
|
||||
let media = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64()), representations: representations, reference: nil, partialReference: nil)
|
||||
let media = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64()), representations: representations.map({ $0.representation }), reference: nil, partialReference: nil)
|
||||
collectableItems.append(CollectableExternalShareItem(url: "", text: "", mediaReference: .standalone(media: media)))
|
||||
case let .media(mediaReference):
|
||||
collectableItems.append(CollectableExternalShareItem(url: "", text: "", mediaReference: mediaReference))
|
||||
@ -543,8 +543,8 @@ public final class ShareController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
private func saveToCameraRoll(image: [TelegramMediaImageRepresentation]) {
|
||||
let media = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: image, reference: nil, partialReference: nil)
|
||||
private func saveToCameraRoll(representations: [ImageRepresentationWithReference]) {
|
||||
let media = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: representations.map({ $0.representation }), reference: nil, partialReference: nil)
|
||||
self.controllerNode.transitionToProgress(signal: TelegramUI.saveToCameraRoll(applicationContext: self.account.telegramApplicationContext, postbox: self.account.postbox, mediaReference: .standalone(media: media)))
|
||||
}
|
||||
|
||||
|
||||
@ -189,11 +189,12 @@ protocol SharedMediaPlaylistLocation {
|
||||
func isEqual(to: SharedMediaPlaylistLocation) -> Bool
|
||||
}
|
||||
|
||||
protocol SharedMediaPlaylist {
|
||||
protocol SharedMediaPlaylist: class {
|
||||
var id: SharedMediaPlaylistId { get }
|
||||
var location: SharedMediaPlaylistLocation { get }
|
||||
var state: Signal<SharedMediaPlaylistState, NoError> { get }
|
||||
var looping: MusicPlaybackSettingsLooping { get }
|
||||
var currentItemDisappeared: (() -> Void)? { get set }
|
||||
|
||||
func control(_ action: SharedMediaPlaylistControlAction)
|
||||
func setOrder(_ order: MusicPlaybackSettingsOrder)
|
||||
@ -405,6 +406,7 @@ final class SharedMediaPlayer {
|
||||
private let markItemAsPlayedDisposable = MetaDisposable()
|
||||
|
||||
var playedToEnd: (() -> Void)?
|
||||
var cancelled: (() -> Void)?
|
||||
|
||||
private var inForegroundDisposable: Disposable?
|
||||
|
||||
@ -427,6 +429,10 @@ final class SharedMediaPlayer {
|
||||
self.forceAudioToSpeaker = !DeviceProximityManager.shared().currentValue()
|
||||
}
|
||||
|
||||
playlist.currentItemDisappeared = { [weak self] in
|
||||
self?.cancelled?()
|
||||
}
|
||||
|
||||
self.stateDisposable = (playlist.state
|
||||
|> deliverOnMainQueue).start(next: { [weak self] state in
|
||||
if let strongSelf = self {
|
||||
|
||||
@ -219,7 +219,7 @@ private final class LegacyComponentsGlobalsProviderImpl: NSObject, LegacyCompone
|
||||
let convertedType: ManagedAudioSessionType
|
||||
switch type {
|
||||
case TGAudioSessionTypePlayAndRecord, TGAudioSessionTypePlayAndRecordHeadphones:
|
||||
convertedType = .record
|
||||
convertedType = .record(speaker: false)
|
||||
default:
|
||||
convertedType = .play
|
||||
}
|
||||
|
||||
@ -95,12 +95,12 @@ final class ThemeGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
let displaySize = largestSize.dimensions.fitted(CGSize(width: 1280.0, height: 1280.0)).dividedByScreenScale().integralFloor
|
||||
self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: displaySize, boundingSize: displaySize, intrinsicInsets: UIEdgeInsets()))()
|
||||
|
||||
let convertedRepresentations: [(TelegramMediaImageRepresentation, MediaResourceReference)] = representations.map({ ($0, .wallpaper(resource: $0.resource)) })
|
||||
let convertedRepresentations: [ImageRepresentationWithReference] = representations.map({ ImageRepresentationWithReference(representation: $0, reference: .wallpaper(resource: $0.resource)) })
|
||||
self.imageNode.setSignal(chatAvatarGalleryPhoto(account: account, representations: convertedRepresentations), dispatchOnDisplayLink: false)
|
||||
self.zoomableContent = (largestSize.dimensions, self.imageNode)
|
||||
|
||||
if let largestIndex = convertedRepresentations.index(where: { $0.0 == largestSize }) {
|
||||
self.fetchDisposable.set(fetchedMediaResource(postbox: self.account.postbox, reference: convertedRepresentations[largestIndex].1).start())
|
||||
if let largestIndex = convertedRepresentations.index(where: { $0.representation == largestSize }) {
|
||||
self.fetchDisposable.set(fetchedMediaResource(postbox: self.account.postbox, reference: convertedRepresentations[largestIndex].reference).start())
|
||||
}
|
||||
} else {
|
||||
self._ready.set(.single(Void()))
|
||||
|
||||
@ -426,7 +426,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
strongSelf.fetchStatus = fetchStatus
|
||||
|
||||
if !item.hideControls {
|
||||
strongSelf.statusButtonNode.isHidden = !initialBuffering && (strongSelf.didPause || !isPaused || value == nil) && !fetching
|
||||
strongSelf.statusButtonNode.isHidden = !initialBuffering && (strongSelf.didPause || !isPaused) && !fetching
|
||||
}
|
||||
|
||||
if isAnimated || disablePlayerControls {
|
||||
|
||||
@ -840,7 +840,7 @@ public func userInfoController(account: Account, peerId: PeerId, mode: UserInfoC
|
||||
let galleryController = AvatarGalleryController(account: account, peer: peer, remoteEntries: cachedAvatarEntries.with { $0 }, replaceRootController: { controller, ready in
|
||||
})
|
||||
hiddenAvatarRepresentationDisposable.set((galleryController.hiddenMedia |> deliverOnMainQueue).start(next: { entry in
|
||||
avatarAndNameInfoContext.hiddenAvatarRepresentation = entry?.representations.first
|
||||
avatarAndNameInfoContext.hiddenAvatarRepresentation = entry?.representations.first?.representation
|
||||
updateHiddenAvatarImpl?()
|
||||
}))
|
||||
presentControllerImpl?(galleryController, AvatarGalleryControllerPresentationArguments(transitionArguments: { entry in
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user