Sharing refactoring

This commit is contained in:
Ali 2023-08-15 23:57:04 +04:00
parent 1faf0a9d39
commit 77a5857a25
137 changed files with 3604 additions and 1815 deletions

View File

@ -1191,7 +1191,8 @@ swift_library(
"-warnings-as-errors",
],
deps = [
"//submodules/TelegramUI:TelegramUI"
"//submodules/TelegramUI:TelegramUI",
"//submodules/TelegramUI/Components/ShareExtensionContext"
],
)

View File

@ -1,6 +1,7 @@
import UIKit
import TelegramUI
import BuildConfig
import ShareExtensionContext
@objc(ShareRootController)
class ShareRootController: UIViewController {

View File

@ -9856,3 +9856,6 @@ Sorry for the inconvenience.";
"Location.TypeCity" = "City";
"Location.TypeStreet" = "Street";
"Location.TypeLocation" = "Location";
"Story.ViewList.ViewerCount_1" = "1 Viewer";
"Story.ViewList.ViewerCount_any" = "%d Viewers";

View File

@ -659,6 +659,9 @@ public protocol ChatController: ViewController {
var purposefulAction: (() -> Void)? { get set }
var selectedMessageIds: Set<EngineMessage.Id>? { get }
var presentationInterfaceStateSignal: Signal<Any, NoError> { get }
func updatePresentationMode(_ mode: ChatControllerPresentationMode)
func beginMessageSearch(_ query: String)
func displayPromoAnnouncement(text: String)

View File

@ -20,6 +20,10 @@ public func freeMediaFileResourceInteractiveFetched(account: Account, userLocati
return fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: userLocation, userContentType: MediaResourceUserContentType(file: fileReference.media), reference: fileReference.resourceReference(resource))
}
public func freeMediaFileResourceInteractiveFetched(postbox: Postbox, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference, resource: MediaResource) -> Signal<FetchResourceSourceType, FetchResourceError> {
return fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: MediaResourceUserContentType(file: fileReference.media), reference: fileReference.resourceReference(resource))
}
public func cancelFreeMediaFileInteractiveFetch(account: Account, file: TelegramMediaFile) {
account.postbox.mediaBox.cancelInteractiveResourceFetch(file.resource)
}

View File

@ -2,7 +2,10 @@ import Foundation
import Display
import SwiftSignalKit
import TelegramCore
import Postbox
import TelegramPresentationData
import AnimationCache
import MultiAnimationRenderer
public struct ChatListNodePeersFilter: OptionSet {
public var rawValue: Int32
@ -56,7 +59,68 @@ public final class PeerSelectionControllerParams {
public let selectForumThreads: Bool
public let hasCreation: Bool
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, filter: ChatListNodePeersFilter = [.onlyWriteable], requestPeerType: [ReplyMarkupButtonRequestPeerType]? = nil, forumPeerId: EnginePeer.Id? = nil, hasFilters: Bool = false, hasChatListSelector: Bool = true, hasContactSelector: Bool = true, hasGlobalSearch: Bool = true, title: String? = nil, attemptSelection: ((EnginePeer, Int64?) -> Void)? = nil, createNewGroup: (() -> Void)? = nil, pretendPresentedInModal: Bool = false, multipleSelection: Bool = false, forwardedMessageIds: [EngineMessage.Id] = [], hasTypeHeaders: Bool = false, selectForumThreads: Bool = false, hasCreation: Bool = false) {
/*public convenience init(
context: AccountContext,
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil,
filter: ChatListNodePeersFilter = [.onlyWriteable],
requestPeerType: [ReplyMarkupButtonRequestPeerType]? = nil,
forumPeerId: EnginePeer.Id? = nil,
hasFilters: Bool = false,
hasChatListSelector: Bool = true,
hasContactSelector: Bool = true,
hasGlobalSearch: Bool = true,
title: String? = nil,
attemptSelection: ((EnginePeer, Int64?) -> Void)? = nil,
createNewGroup: (() -> Void)? = nil,
pretendPresentedInModal: Bool = false,
multipleSelection: Bool = false,
forwardedMessageIds: [EngineMessage.Id] = [],
hasTypeHeaders: Bool = false,
selectForumThreads: Bool = false,
hasCreation: Bool = false
) {
self.init(
context: .account(context),
updatedPresentationData: updatedPresentationData,
filter: filter,
requestPeerType: requestPeerType,
forumPeerId: forumPeerId,
hasFilters: hasFilters,
hasChatListSelector: hasChatListSelector,
hasContactSelector: hasContactSelector,
hasGlobalSearch: hasGlobalSearch,
title: title,
attemptSelection: attemptSelection,
createNewGroup: createNewGroup,
pretendPresentedInModal: pretendPresentedInModal,
multipleSelection: multipleSelection,
forwardedMessageIds: forwardedMessageIds,
hasTypeHeaders: hasTypeHeaders,
selectForumThreads: selectForumThreads,
hasCreation: hasCreation
)
}*/
public init(
context: AccountContext,
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil,
filter: ChatListNodePeersFilter = [.onlyWriteable],
requestPeerType: [ReplyMarkupButtonRequestPeerType]? = nil,
forumPeerId: EnginePeer.Id? = nil,
hasFilters: Bool = false,
hasChatListSelector: Bool = true,
hasContactSelector: Bool = true,
hasGlobalSearch: Bool = true,
title: String? = nil,
attemptSelection: ((EnginePeer, Int64?) -> Void)? = nil,
createNewGroup: (() -> Void)? = nil,
pretendPresentedInModal: Bool = false,
multipleSelection: Bool = false,
forwardedMessageIds: [EngineMessage.Id] = [],
hasTypeHeaders: Bool = false,
selectForumThreads: Bool = false,
hasCreation: Bool = false
) {
self.context = context
self.updatedPresentationData = updatedPresentationData
self.filter = filter
@ -85,6 +149,39 @@ public enum AttachmentTextInputPanelSendMode {
case whenOnline
}
public enum PeerSelectionControllerContext {
public final class Custom {
public let accountPeerId: EnginePeer.Id
public let postbox: Postbox
public let network: Network
public let animationCache: AnimationCache
public let animationRenderer: MultiAnimationRenderer
public let presentationData: PresentationData
public let updatedPresentationData: Signal<PresentationData, NoError>
public init(
accountPeerId: EnginePeer.Id,
postbox: Postbox,
network: Network,
animationCache: AnimationCache,
animationRenderer: MultiAnimationRenderer,
presentationData: PresentationData,
updatedPresentationData: Signal<PresentationData, NoError>
) {
self.accountPeerId = accountPeerId
self.postbox = postbox
self.network = network
self.animationCache = animationCache
self.animationRenderer = animationRenderer
self.presentationData = presentationData
self.updatedPresentationData = updatedPresentationData
}
}
case account(AccountContext)
case custom(Custom)
}
public protocol PeerSelectionController: ViewController {
var peerSelected: ((EnginePeer, Int64?) -> Void)? { get set }
var multiplePeersSelected: (([EnginePeer], [EnginePeer.Id: EnginePeer], NSAttributedString, AttachmentTextInputPanelSendMode, ChatInterfaceForwardOptionsState?) -> Void)? { get set }

View File

@ -11,6 +11,7 @@ swift_library(
],
deps = [
"//submodules/TelegramCore:TelegramCore",
"//submodules/Postbox",
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
"//submodules/Display:Display",
"//submodules/AvatarNode:AvatarNode",

View File

@ -3,12 +3,16 @@ import UIKit
import AsyncDisplayKit
import Display
import TelegramCore
import Postbox
import TelegramPresentationData
import AvatarNode
import AccountContext
public class ActionSheetPeerItem: ActionSheetItem {
public let context: AccountContext
public let accountPeerId: EnginePeer.Id
public let postbox: Postbox
public let network: Network
public let contentSettings: ContentSettings
public let peer: EnginePeer
public let theme: PresentationTheme
public let title: String
@ -16,8 +20,37 @@ public class ActionSheetPeerItem: ActionSheetItem {
public let strings: PresentationStrings
public let action: () -> Void
public init(context: AccountContext, peer: EnginePeer, title: String, isSelected: Bool, strings: PresentationStrings, theme: PresentationTheme, action: @escaping () -> Void) {
self.context = context
public convenience init(context: AccountContext, peer: EnginePeer, title: String, isSelected: Bool, strings: PresentationStrings, theme: PresentationTheme, action: @escaping () -> Void) {
self.init(
accountPeerId: context.account.peerId,
postbox: context.account.postbox,
network: context.account.network,
contentSettings: context.currentContentSettings.with { $0 },
peer: peer,
title: title,
isSelected: isSelected,
strings: strings,
theme: theme,
action: action
)
}
public init(
accountPeerId: EnginePeer.Id,
postbox: Postbox,
network: Network,
contentSettings: ContentSettings,
peer: EnginePeer,
title: String,
isSelected: Bool,
strings: PresentationStrings,
theme: PresentationTheme,
action: @escaping () -> Void
) {
self.accountPeerId = accountPeerId
self.postbox = postbox
self.network = network
self.contentSettings = contentSettings
self.peer = peer
self.title = title
self.isSelected = isSelected
@ -121,7 +154,7 @@ public class ActionSheetPeerItemNode: ActionSheetItemNode {
let textColor: UIColor = self.theme.primaryTextColor
self.label.attributedText = NSAttributedString(string: item.title, font: defaultFont, textColor: textColor)
self.avatarNode.setPeer(context: item.context, theme: item.theme, peer: item.peer)
self.avatarNode.setPeer(accountPeerId: item.accountPeerId, postbox: item.postbox, network: item.network, contentSettings: item.contentSettings, theme: item.theme, peer: item.peer)
self.checkNode.isHidden = !item.isSelected

View File

@ -1061,7 +1061,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
avatarVideo = Signal<TelegramMediaResource?, NoError> { subscriber in
let entityRenderer: LegacyPaintEntityRenderer? = avatarAdjustments.flatMap { adjustments in
if let paintingData = adjustments.paintingData, paintingData.hasAnimation {
return LegacyPaintEntityRenderer(account: nil, adjustments: adjustments)
return LegacyPaintEntityRenderer(postbox: nil, adjustments: adjustments)
} else {
return nil
}

View File

@ -13,6 +13,7 @@ swift_library(
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
"//submodules/Display:Display",
"//submodules/TelegramCore:TelegramCore",
"//submodules/Postbox",
"//submodules/TelegramPresentationData:TelegramPresentationData",
"//submodules/AnimationUI:AnimationUI",
"//submodules/AppBundle:AppBundle",

View File

@ -3,6 +3,7 @@ import UIKit
import AsyncDisplayKit
import Display
import TelegramCore
import Postbox
import SwiftSignalKit
import TelegramPresentationData
import AnimationUI
@ -381,6 +382,120 @@ public final class AvatarNode: ASDisplayNode {
self.imageNode.isHidden = true
}
public func setPeer(
accountPeerId: EnginePeer.Id,
postbox: Postbox,
network: Network,
contentSettings: ContentSettings,
theme: PresentationTheme,
peer: EnginePeer?,
authorOfMessage: MessageReference? = nil,
overrideImage: AvatarNodeImageOverride? = nil,
emptyColor: UIColor? = nil,
clipStyle: AvatarNodeClipStyle = .round,
synchronousLoad: Bool = false,
displayDimensions: CGSize = CGSize(width: 60.0, height: 60.0),
storeUnrounded: Bool = false
) {
var synchronousLoad = synchronousLoad
var representation: TelegramMediaImageRepresentation?
var icon = AvatarNodeIcon.none
if let overrideImage = overrideImage {
switch overrideImage {
case .none:
representation = nil
case let .image(image):
representation = image
synchronousLoad = false
case .savedMessagesIcon:
representation = nil
icon = .savedMessagesIcon
case .repliesIcon:
representation = nil
icon = .repliesIcon
case let .archivedChatsIcon(hiddenByDefault):
representation = nil
icon = .archivedChatsIcon(hiddenByDefault: hiddenByDefault)
case let .editAvatarIcon(forceNone):
representation = forceNone ? nil : peer?.smallProfileImage
icon = .editAvatarIcon
case .deletedIcon:
representation = nil
icon = .deletedIcon
case .phoneIcon:
representation = nil
icon = .phoneIcon
}
} else if peer?.restrictionText(platform: "ios", contentSettings: contentSettings) == nil {
representation = peer?.smallProfileImage
}
let updatedState: AvatarNodeState = .peerAvatar(peer?.id ?? EnginePeer.Id(0), peer?.displayLetters ?? [], representation, clipStyle)
if updatedState != self.state || overrideImage != self.overrideImage || theme !== self.theme {
self.state = updatedState
self.overrideImage = overrideImage
self.theme = theme
let parameters: AvatarNodeParameters
if let peer = peer, let signal = peerAvatarImage(postbox: postbox, network: network, peerReference: PeerReference(peer._asPeer()), authorOfMessage: authorOfMessage, representation: representation, displayDimensions: displayDimensions, clipStyle: clipStyle, emptyColor: emptyColor, synchronousLoad: synchronousLoad, provideUnrounded: storeUnrounded) {
self.contents = nil
self.displaySuspended = true
self.imageReady.set(self.imageNode.contentReady)
self.imageNode.setSignal(signal |> beforeNext { [weak self] next in
Queue.mainQueue().async {
self?.unroundedImage = next?.1
}
}
|> map { next -> UIImage? in
return next?.0
})
if case .editAvatarIcon = icon {
if self.editOverlayNode == nil {
let editOverlayNode = AvatarEditOverlayNode()
editOverlayNode.frame = self.imageNode.frame
editOverlayNode.isUserInteractionEnabled = false
self.addSubnode(editOverlayNode)
self.editOverlayNode = editOverlayNode
}
self.editOverlayNode?.isHidden = false
} else {
self.editOverlayNode?.isHidden = true
}
parameters = AvatarNodeParameters(theme: theme, accountPeerId: accountPeerId, peerId: peer.id, colors: calculateColors(explicitColorIndex: nil, peerId: peer.id, icon: icon, theme: theme), letters: peer.displayLetters, font: self.font, icon: icon, explicitColorIndex: nil, hasImage: true, clipStyle: clipStyle)
} else {
self.imageReady.set(.single(true))
self.displaySuspended = false
if self.isNodeLoaded {
self.imageNode.contents = nil
}
self.editOverlayNode?.isHidden = true
let colors = calculateColors(explicitColorIndex: nil, peerId: peer?.id ?? EnginePeer.Id(0), icon: icon, theme: theme)
parameters = AvatarNodeParameters(theme: theme, accountPeerId: accountPeerId, peerId: peer?.id ?? EnginePeer.Id(0), colors: colors, letters: peer?.displayLetters ?? [], font: self.font, icon: icon, explicitColorIndex: nil, hasImage: false, clipStyle: clipStyle)
if let badgeView = self.badgeView {
let badgeColor: UIColor
if colors.isEmpty {
badgeColor = .white
} else {
badgeColor = colors[colors.count - 1]
}
badgeView.update(content: .color(badgeColor))
}
}
if self.parameters == nil || self.parameters != parameters {
self.parameters = parameters
self.setNeedsDisplay()
if synchronousLoad {
self.recursivelyEnsureDisplaySynchronously(true)
}
}
}
}
public func setPeer(
context genericContext: AccountContext,
account: Account? = nil,
@ -778,6 +893,38 @@ public final class AvatarNode: ASDisplayNode {
self.contentNode.playArchiveAnimation()
}
public func setPeer(
accountPeerId: EnginePeer.Id,
postbox: Postbox,
network: Network,
contentSettings: ContentSettings,
theme: PresentationTheme,
peer: EnginePeer?,
authorOfMessage: MessageReference? = nil,
overrideImage: AvatarNodeImageOverride? = nil,
emptyColor: UIColor? = nil,
clipStyle: AvatarNodeClipStyle = .round,
synchronousLoad: Bool = false,
displayDimensions: CGSize = CGSize(width: 60.0, height: 60.0),
storeUnrounded: Bool = false
) {
self.contentNode.setPeer(
accountPeerId: accountPeerId,
postbox: postbox,
network: network,
contentSettings: contentSettings,
theme: theme,
peer: peer,
authorOfMessage: authorOfMessage,
overrideImage: overrideImage,
emptyColor: emptyColor,
clipStyle: clipStyle,
synchronousLoad: synchronousLoad,
displayDimensions: displayDimensions,
storeUnrounded: storeUnrounded
)
}
public func setPeer(
context: AccountContext,
account: Account? = nil,

View File

@ -6,6 +6,7 @@ import ImageIO
import TelegramCore
import TinyThumbnail
import FastBlur
import Postbox
private let roundCorners = { () -> UIImage in
let diameter: CGFloat = 60.0
@ -27,8 +28,12 @@ public enum PeerAvatarImageType {
}
public func peerAvatarImageData(account: Account, peerReference: PeerReference?, authorOfMessage: MessageReference?, representation: TelegramMediaImageRepresentation?, synchronousLoad: Bool) -> Signal<(Data, PeerAvatarImageType)?, NoError>? {
return peerAvatarImageData(postbox: account.postbox, network: account.network, peerReference: peerReference, authorOfMessage: authorOfMessage, representation: representation, synchronousLoad: synchronousLoad)
}
public func peerAvatarImageData(postbox: Postbox, network: Network, peerReference: PeerReference?, authorOfMessage: MessageReference?, representation: TelegramMediaImageRepresentation?, synchronousLoad: Bool) -> Signal<(Data, PeerAvatarImageType)?, NoError>? {
if let smallProfileImage = representation {
let resourceData = account.postbox.mediaBox.resourceData(smallProfileImage.resource, attemptSynchronously: synchronousLoad)
let resourceData = postbox.mediaBox.resourceData(smallProfileImage.resource, attemptSynchronously: synchronousLoad)
let imageData = resourceData
|> take(1)
|> mapToSignal { maybeData -> Signal<(Data, PeerAvatarImageType)?, NoError> in
@ -65,11 +70,11 @@ public func peerAvatarImageData(account: Account, peerReference: PeerReference?,
})
var fetchedDataDisposable: Disposable?
if let peerReference = peerReference {
fetchedDataDisposable = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: .avatar, reference: .avatar(peer: peerReference, resource: smallProfileImage.resource), statsCategory: .generic).start()
fetchedDataDisposable = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: .other, userContentType: .avatar, reference: .avatar(peer: peerReference, resource: smallProfileImage.resource), statsCategory: .generic).start()
} else if let authorOfMessage = authorOfMessage {
fetchedDataDisposable = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: .avatar, reference: .messageAuthorAvatar(message: authorOfMessage, resource: smallProfileImage.resource), statsCategory: .generic).start()
fetchedDataDisposable = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: .other, userContentType: .avatar, reference: .messageAuthorAvatar(message: authorOfMessage, resource: smallProfileImage.resource), statsCategory: .generic).start()
} else {
fetchedDataDisposable = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: .avatar, reference: .standalone(resource: smallProfileImage.resource), statsCategory: .generic).start()
fetchedDataDisposable = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: .other, userContentType: .avatar, reference: .standalone(resource: smallProfileImage.resource), statsCategory: .generic).start()
}
return ActionDisposable {
resourceDataDisposable.dispose()
@ -85,6 +90,22 @@ public func peerAvatarImageData(account: Account, peerReference: PeerReference?,
}
public func peerAvatarCompleteImage(account: Account, peer: EnginePeer, forceProvidedRepresentation: Bool = false, representation: TelegramMediaImageRepresentation? = nil, size: CGSize, round: Bool = true, font: UIFont = avatarPlaceholderFont(size: 13.0), drawLetters: Bool = true, fullSize: Bool = false, blurred: Bool = false) -> Signal<UIImage?, NoError> {
return peerAvatarCompleteImage(
postbox: account.postbox,
network: account.network,
peer: peer,
forceProvidedRepresentation: forceProvidedRepresentation,
representation: representation,
size: size,
round: round,
font: font,
drawLetters: drawLetters,
fullSize: fullSize,
blurred: blurred
)
}
public func peerAvatarCompleteImage(postbox: Postbox, network: Network, peer: EnginePeer, forceProvidedRepresentation: Bool = false, representation: TelegramMediaImageRepresentation? = nil, size: CGSize, round: Bool = true, font: UIFont = avatarPlaceholderFont(size: 13.0), drawLetters: Bool = true, fullSize: Bool = false, blurred: Bool = false) -> Signal<UIImage?, NoError> {
let iconSignal: Signal<UIImage?, NoError>
let clipStyle: AvatarNodeClipStyle
@ -105,8 +126,8 @@ public func peerAvatarCompleteImage(account: Account, peer: EnginePeer, forcePro
thumbnailRepresentation = peer.profileImageRepresentations.first
}
if let signal = peerAvatarImage(account: account, peerReference: PeerReference(peer._asPeer()), authorOfMessage: nil, representation: thumbnailRepresentation, displayDimensions: size, clipStyle: clipStyle, blurred: blurred, inset: 0.0, emptyColor: nil, synchronousLoad: fullSize) {
if fullSize, let fullSizeSignal = peerAvatarImage(account: account, peerReference: PeerReference(peer._asPeer()), authorOfMessage: nil, representation: peer.profileImageRepresentations.last, displayDimensions: size, emptyColor: nil, synchronousLoad: true) {
if let signal = peerAvatarImage(postbox: postbox, network: network, peerReference: PeerReference(peer._asPeer()), authorOfMessage: nil, representation: thumbnailRepresentation, displayDimensions: size, clipStyle: clipStyle, blurred: blurred, inset: 0.0, emptyColor: nil, synchronousLoad: fullSize) {
if fullSize, let fullSizeSignal = peerAvatarImage(postbox: postbox, network: network, peerReference: PeerReference(peer._asPeer()), authorOfMessage: nil, representation: peer.profileImageRepresentations.last, displayDimensions: size, emptyColor: nil, synchronousLoad: true) {
iconSignal = combineLatest(.single(nil) |> then(signal), .single(nil) |> then(fullSizeSignal))
|> mapToSignal { thumbnailImage, fullSizeImage -> Signal<UIImage?, NoError> in
if let fullSizeImage = fullSizeImage {
@ -151,7 +172,24 @@ public func peerAvatarCompleteImage(account: Account, peer: EnginePeer, forcePro
}
public func peerAvatarImage(account: Account, peerReference: PeerReference?, authorOfMessage: MessageReference?, representation: TelegramMediaImageRepresentation?, displayDimensions: CGSize = CGSize(width: 60.0, height: 60.0), clipStyle: AvatarNodeClipStyle = .round, blurred: Bool = false, inset: CGFloat = 0.0, emptyColor: UIColor? = nil, synchronousLoad: Bool = false, provideUnrounded: Bool = false) -> Signal<(UIImage, UIImage)?, NoError>? {
if let imageData = peerAvatarImageData(account: account, peerReference: peerReference, authorOfMessage: authorOfMessage, representation: representation, synchronousLoad: synchronousLoad) {
return peerAvatarImage(
postbox: account.postbox,
network: account.network,
peerReference: peerReference,
authorOfMessage: authorOfMessage,
representation: representation,
displayDimensions: displayDimensions,
clipStyle: clipStyle,
blurred: blurred,
inset: inset,
emptyColor: emptyColor,
synchronousLoad: synchronousLoad,
provideUnrounded: synchronousLoad
)
}
public func peerAvatarImage(postbox: Postbox, network: Network, peerReference: PeerReference?, authorOfMessage: MessageReference?, representation: TelegramMediaImageRepresentation?, displayDimensions: CGSize = CGSize(width: 60.0, height: 60.0), clipStyle: AvatarNodeClipStyle = .round, blurred: Bool = false, inset: CGFloat = 0.0, emptyColor: UIColor? = nil, synchronousLoad: Bool = false, provideUnrounded: Bool = false) -> Signal<(UIImage, UIImage)?, NoError>? {
if let imageData = peerAvatarImageData(postbox: postbox, network: network, peerReference: peerReference, authorOfMessage: authorOfMessage, representation: representation, synchronousLoad: synchronousLoad) {
return imageData
|> mapToSignal { data -> Signal<(UIImage, UIImage)?, NoError> in
let generate = deferred { () -> Signal<(UIImage, UIImage)?, NoError> in

View File

@ -537,7 +537,7 @@ public class BrowserScreen: ViewController {
action(.default)
}))]
let contextController = ContextController(account: self.context.account, presentationData: self.presentationData, source: source, items: .single(ContextController.Items(content: .list(items))))
let contextController = ContextController(presentationData: self.presentationData, source: source, items: .single(ContextController.Items(content: .list(items))))
self.controller?.present(contextController, in: .window(.root))
})
}

View File

@ -377,7 +377,7 @@ public final class CallListController: TelegramBaseController {
}
}
let contextController = ContextController(account: self.context.account, presentationData: self.presentationData, source: .extracted(ExtractedContentSourceImpl(controller: self, sourceNode: buttonNode.contentNode, keepInPlace: false, blurBackground: false)), items: .single(ContextController.Items(content: .list(items))), gesture: nil)
let contextController = ContextController(presentationData: self.presentationData, source: .extracted(ExtractedContentSourceImpl(controller: self, sourceNode: buttonNode.contentNode, keepInPlace: false, blurBackground: false)), items: .single(ContextController.Items(content: .list(items))), gesture: nil)
self.presentInGlobalOverlay(contextController)
}
@ -500,7 +500,7 @@ public final class CallListController: TelegramBaseController {
})
})))
let controller = ContextController(account: self.context.account, presentationData: self.presentationData, source: .extracted(CallListTabBarContextExtractedContentSource(controller: self, sourceNode: sourceNode)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
let controller = ContextController(presentationData: self.presentationData, source: .extracted(CallListTabBarContextExtractedContentSource(controller: self, sourceNode: sourceNode)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
self.context.sharedContext.mainWindow?.presentInGlobalOverlay(controller)
}
}

View File

@ -14,12 +14,16 @@ swift_library(
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
"//submodules/Display:Display",
"//submodules/TelegramCore:TelegramCore",
"//submodules/Postbox",
"//submodules/ListSectionHeaderNode:ListSectionHeaderNode",
"//submodules/HorizontalPeerItem:HorizontalPeerItem",
"//submodules/MergeLists:MergeLists",
"//submodules/TelegramPresentationData:TelegramPresentationData",
"//submodules/ContextUI:ContextUI",
"//submodules/AccountContext:AccountContext",
"//submodules/TelegramUIPreferences",
"//submodules/TelegramUI/Components/AnimationCache",
"//submodules/TelegramUI/Components/MultiAnimationRenderer",
],
visibility = [
"//visibility:public",

View File

@ -4,12 +4,16 @@ import AsyncDisplayKit
import Display
import SwiftSignalKit
import TelegramCore
import Postbox
import TelegramPresentationData
import MergeLists
import HorizontalPeerItem
import ListSectionHeaderNode
import ContextUI
import AccountContext
import TelegramUIPreferences
import AnimationCache
import MultiAnimationRenderer
private func calculateItemCustomWidth(width: CGFloat) -> CGFloat {
let itemInsets = UIEdgeInsets(top: 0.0, left: 6.0, bottom: 0.0, right: 6.0)
@ -73,10 +77,42 @@ private struct ChatListSearchRecentPeersEntry: Comparable, Identifiable {
return lhs.index < rhs.index
}
func item(context: AccountContext, mode: HorizontalPeerItemMode, peerSelected: @escaping (EnginePeer) -> Void, peerContextAction: @escaping (EnginePeer, ASDisplayNode, ContextGesture?, CGPoint?) -> Void, isPeerSelected: @escaping (EnginePeer.Id) -> Bool) -> ListViewItem {
return HorizontalPeerItem(theme: self.theme, strings: self.strings, mode: mode, context: context, peer: self.peer, presence: self.presence, unreadBadge: self.unreadBadge, action: peerSelected, contextAction: { peer, node, gesture, location in
peerContextAction(peer, node, gesture, location)
}, isPeerSelected: isPeerSelected, customWidth: self.itemCustomWidth)
func item(
accountPeerId: EnginePeer.Id,
postbox: Postbox,
network: Network,
energyUsageSettings: EnergyUsageSettings,
contentSettings: ContentSettings,
animationCache: AnimationCache,
animationRenderer: MultiAnimationRenderer,
resolveInlineStickers: @escaping ([Int64]) -> Signal<[Int64: TelegramMediaFile], NoError>,
mode: HorizontalPeerItemMode,
peerSelected: @escaping (EnginePeer) -> Void,
peerContextAction: @escaping (EnginePeer, ASDisplayNode, ContextGesture?, CGPoint?) -> Void,
isPeerSelected: @escaping (EnginePeer.Id) -> Bool
) -> ListViewItem {
return HorizontalPeerItem(
theme: self.theme,
strings: self.strings,
mode: mode,
accountPeerId: accountPeerId,
postbox: postbox,
network: network,
energyUsageSettings: energyUsageSettings,
contentSettings: contentSettings,
animationCache: animationCache,
animationRenderer: animationRenderer,
resolveInlineStickers: resolveInlineStickers,
peer: self.peer,
presence: self.presence,
unreadBadge: self.unreadBadge,
action: peerSelected,
contextAction: { peer, node, gesture, location in
peerContextAction(peer, node, gesture, location)
},
isPeerSelected: isPeerSelected,
customWidth: self.itemCustomWidth
)
}
}
@ -88,12 +124,56 @@ private struct ChatListSearchRecentNodeTransition {
let animated: Bool
}
private func preparedRecentPeersTransition(context: AccountContext, mode: HorizontalPeerItemMode, peerSelected: @escaping (EnginePeer) -> Void, peerContextAction: @escaping (EnginePeer, ASDisplayNode, ContextGesture?, CGPoint?) -> Void, isPeerSelected: @escaping (EnginePeer.Id) -> Bool, share: Bool = false, from fromEntries: [ChatListSearchRecentPeersEntry], to toEntries: [ChatListSearchRecentPeersEntry], firstTime: Bool, animated: Bool) -> ChatListSearchRecentNodeTransition {
private func preparedRecentPeersTransition(
accountPeerId: EnginePeer.Id,
postbox: Postbox,
network: Network,
energyUsageSettings: EnergyUsageSettings,
contentSettings: ContentSettings,
animationCache: AnimationCache,
animationRenderer: MultiAnimationRenderer,
resolveInlineStickers: @escaping ([Int64]) -> Signal<[Int64: TelegramMediaFile], NoError>,
mode: HorizontalPeerItemMode,
peerSelected: @escaping (EnginePeer) -> Void,
peerContextAction: @escaping (EnginePeer, ASDisplayNode, ContextGesture?, CGPoint?) -> Void,
isPeerSelected: @escaping (EnginePeer.Id) -> Bool,
share: Bool = false,
from fromEntries: [ChatListSearchRecentPeersEntry],
to toEntries: [ChatListSearchRecentPeersEntry],
firstTime: Bool,
animated: Bool
) -> ChatListSearchRecentNodeTransition {
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, mode: mode, peerSelected: peerSelected, peerContextAction: peerContextAction, isPeerSelected: isPeerSelected), directionHint: .Down) }
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, mode: mode, peerSelected: peerSelected, peerContextAction: peerContextAction, isPeerSelected: isPeerSelected), directionHint: nil) }
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(
accountPeerId: accountPeerId,
postbox: postbox,
network: network,
energyUsageSettings: energyUsageSettings,
contentSettings: contentSettings,
animationCache: animationCache,
animationRenderer: animationRenderer,
resolveInlineStickers: resolveInlineStickers,
mode: mode,
peerSelected: peerSelected,
peerContextAction: peerContextAction,
isPeerSelected: isPeerSelected
), directionHint: .Down) }
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(
accountPeerId: accountPeerId,
postbox: postbox,
network: network,
energyUsageSettings: energyUsageSettings,
contentSettings: contentSettings,
animationCache: animationCache,
animationRenderer: animationRenderer,
resolveInlineStickers: resolveInlineStickers,
mode: mode,
peerSelected: peerSelected,
peerContextAction: peerContextAction,
isPeerSelected: isPeerSelected
), directionHint: nil) }
return ChatListSearchRecentNodeTransition(deletions: deletions, insertions: insertions, updates: updates, firstTime: firstTime, animated: animated)
}
@ -122,7 +202,19 @@ public final class ChatListSearchRecentPeersNode: ASDisplayNode {
return self.ready.get()
}
public init(context: AccountContext, theme: PresentationTheme, mode: HorizontalPeerItemMode, strings: PresentationStrings, peerSelected: @escaping (EnginePeer) -> Void, peerContextAction: @escaping (EnginePeer, ASDisplayNode, ContextGesture?, CGPoint?) -> Void, isPeerSelected: @escaping (EnginePeer.Id) -> Bool, share: Bool = false) {
public init(
accountPeerId: EnginePeer.Id,
postbox: Postbox,
network: Network,
energyUsageSettings: EnergyUsageSettings,
contentSettings: ContentSettings,
animationCache: AnimationCache,
animationRenderer: MultiAnimationRenderer,
resolveInlineStickers: @escaping ([Int64]) -> Signal<[Int64: TelegramMediaFile], NoError>,
theme: PresentationTheme,
mode: HorizontalPeerItemMode,
strings: PresentationStrings,
peerSelected: @escaping (EnginePeer) -> Void, peerContextAction: @escaping (EnginePeer, ASDisplayNode, ContextGesture?, CGPoint?) -> Void, isPeerSelected: @escaping (EnginePeer.Id) -> Bool, share: Bool = false) {
self.theme = theme
self.strings = strings
self.themeAndStringsPromise = Promise((self.theme, self.strings))
@ -144,7 +236,7 @@ public final class ChatListSearchRecentPeersNode: ASDisplayNode {
let peersDisposable = DisposableSet()
let recent: Signal<([EnginePeer], [EnginePeer.Id: (Int32, Bool)], [EnginePeer.Id : EnginePeer.Presence]), NoError> = context.engine.peers.recentPeers()
let recent: Signal<([EnginePeer], [EnginePeer.Id: (Int32, Bool)], [EnginePeer.Id : EnginePeer.Presence]), NoError> = _internal_recentPeers(accountPeerId: accountPeerId, postbox: postbox)
|> filter { value -> Bool in
switch value {
case .disabled:
@ -162,15 +254,27 @@ public final class ChatListSearchRecentPeersNode: ASDisplayNode {
peers.filter {
!$0.isDeleted
}.map {
context.account.postbox.peerView(id: $0.id)
postbox.peerView(id: $0.id)
}
)
|> mapToSignal { peerViews -> Signal<([EnginePeer], [EnginePeer.Id: (Int32, Bool)], [EnginePeer.Id: EnginePeer.Presence]), NoError> in
return context.engine.data.subscribe(
EngineDataMap(peerViews.map { item in
return TelegramEngine.EngineData.Item.Messages.PeerUnreadCount(id: item.peerId)
})
)
return postbox.combinedView(keys: peerViews.map { item -> PostboxViewKey in
let key = PostboxViewKey.unreadCounts(items: [UnreadMessageCountsItem.peer(id: item.peerId, handleThreads: true)])
return key
})
|> map { views -> [EnginePeer.Id: Int] in
var result: [EnginePeer.Id: Int] = [:]
for item in peerViews {
let key = PostboxViewKey.unreadCounts(items: [UnreadMessageCountsItem.peer(id: item.peerId, handleThreads: true)])
if let view = views.views[key] as? UnreadMessageCountsView {
result[item.peerId] = Int(view.count(for: .peer(id: item.peerId, handleThreads: true)) ?? 0)
} else {
result[item.peerId] = 0
}
}
return result
}
|> map { unreadCounts in
var peers: [EnginePeer] = []
var unread: [EnginePeer.Id: (Int32, Bool)] = [:]
@ -216,7 +320,24 @@ public final class ChatListSearchRecentPeersNode: ASDisplayNode {
let animated = !firstTime.swap(false)
let transition = preparedRecentPeersTransition(context: context, mode: mode, peerSelected: peerSelected, peerContextAction: peerContextAction, isPeerSelected: isPeerSelected, from: previous.swap(entries), to: entries, firstTime: !animated, animated: animated)
let transition = preparedRecentPeersTransition(
accountPeerId: accountPeerId,
postbox: postbox,
network: network,
energyUsageSettings: energyUsageSettings,
contentSettings: contentSettings,
animationCache: animationCache,
animationRenderer: animationRenderer,
resolveInlineStickers: resolveInlineStickers,
mode: mode,
peerSelected: peerSelected,
peerContextAction: peerContextAction,
isPeerSelected: isPeerSelected,
from: previous.swap(entries),
to: entries,
firstTime: !animated,
animated: animated
)
strongSelf.enqueueTransition(transition)
@ -227,7 +348,7 @@ public final class ChatListSearchRecentPeersNode: ASDisplayNode {
}
}))
if case .actionSheet = mode {
peersDisposable.add(context.engine.peers.managedUpdatedRecentPeers().start())
peersDisposable.add(_internal_managedUpdatedRecentPeers(accountPeerId: accountPeerId, postbox: postbox, network: network).start())
}
self.disposable.set(peersDisposable)
}

View File

@ -1293,7 +1293,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
case let .groupReference(groupReference):
let chatListController = ChatListControllerImpl(context: strongSelf.context, location: .chatList(groupId: groupReference.groupId), controlsHistoryPreload: false, hideNetworkActivityStatus: true, previewing: true, enableDebugActions: false)
chatListController.navigationPresentation = .master
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatListController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController)), items: archiveContextMenuItems(context: strongSelf.context, groupId: groupReference.groupId._asGroup(), chatListController: strongSelf) |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
let contextController = ContextController(presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatListController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController)), items: archiveContextMenuItems(context: strongSelf.context, groupId: groupReference.groupId._asGroup(), chatListController: strongSelf) |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
strongSelf.presentInGlobalOverlay(contextController)
case let .peer(peerData):
let peer = peerData.peer
@ -1311,12 +1311,12 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
chatController.canReadHistory.set(false)
source = .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController))
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: source, items: chatForumTopicMenuItems(context: strongSelf.context, peerId: peer.peerId, threadId: threadId, isPinned: nil, isClosed: nil, chatListController: strongSelf, joined: joined, canSelect: false) |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
let contextController = ContextController(presentationData: strongSelf.presentationData, source: source, items: chatForumTopicMenuItems(context: strongSelf.context, peerId: peer.peerId, threadId: threadId, isPinned: nil, isClosed: nil, chatListController: strongSelf, joined: joined, canSelect: false) |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
strongSelf.presentInGlobalOverlay(contextController)
} else {
let chatListController = ChatListControllerImpl(context: strongSelf.context, location: .forum(peerId: channel.id), controlsHistoryPreload: false, hideNetworkActivityStatus: true, previewing: true, enableDebugActions: false)
chatListController.navigationPresentation = .master
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatListController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController)), items: chatContextMenuItems(context: strongSelf.context, peerId: peer.peerId, promoInfo: promoInfo, source: .chatList(filter: strongSelf.chatListDisplayNode.mainContainerNode.currentItemNode.chatListFilter), chatListController: strongSelf, joined: joined) |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
let contextController = ContextController(presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatListController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController)), items: chatContextMenuItems(context: strongSelf.context, peerId: peer.peerId, promoInfo: promoInfo, source: .chatList(filter: strongSelf.chatListDisplayNode.mainContainerNode.currentItemNode.chatListFilter), chatListController: strongSelf, joined: joined) |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
strongSelf.presentInGlobalOverlay(contextController)
}
} else {
@ -1329,7 +1329,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
source = .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController))
}
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: source, items: chatContextMenuItems(context: strongSelf.context, peerId: peer.peerId, promoInfo: promoInfo, source: .chatList(filter: strongSelf.chatListDisplayNode.mainContainerNode.currentItemNode.chatListFilter), chatListController: strongSelf, joined: joined) |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
let contextController = ContextController(presentationData: strongSelf.presentationData, source: source, items: chatContextMenuItems(context: strongSelf.context, peerId: peer.peerId, promoInfo: promoInfo, source: .chatList(filter: strongSelf.chatListDisplayNode.mainContainerNode.currentItemNode.chatListFilter), chatListController: strongSelf, joined: joined) |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
strongSelf.presentInGlobalOverlay(contextController)
}
case let .forum(pinnedIndex, _, threadId, _, _):
@ -1347,7 +1347,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
chatController.canReadHistory.set(false)
source = .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController))
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: source, items: chatForumTopicMenuItems(context: strongSelf.context, peerId: peer.peerId, threadId: threadId, isPinned: isPinned, isClosed: threadInfo?.isClosed, chatListController: strongSelf, joined: joined, canSelect: true) |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
let contextController = ContextController(presentationData: strongSelf.presentationData, source: source, items: chatForumTopicMenuItems(context: strongSelf.context, peerId: peer.peerId, threadId: threadId, isPinned: isPinned, isClosed: threadInfo?.isClosed, chatListController: strongSelf, joined: joined, canSelect: true) |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
strongSelf.presentInGlobalOverlay(contextController)
}
}
@ -1378,7 +1378,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
if case let .channel(channel) = peer, channel.flags.contains(.isForum) {
let chatListController = ChatListControllerImpl(context: strongSelf.context, location: .forum(peerId: channel.id), controlsHistoryPreload: false, hideNetworkActivityStatus: true, previewing: true, enableDebugActions: false)
chatListController.navigationPresentation = .master
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatListController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController)), items: chatContextMenuItems(context: strongSelf.context, peerId: peer.id, promoInfo: nil, source: .search(source), chatListController: strongSelf, joined: false) |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
let contextController = ContextController(presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatListController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController)), items: chatContextMenuItems(context: strongSelf.context, peerId: peer.id, promoInfo: nil, source: .search(source), chatListController: strongSelf, joined: false) |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
strongSelf.presentInGlobalOverlay(contextController)
} else {
let contextContentSource: ContextContentSource
@ -1394,7 +1394,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
contextContentSource = .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController))
}
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: contextContentSource, items: chatContextMenuItems(context: strongSelf.context, peerId: peer.id, promoInfo: nil, source: .search(source), chatListController: strongSelf, joined: false) |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
let contextController = ContextController(presentationData: strongSelf.presentationData, source: contextContentSource, items: chatContextMenuItems(context: strongSelf.context, peerId: peer.id, promoInfo: nil, source: .search(source), chatListController: strongSelf, joined: false) |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
strongSelf.presentInGlobalOverlay(contextController)
}
}
@ -1769,7 +1769,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
})))
}
let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatListHeaderBarContextExtractedContentSource(controller: strongSelf, sourceNode: sourceNode, keepInPlace: keepInPlace)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
let controller = ContextController(presentationData: strongSelf.presentationData, source: .extracted(ChatListHeaderBarContextExtractedContentSource(controller: strongSelf, sourceNode: sourceNode, keepInPlace: keepInPlace)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
strongSelf.context.sharedContext.mainWindow?.presentInGlobalOverlay(controller)
})
}
@ -2938,7 +2938,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
})))
}
let controller = ContextController(account: self.context.account, presentationData: self.presentationData, source: .extracted(ChatListHeaderBarContextExtractedContentSource(controller: self, sourceNode: sourceNode, keepInPlace: false)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
let controller = ContextController(presentationData: self.presentationData, source: .extracted(ChatListHeaderBarContextExtractedContentSource(controller: self, sourceNode: sourceNode, keepInPlace: false)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
self.context.sharedContext.mainWindow?.presentInGlobalOverlay(controller)
})
}
@ -3340,7 +3340,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
}
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(controller: sourceController, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
let contextController = ContextController(presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(controller: sourceController, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
sourceController.presentInGlobalOverlay(contextController)
})
}
@ -3400,7 +3400,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
})))
}
let contextController = ContextController(account: self.context.account, presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(controller: self, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
let contextController = ContextController(presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(controller: self, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
self.presentInGlobalOverlay(contextController)
})
}
@ -5549,7 +5549,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
}
}
let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatListTabBarContextExtractedContentSource(controller: strongSelf, sourceNode: sourceNode)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
let controller = ContextController(presentationData: strongSelf.presentationData, source: .extracted(ChatListTabBarContextExtractedContentSource(controller: strongSelf, sourceNode: sourceNode)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
strongSelf.context.sharedContext.mainWindow?.presentInGlobalOverlay(controller)
})
}

View File

@ -1548,7 +1548,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset initi
})
})))
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .extracted(InviteLinkContextExtractedContentSource(controller: controller, sourceNode: node, keepInPlace: false, blurBackground: true)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
let contextController = ContextController(presentationData: presentationData, source: .extracted(InviteLinkContextExtractedContentSource(controller: controller, sourceNode: node, keepInPlace: false, blurBackground: true)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
presentInGlobalOverlayImpl?(contextController)
})
},
@ -1589,7 +1589,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset initi
})
})))
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
let contextController = ContextController(presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
presentInGlobalOverlayImpl?(contextController)
}
)

View File

@ -120,13 +120,28 @@ class ChatListRecentPeersListItemNode: ListViewItemNode {
peersNode = currentPeersNode
peersNode.updateThemeAndStrings(theme: item.theme, strings: item.strings)
} else {
peersNode = ChatListSearchRecentPeersNode(context: item.context, theme: item.theme, mode: .list(compact: false), strings: item.strings, peerSelected: { peer in
self?.item?.peerSelected(peer)
}, peerContextAction: { peer, node, gesture, location in
self?.item?.peerContextAction(peer, node, gesture, location)
}, isPeerSelected: { _ in
return false
})
peersNode = ChatListSearchRecentPeersNode(
accountPeerId: item.context.account.peerId,
postbox: item.context.account.postbox,
network: item.context.account.network,
energyUsageSettings: item.context.sharedContext.energyUsageSettings,
contentSettings: item.context.currentContentSettings.with { $0 },
animationCache: item.context.animationCache,
animationRenderer: item.context.animationRenderer,
resolveInlineStickers: item.context.engine.stickers.resolveInlineStickers,
theme: item.theme,
mode: .list(compact: false),
strings: item.strings,
peerSelected: { peer in
self?.item?.peerSelected(peer)
},
peerContextAction: { peer, node, gesture, location in
self?.item?.peerContextAction(peer, node, gesture, location)
},
isPeerSelected: { _ in
return false
}
)
strongSelf.ready.set(peersNode.isReady)
strongSelf.peersNode = peersNode
strongSelf.addSubnode(peersNode)

View File

@ -1046,7 +1046,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
return items
}
let controller = ContextController(account: self.context.account, presentationData: self.presentationData, source: .extracted(MessageContextExtractedContentSource(sourceNode: node, shouldBeDismissed: shouldBeDismissed)), items: items |> map { ContextController.Items(content: .list($0)) }, recognizer: nil, gesture: gesture)
let controller = ContextController(presentationData: self.presentationData, source: .extracted(MessageContextExtractedContentSource(sourceNode: node, shouldBeDismissed: shouldBeDismissed)), items: items |> map { ContextController.Items(content: .list($0)) }, recognizer: nil, gesture: gesture)
self.presentInGlobalOverlay?(controller, nil)
return
@ -1120,7 +1120,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
return items
}
let controller = ContextController(account: self.context.account, presentationData: self.presentationData, source: .extracted(MessageContextExtractedContentSource(sourceNode: node)), items: items |> map { ContextController.Items(content: .list($0)) }, recognizer: nil, gesture: gesture)
let controller = ContextController(presentationData: self.presentationData, source: .extracted(MessageContextExtractedContentSource(sourceNode: node)), items: items |> map { ContextController.Items(content: .list($0)) }, recognizer: nil, gesture: gesture)
self.presentInGlobalOverlay?(controller, nil)
}
@ -1184,7 +1184,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
switch previewData {
case let .gallery(gallery):
gallery.setHintWillBePresentedInPreviewingContext(true)
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: gallery, sourceNode: node)), items: items |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
let contextController = ContextController(presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: gallery, sourceNode: node)), items: items |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
strongSelf.presentInGlobalOverlay?(contextController, nil)
case .instantPage:
break

View File

@ -572,7 +572,7 @@ public class ContactsController: ViewController {
})))
return items
}
let contextController = ContextController(account: self.context.account, presentationData: self.presentationData, source: .reference(HeaderContextReferenceContentSource(controller: self, sourceView: sourceView)), items: items |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
let contextController = ContextController(presentationData: self.presentationData, source: .reference(HeaderContextReferenceContentSource(controller: self, sourceView: sourceView)), items: items |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
self.presentInGlobalOverlay(contextController)
}
@ -644,7 +644,7 @@ public class ContactsController: ViewController {
})
})))
let controller = ContextController(account: self.context.account, presentationData: self.presentationData, source: .extracted(ContactsTabBarContextExtractedContentSource(controller: self, sourceNode: sourceNode)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
let controller = ContextController(presentationData: self.presentationData, source: .extracted(ContactsTabBarContextExtractedContentSource(controller: self, sourceNode: sourceNode)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
self.context.sharedContext.mainWindow?.presentInGlobalOverlay(controller)
}
}

View File

@ -436,12 +436,12 @@ final class ContactsControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
let items = contactContextMenuItems(context: self.context, peerId: peer.id, contactsController: contactsController, isStories: isStories) |> map { ContextController.Items(content: .list($0)) }
if isStories, let node = node?.subnodes?.first(where: { $0 is ContextExtractedContentContainingNode }) as? ContextExtractedContentContainingNode {
let controller = ContextController(account: self.context.account, presentationData: self.presentationData, source: .extracted(ContactContextExtractedContentSource(sourceNode: node, shouldBeDismissed: .single(false))), items: items, recognizer: nil, gesture: gesture)
let controller = ContextController(presentationData: self.presentationData, source: .extracted(ContactContextExtractedContentSource(sourceNode: node, shouldBeDismissed: .single(false))), items: items, recognizer: nil, gesture: gesture)
contactsController.presentInGlobalOverlay(controller)
} else {
let chatController = self.context.sharedContext.makeChatController(context: self.context, chatLocation: .peer(id: peer.id), subject: nil, botStart: nil, mode: .standard(previewing: true))
chatController.canReadHistory.set(false)
let contextController = ContextController(account: self.context.account, presentationData: self.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: items, gesture: gesture)
let contextController = ContextController(presentationData: self.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: items, gesture: gesture)
contactsController.presentInGlobalOverlay(contextController)
}
}

View File

@ -296,7 +296,6 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
}
init(
account: Account,
controller: ContextController,
presentationData: PresentationData,
source: ContextContentSource,
@ -2465,7 +2464,6 @@ public final class ContextController: ViewController, StandalonePresentableContr
}
}
private let account: Account
private var presentationData: PresentationData
private let source: ContextContentSource
private var items: Signal<ContextController.Items, NoError>
@ -2520,8 +2518,7 @@ public final class ContextController: ViewController, StandalonePresentableContr
public var getOverlayViews: (() -> [UIView])?
public init(account: Account, presentationData: PresentationData, source: ContextContentSource, items: Signal<ContextController.Items, NoError>, recognizer: TapLongTapOrDoubleTapGestureRecognizer? = nil, gesture: ContextGesture? = nil, workaroundUseLegacyImplementation: Bool = false) {
self.account = account
public init(presentationData: PresentationData, source: ContextContentSource, items: Signal<ContextController.Items, NoError>, recognizer: TapLongTapOrDoubleTapGestureRecognizer? = nil, gesture: ContextGesture? = nil, workaroundUseLegacyImplementation: Bool = false) {
self.presentationData = presentationData
self.source = source
self.items = items
@ -2588,7 +2585,7 @@ public final class ContextController: ViewController, StandalonePresentableContr
}
override public func loadDisplayNode() {
self.displayNode = ContextControllerNode(account: self.account, controller: self, presentationData: self.presentationData, source: self.source, items: self.items, beginDismiss: { [weak self] result in
self.displayNode = ContextControllerNode(controller: self, presentationData: self.presentationData, source: self.source, items: self.items, beginDismiss: { [weak self] result in
self?.dismiss(result: result, completion: nil)
}, recognizer: self.recognizer, gesture: self.gesture, beganAnimatingOut: { [weak self] in
guard let strongSelf = self else {

View File

@ -984,7 +984,7 @@ private final class DrawingScreenComponent: CombinedComponent {
)
]
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }.withUpdated(theme: defaultDarkPresentationTheme)
let contextController = ContextController(account: self.context.account, presentationData: presentationData, source: .reference(ReferenceContentSource(sourceView: sourceView, contentArea: UIScreen.main.bounds, customPosition: CGPoint(x: 7.0, y: 3.0))), items: .single(ContextController.Items(content: .list(items))))
let contextController = ContextController(presentationData: presentationData, source: .reference(ReferenceContentSource(sourceView: sourceView, contentArea: UIScreen.main.bounds, customPosition: CGPoint(x: 7.0, y: 3.0))), items: .single(ContextController.Items(content: .list(items))))
self.present(contextController)
}
@ -3384,7 +3384,7 @@ public final class DrawingToolsInteraction {
}
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }.withUpdated(theme: defaultDarkPresentationTheme)
let contextController = ContextController(account: self.context.account, presentationData: presentationData, source: .reference(ReferenceContentSource(sourceView: sourceView, contentArea: CGRect(origin: .zero, size: CGSize(width: validLayout.size.width, height: validLayout.size.height - (validLayout.inputHeight ?? 0.0))), customPosition: CGPoint(x: 0.0, y: 1.0))), items: .single(ContextController.Items(content: .list(items))))
let contextController = ContextController(presentationData: presentationData, source: .reference(ReferenceContentSource(sourceView: sourceView, contentArea: CGRect(origin: .zero, size: CGSize(width: validLayout.size.width, height: validLayout.size.height - (validLayout.inputHeight ?? 0.0))), customPosition: CGPoint(x: 0.0, y: 1.0))), items: .single(ContextController.Items(content: .list(items))))
self.present(contextController, .window(.root), nil)
self.currentFontPicker = contextController
contextController.view.disablesInteractiveKeyboardGestureRecognizer = true

View File

@ -784,7 +784,7 @@ public class StickerPickerScreen: ViewController {
})))
}
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: gallery, sourceView: sourceView, sourceRect: sourceRect)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
let contextController = ContextController(presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: gallery, sourceView: sourceView, sourceRect: sourceRect)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
controller.presentInGlobalOverlay(contextController)
})
}

View File

@ -559,7 +559,7 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
return
}
let contextController = ContextController(account: self.context.account, presentationData: self.presentationData.withUpdated(theme: defaultDarkColorPresentationTheme), source: .reference(HeaderContextReferenceContentSource(controller: controller, sourceNode: self.moreBarButton.referenceNode)), items: items |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
let contextController = ContextController(presentationData: self.presentationData.withUpdated(theme: defaultDarkColorPresentationTheme), source: .reference(HeaderContextReferenceContentSource(controller: controller, sourceNode: self.moreBarButton.referenceNode)), items: items |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
controller.presentInGlobalOverlay(contextController)
}

View File

@ -2432,7 +2432,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
let items: Signal<[ContextMenuItem], NoError> = self.contextMenuMainItems(dismiss: {
dismissImpl?()
})
let contextController = ContextController(account: self.context.account, presentationData: self.presentationData.withUpdated(theme: defaultDarkColorPresentationTheme), source: .reference(HeaderContextReferenceContentSource(controller: controller, sourceNode: self.moreBarButton.referenceNode)), items: items |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
let contextController = ContextController(presentationData: self.presentationData.withUpdated(theme: defaultDarkColorPresentationTheme), source: .reference(HeaderContextReferenceContentSource(controller: controller, sourceNode: self.moreBarButton.referenceNode)), items: items |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
self.isShowingContextMenuPromise.set(true)
controller.presentInGlobalOverlay(contextController)
dismissImpl = { [weak contextController] in

View File

@ -145,8 +145,8 @@ final class GameControllerNode: ViewControllerTracingNode {
if let (botPeer, gameName) = self.shareData(), let addressName = botPeer.addressName, !addressName.isEmpty, !gameName.isEmpty {
if eventName == "share_score" {
self.present(ShareController(context: self.context, subject: .fromExternal({ [weak self] peerIds, threadIds, text, account, _ in
if let strongSelf = self, let message = strongSelf.message {
let signals = peerIds.map { TelegramEngine(account: account).messages.forwardGameWithScore(messageId: message.id, to: $0, threadId: threadIds[$0], as: nil) }
if let strongSelf = self, let message = strongSelf.message, let account = account as? ShareControllerAppAccountContext {
let signals = peerIds.map { TelegramEngine(account: account.context.account).messages.forwardGameWithScore(messageId: message.id, to: $0, threadId: threadIds[$0], as: nil) }
return .single(.preparing(false))
|> castError(ShareControllerError.self)
|> then(

View File

@ -12,6 +12,7 @@ swift_library(
deps = [
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
"//submodules/TelegramCore:TelegramCore",
"//submodules/Postbox:Postbox",
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
"//submodules/Display:Display",
"//submodules/TelegramPresentationData:TelegramPresentationData",
@ -20,6 +21,9 @@ swift_library(
"//submodules/TelegramStringFormatting:TelegramStringFormatting",
"//submodules/ContextUI:ContextUI",
"//submodules/AccountContext:AccountContext",
"//submodules/TelegramUIPreferences",
"//submodules/TelegramUI/Components/AnimationCache",
"//submodules/TelegramUI/Components/MultiAnimationRenderer",
],
visibility = [
"//visibility:public",

View File

@ -3,6 +3,7 @@ import UIKit
import Display
import AsyncDisplayKit
import TelegramCore
import Postbox
import SwiftSignalKit
import TelegramPresentationData
import TelegramStringFormatting
@ -10,6 +11,9 @@ import PeerOnlineMarkerNode
import SelectablePeerNode
import ContextUI
import AccountContext
import TelegramUIPreferences
import AnimationCache
import MultiAnimationRenderer
public enum HorizontalPeerItemMode {
case list(compact: Bool)
@ -22,7 +26,15 @@ public final class HorizontalPeerItem: ListViewItem {
let theme: PresentationTheme
let strings: PresentationStrings
let mode: HorizontalPeerItemMode
let context: AccountContext
let accountPeerId: EnginePeer.Id
let postbox: Postbox
let network: Network
let energyUsageSettings: EnergyUsageSettings
let contentSettings: ContentSettings
let animationCache: AnimationCache
let animationRenderer: MultiAnimationRenderer
let resolveInlineStickers: ([Int64]) -> Signal<[Int64: TelegramMediaFile], NoError>
public let peer: EnginePeer
let action: (EnginePeer) -> Void
let contextAction: ((EnginePeer, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?
@ -31,11 +43,37 @@ public final class HorizontalPeerItem: ListViewItem {
let presence: EnginePeer.Presence?
let unreadBadge: (Int32, Bool)?
public init(theme: PresentationTheme, strings: PresentationStrings, mode: HorizontalPeerItemMode, context: AccountContext, peer: EnginePeer, presence: EnginePeer.Presence?, unreadBadge: (Int32, Bool)?, action: @escaping (EnginePeer) -> Void, contextAction: ((EnginePeer, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, isPeerSelected: @escaping (EnginePeer.Id) -> Bool, customWidth: CGFloat?) {
public init(
theme: PresentationTheme,
strings: PresentationStrings,
mode: HorizontalPeerItemMode,
accountPeerId: EnginePeer.Id,
postbox: Postbox,
network: Network,
energyUsageSettings: EnergyUsageSettings,
contentSettings: ContentSettings,
animationCache: AnimationCache,
animationRenderer: MultiAnimationRenderer,
resolveInlineStickers: @escaping ([Int64]) -> Signal<[Int64: TelegramMediaFile], NoError>,
peer: EnginePeer,
presence: EnginePeer.Presence?,
unreadBadge: (Int32, Bool)?,
action: @escaping (EnginePeer) -> Void,
contextAction: ((EnginePeer, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?,
isPeerSelected: @escaping (EnginePeer.Id) -> Bool,
customWidth: CGFloat?
) {
self.theme = theme
self.strings = strings
self.mode = mode
self.context = context
self.accountPeerId = accountPeerId
self.postbox = postbox
self.network = network
self.energyUsageSettings = energyUsageSettings
self.contentSettings = contentSettings
self.animationCache = animationCache
self.animationRenderer = animationRenderer
self.resolveInlineStickers = resolveInlineStickers
self.peer = peer
self.action = action
self.contextAction = contextAction
@ -186,7 +224,7 @@ public final class HorizontalPeerItemNode: ListViewItemNode {
} else {
strongSelf.peerNode.compact = false
}
strongSelf.peerNode.setup(context: item.context, theme: item.theme, strings: item.strings, peer: EngineRenderedPeer(peer: item.peer), numberOfLines: 1, synchronousLoad: synchronousLoads)
strongSelf.peerNode.setup(accountPeerId: item.accountPeerId, postbox: item.postbox, network: item.network, energyUsageSettings: item.energyUsageSettings, contentSettings: item.contentSettings, animationCache: item.animationCache, animationRenderer: item.animationRenderer, resolveInlineStickers: item.resolveInlineStickers, theme: item.theme, strings: item.strings, peer: EngineRenderedPeer(peer: item.peer), numberOfLines: 1, synchronousLoad: synchronousLoads)
strongSelf.peerNode.frame = CGRect(origin: CGPoint(), size: itemLayout.size)
strongSelf.peerNode.updateSelection(selected: item.isPeerSelected(item.peer.id), animated: false)

View File

@ -465,7 +465,7 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese
})
})))
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .reference(InviteLinkContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
let contextController = ContextController(presentationData: presentationData, source: .reference(InviteLinkContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
presentInGlobalOverlayImpl?(contextController)
}, peerAction: { peer, isEnabled in
let presentationData = context.sharedContext.currentPresentationData.with { $0 }

View File

@ -418,7 +418,7 @@ public final class InviteLinkInviteController: ViewController {
})
})))
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .reference(InviteLinkContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
let contextController = ContextController(presentationData: presentationData, source: .reference(InviteLinkContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
self?.controller?.presentInGlobalOverlay(contextController)
}, copyLink: { [weak self] invite in
UIPasteboard.general.string = invite.link

View File

@ -586,7 +586,7 @@ public func inviteLinkListController(context: AccountContext, updatedPresentatio
})))
}
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .reference(InviteLinkContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
let contextController = ContextController(presentationData: presentationData, source: .reference(InviteLinkContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
presentInGlobalOverlayImpl?(contextController)
}, createLink: {
let controller = inviteLinkEditController(context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, invite: nil, completion: { invite in
@ -790,7 +790,7 @@ public func inviteLinkListController(context: AccountContext, updatedPresentatio
})))
}
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .extracted(InviteLinkContextExtractedContentSource(controller: controller, sourceNode: node, keepInPlace: false, blurBackground: true)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
let contextController = ContextController(presentationData: presentationData, source: .extracted(InviteLinkContextExtractedContentSource(controller: controller, sourceNode: node, keepInPlace: false, blurBackground: true)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
presentInGlobalOverlayImpl?(contextController)
}, openAdmin: { admin in
let controller = inviteLinkListController(context: context, peerId: peerId, admin: admin)

View File

@ -686,7 +686,7 @@ public final class InviteLinkViewController: ViewController {
}
}
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .reference(InviteLinkContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
let contextController = ContextController(presentationData: presentationData, source: .reference(InviteLinkContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
self?.controller?.presentInGlobalOverlay(contextController)
})
})

View File

@ -268,7 +268,7 @@ public func inviteRequestsController(context: AccountContext, updatedPresentatio
// dismissPromise.set(true)
// }
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .extracted(source), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
let contextController = ContextController(presentationData: presentationData, source: .extracted(source), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
presentInGlobalOverlayImpl?(contextController)
})
})

View File

@ -455,7 +455,7 @@ public final class InviteRequestsSearchContainerNode: SearchDisplayControllerCon
// dismissPromise.set(true)
// }
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .extracted(source), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
let contextController = ContextController(presentationData: presentationData, source: .extracted(source), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
presentInGlobalOverlay(contextController)
})
})

View File

@ -78,7 +78,7 @@ private class LegacyPaintStickerEntity: LegacyPaintEntity {
return self.entity.mirrored
}
let account: Account
let postbox: Postbox
let file: TelegramMediaFile?
let entity: DrawingStickerEntity
let animated: Bool
@ -96,8 +96,8 @@ private class LegacyPaintStickerEntity: LegacyPaintEntity {
let imagePromise = Promise<UIImage>()
init(account: Account, entity: DrawingStickerEntity) {
self.account = account
init(postbox: Postbox, entity: DrawingStickerEntity) {
self.postbox = postbox
self.entity = entity
self.animated = entity.isAnimated
@ -105,7 +105,7 @@ private class LegacyPaintStickerEntity: LegacyPaintEntity {
case let .file(file):
self.file = file
if file.isAnimatedSticker || file.isVideoSticker || file.mimeType == "video/webm" {
self.source = AnimatedStickerResourceSource(account: account, resource: file.resource, isVideo: file.isVideoSticker || file.mimeType == "video/webm")
self.source = AnimatedStickerResourceSource(postbox: postbox, resource: file.resource, isVideo: file.isVideoSticker || file.mimeType == "video/webm")
if let source = self.source {
let dimensions = file.dimensions ?? PixelDimensions(width: 512, height: 512)
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 384, height: 384))
@ -132,7 +132,7 @@ private class LegacyPaintStickerEntity: LegacyPaintEntity {
}))
}
} else {
self.disposables.add((chatMessageSticker(account: self.account, userLocation: .other, file: file, small: false, fetched: true, onlyFullSize: true, thumbnail: false, synchronousLoad: false)
self.disposables.add((chatMessageSticker(postbox: self.postbox, userLocation: .other, file: file, small: false, fetched: true, onlyFullSize: true, thumbnail: false, synchronousLoad: false)
|> deliverOn(self.queue)).start(next: { [weak self] generator in
if let strongSelf = self {
let context = generator(TransformImageArguments(corners: ImageCorners(), imageSize: entity.baseSize, boundingSize: entity.baseSize, intrinsicInsets: UIEdgeInsets()))
@ -412,7 +412,7 @@ private class LegacyPaintVectorEntity: LegacyPaintEntity {
}
public final class LegacyPaintEntityRenderer: NSObject, TGPhotoPaintEntityRenderer {
private let account: Account?
private let postbox: Postbox?
private let queue = Queue()
private let entities: [LegacyPaintEntity]
@ -421,8 +421,8 @@ public final class LegacyPaintEntityRenderer: NSObject, TGPhotoPaintEntityRender
private let isAvatar: Bool
public init(account: Account?, adjustments: TGMediaEditAdjustments) {
self.account = account
public init(postbox: Postbox?, adjustments: TGMediaEditAdjustments) {
self.postbox = postbox
self.originalSize = adjustments.originalSize
self.cropRect = adjustments.cropRect.isEmpty ? nil : adjustments.cropRect
self.isAvatar = ((adjustments as? TGVideoEditAdjustments)?.documentId ?? 0) != 0
@ -431,14 +431,14 @@ public final class LegacyPaintEntityRenderer: NSObject, TGPhotoPaintEntityRender
if let paintingData = adjustments.paintingData, let entitiesData = paintingData.entitiesData {
let entities = decodeDrawingEntities(data: entitiesData)
for entity in entities {
if let sticker = entity as? DrawingStickerEntity, let account {
renderEntities.append(LegacyPaintStickerEntity(account: account, entity: sticker))
if let sticker = entity as? DrawingStickerEntity, let postbox {
renderEntities.append(LegacyPaintStickerEntity(postbox: postbox, entity: sticker))
} else if let text = entity as? DrawingTextEntity {
renderEntities.append(LegacyPaintTextEntity(entity: text))
if let renderSubEntities = text.renderSubEntities, let account {
if let renderSubEntities = text.renderSubEntities, let postbox {
for entity in renderSubEntities {
if let entity = entity as? DrawingStickerEntity {
renderEntities.append(LegacyPaintStickerEntity(account: account, entity: entity))
renderEntities.append(LegacyPaintStickerEntity(postbox: postbox, entity: entity))
}
}
}

View File

@ -1850,7 +1850,6 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
self.titleView.isHighlighted = true
let contextController = ContextController(
account: self.context.account,
presentationData: self.presentationData,
source: .reference(MediaPickerContextReferenceContentSource(controller: self, sourceNode: self.titleView.contextSourceNode)),
items: .single(ContextController.Items(content: .custom(content))),
@ -2226,7 +2225,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
return ContextController.Items(content: .list(items))
}
let contextController = ContextController(account: self.context.account, presentationData: self.presentationData, source: .reference(MediaPickerContextReferenceContentSource(controller: self, sourceNode: node)), items: items, gesture: gesture)
let contextController = ContextController(presentationData: self.presentationData, source: .reference(MediaPickerContextReferenceContentSource(controller: self, sourceNode: node)), items: items, gesture: gesture)
self.presentInGlobalOverlay(contextController)
}
}

View File

@ -1655,7 +1655,7 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
})
})))
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .reference(InviteLinkContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
let contextController = ContextController(presentationData: presentationData, source: .reference(InviteLinkContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
presentInGlobalOverlayImpl?(contextController)
}, manageInviteLinks: {
let controller = inviteLinkListController(context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, admin: nil)

View File

@ -488,7 +488,7 @@ public func peersNearbyController(context: AccountContext) -> ViewController {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let chatController = context.sharedContext.makeChatController(context: context, chatLocation: .peer(id: peer.id), subject: nil, botStart: nil, mode: .standard(previewing: true))
chatController.canReadHistory.set(false)
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: peerNearbyContextMenuItems(context: context, peerId: peer.id, present: { c in
let contextController = ContextController(presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: peerNearbyContextMenuItems(context: context, peerId: peer.id, present: { c in
presentControllerImpl?(c, nil)
}) |> map { ContextController.Items(content: .list($0), animationCache: nil) }, gesture: gesture)
presentInGlobalOverlayImpl?(contextController)

View File

@ -12,6 +12,7 @@ swift_library(
deps = [
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
"//submodules/TelegramCore:TelegramCore",
"//submodules/Postbox:Postbox",
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
"//submodules/Display:Display",
"//submodules/TelegramPresentationData:TelegramPresentationData",
@ -24,6 +25,9 @@ swift_library(
"//submodules/CheckNode:CheckNode",
"//submodules/ComponentFlow:ComponentFlow",
"//submodules/TelegramUI/Components/EmojiStatusComponent:EmojiStatusComponent",
"//submodules/TelegramUIPreferences",
"//submodules/TelegramUI/Components/AnimationCache",
"//submodules/TelegramUI/Components/MultiAnimationRenderer",
],
visibility = [
"//visibility:public",

View File

@ -3,6 +3,7 @@ import UIKit
import AsyncDisplayKit
import Display
import TelegramCore
import Postbox
import SwiftSignalKit
import TelegramPresentationData
import AvatarNode
@ -14,6 +15,9 @@ import AccountContext
import CheckNode
import ComponentFlow
import EmojiStatusComponent
import AnimationCache
import MultiAnimationRenderer
import TelegramUIPreferences
private let avatarFont = avatarPlaceholderFont(size: 24.0)
private let textFont = Font.regular(11.0)
@ -144,6 +148,30 @@ public final class SelectablePeerNode: ASDisplayNode {
}
public func setup(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, peer: EngineRenderedPeer, customTitle: String? = nil, iconId: Int64? = nil, iconColor: Int32? = nil, online: Bool = false, numberOfLines: Int = 2, synchronousLoad: Bool) {
self.setup(
accountPeerId: context.account.peerId,
postbox: context.account.postbox,
network: context.account.network,
energyUsageSettings: context.sharedContext.energyUsageSettings,
contentSettings: context.currentContentSettings.with { $0 },
animationCache: context.animationCache,
animationRenderer: context.animationRenderer,
resolveInlineStickers: { fileIds in
return context.engine.stickers.resolveInlineStickers(fileIds: fileIds)
},
theme: theme,
strings: strings,
peer: peer,
customTitle: customTitle,
iconId: iconId,
iconColor: iconColor,
online: online,
numberOfLines: numberOfLines,
synchronousLoad: synchronousLoad
)
}
public func setup(accountPeerId: EnginePeer.Id, postbox: Postbox, network: Network, energyUsageSettings: EnergyUsageSettings, contentSettings: ContentSettings, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, resolveInlineStickers: @escaping ([Int64]) -> Signal<[Int64: TelegramMediaFile], NoError>, theme: PresentationTheme, strings: PresentationStrings, peer: EngineRenderedPeer, customTitle: String? = nil, iconId: Int64? = nil, iconColor: Int32? = nil, online: Bool = false, numberOfLines: Int = 2, synchronousLoad: Bool) {
let isFirstTime = self.peer == nil
self.peer = peer
guard let mainPeer = peer.chatMainPeer else {
@ -159,7 +187,7 @@ public final class SelectablePeerNode: ASDisplayNode {
let text: String
var overrideImage: AvatarNodeImageOverride?
if peer.peerId == context.account.peerId {
if peer.peerId == accountPeerId {
text = self.compact ? strings.DeleteAccount_SavedMessages : strings.DialogList_SavedMessages
overrideImage = .savedMessagesIcon
} else if peer.peerId.isReplies {
@ -173,7 +201,7 @@ public final class SelectablePeerNode: ASDisplayNode {
}
self.textNode.maximumNumberOfLines = numberOfLines
self.textNode.attributedText = NSAttributedString(string: customTitle ?? text, font: textFont, textColor: self.currentSelected ? self.theme.selectedTextColor : defaultColor, paragraphAlignment: .center)
self.avatarNode.setPeer(context: context, theme: theme, peer: mainPeer, overrideImage: overrideImage, emptyColor: self.theme.avatarPlaceholderColor, clipStyle: isForum ? .roundedRect : .round, synchronousLoad: synchronousLoad)
self.avatarNode.setPeer(accountPeerId: accountPeerId, postbox: postbox, network: network, contentSettings: contentSettings, theme: theme, peer: mainPeer, overrideImage: overrideImage, emptyColor: self.theme.avatarPlaceholderColor, clipStyle: isForum ? .roundedRect : .round, synchronousLoad: synchronousLoad)
let onlineLayout = self.onlineNode.asyncLayout()
let (onlineSize, onlineApply) = onlineLayout(online, false)
@ -195,9 +223,11 @@ public final class SelectablePeerNode: ASDisplayNode {
let iconSize = self.iconView.update(
transition: .easeInOut(duration: 0.2),
component: AnyComponent(EmojiStatusComponent(
context: context,
animationCache: context.animationCache,
animationRenderer: context.animationRenderer,
postbox: postbox,
energyUsageSettings: energyUsageSettings,
resolveInlineStickers: resolveInlineStickers,
animationCache: animationCache,
animationRenderer: animationRenderer,
content: iconContent,
isVisibleForAnimations: true,
action: nil

View File

@ -423,7 +423,6 @@ public func storageUsageExceptionsScreen(
let source: ContextContentSource = .reference(StorageUsageExceptionsContextReferenceContentSource(sourceView: sourceNode.labelNode.view))
let contextController = ContextController(
account: context.account,
presentationData: presentationData,
source: source,
items: items,

View File

@ -43,7 +43,26 @@ private struct PeersEntry: Comparable, Identifiable {
}
func item(context: AccountContext) -> ListViewItem {
return HorizontalPeerItem(theme: self.theme, strings: self.strings, mode: .list(compact: true), context: context, peer: self.peer, presence: nil, unreadBadge: nil, action: { _ in }, contextAction: nil, isPeerSelected: { _ in return false }, customWidth: nil)
return HorizontalPeerItem(
theme: self.theme,
strings: self.strings,
mode: .list(compact: true),
accountPeerId: context.account.peerId,
postbox: context.account.postbox,
network: context.account.network,
energyUsageSettings: context.sharedContext.energyUsageSettings,
contentSettings: context.currentContentSettings.with { $0 },
animationCache: context.animationCache,
animationRenderer: context.animationRenderer,
resolveInlineStickers: context.engine.stickers.resolveInlineStickers,
peer: self.peer,
presence: nil,
unreadBadge: nil,
action: { _ in },
contextAction: nil,
isPeerSelected: { _ in return false },
customWidth: nil
)
}
}

View File

@ -438,12 +438,41 @@ public func passcodeOptionsAccessController(context: AccountContext, animateIn:
}
}
public func passcodeEntryController(context: AccountContext, animateIn: Bool = true, modalPresentation: Bool = false, completion: @escaping (Bool) -> Void) -> Signal<ViewController?, NoError> {
return context.sharedContext.accountManager.transaction { transaction -> PostboxAccessChallengeData in
public func passcodeEntryController(
context: AccountContext,
animateIn: Bool = true,
modalPresentation: Bool = false,
completion: @escaping (Bool) -> Void
) -> Signal<ViewController?, NoError> {
return passcodeEntryController(
accountManager: context.sharedContext.accountManager,
applicationBindings: context.sharedContext.applicationBindings,
presentationData: context.sharedContext.currentPresentationData.with { $0 },
updatedPresentationData: context.sharedContext.presentationData,
statusBarHost: context.sharedContext.mainWindow?.statusBarHost,
appLockContext: context.sharedContext.appLockContext,
animateIn: animateIn,
modalPresentation: modalPresentation,
completion: completion
)
}
public func passcodeEntryController(
accountManager: AccountManager<TelegramAccountManagerTypes>,
applicationBindings: TelegramApplicationBindings,
presentationData: PresentationData,
updatedPresentationData: Signal<PresentationData, NoError>,
statusBarHost: StatusBarHost?,
appLockContext: AppLockContext,
animateIn: Bool = true,
modalPresentation: Bool = false,
completion: @escaping (Bool) -> Void
) -> Signal<ViewController?, NoError> {
return accountManager.transaction { transaction -> PostboxAccessChallengeData in
return transaction.getAccessChallengeData()
}
|> mapToSignal { accessChallengeData -> Signal<(PostboxAccessChallengeData, PresentationPasscodeSettings?), NoError> in
return context.sharedContext.accountManager.transaction { transaction -> (PostboxAccessChallengeData, PresentationPasscodeSettings?) in
return accountManager.transaction { transaction -> (PostboxAccessChallengeData, PresentationPasscodeSettings?) in
let passcodeSettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.presentationPasscodeSettings)?.get(PresentationPasscodeSettings.self)
return (accessChallengeData, passcodeSettings)
}
@ -459,12 +488,12 @@ public func passcodeEntryController(context: AccountContext, animateIn: Bool = t
biometrics = .enabled(nil)
#else
if let passcodeSettings = passcodeSettings, passcodeSettings.enableBiometrics {
biometrics = .enabled(context.sharedContext.applicationBindings.isMainApp ? passcodeSettings.biometricsDomainState : passcodeSettings.shareBiometricsDomainState)
biometrics = .enabled(applicationBindings.isMainApp ? passcodeSettings.biometricsDomainState : passcodeSettings.shareBiometricsDomainState)
} else {
biometrics = .none
}
#endif
let controller = PasscodeEntryController(applicationBindings: context.sharedContext.applicationBindings, accountManager: context.sharedContext.accountManager, appLockContext: context.sharedContext.appLockContext, presentationData: context.sharedContext.currentPresentationData.with { $0 }, presentationDataSignal: context.sharedContext.presentationData, statusBarHost: context.sharedContext.mainWindow?.statusBarHost, challengeData: challenge, biometrics: biometrics, arguments: PasscodeEntryControllerPresentationArguments(animated: false, fadeIn: true, cancel: {
let controller = PasscodeEntryController(applicationBindings: applicationBindings, accountManager: accountManager, appLockContext: appLockContext, presentationData: presentationData, presentationDataSignal: updatedPresentationData, statusBarHost: statusBarHost, challengeData: challenge, biometrics: biometrics, arguments: PasscodeEntryControllerPresentationArguments(animated: false, fadeIn: true, cancel: {
completion(false)
}, modalPresentation: modalPresentation))
controller.presentationCompleted = { [weak controller] in

View File

@ -687,7 +687,7 @@ public func themePickerController(context: AccountContext, focusOnItemTag: Theme
})))
}
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: themeController, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
let contextController = ContextController(presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: themeController, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
presentInGlobalOverlayImpl?(contextController, nil)
})
}, colorContextAction: { isCurrent, reference, accentColor, node, gesture in
@ -936,7 +936,7 @@ public func themePickerController(context: AccountContext, focusOnItemTag: Theme
}
}
}
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: themeController, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
let contextController = ContextController(presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: themeController, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
presentInGlobalOverlayImpl?(contextController, nil)
})
})

View File

@ -746,7 +746,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
})))
}
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: themeController, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
let contextController = ContextController(presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: themeController, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
presentInGlobalOverlayImpl?(contextController, nil)
})
}, colorContextAction: { isCurrent, reference, accentColor, node, gesture in
@ -995,7 +995,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
}
}
}
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: themeController, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
let contextController = ContextController(presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: themeController, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
presentInGlobalOverlayImpl?(contextController, nil)
})
})

View File

@ -37,6 +37,8 @@ swift_library(
"//submodules/TelegramUniversalVideoContent:TelegramUniversalVideoContent",
"//submodules/ComponentFlow:ComponentFlow",
"//submodules/TelegramUI/Components/EmojiStatusComponent:EmojiStatusComponent",
"//submodules/TelegramUI/Components/AnimationCache",
"//submodules/TelegramUI/Components/MultiAnimationRenderer",
],
visibility = [
"//visibility:public",

View File

@ -16,6 +16,9 @@ import StickerResources
import SaveToCameraRoll
import TelegramStringFormatting
import WallpaperBackgroundNode
import TelegramIntents
import AnimationCache
import MultiAnimationRenderer
public struct ShareControllerAction {
let title: String
@ -66,7 +69,7 @@ public enum ShareControllerSubject {
case image([ImageRepresentationWithReference])
case media(AnyMediaReference)
case mapMedia(TelegramMediaMap)
case fromExternal(([PeerId], [PeerId: Int64], String, Account, Bool) -> Signal<ShareControllerExternalStatus, ShareControllerError>)
case fromExternal(([PeerId], [PeerId: Int64], String, ShareControllerAccountContext, Bool) -> Signal<ShareControllerExternalStatus, ShareControllerError>)
}
private enum ExternalShareItem {
@ -297,6 +300,121 @@ private func collectExternalShareItems(strings: PresentationStrings, dateTimeFor
})
}
public protocol ShareControllerEnvironment: AnyObject {
var presentationData: PresentationData { get }
var updatedPresentationData: Signal<PresentationData, NoError> { get }
var isMainApp: Bool { get }
var energyUsageSettings: EnergyUsageSettings { get }
var mediaManager: MediaManager? { get }
func setAccountUserInterfaceInUse(id: AccountRecordId) -> Disposable
func donateSendMessageIntent(account: ShareControllerAccountContext, peerIds: [EnginePeer.Id])
}
public final class ShareControllerAppEnvironment: ShareControllerEnvironment {
let sharedContext: SharedAccountContext
public private(set) var presentationData: PresentationData
public var updatedPresentationData: Signal<PresentationData, NoError> {
return self.sharedContext.presentationData
}
public var isMainApp: Bool {
return self.sharedContext.applicationBindings.isMainApp
}
public var energyUsageSettings: EnergyUsageSettings {
return self.sharedContext.energyUsageSettings
}
public var mediaManager: MediaManager? {
return self.sharedContext.mediaManager
}
public init(sharedContext: SharedAccountContext) {
self.sharedContext = sharedContext
self.presentationData = sharedContext.currentPresentationData.with { $0 }
}
public func setAccountUserInterfaceInUse(id: AccountRecordId) -> Disposable {
return self.sharedContext.setAccountUserInterfaceInUse(id)
}
public func donateSendMessageIntent(account: ShareControllerAccountContext, peerIds: [EnginePeer.Id]) {
if let account = account as? ShareControllerAppAccountContext {
TelegramIntents.donateSendMessageIntent(account: account.context.account, sharedContext: self.sharedContext, intentContext: .share, peerIds: peerIds)
} else {
assertionFailure()
}
}
}
public protocol ShareControllerAccountContext: AnyObject {
var accountId: AccountRecordId { get }
var accountPeerId: EnginePeer.Id { get }
var stateManager: AccountStateManager { get }
var animationCache: AnimationCache { get }
var animationRenderer: MultiAnimationRenderer { get }
var contentSettings: ContentSettings { get }
var appConfiguration: AppConfiguration { get }
func resolveInlineStickers(fileIds: [Int64]) -> Signal<[Int64: TelegramMediaFile], NoError>
}
public final class ShareControllerAppAccountContext: ShareControllerAccountContext {
public let context: AccountContext
public var accountId: AccountRecordId {
return self.context.account.id
}
public var accountPeerId: EnginePeer.Id {
return self.context.account.stateManager.accountPeerId
}
public var stateManager: AccountStateManager {
return self.context.account.stateManager
}
public var animationCache: AnimationCache {
return self.context.animationCache
}
public var animationRenderer: MultiAnimationRenderer {
return self.context.animationRenderer
}
public var contentSettings: ContentSettings {
return self.context.currentContentSettings.with { $0 }
}
public var appConfiguration: AppConfiguration {
return self.context.currentAppConfiguration.with { $0 }
}
public init(context: AccountContext) {
self.context = context
}
public func resolveInlineStickers(fileIds: [Int64]) -> Signal<[Int64: TelegramMediaFile], NoError> {
return self.context.engine.stickers.resolveInlineStickers(fileIds: fileIds)
}
}
public final class ShareControllerSwitchableAccount: Equatable {
public let account: ShareControllerAccountContext
public let peer: Peer
public init(account: ShareControllerAccountContext, peer: Peer) {
self.account = account
self.peer = peer
}
public static func ==(lhs: ShareControllerSwitchableAccount, rhs: ShareControllerSwitchableAccount) -> Bool {
if lhs.account !== rhs.account {
return false
}
if !arePeersEqual(lhs.peer, rhs.peer) {
return false
}
return true
}
}
public final class ShareController: ViewController {
private var controllerNode: ShareControllerNode {
return self.displayNode as! ShareControllerNode
@ -309,9 +427,8 @@ public final class ShareController: ViewController {
private var animatedIn = false
private let sharedContext: SharedAccountContext
private let currentContext: AccountContext
private var currentAccount: Account
private let environment: ShareControllerEnvironment
private var currentContext: ShareControllerAccountContext
private var presentationData: PresentationData
private var presentationDataDisposable: Disposable?
private let forceTheme: PresentationTheme?
@ -321,7 +438,7 @@ public final class ShareController: ViewController {
private let immediateExternalShare: Bool
private let subject: ShareControllerSubject
private let presetText: String?
private let switchableAccounts: [AccountWithInfo]
private let switchableAccounts: [ShareControllerSwitchableAccount]
private let immediatePeerId: PeerId?
private let segmentedValues: [ShareControllerSegmentedValue]?
private let fromForeignApp: Bool
@ -349,13 +466,31 @@ public final class ShareController: ViewController {
public var debugAction: (() -> Void)?
public convenience init(context: AccountContext, subject: ShareControllerSubject, presetText: String? = nil, preferredAction: ShareControllerPreferredAction = .default, showInChat: ((Message) -> Void)? = nil, fromForeignApp: Bool = false, segmentedValues: [ShareControllerSegmentedValue]? = nil, externalShare: Bool = true, immediateExternalShare: Bool = false, switchableAccounts: [AccountWithInfo] = [], immediatePeerId: PeerId? = nil, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, forceTheme: PresentationTheme? = nil, forcedActionTitle: String? = nil, shareAsLink: Bool = false) {
self.init(sharedContext: context.sharedContext, currentContext: context, subject: subject, presetText: presetText, preferredAction: preferredAction, showInChat: showInChat, fromForeignApp: fromForeignApp, segmentedValues: segmentedValues, externalShare: externalShare, immediateExternalShare: immediateExternalShare, switchableAccounts: switchableAccounts, immediatePeerId: immediatePeerId, updatedPresentationData: updatedPresentationData, forceTheme: forceTheme, forcedActionTitle: forcedActionTitle, shareAsLink: shareAsLink)
self.init(
environment: ShareControllerAppEnvironment(sharedContext: context.sharedContext),
currentContext: ShareControllerAppAccountContext(context: context),
subject: subject,
presetText: presetText,
preferredAction: preferredAction,
showInChat: showInChat,
fromForeignApp: fromForeignApp,
segmentedValues: segmentedValues,
externalShare: externalShare,
immediateExternalShare: immediateExternalShare,
switchableAccounts: switchableAccounts.map { info in
return ShareControllerSwitchableAccount(account: ShareControllerAppAccountContext(context: context.sharedContext.makeTempAccountContext(account: info.account)), peer: info.peer)
},
immediatePeerId: immediatePeerId,
updatedPresentationData: updatedPresentationData,
forceTheme: forceTheme,
forcedActionTitle: forcedActionTitle,
shareAsLink: shareAsLink
)
}
public init(sharedContext: SharedAccountContext, currentContext: AccountContext, subject: ShareControllerSubject, presetText: String? = nil, preferredAction: ShareControllerPreferredAction = .default, showInChat: ((Message) -> Void)? = nil, fromForeignApp: Bool = false, segmentedValues: [ShareControllerSegmentedValue]? = nil, externalShare: Bool = true, immediateExternalShare: Bool = false, switchableAccounts: [AccountWithInfo] = [], immediatePeerId: PeerId? = nil, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, forceTheme: PresentationTheme? = nil, forcedActionTitle: String? = nil, shareAsLink: Bool = false) {
self.sharedContext = sharedContext
public init(environment: ShareControllerEnvironment, currentContext: ShareControllerAccountContext, subject: ShareControllerSubject, presetText: String? = nil, preferredAction: ShareControllerPreferredAction = .default, showInChat: ((Message) -> Void)? = nil, fromForeignApp: Bool = false, segmentedValues: [ShareControllerSegmentedValue]? = nil, externalShare: Bool = true, immediateExternalShare: Bool = false, switchableAccounts: [ShareControllerSwitchableAccount] = [], immediatePeerId: PeerId? = nil, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, forceTheme: PresentationTheme? = nil, forcedActionTitle: String? = nil, shareAsLink: Bool = false) {
self.environment = environment
self.currentContext = currentContext
self.currentAccount = currentContext.account
self.subject = subject
self.presetText = presetText
self.externalShare = externalShare
@ -367,7 +502,7 @@ public final class ShareController: ViewController {
self.forceTheme = forceTheme
self.shareAsLink = shareAsLink
self.presentationData = updatedPresentationData?.initial ?? sharedContext.currentPresentationData.with { $0 }
self.presentationData = updatedPresentationData?.initial ?? environment.presentationData
if let forceTheme = self.forceTheme {
self.presentationData = self.presentationData.withUpdated(theme: forceTheme)
}
@ -422,12 +557,12 @@ public final class ShareController: ViewController {
canSave = true
isVideo = file.isVideo
}
if case .saveToCameraRoll = preferredAction, canSave {
if let currentContext = currentContext as? ShareControllerAppAccountContext, case .saveToCameraRoll = preferredAction, canSave {
self.actionIsMediaSaving = true
self.defaultAction = ShareControllerAction(title: isVideo ? self.presentationData.strings.Gallery_SaveVideo : self.presentationData.strings.Gallery_SaveImage, action: { [weak self] in
if let strongSelf = self {
if case let .message(message, media) = mediaReference, let messageId = message.id, let file = media as? TelegramMediaFile {
let _ = (messageMediaFileStatus(context: currentContext, messageId: messageId, file: file)
let _ = (messageMediaFileStatus(context: currentContext.context, messageId: messageId, file: file)
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self] fetchStatus in
if let strongSelf = self {
@ -490,7 +625,7 @@ public final class ShareController: ViewController {
guard let strongSelf = self else {
return
}
let _ = (TelegramEngine(account: strongSelf.currentAccount).messages.exportMessageLink(peerId: chatPeer.id, messageId: message.id)
let _ = (_internal_exportMessageLink(postbox: strongSelf.currentContext.stateManager.postbox, network: strongSelf.currentContext.stateManager.network, peerId: chatPeer.id, messageId: message.id)
|> map { result -> String? in
return result
}
@ -517,14 +652,14 @@ public final class ShareController: ViewController {
})
}
self.presentationDataDisposable = ((updatedPresentationData?.signal ?? self.sharedContext.presentationData)
self.presentationDataDisposable = ((updatedPresentationData?.signal ?? self.environment.updatedPresentationData)
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
if let strongSelf = self, strongSelf.isNodeLoaded {
strongSelf.controllerNode.updatePresentationData(presentationData)
}
})
self.switchToAccount(account: currentAccount, animateIn: false)
self.switchToAccount(account: self.currentContext, animateIn: false)
if self.fromForeignApp {
if let application = UIApplication.value(forKeyPath: #keyPath(UIApplication.shared)) as? UIApplication {
@ -555,7 +690,7 @@ public final class ShareController: ViewController {
fromPublicChannel = true
}
self.displayNode = ShareControllerNode(sharedContext: self.sharedContext, presentationData: self.presentationData, presetText: self.presetText, defaultAction: self.defaultAction, requestLayout: { [weak self] transition in
self.displayNode = ShareControllerNode(environment: self.environment, presentationData: self.presentationData, presetText: self.presetText, defaultAction: self.defaultAction, requestLayout: { [weak self] transition in
self?.requestLayout(transition: transition)
}, presentError: { [weak self] title, text in
guard let strongSelf = self else {
@ -833,13 +968,13 @@ public final class ShareController: ViewController {
}
var useLegacy = false
if self.sharedContext.applicationBindings.isMainApp {
if self.environment.isMainApp {
useLegacy = true
}
if peerIds.contains(where: { $0.namespace == Namespaces.Peer.SecretChat }) {
useLegacy = true
}
if let data = self.currentContext.currentAppConfiguration.with({ $0 }).data {
if let currentContext = self.currentContext as? ShareControllerAppAccountContext, let data = currentContext.context.currentAppConfiguration.with({ $0 }).data {
if let _ = data["ios_disable_modern_sharing"] {
useLegacy = true
}
@ -852,7 +987,7 @@ public final class ShareController: ViewController {
}
}
self.controllerNode.shareExternal = { [weak self] _ in
if let strongSelf = self {
if let strongSelf = self, let currentContext = strongSelf.currentContext as? ShareControllerAppAccountContext {
var collectableItems: [CollectableExternalShareItem] = []
var subject = strongSelf.subject
if let segmentedValues = strongSelf.segmentedValues {
@ -909,7 +1044,7 @@ public final class ShareController: ViewController {
}
}
}
let accountPeerId = strongSelf.currentAccount.peerId
let accountPeerId = strongSelf.currentContext.accountPeerId
let authorPeerId: PeerId?
if let author = message.effectiveAuthor {
authorPeerId = author.id
@ -922,7 +1057,7 @@ public final class ShareController: ViewController {
var restrictedText: String?
for attribute in message.attributes {
if let attribute = attribute as? RestrictedContentMessageAttribute {
restrictedText = attribute.platformText(platform: "ios", contentSettings: strongSelf.currentContext.currentContentSettings.with { $0 }) ?? ""
restrictedText = attribute.platformText(platform: "ios", contentSettings: strongSelf.currentContext.contentSettings) ?? ""
}
}
@ -935,7 +1070,7 @@ public final class ShareController: ViewController {
case .fromExternal:
break
}
return (collectExternalShareItems(strings: strongSelf.presentationData.strings, dateTimeFormat: strongSelf.presentationData.dateTimeFormat, nameOrder: strongSelf.presentationData.nameDisplayOrder, engine: TelegramEngine(account: strongSelf.currentAccount), postbox: strongSelf.currentAccount.postbox, collectableItems: collectableItems, takeOne: !strongSelf.immediateExternalShare)
return (collectExternalShareItems(strings: strongSelf.presentationData.strings, dateTimeFormat: strongSelf.presentationData.dateTimeFormat, nameOrder: strongSelf.presentationData.nameDisplayOrder, engine: currentContext.context.engine, postbox: strongSelf.currentContext.stateManager.postbox, collectableItems: collectableItems, takeOne: !strongSelf.immediateExternalShare)
|> deliverOnMainQueue)
|> map { state in
switch state {
@ -992,7 +1127,7 @@ public final class ShareController: ViewController {
}
strongSelf.controllerNode.animateOut(shared: false, completion: {})
let presentationData = strongSelf.sharedContext.currentPresentationData.with { $0 }
let presentationData = strongSelf.environment.presentationData
let controller = ActionSheetController(presentationData: presentationData)
controller.dismissed = { [weak self] cancelled in
if cancelled {
@ -1004,10 +1139,21 @@ public final class ShareController: ViewController {
}
var items: [ActionSheetItem] = []
for info in strongSelf.switchableAccounts {
items.append(ActionSheetPeerItem(context: strongSelf.sharedContext.makeTempAccountContext(account: info.account), peer: EnginePeer(info.peer), title: EnginePeer(info.peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), isSelected: info.account.id == strongSelf.currentAccount.id, strings: presentationData.strings, theme: presentationData.theme, action: { [weak self] in
dismissAction()
self?.switchToAccount(account: info.account, animateIn: true)
}))
items.append(ActionSheetPeerItem(
accountPeerId: info.account.accountPeerId,
postbox: info.account.stateManager.postbox,
network: info.account.stateManager.network,
contentSettings: info.account.contentSettings,
peer: EnginePeer(info.peer),
title: EnginePeer(info.peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder),
isSelected: info.account.accountId == strongSelf.currentContext.accountId,
strings: presentationData.strings,
theme: presentationData.theme,
action: { [weak self] in
dismissAction()
self?.switchToAccount(account: info.account, animateIn: true)
}
))
}
controller.setItemGroups([
ActionSheetItemGroup(items: items)
@ -1023,7 +1169,7 @@ public final class ShareController: ViewController {
self.peersDisposable.set((self.peers.get()
|> deliverOnMainQueue).start(next: { [weak self] next in
if let strongSelf = self {
strongSelf.controllerNode.updatePeers(context: strongSelf.sharedContext.makeTempAccountContext(account: strongSelf.currentAccount), switchableAccounts: strongSelf.switchableAccounts, peers: next.0, accountPeer: next.1, defaultAction: strongSelf.defaultAction)
strongSelf.controllerNode.updatePeers(context: strongSelf.currentContext, switchableAccounts: strongSelf.switchableAccounts, peers: next.0, accountPeer: next.1, defaultAction: strongSelf.defaultAction)
}
}))
self._ready.set(self.controllerNode.ready.get())
@ -1034,9 +1180,20 @@ public final class ShareController: ViewController {
}
private func shareModern(text: String, peerIds: [EnginePeer.Id], topicIds: [EnginePeer.Id: Int64], showNames: Bool, silently: Bool) -> Signal<ShareState, ShareControllerError> {
return self.currentContext.engine.data.get(EngineDataMap(
peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:))
))
return self.currentContext.stateManager.postbox.combinedView(
keys: peerIds.map { peerId in
return PostboxViewKey.basicPeer(peerId)
}
)
|> map { views -> [EnginePeer.Id: EnginePeer?] in
var result: [EnginePeer.Id: EnginePeer?] = [:]
for peerId in peerIds {
if let view = views.views[PostboxViewKey.basicPeer(peerId)] as? BasicPeerView, let peer = view.peer {
result[peerId] = EnginePeer(peer)
}
}
return result
}
|> deliverOnMainQueue
|> castError(ShareControllerError.self)
|> mapToSignal { [weak self] peers -> Signal<ShareState, ShareControllerError> in
@ -1111,7 +1268,24 @@ public final class ShareController: ViewController {
))
}
messages = transformMessages(messages, showNames: showNames, silently: silently)
shareSignals.append(standaloneSendEnqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
shareSignals.append(standaloneSendEnqueueMessages(
accountPeerId: strongSelf.currentContext.accountPeerId,
postbox: strongSelf.currentContext.stateManager.postbox,
network: strongSelf.currentContext.stateManager.network,
stateManager: strongSelf.currentContext.stateManager,
auxiliaryMethods: AccountAuxiliaryMethods(fetchResource: { account, resource, ranges, _ in
return nil
}, fetchResourceMediaReferenceHash: { resource in
return .single(nil)
}, prepareSecretThumbnailData: { data in
return nil
}, backgroundUpload: { postbox, _, resource in
return .single(nil)
}),
peerId: peerId,
threadId: topicIds[peerId],
messages: messages
))
}
case let .text(string):
for peerId in peerIds {
@ -1155,7 +1329,24 @@ public final class ShareController: ViewController {
replyToMessageId: replyToMessageId
))
messages = transformMessages(messages, showNames: showNames, silently: silently)
shareSignals.append(standaloneSendEnqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
shareSignals.append(standaloneSendEnqueueMessages(
accountPeerId: strongSelf.currentContext.accountPeerId,
postbox: strongSelf.currentContext.stateManager.postbox,
network: strongSelf.currentContext.stateManager.network,
stateManager: strongSelf.currentContext.stateManager,
auxiliaryMethods: AccountAuxiliaryMethods(fetchResource: { account, resource, ranges, _ in
return nil
}, fetchResourceMediaReferenceHash: { resource in
return .single(nil)
}, prepareSecretThumbnailData: { data in
return nil
}, backgroundUpload: { postbox, _, resource in
return .single(nil)
}),
peerId: peerId,
threadId: topicIds[peerId],
messages: messages
))
}
case let .quote(string, url):
for peerId in peerIds {
@ -1203,7 +1394,24 @@ public final class ShareController: ViewController {
replyToMessageId: replyToMessageId
))
messages = transformMessages(messages, showNames: showNames, silently: silently)
shareSignals.append(standaloneSendEnqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
shareSignals.append(standaloneSendEnqueueMessages(
accountPeerId: strongSelf.currentContext.accountPeerId,
postbox: strongSelf.currentContext.stateManager.postbox,
network: strongSelf.currentContext.stateManager.network,
stateManager: strongSelf.currentContext.stateManager,
auxiliaryMethods: AccountAuxiliaryMethods(fetchResource: { account, resource, ranges, _ in
return nil
}, fetchResourceMediaReferenceHash: { resource in
return .single(nil)
}, prepareSecretThumbnailData: { data in
return nil
}, backgroundUpload: { postbox, _, resource in
return .single(nil)
}),
peerId: peerId,
threadId: topicIds[peerId],
messages: messages
))
}
case let .image(representations):
for peerId in peerIds {
@ -1246,7 +1454,24 @@ public final class ShareController: ViewController {
))
}
messages = transformMessages(messages, showNames: showNames, silently: silently)
shareSignals.append(standaloneSendEnqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
shareSignals.append(standaloneSendEnqueueMessages(
accountPeerId: strongSelf.currentContext.accountPeerId,
postbox: strongSelf.currentContext.stateManager.postbox,
network: strongSelf.currentContext.stateManager.network,
stateManager: strongSelf.currentContext.stateManager,
auxiliaryMethods: AccountAuxiliaryMethods(fetchResource: { account, resource, ranges, _ in
return nil
}, fetchResourceMediaReferenceHash: { resource in
return .single(nil)
}, prepareSecretThumbnailData: { data in
return nil
}, backgroundUpload: { postbox, _, resource in
return .single(nil)
}),
peerId: peerId,
threadId: topicIds[peerId],
messages: messages
))
}
case let .media(mediaReference):
var sendTextAsCaption = false
@ -1339,7 +1564,24 @@ public final class ShareController: ViewController {
replyToMessageId: replyToMessageId
))
messages = transformMessages(messages, showNames: showNames, silently: silently)
shareSignals.append(standaloneSendEnqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
shareSignals.append(standaloneSendEnqueueMessages(
accountPeerId: strongSelf.currentContext.accountPeerId,
postbox: strongSelf.currentContext.stateManager.postbox,
network: strongSelf.currentContext.stateManager.network,
stateManager: strongSelf.currentContext.stateManager,
auxiliaryMethods: AccountAuxiliaryMethods(fetchResource: { account, resource, ranges, _ in
return nil
}, fetchResourceMediaReferenceHash: { resource in
return .single(nil)
}, prepareSecretThumbnailData: { data in
return nil
}, backgroundUpload: { postbox, _, resource in
return .single(nil)
}),
peerId: peerId,
threadId: topicIds[peerId],
messages: messages
))
}
case let .mapMedia(media):
for peerId in peerIds {
@ -1381,7 +1623,24 @@ public final class ShareController: ViewController {
replyToMessageId: replyToMessageId
))
messages = transformMessages(messages, showNames: showNames, silently: silently)
shareSignals.append(standaloneSendEnqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
shareSignals.append(standaloneSendEnqueueMessages(
accountPeerId: strongSelf.currentContext.accountPeerId,
postbox: strongSelf.currentContext.stateManager.postbox,
network: strongSelf.currentContext.stateManager.network,
stateManager: strongSelf.currentContext.stateManager,
auxiliaryMethods: AccountAuxiliaryMethods(fetchResource: { account, resource, ranges, _ in
return nil
}, fetchResourceMediaReferenceHash: { resource in
return .single(nil)
}, prepareSecretThumbnailData: { data in
return nil
}, backgroundUpload: { postbox, _, resource in
return .single(nil)
}),
peerId: peerId,
threadId: topicIds[peerId],
messages: messages
))
}
case let .messages(messages):
for peerId in peerIds {
@ -1484,10 +1743,27 @@ public final class ShareController: ViewController {
))
}
messagesToEnqueue = transformMessages(messagesToEnqueue, showNames: showNames, silently: silently)
shareSignals.append(standaloneSendEnqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messagesToEnqueue))
shareSignals.append(standaloneSendEnqueueMessages(
accountPeerId: strongSelf.currentContext.accountPeerId,
postbox: strongSelf.currentContext.stateManager.postbox,
network: strongSelf.currentContext.stateManager.network,
stateManager: strongSelf.currentContext.stateManager,
auxiliaryMethods: AccountAuxiliaryMethods(fetchResource: { account, resource, ranges, _ in
return nil
}, fetchResourceMediaReferenceHash: { resource in
return .single(nil)
}, prepareSecretThumbnailData: { data in
return nil
}, backgroundUpload: { postbox, _, resource in
return .single(nil)
}),
peerId: peerId,
threadId: topicIds[peerId],
messages: messagesToEnqueue
))
}
case let .fromExternal(f):
return f(peerIds, topicIds, text, strongSelf.currentAccount, silently)
return f(peerIds, topicIds, text, strongSelf.currentContext, silently)
|> map { state -> ShareState in
switch state {
case let .preparing(long):
@ -1499,14 +1775,21 @@ public final class ShareController: ViewController {
}
}
}
let account = strongSelf.currentAccount
let account = strongSelf.currentContext
let queue = Queue.mainQueue()
//var displayedError = false
return combineLatest(queue: queue, shareSignals)
|> `catch` { error -> Signal<[StandaloneSendMessageStatus], ShareControllerError> in
Queue.mainQueue().async {
let _ = (TelegramEngine(account: account).data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: error.peerId))
|> deliverOnMainQueue).start(next: { peer in
let _ = (account.stateManager.postbox.combinedView(keys: [PostboxViewKey.basicPeer(error.peerId)])
|> map { views -> EnginePeer? in
if let view = views.views[PostboxViewKey.basicPeer(error.peerId)] as? BasicPeerView {
return view.peer.flatMap(EnginePeer.init)
} else {
return nil
}
}
|> deliverOnMainQueue).start(next: { peer in
guard let strongSelf = self, let peer = peer else {
return
}
@ -1535,13 +1818,16 @@ public final class ShareController: ViewController {
}
private func shareLegacy(text: String, peerIds: [EnginePeer.Id], topicIds: [EnginePeer.Id: Int64], showNames: Bool, silently: Bool) -> Signal<ShareState, ShareControllerError> {
return self.currentContext.engine.data.get(EngineDataMap(
guard let currentContext = self.currentContext as? ShareControllerAppAccountContext else {
return .single(.done)
}
return currentContext.context.engine.data.get(EngineDataMap(
peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:))
))
|> deliverOnMainQueue
|> castError(ShareControllerError.self)
|> mapToSignal { [weak self] peers -> Signal<ShareState, ShareControllerError> in
guard let strongSelf = self else {
guard let strongSelf = self, let currentContext = strongSelf.currentContext as? ShareControllerAppAccountContext else {
return .complete()
}
@ -1599,7 +1885,7 @@ public final class ShareController: ViewController {
messages.append(.message(text: url, attributes: [], inlineStickers: [:], mediaReference: nil, replyToMessageId: replyToMessageId, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
}
messages = transformMessages(messages, showNames: showNames, silently: silently)
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
shareSignals.append(enqueueMessages(account: currentContext.context.account, peerId: peerId, messages: messages))
}
case let .text(string):
for peerId in peerIds {
@ -1631,7 +1917,7 @@ public final class ShareController: ViewController {
}
messages.append(.message(text: string, attributes: [], inlineStickers: [:], mediaReference: nil, replyToMessageId: replyToMessageId, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
messages = transformMessages(messages, showNames: showNames, silently: silently)
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
shareSignals.append(enqueueMessages(account: currentContext.context.account, peerId: peerId, messages: messages))
}
case let .quote(string, url):
for peerId in peerIds {
@ -1666,7 +1952,7 @@ public final class ShareController: ViewController {
let entities = generateChatInputTextEntities(attributedText)
messages.append(.message(text: attributedText.string, attributes: [TextEntitiesMessageAttribute(entities: entities)], inlineStickers: [:], mediaReference: nil, replyToMessageId: replyToMessageId, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
messages = transformMessages(messages, showNames: showNames, silently: silently)
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
shareSignals.append(enqueueMessages(account: currentContext.context.account, peerId: peerId, messages: messages))
}
case let .image(representations):
for peerId in peerIds {
@ -1695,7 +1981,7 @@ public final class ShareController: ViewController {
var messages: [EnqueueMessage] = []
messages.append(.message(text: text, attributes: [], inlineStickers: [:], mediaReference: .standalone(media: TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: Int64.random(in: Int64.min ... Int64.max)), representations: representations.map({ $0.representation }), immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])), replyToMessageId: replyToMessageId, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
messages = transformMessages(messages, showNames: showNames, silently: silently)
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
shareSignals.append(enqueueMessages(account: currentContext.context.account, peerId: peerId, messages: messages))
}
case let .media(mediaReference):
var sendTextAsCaption = false
@ -1772,7 +2058,7 @@ public final class ShareController: ViewController {
}
messages.append(.message(text: sendTextAsCaption ? text : "", attributes: [], inlineStickers: [:], mediaReference: mediaReference, replyToMessageId: replyToMessageId, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
messages = transformMessages(messages, showNames: showNames, silently: silently)
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
shareSignals.append(enqueueMessages(account: currentContext.context.account, peerId: peerId, messages: messages))
}
case let .mapMedia(media):
for peerId in peerIds {
@ -1804,7 +2090,7 @@ public final class ShareController: ViewController {
}
messages.append(.message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: media), replyToMessageId: replyToMessageId, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
messages = transformMessages(messages, showNames: showNames, silently: silently)
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
shareSignals.append(enqueueMessages(account: currentContext.context.account, peerId: peerId, messages: messages))
}
case let .messages(messages):
for peerId in peerIds {
@ -1895,10 +2181,10 @@ public final class ShareController: ViewController {
messagesToEnqueue.append(.forward(source: message.id, threadId: threadId, grouping: .auto, attributes: [], correlationId: nil))
}
messagesToEnqueue = transformMessages(messagesToEnqueue, showNames: showNames, silently: silently)
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messagesToEnqueue))
shareSignals.append(enqueueMessages(account: currentContext.context.account, peerId: peerId, messages: messagesToEnqueue))
}
case let .fromExternal(f):
return f(peerIds, topicIds, text, strongSelf.currentAccount, silently)
return f(peerIds, topicIds, text, currentContext, silently)
|> map { state -> ShareState in
switch state {
case let .preparing(long):
@ -1910,7 +2196,7 @@ public final class ShareController: ViewController {
}
}
}
let account = strongSelf.currentAccount
let account = currentContext.context.account
let queue = Queue.mainQueue()
var displayedError = false
return combineLatest(queue: queue, shareSignals)
@ -1992,15 +2278,14 @@ public final class ShareController: ViewController {
}
private func saveToCameraRoll(messages: [Message], completion: @escaping () -> Void) {
let postbox = self.currentAccount.postbox
guard let accountContext = self.currentContext as? ShareControllerAppAccountContext else {
return
}
let context = accountContext.context
let postbox = self.currentContext.stateManager.postbox
let signals: [Signal<Float, NoError>] = messages.compactMap { message -> Signal<Float, NoError>? in
if let media = message.media.first {
let context: AccountContext
if self.currentContext.account.id == self.currentAccount.id {
context = self.currentContext
} else {
context = self.sharedContext.makeTempAccountContext(account: self.currentAccount)
}
return SaveToCameraRoll.saveToCameraRoll(context: context, postbox: postbox, userLocation: .peer(message.id.peerId), mediaReference: .message(message: MessageReference(message), media: media))
} else {
return nil
@ -2021,34 +2306,63 @@ public final class ShareController: ViewController {
}
private func saveToCameraRoll(representations: [ImageRepresentationWithReference]) {
let media = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: representations.map({ $0.representation }), immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])
let context: AccountContext
if self.currentContext.account.id == self.currentAccount.id {
context = self.currentContext
} else {
context = self.sharedContext.makeTempAccountContext(account: self.currentAccount)
guard let accountContext = self.currentContext as? ShareControllerAppAccountContext else {
return
}
let context = accountContext.context
let media = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: representations.map({ $0.representation }), immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])
self.controllerNode.transitionToProgressWithValue(signal: SaveToCameraRoll.saveToCameraRoll(context: context, postbox: context.account.postbox, userLocation: .other, mediaReference: .standalone(media: media)) |> map(Optional.init), dismissImmediately: true, completion: {})
}
private func saveToCameraRoll(mediaReference: AnyMediaReference, completion: (() -> Void)?) {
let context: AccountContext
if self.currentContext.account.id == self.currentAccount.id {
context = self.currentContext
} else {
context = self.sharedContext.makeTempAccountContext(account: self.currentAccount)
guard let accountContext = self.currentContext as? ShareControllerAppAccountContext else {
return
}
let context = accountContext.context
self.controllerNode.transitionToProgressWithValue(signal: SaveToCameraRoll.saveToCameraRoll(context: context, postbox: context.account.postbox, userLocation: .other, mediaReference: mediaReference) |> map(Optional.init), dismissImmediately: completion == nil, completion: completion ?? {})
}
private func switchToAccount(account: Account, animateIn: Bool) {
self.currentAccount = account
self.accountActiveDisposable.set(self.sharedContext.setAccountUserInterfaceInUse(account.id))
private func switchToAccount(account: ShareControllerAccountContext, animateIn: Bool) {
self.currentContext = account
self.accountActiveDisposable.set(self.environment.setAccountUserInterfaceInUse(id: account.accountId))
let tailChatList = account.stateManager.postbox.tailChatListView(
groupId: .root,
filterPredicate: nil,
count: 150,
summaryComponents: ChatListEntrySummaryComponents(
components: [
ChatListEntryMessageTagSummaryKey(
tag: .unseenPersonalMessage,
actionType: PendingMessageActionType.consumeUnseenPersonalMessage
): ChatListEntrySummaryComponents.Component(
tagSummary: ChatListEntryMessageTagSummaryComponent(namespace: Namespaces.Message.Cloud),
actionsSummary: ChatListEntryPendingMessageActionsSummaryComponent(namespace: Namespaces.Message.Cloud)
),
ChatListEntryMessageTagSummaryKey(
tag: .unseenReaction,
actionType: PendingMessageActionType.readReaction
): ChatListEntrySummaryComponents.Component(
tagSummary: ChatListEntryMessageTagSummaryComponent(namespace: Namespaces.Message.Cloud),
actionsSummary: ChatListEntryPendingMessageActionsSummaryComponent(namespace: Namespaces.Message.Cloud)
)
]
)
)
let peer = self.currentContext.stateManager.postbox.combinedView(keys: [PostboxViewKey.basicPeer(self.currentContext.accountPeerId)])
|> take(1)
|> map { views -> EnginePeer? in
guard let view = views.views[PostboxViewKey.basicPeer(self.currentContext.accountPeerId)] as? BasicPeerView else {
return nil
}
return view.peer.flatMap(EnginePeer.init)
}
self.peers.set(combineLatest(
TelegramEngine(account: self.currentAccount).data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.currentAccount.peerId)),
self.currentAccount.viewTracker.tailChatListView(groupId: .root, count: 150)
|> take(1)
peer,
tailChatList |> take(1)
)
|> mapToSignal { maybeAccountPeer, view -> Signal<([(EngineRenderedPeer, EnginePeer.Presence?)], EnginePeer), NoError> in
let accountPeer = maybeAccountPeer!
@ -2065,9 +2379,17 @@ public final class ShareController: ViewController {
}
}
return TelegramEngine(account: account).data.subscribe(EngineDataMap(
peers.map { TelegramEngine.EngineData.Item.Peer.Presence(id: $0.peerId) }
))
let key = PostboxViewKey.peerPresences(peerIds: Set(peers.map(\.peerId)))
return account.stateManager.postbox.combinedView(keys: [key])
|> map { views -> [EnginePeer.Id: EnginePeer.Presence?] in
var result: [EnginePeer.Id: EnginePeer.Presence?] = [:]
if let view = views.views[key] as? PeerPresencesView {
result = view.presences.mapValues { value -> EnginePeer.Presence? in
return EnginePeer.Presence(value)
}
}
return result
}
|> map { presenceMap -> ([(EngineRenderedPeer, EnginePeer.Presence?)], EnginePeer) in
var resultPeers: [(EngineRenderedPeer, EnginePeer.Presence?)] = []
for peer in peers {
@ -2080,7 +2402,7 @@ public final class ShareController: ViewController {
self.peersDisposable.set((self.peers.get()
|> deliverOnMainQueue).start(next: { [weak self] next in
if let strongSelf = self {
strongSelf.controllerNode.updatePeers(context: strongSelf.sharedContext.makeTempAccountContext(account: strongSelf.currentAccount), switchableAccounts: strongSelf.switchableAccounts, peers: next.0, accountPeer: next.1, defaultAction: strongSelf.defaultAction)
strongSelf.controllerNode.updatePeers(context: strongSelf.currentContext, switchableAccounts: strongSelf.switchableAccounts, peers: next.0, accountPeer: next.1, defaultAction: strongSelf.defaultAction)
if animateIn && !animatedIn {
animatedIn = true

View File

@ -22,8 +22,8 @@ enum ShareExternalState {
}
final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate {
private let sharedContext: SharedAccountContext
private var context: AccountContext?
private let environment: ShareControllerEnvironment
private var context: ShareControllerAccountContext?
private var presentationData: PresentationData
private let forceTheme: PresentationTheme?
private let externalShare: Bool
@ -87,8 +87,8 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
private let showNames = ValuePromise<Bool>(true)
init(sharedContext: SharedAccountContext, presentationData: PresentationData, presetText: String?, defaultAction: ShareControllerAction?, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void, presentError: @escaping (String?, String) -> Void, externalShare: Bool, immediateExternalShare: Bool, immediatePeerId: PeerId?, fromForeignApp: Bool, forceTheme: PresentationTheme?, fromPublicChannel: Bool, segmentedValues: [ShareControllerSegmentedValue]?) {
self.sharedContext = sharedContext
init(environment: ShareControllerEnvironment, presentationData: PresentationData, presetText: String?, defaultAction: ShareControllerAction?, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void, presentError: @escaping (String?, String) -> Void, externalShare: Bool, immediateExternalShare: Bool, immediatePeerId: PeerId?, fromForeignApp: Bool, forceTheme: PresentationTheme?, fromPublicChannel: Bool, segmentedValues: [ShareControllerSegmentedValue]?) {
self.environment = environment
self.presentationData = presentationData
self.forceTheme = forceTheme
self.externalShare = externalShare
@ -191,7 +191,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
}
}
self.actionButtonNode.contextAction = { [weak self] node, gesture in
if let strongSelf = self, let context = strongSelf.context, let node = node as? ContextReferenceContentNode {
if let strongSelf = self, let node = node as? ContextReferenceContentNode {
let presentationData = strongSelf.presentationData
let fromForeignApp = strongSelf.fromForeignApp
let items: Signal<ContextController.Items, NoError> =
@ -237,7 +237,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
])
return ContextController.Items(content: .list(items), animationCache: nil)
}
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .reference(ShareContextReferenceContentSource(sourceNode: node, customPosition: CGPoint(x: 0.0, y: fromForeignApp ? -116.0 : 0.0))), items: items, gesture: gesture)
let contextController = ContextController(presentationData: presentationData, source: .reference(ShareContextReferenceContentSource(sourceNode: node, customPosition: CGPoint(x: 0.0, y: fromForeignApp ? -116.0 : 0.0))), items: items, gesture: gesture)
contextController.immediateItemsTransitionAnimation = true
strongSelf.present?(contextController)
}
@ -378,7 +378,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
var didPresent = false
var presentImpl: (() -> Void)?
let threads = threadList(context: context, peerId: mainPeer.id)
let threads = threadList(accountPeerId: context.accountPeerId, postbox: context.stateManager.postbox, peerId: mainPeer.id)
|> deliverOnMainQueue
|> beforeNext { _ in
if !didPresent {
@ -388,7 +388,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
}
let topicsContentNode = ShareTopicsContainerNode(
sharedContext: self.sharedContext,
environment: self.environment,
context: context,
theme: self.presentationData.theme,
strings: self.presentationData.strings,
@ -781,9 +781,20 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
}
if let context = self.context, let tryShare = self.tryShare {
let _ = (context.engine.data.get(EngineDataMap(
peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:))
))
let _ = (context.stateManager.postbox.combinedView(
keys: peerIds.map { peerId in
return PostboxViewKey.basicPeer(peerId)
}
)
|> map { views -> [EnginePeer.Id: EnginePeer?] in
var result: [EnginePeer.Id: EnginePeer?] = [:]
for peerId in peerIds {
if let view = views.views[PostboxViewKey.basicPeer(peerId)] as? BasicPeerView, let peer = view.peer {
result[peerId] = EnginePeer(peer)
}
}
return result
}
|> deliverOnMainQueue).start(next: { [weak self] peers in
guard let self else {
return
@ -839,7 +850,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
}
if let context = self.context {
donateSendMessageIntent(account: context.account, sharedContext: self.sharedContext, intentContext: .share, peerIds: peerIds)
self.environment.donateSendMessageIntent(account: context, peerIds: peerIds)
}
if let signal = self.share?(self.inputFieldNode.text, peerIds, topicIds, showNames, silently) {
@ -879,7 +890,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
self.completed?(peerIds)
let delay: Double
if let peerId = peerIds.first, peerIds.count == 1 && peerId == self.context?.account.peerId {
if let peerId = peerIds.first, peerIds.count == 1 && peerId == self.context?.accountPeerId {
delay = 0.88
} else {
delay = 0.44
@ -903,7 +914,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
if fromForeignApp, case let .preparing(long) = status, !transitioned {
transitioned = true
if long {
strongSelf.transitionToContentNode(ShareProlongedLoadingContainerNode(theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, forceNativeAppearance: true, account: strongSelf.context?.account, sharedContext: strongSelf.sharedContext), fastOut: true)
strongSelf.transitionToContentNode(ShareProlongedLoadingContainerNode(theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, forceNativeAppearance: true, postbox: strongSelf.context?.stateManager.postbox, environment: strongSelf.environment), fastOut: true)
} else {
strongSelf.transitionToContentNode(ShareLoadingContainerNode(theme: strongSelf.presentationData.theme, forceNativeAppearance: true), fastOut: true)
}
@ -1012,7 +1023,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
}
}
func updatePeers(context: AccountContext, switchableAccounts: [AccountWithInfo], peers: [(EngineRenderedPeer, EnginePeer.Presence?)], accountPeer: EnginePeer, defaultAction: ShareControllerAction?) {
func updatePeers(context: ShareControllerAccountContext, switchableAccounts: [ShareControllerSwitchableAccount], peers: [(EngineRenderedPeer, EnginePeer.Presence?)], accountPeer: EnginePeer, defaultAction: ShareControllerAction?) {
self.context = context
if let peersContentNode = self.peersContentNode, peersContentNode.accountPeer.id == accountPeer.id {
@ -1022,27 +1033,47 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
if let peerId = self.immediatePeerId {
self.immediatePeerId = nil
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.RenderedPeer(id: peerId))
let _ = (context.stateManager.postbox.combinedView(keys: [PostboxViewKey.peer(peerId: peerId, components: [])])
|> take(1)
|> map { views -> EngineRenderedPeer? in
guard let view = views.views[PostboxViewKey.peer(peerId: peerId, components: [])] as? PeerView else {
return nil
}
var peers: [EnginePeer.Id: EnginePeer] = [:]
guard let peer = view.peers[peerId] else {
return nil
}
peers[peer.id] = EnginePeer(peer)
if let secretChat = peer as? TelegramSecretChat {
guard let mainPeer = view.peers[secretChat.regularPeerId] else {
return nil
}
peers[mainPeer.id] = EnginePeer(mainPeer)
}
return EngineRenderedPeer(peerId: peerId, peers: peers, associatedMedia: view.media)
}
|> deliverOnMainQueue).start(next: { [weak self] peer in
if let strongSelf = self, let peer = peer {
strongSelf.controllerInteraction?.togglePeer(peer, peer.peerId != context.account.peerId)
strongSelf.controllerInteraction?.togglePeer(peer, peer.peerId != context.accountPeerId)
}
})
}
let animated = self.peersContentNode == nil
let peersContentNode = SharePeersContainerNode(sharedContext: self.sharedContext, context: context, switchableAccounts: switchableAccounts, theme: self.presentationData.theme, strings: self.presentationData.strings, nameDisplayOrder: self.presentationData.nameDisplayOrder, peers: peers, accountPeer: accountPeer, controllerInteraction: self.controllerInteraction!, externalShare: self.externalShare, switchToAnotherAccount: { [weak self] in
let peersContentNode = SharePeersContainerNode(environment: self.environment, context: context, switchableAccounts: switchableAccounts, theme: self.presentationData.theme, strings: self.presentationData.strings, nameDisplayOrder: self.presentationData.nameDisplayOrder, peers: peers, accountPeer: accountPeer, controllerInteraction: self.controllerInteraction!, externalShare: self.externalShare, switchToAnotherAccount: { [weak self] in
self?.switchToAnotherAccount?()
}, debugAction: { [weak self] in
self?.debugAction?()
}, extendedInitialReveal: self.presetText != nil, segmentedValues: self.segmentedValues)
self.peersContentNode = peersContentNode
peersContentNode.openSearch = { [weak self] in
let _ = (context.engine.peers.recentlySearchedPeers()
let _ = (_internal_recentlySearchedPeers(postbox: context.stateManager.postbox)
|> take(1)
|> deliverOnMainQueue).start(next: { peers in
if let strongSelf = self {
let searchContentNode = ShareSearchContainerNode(sharedContext: strongSelf.sharedContext, context: context, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, controllerInteraction: strongSelf.controllerInteraction!, recentPeers: peers.filter({ $0.peer.peerId.namespace != Namespaces.Peer.SecretChat }).map({ EngineRenderedPeer($0.peer) }))
let searchContentNode = ShareSearchContainerNode(environment: strongSelf.environment, context: context, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, controllerInteraction: strongSelf.controllerInteraction!, recentPeers: peers.filter({ $0.peer.peerId.namespace != Namespaces.Peer.SecretChat }).map({ EngineRenderedPeer($0.peer) }))
searchContentNode.cancel = {
if let strongSelf = self, let peersContentNode = strongSelf.peersContentNode {
strongSelf.transitionToContentNode(peersContentNode)
@ -1216,7 +1247,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
transition.updateAlpha(node: self.actionSeparatorNode, alpha: 0.0)
transition.updateAlpha(node: self.actionsBackgroundNode, alpha: 0.0)
self.transitionToContentNode(ShareProlongedLoadingContainerNode(theme: self.presentationData.theme, strings: self.presentationData.strings, forceNativeAppearance: true, account: self.context?.account, sharedContext: self.sharedContext), fastOut: true)
self.transitionToContentNode(ShareProlongedLoadingContainerNode(theme: self.presentationData.theme, strings: self.presentationData.strings, forceNativeAppearance: true, postbox: self.context?.stateManager.postbox, environment: self.environment), fastOut: true)
let timestamp = CACurrentMediaTime()
self.shareDisposable.set(signal.start(completed: { [weak self] in
let minDelay = 0.6
@ -1307,7 +1338,7 @@ private final class ShareContextReferenceContentSource: ContextReferenceContentS
}
}
private func threadList(context: AccountContext, peerId: EnginePeer.Id) -> Signal<EngineChatList, NoError> {
private func threadList(accountPeerId: EnginePeer.Id, postbox: Postbox, peerId: EnginePeer.Id) -> Signal<EngineChatList, NoError> {
let viewKey: PostboxViewKey = .messageHistoryThreadIndex(
id: peerId,
summaryComponents: ChatListEntrySummaryComponents(
@ -1315,10 +1346,10 @@ private func threadList(context: AccountContext, peerId: EnginePeer.Id) -> Signa
)
)
return context.account.postbox.combinedView(keys: [viewKey])
return postbox.combinedView(keys: [viewKey])
|> mapToSignal { view -> Signal<CombinedView, NoError> in
return context.account.postbox.transaction { transaction -> CombinedView in
if let peer = transaction.getPeer(context.account.peerId) {
return postbox.transaction { transaction -> CombinedView in
if let peer = transaction.getPeer(accountPeerId) {
transaction.updatePeersInternal([peer]) { current, _ in
return current ?? peer
}

View File

@ -91,7 +91,8 @@ final class ShareControllerGridSectionNode: ASDisplayNode {
}
final class ShareControllerPeerGridItem: GridItem {
let context: AccountContext
let environment: ShareControllerEnvironment
let context: ShareControllerAccountContext
let theme: PresentationTheme
let strings: PresentationStrings
let peer: EngineRenderedPeer?
@ -103,7 +104,8 @@ final class ShareControllerPeerGridItem: GridItem {
let section: GridSection?
init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, peer: EngineRenderedPeer?, presence: EnginePeer.Presence?, topicId: Int64?, threadData: MessageHistoryThreadData?, controllerInteraction: ShareControllerInteraction, sectionTitle: String? = nil, search: Bool = false) {
init(environment: ShareControllerEnvironment, context: ShareControllerAccountContext, theme: PresentationTheme, strings: PresentationStrings, peer: EngineRenderedPeer?, presence: EnginePeer.Presence?, topicId: Int64?, threadData: MessageHistoryThreadData?, controllerInteraction: ShareControllerInteraction, sectionTitle: String? = nil, search: Bool = false) {
self.environment = environment
self.context = context
self.theme = theme
self.strings = strings
@ -124,7 +126,7 @@ final class ShareControllerPeerGridItem: GridItem {
func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode {
let node = ShareControllerPeerGridItemNode()
node.controllerInteraction = self.controllerInteraction
node.setup(context: self.context, theme: self.theme, strings: self.strings, peer: self.peer, presence: self.presence, topicId: self.topicId, threadData: self.threadData, search: self.search, synchronousLoad: synchronousLoad, force: false)
node.setup(environment: self.environment, context: self.context, theme: self.theme, strings: self.strings, peer: self.peer, presence: self.presence, topicId: self.topicId, threadData: self.threadData, search: self.search, synchronousLoad: synchronousLoad, force: false)
return node
}
@ -134,12 +136,12 @@ final class ShareControllerPeerGridItem: GridItem {
return
}
node.controllerInteraction = self.controllerInteraction
node.setup(context: self.context, theme: self.theme, strings: self.strings, peer: self.peer, presence: self.presence, topicId: self.topicId, threadData: self.threadData, search: self.search, synchronousLoad: false, force: false)
node.setup(environment: self.environment, context: self.context, theme: self.theme, strings: self.strings, peer: self.peer, presence: self.presence, topicId: self.topicId, threadData: self.threadData, search: self.search, synchronousLoad: false, force: false)
}
}
final class ShareControllerPeerGridItemNode: GridItemNode {
private var currentState: (AccountContext, PresentationTheme, PresentationStrings, EngineRenderedPeer?, Bool, EnginePeer.Presence?, Int64?, MessageHistoryThreadData?)?
private var currentState: (ShareControllerEnvironment, ShareControllerAccountContext, PresentationTheme, PresentationStrings, EngineRenderedPeer?, Bool, EnginePeer.Presence?, Int64?, MessageHistoryThreadData?)?
private let peerNode: SelectablePeerNode
private var presenceManager: PeerPresenceStatusManager?
@ -149,7 +151,7 @@ final class ShareControllerPeerGridItemNode: GridItemNode {
private var absoluteLocation: (CGRect, CGSize)?
var peerId: EnginePeer.Id? {
return self.currentState?.3?.peerId
return self.currentState?.4?.peerId
}
override init() {
@ -159,7 +161,7 @@ final class ShareControllerPeerGridItemNode: GridItemNode {
self.peerNode.toggleSelection = { [weak self] in
if let strongSelf = self {
if let (_, _, _, maybePeer, search, _, _, _) = strongSelf.currentState, let peer = maybePeer {
if let (_, _, _, _, maybePeer, search, _, _, _) = strongSelf.currentState, let peer = maybePeer {
if let _ = peer.peers[peer.peerId] {
strongSelf.controllerInteraction?.togglePeer(peer, search)
}
@ -171,7 +173,7 @@ final class ShareControllerPeerGridItemNode: GridItemNode {
guard let strongSelf = self, let currentState = strongSelf.currentState else {
return
}
strongSelf.setup(context: currentState.0, theme: currentState.1, strings: currentState.2, peer: currentState.3, presence: currentState.5, topicId: currentState.6, threadData: currentState.7, search: currentState.4, synchronousLoad: false, force: true)
strongSelf.setup(environment: currentState.0, context: currentState.1, theme: currentState.2, strings: currentState.3, peer: currentState.4, presence: currentState.6, topicId: currentState.7, threadData: currentState.8, search: currentState.5, synchronousLoad: false, force: true)
})
}
@ -183,13 +185,13 @@ final class ShareControllerPeerGridItemNode: GridItemNode {
}
}
func setup(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, peer: EngineRenderedPeer?, presence: EnginePeer.Presence?, topicId: Int64?, threadData: MessageHistoryThreadData?, search: Bool, synchronousLoad: Bool, force: Bool) {
if force || self.currentState == nil || self.currentState!.0 !== context || self.currentState!.2 !== theme || self.currentState!.3 != peer || self.currentState!.5 != presence || self.currentState!.6 != topicId {
func setup(environment: ShareControllerEnvironment, context: ShareControllerAccountContext, theme: PresentationTheme, strings: PresentationStrings, peer: EngineRenderedPeer?, presence: EnginePeer.Presence?, topicId: Int64?, threadData: MessageHistoryThreadData?, search: Bool, synchronousLoad: Bool, force: Bool) {
if force || self.currentState == nil || self.currentState!.1 !== context || self.currentState!.3 !== theme || self.currentState!.4 != peer || self.currentState!.6 != presence || self.currentState!.7 != topicId {
let itemTheme = SelectablePeerNodeTheme(textColor: theme.actionSheet.primaryTextColor, secretTextColor: theme.chatList.secretTitleColor, selectedTextColor: theme.actionSheet.controlAccentColor, checkBackgroundColor: theme.actionSheet.opaqueItemBackgroundColor, checkFillColor: theme.actionSheet.controlAccentColor, checkColor: theme.actionSheet.checkContentColor, avatarPlaceholderColor: theme.list.mediaPlaceholderColor)
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
var online = false
if case let .user(peer) = peer?.peer, let presence = presence, !isServicePeer(peer) && !peer.flags.contains(.isSupport) && peer.id != context.account.peerId {
if case let .user(peer) = peer?.peer, let presence = presence, !isServicePeer(peer) && !peer.flags.contains(.isSupport) && peer.id != context.accountPeerId {
let relativeStatus = relativeUserPresenceStatus(presence, relativeTo: timestamp)
if case .online = relativeStatus {
online = true
@ -198,7 +200,27 @@ final class ShareControllerPeerGridItemNode: GridItemNode {
self.peerNode.theme = itemTheme
if let peer = peer {
self.peerNode.setup(context: context, theme: theme, strings: strings, peer: peer, customTitle: threadData?.info.title, iconId: threadData?.info.icon, iconColor: threadData?.info.iconColor ?? 0, online: online, synchronousLoad: synchronousLoad)
let resolveInlineStickers = context.resolveInlineStickers
self.peerNode.setup(
accountPeerId: context.accountPeerId,
postbox: context.stateManager.postbox,
network: context.stateManager.network,
energyUsageSettings: environment.energyUsageSettings,
contentSettings: context.contentSettings,
animationCache: context.animationCache,
animationRenderer: context.animationRenderer,
resolveInlineStickers: { fileIds in
return resolveInlineStickers(fileIds)
},
theme: theme,
strings: strings,
peer: peer,
customTitle: threadData?.info.title,
iconId: threadData?.info.icon,
iconColor: threadData?.info.iconColor ?? 0,
online: online,
synchronousLoad: synchronousLoad
)
if let shimmerNode = self.placeholderNode {
self.placeholderNode = nil
shimmerNode.removeFromSupernode()
@ -230,7 +252,7 @@ final class ShareControllerPeerGridItemNode: GridItemNode {
shimmerNode.update(backgroundColor: theme.list.itemBlocksBackgroundColor, foregroundColor: theme.list.mediaPlaceholderColor, shimmeringColor: theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), shapes: shapes, horizontal: true, size: self.bounds.size)
}
self.currentState = (context, theme, strings, peer, search, presence, topicId, threadData)
self.currentState = (environment, context, theme, strings, peer, search, presence, topicId, threadData)
self.setNeedsLayout()
if let presence = presence {
self.presenceManager?.reset(presence: presence)
@ -241,7 +263,7 @@ final class ShareControllerPeerGridItemNode: GridItemNode {
func updateSelection(animated: Bool) {
var selected = false
if let controllerInteraction = self.controllerInteraction, let (_, _, _, maybePeer, _, _, _, _) = self.currentState, let peer = maybePeer {
if let controllerInteraction = self.controllerInteraction, let (_, _, _, _, maybePeer, _, _, _, _) = self.currentState, let peer = maybePeer {
selected = controllerInteraction.selectedPeerIds.contains(peer.peerId)
}
@ -255,7 +277,7 @@ final class ShareControllerPeerGridItemNode: GridItemNode {
self.peerNode.frame = bounds
self.placeholderNode?.frame = bounds
if let (_, theme, _, _, _, _, _, _) = self.currentState, let shimmerNode = self.placeholderNode {
if let (_, _, theme, _, _, _, _, _, _) = self.currentState, let shimmerNode = self.placeholderNode {
var shapes: [ShimmerEffectNode.Shape] = []
let titleLineWidth: CGFloat = 56.0

View File

@ -9,7 +9,8 @@ import ChatListSearchRecentPeersNode
import AccountContext
final class ShareControllerRecentPeersGridItem: GridItem {
let context: AccountContext
let environment: ShareControllerEnvironment
let context: ShareControllerAccountContext
let theme: PresentationTheme
let strings: PresentationStrings
let controllerInteraction: ShareControllerInteraction
@ -17,7 +18,8 @@ final class ShareControllerRecentPeersGridItem: GridItem {
let section: GridSection? = nil
let fillsRowWithHeight: (CGFloat, Bool)? = (102.0, true)
init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, controllerInteraction: ShareControllerInteraction) {
init(environment: ShareControllerEnvironment, context: ShareControllerAccountContext, theme: PresentationTheme, strings: PresentationStrings, controllerInteraction: ShareControllerInteraction) {
self.environment = environment
self.context = context
self.theme = theme
self.strings = strings
@ -27,7 +29,7 @@ final class ShareControllerRecentPeersGridItem: GridItem {
func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode {
let node = ShareControllerRecentPeersGridItemNode()
node.controllerInteraction = self.controllerInteraction
node.setup(context: self.context, theme: self.theme, strings: self.strings)
node.setup(environment: self.environment, context: self.context, theme: self.theme, strings: self.strings)
return node
}
@ -37,12 +39,12 @@ final class ShareControllerRecentPeersGridItem: GridItem {
return
}
node.controllerInteraction = self.controllerInteraction
node.setup(context: self.context, theme: self.theme, strings: self.strings)
node.setup(environment: self.environment, context: self.context, theme: self.theme, strings: self.strings)
}
}
final class ShareControllerRecentPeersGridItemNode: GridItemNode {
private var currentState: (AccountContext, PresentationTheme, PresentationStrings)?
private var currentState: (ShareControllerAccountContext, PresentationTheme, PresentationStrings)?
var controllerInteraction: ShareControllerInteraction?
@ -52,18 +54,34 @@ final class ShareControllerRecentPeersGridItemNode: GridItemNode {
super.init()
}
func setup(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings) {
func setup(environment: ShareControllerEnvironment, context: ShareControllerAccountContext, theme: PresentationTheme, strings: PresentationStrings) {
if self.currentState == nil || self.currentState!.0 !== context || self.currentState!.1 !== theme {
let peersNode: ChatListSearchRecentPeersNode
if let currentPeersNode = self.peersNode {
peersNode = currentPeersNode
peersNode.updateThemeAndStrings(theme: theme, strings: strings)
} else {
peersNode = ChatListSearchRecentPeersNode(context: context, theme: theme, mode: .actionSheet, strings: strings, peerSelected: { [weak self] peer in
self?.controllerInteraction?.togglePeer(EngineRenderedPeer(peer: peer), true)
}, peerContextAction: { _, _, gesture, _ in gesture?.cancel() }, isPeerSelected: { [weak self] peerId in
return self?.controllerInteraction?.selectedPeerIds.contains(peerId) ?? false
}, share: true)
peersNode = ChatListSearchRecentPeersNode(
accountPeerId: context.accountPeerId,
postbox: context.stateManager.postbox,
network: context.stateManager.network,
energyUsageSettings: environment.energyUsageSettings,
contentSettings: context.contentSettings,
animationCache: context.animationCache,
animationRenderer: context.animationRenderer,
resolveInlineStickers: context.resolveInlineStickers,
theme: theme,
mode: .actionSheet,
strings: strings,
peerSelected: { [weak self] peer in
self?.controllerInteraction?.togglePeer(EngineRenderedPeer(peer: peer), true)
},
peerContextAction: { _, _, gesture, _ in gesture?.cancel() },
isPeerSelected: { [weak self] peerId in
return self?.controllerInteraction?.selectedPeerIds.contains(peerId) ?? false
},
share: true
)
self.peersNode = peersNode
self.addSubnode(peersNode)
}

View File

@ -11,6 +11,7 @@ import TelegramAnimatedStickerNode
import AppBundle
import TelegramUniversalVideoContent
import TelegramCore
import Postbox
import AccountContext
private func fileSize(_ path: String, useTotalFileAllocatedSize: Bool = false) -> Int64? {
@ -231,7 +232,7 @@ public final class ShareProlongedLoadingContainerNode: ASDisplayNode, ShareConte
return self.elapsedTime + 3.0 + 0.15
}
public init(theme: PresentationTheme, strings: PresentationStrings, forceNativeAppearance: Bool, account: Account?, sharedContext: SharedAccountContext) {
public init(theme: PresentationTheme, strings: PresentationStrings, forceNativeAppearance: Bool, postbox: Postbox?, environment: ShareControllerEnvironment) {
self.theme = theme
self.strings = strings
@ -272,14 +273,14 @@ public final class ShareProlongedLoadingContainerNode: ASDisplayNode, ShareConte
}
}))
if let account = account, let path = getAppBundle().path(forResource: "BlankVideo", ofType: "m4v"), let size = fileSize(path) {
if let postbox, let mediaManager = environment.mediaManager, let path = getAppBundle().path(forResource: "BlankVideo", ofType: "m4v"), let size = fileSize(path) {
let decoration = ChatBubbleVideoDecoration(corners: ImageCorners(), nativeSize: CGSize(width: 100.0, height: 100.0), contentMode: .aspectFit, backgroundColor: .black)
let dummyFile = TelegramMediaFile(fileId: EngineMedia.Id(namespace: 0, id: 1), partialReference: nil, resource: LocalFileReferenceMediaResource(localFilePath: path, randomId: 12345), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/mp4", size: size, attributes: [.Video(duration: 1, size: PixelDimensions(width: 100, height: 100), flags: [], preloadSize: nil)])
let videoContent = NativeVideoContent(id: .message(1, EngineMedia.Id(namespace: 0, id: 1)), userLocation: .other, fileReference: .standalone(media: dummyFile), streamVideo: .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .black, storeAfterDownload: nil)
let videoNode = UniversalVideoNode(postbox: account.postbox, audioSession: sharedContext.mediaManager.audioSession, manager: sharedContext.mediaManager.universalVideoManager, decoration: decoration, content: videoContent, priority: .embedded)
let videoNode = UniversalVideoNode(postbox: postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: decoration, content: videoContent, priority: .embedded)
videoNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 2.0, height: 2.0))
videoNode.alpha = 0.01
self.videoNode = videoNode

View File

@ -75,8 +75,8 @@ private struct SharePeerEntry: Comparable, Identifiable {
return lhs.index < rhs.index
}
func item(context: AccountContext, interfaceInteraction: ShareControllerInteraction) -> GridItem {
return ShareControllerPeerGridItem(context: context, theme: self.theme, strings: self.strings, peer: self.peer, presence: self.presence, topicId: self.threadId, threadData: self.threadData, controllerInteraction: interfaceInteraction, search: false)
func item(environment: ShareControllerEnvironment, context: ShareControllerAccountContext, interfaceInteraction: ShareControllerInteraction) -> GridItem {
return ShareControllerPeerGridItem(environment: environment, context: context, theme: self.theme, strings: self.strings, peer: self.peer, presence: self.presence, topicId: self.threadId, threadData: self.threadData, controllerInteraction: interfaceInteraction, search: false)
}
}
@ -89,19 +89,19 @@ private struct ShareGridTransaction {
private let avatarFont = avatarPlaceholderFont(size: 17.0)
private func preparedGridEntryTransition(context: AccountContext, from fromEntries: [SharePeerEntry], to toEntries: [SharePeerEntry], interfaceInteraction: ShareControllerInteraction) -> ShareGridTransaction {
private func preparedGridEntryTransition(environment: ShareControllerEnvironment, context: ShareControllerAccountContext, from fromEntries: [SharePeerEntry], to toEntries: [SharePeerEntry], interfaceInteraction: ShareControllerInteraction) -> ShareGridTransaction {
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices
let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(context: context, interfaceInteraction: interfaceInteraction), previousIndex: $0.2) }
let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, interfaceInteraction: interfaceInteraction)) }
let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(environment: environment, context: context, interfaceInteraction: interfaceInteraction), previousIndex: $0.2) }
let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(environment: environment, context: context, interfaceInteraction: interfaceInteraction)) }
return ShareGridTransaction(deletions: deletions, insertions: insertions, updates: updates, animated: false)
}
final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode {
private let sharedContext: SharedAccountContext
private let context: AccountContext
private let environment: ShareControllerEnvironment
private let context: ShareControllerAccountContext
private var theme: PresentationTheme
private let themePromise: Promise<PresentationTheme>
private let strings: PresentationStrings
@ -152,8 +152,8 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode {
}
private let tick = ValuePromise<Int>(0)
init(sharedContext: SharedAccountContext, context: AccountContext, switchableAccounts: [AccountWithInfo], theme: PresentationTheme, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, peers: [(EngineRenderedPeer, EnginePeer.Presence?)], accountPeer: EnginePeer, controllerInteraction: ShareControllerInteraction, externalShare: Bool, switchToAnotherAccount: @escaping () -> Void, debugAction: @escaping () -> Void, extendedInitialReveal: Bool, segmentedValues: [ShareControllerSegmentedValue]?) {
self.sharedContext = sharedContext
init(environment: ShareControllerEnvironment, context: ShareControllerAccountContext, switchableAccounts: [ShareControllerSwitchableAccount], theme: PresentationTheme, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, peers: [(EngineRenderedPeer, EnginePeer.Presence?)], accountPeer: EnginePeer, controllerInteraction: ShareControllerInteraction, externalShare: Bool, switchToAnotherAccount: @escaping () -> Void, debugAction: @escaping () -> Void, extendedInitialReveal: Bool, segmentedValues: [ShareControllerSegmentedValue]?) {
self.environment = environment
self.context = context
self.theme = theme
self.themePromise = Promise()
@ -213,9 +213,18 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode {
self.contentTitleAccountNode = AvatarNode(font: avatarFont)
var hasOtherAccounts = false
if switchableAccounts.count > 1, let info = switchableAccounts.first(where: { $0.account.id == context.account.id }) {
if switchableAccounts.count > 1, let info = switchableAccounts.first(where: { $0.account.accountId == context.accountId }) {
hasOtherAccounts = true
self.contentTitleAccountNode.setPeer(context: context, theme: theme, peer: EnginePeer(info.peer), emptyColor: nil, synchronousLoad: false)
self.contentTitleAccountNode.setPeer(
accountPeerId: context.accountPeerId,
postbox: context.stateManager.postbox,
network: context.stateManager.network,
contentSettings: context.contentSettings,
theme: theme,
peer: EnginePeer(info.peer),
emptyColor: nil,
synchronousLoad: false
)
} else {
self.contentTitleAccountNode.isHidden = true
}
@ -284,7 +293,7 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode {
strongSelf.entries = entries
let firstTime = previousEntries == nil
let transition = preparedGridEntryTransition(context: context, from: previousEntries ?? [], to: entries, interfaceInteraction: controllerInteraction)
let transition = preparedGridEntryTransition(environment: environment, context: context, from: previousEntries ?? [], to: entries, interfaceInteraction: controllerInteraction)
strongSelf.enqueueTransition(transition, firstTime: firstTime)
}
}))

View File

@ -83,17 +83,17 @@ private enum ShareSearchRecentEntry: Comparable, Identifiable {
}
}
func item(context: AccountContext, interfaceInteraction: ShareControllerInteraction) -> GridItem {
func item(environment: ShareControllerEnvironment, context: ShareControllerAccountContext, interfaceInteraction: ShareControllerInteraction) -> GridItem {
switch self {
case let .topPeers(theme, strings):
return ShareControllerRecentPeersGridItem(context: context, theme: theme, strings: strings, controllerInteraction: interfaceInteraction)
return ShareControllerRecentPeersGridItem(environment: environment, context: context, theme: theme, strings: strings, controllerInteraction: interfaceInteraction)
case let .peer(_, theme, peer, associatedPeer, presence, strings):
var peers: [EnginePeer.Id: EnginePeer] = [peer.id: peer]
if let associatedPeer = associatedPeer {
peers[associatedPeer.id] = associatedPeer
}
let peer = EngineRenderedPeer(peerId: peer.id, peers: peers, associatedMedia: [:])
return ShareControllerPeerGridItem(context: context, theme: theme, strings: strings, peer: peer, presence: presence, topicId: nil, threadData: nil, controllerInteraction: interfaceInteraction, sectionTitle: strings.DialogList_SearchSectionRecent, search: true)
return ShareControllerPeerGridItem(environment: environment, context: context, theme: theme, strings: strings, peer: peer, presence: presence, topicId: nil, threadData: nil, controllerInteraction: interfaceInteraction, sectionTitle: strings.DialogList_SearchSectionRecent, search: true)
}
}
}
@ -130,8 +130,8 @@ private struct ShareSearchPeerEntry: Comparable, Identifiable {
return lhs.index < rhs.index
}
func item(context: AccountContext, interfaceInteraction: ShareControllerInteraction) -> GridItem {
return ShareControllerPeerGridItem(context: context, theme: self.theme, strings: self.strings, peer: self.peer, presence: self.presence, topicId: nil, threadData: nil, controllerInteraction: interfaceInteraction, search: true)
func item(environment: ShareControllerEnvironment, context: ShareControllerAccountContext, interfaceInteraction: ShareControllerInteraction) -> GridItem {
return ShareControllerPeerGridItem(environment: environment, context: context, theme: self.theme, strings: self.strings, peer: self.peer, presence: self.presence, topicId: nil, threadData: nil, controllerInteraction: interfaceInteraction, search: true)
}
}
@ -143,29 +143,29 @@ private struct ShareSearchGridTransaction {
let crossFade: Bool
}
private func preparedGridEntryTransition(context: AccountContext, from fromEntries: [ShareSearchPeerEntry], to toEntries: [ShareSearchPeerEntry], interfaceInteraction: ShareControllerInteraction, crossFade: Bool) -> ShareSearchGridTransaction {
private func preparedGridEntryTransition(environment: ShareControllerEnvironment, context: ShareControllerAccountContext, from fromEntries: [ShareSearchPeerEntry], to toEntries: [ShareSearchPeerEntry], interfaceInteraction: ShareControllerInteraction, crossFade: Bool) -> ShareSearchGridTransaction {
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices
let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(context: context, interfaceInteraction: interfaceInteraction), previousIndex: $0.2) }
let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, interfaceInteraction: interfaceInteraction)) }
let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(environment: environment, context: context, interfaceInteraction: interfaceInteraction), previousIndex: $0.2) }
let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(environment: environment, context: context, interfaceInteraction: interfaceInteraction)) }
return ShareSearchGridTransaction(deletions: deletions, insertions: insertions, updates: updates, animated: false, crossFade: crossFade)
}
private func preparedRecentEntryTransition(context: AccountContext, from fromEntries: [ShareSearchRecentEntry], to toEntries: [ShareSearchRecentEntry], interfaceInteraction: ShareControllerInteraction) -> ShareSearchGridTransaction {
private func preparedRecentEntryTransition(environment: ShareControllerEnvironment, context: ShareControllerAccountContext, from fromEntries: [ShareSearchRecentEntry], to toEntries: [ShareSearchRecentEntry], interfaceInteraction: ShareControllerInteraction) -> ShareSearchGridTransaction {
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices
let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(context: context, interfaceInteraction: interfaceInteraction), previousIndex: $0.2) }
let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, interfaceInteraction: interfaceInteraction)) }
let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(environment: environment, context: context, interfaceInteraction: interfaceInteraction), previousIndex: $0.2) }
let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(environment: environment, context: context, interfaceInteraction: interfaceInteraction)) }
return ShareSearchGridTransaction(deletions: deletions, insertions: insertions, updates: updates, animated: false, crossFade: false)
}
final class ShareSearchContainerNode: ASDisplayNode, ShareContentContainerNode {
private let sharedContext: SharedAccountContext
private let context: AccountContext
private let environment: ShareControllerEnvironment
private let context: ShareControllerAccountContext
private var theme: PresentationTheme
private let themePromise: Promise<PresentationTheme>
private let strings: PresentationStrings
@ -197,8 +197,8 @@ final class ShareSearchContainerNode: ASDisplayNode, ShareContentContainerNode {
private let searchQuery = ValuePromise<String>("", ignoreRepeated: true)
private let searchDisposable = MetaDisposable()
init(sharedContext: SharedAccountContext, context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, controllerInteraction: ShareControllerInteraction, recentPeers recentPeerList: [EngineRenderedPeer]) {
self.sharedContext = sharedContext
init(environment: ShareControllerEnvironment, context: ShareControllerAccountContext, theme: PresentationTheme, strings: PresentationStrings, controllerInteraction: ShareControllerInteraction, recentPeers recentPeerList: [EngineRenderedPeer]) {
self.environment = environment
self.context = context
self.theme = theme
self.themePromise = Promise<PresentationTheme>()
@ -247,11 +247,11 @@ final class ShareSearchContainerNode: ASDisplayNode, ShareContentContainerNode {
let foundItems = combineLatest(self.searchQuery.get(), self.themePromise.get())
|> mapToSignal { query, theme -> Signal<([ShareSearchPeerEntry]?, Bool), NoError> in
if !query.isEmpty {
let accountPeer = context.account.postbox.loadedPeerWithId(context.account.peerId) |> take(1)
let foundLocalPeers = context.account.postbox.searchPeers(query: query.lowercased())
let accountPeer = context.stateManager.postbox.loadedPeerWithId(context.accountPeerId) |> take(1)
let foundLocalPeers = context.stateManager.postbox.searchPeers(query: query.lowercased())
let foundRemotePeers: Signal<([FoundPeer], [FoundPeer], Bool), NoError> = .single(([], [], true))
|> then(
context.engine.contacts.searchRemotePeers(query: query)
_internal_searchPeers(accountPeerId: context.accountPeerId, postbox: context.stateManager.postbox, network: context.stateManager.network, query: query)
|> delay(0.2, queue: Queue.concurrentDefaultQueue())
|> map { a, b -> ([FoundPeer], [FoundPeer], Bool) in
return (a, b, false)
@ -329,7 +329,7 @@ final class ShareSearchContainerNode: ASDisplayNode, ShareContentContainerNode {
let firstTime = previousEntries.0 == nil
let crossFade = !firstTime && previousEntries.1 && !isPlaceholder
let transition = preparedGridEntryTransition(context: context, from: previousEntries.0 ?? [], to: entries ?? [], interfaceInteraction: controllerInteraction, crossFade: crossFade)
let transition = preparedGridEntryTransition(environment: environment, context: context, from: previousEntries.0 ?? [], to: entries ?? [], interfaceInteraction: controllerInteraction, crossFade: crossFade)
strongSelf.enqueueTransition(transition, firstTime: firstTime)
if (previousEntries.0 == nil) != (entries == nil) {
@ -350,7 +350,7 @@ final class ShareSearchContainerNode: ASDisplayNode, ShareContentContainerNode {
self?.searchQuery.set(text)
}
let hasRecentPeers = context.engine.peers.recentPeers()
let hasRecentPeers = _internal_recentPeers(accountPeerId: context.accountPeerId, postbox: context.stateManager.postbox)
|> map { value -> Bool in
switch value {
case let .peers(peers):
@ -384,7 +384,7 @@ final class ShareSearchContainerNode: ASDisplayNode, ShareContentContainerNode {
strongSelf.recentEntries = entries
let firstTime = previousEntries == nil
let transition = preparedRecentEntryTransition(context: context, from: previousEntries ?? [], to: entries, interfaceInteraction: controllerInteraction)
let transition = preparedRecentEntryTransition(environment: environment, context: context, from: previousEntries ?? [], to: entries, interfaceInteraction: controllerInteraction)
strongSelf.enqueueRecentTransition(transition, firstTime: firstTime)
}
}))

View File

@ -14,7 +14,8 @@ import ComponentFlow
import EmojiStatusComponent
final class ShareTopicGridItem: GridItem {
let context: AccountContext
let environment: ShareControllerEnvironment
let context: ShareControllerAccountContext
let theme: PresentationTheme
let strings: PresentationStrings
let peer: EngineRenderedPeer?
@ -24,7 +25,8 @@ final class ShareTopicGridItem: GridItem {
let section: GridSection?
init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, peer: EngineRenderedPeer?, id: Int64, threadInfo: MessageHistoryThreadData, controllerInteraction: ShareControllerInteraction) {
init(environment: ShareControllerEnvironment, context: ShareControllerAccountContext, theme: PresentationTheme, strings: PresentationStrings, peer: EngineRenderedPeer?, id: Int64, threadInfo: MessageHistoryThreadData, controllerInteraction: ShareControllerInteraction) {
self.environment = environment
self.context = context
self.theme = theme
self.strings = strings
@ -46,7 +48,7 @@ final class ShareTopicGridItem: GridItem {
}
final class ShareTopicGridItemNode: GridItemNode {
private var currentState: (AccountContext, PresentationTheme, PresentationStrings, EngineRenderedPeer?, MessageHistoryThreadData?)?
private var currentState: (ShareControllerAccountContext, PresentationTheme, PresentationStrings, EngineRenderedPeer?, MessageHistoryThreadData?)?
private let iconView: ComponentView<Empty>
private let textNode: ImmediateTextNode
@ -113,7 +115,9 @@ final class ShareTopicGridItemNode: GridItemNode {
let iconSize = self.iconView.update(
transition: .easeInOut(duration: 0.2),
component: AnyComponent(EmojiStatusComponent(
context: item.context,
postbox: item.context.stateManager.postbox,
energyUsageSettings: item.environment.energyUsageSettings,
resolveInlineStickers: item.context.resolveInlineStickers,
animationCache: item.context.animationCache,
animationRenderer: item.context.animationRenderer,
content: iconContent,

View File

@ -52,8 +52,8 @@ private struct ShareTopicEntry: Comparable, Identifiable {
return lhs.index < rhs.index
}
func item(context: AccountContext, interfaceInteraction: ShareControllerInteraction) -> GridItem {
return ShareTopicGridItem(context: context, theme: self.theme, strings: self.strings, peer: self.peer, id: self.id, threadInfo: self.threadData, controllerInteraction: interfaceInteraction)
func item(environment: ShareControllerEnvironment, context: ShareControllerAccountContext, interfaceInteraction: ShareControllerInteraction) -> GridItem {
return ShareTopicGridItem(environment: environment, context: context, theme: self.theme, strings: self.strings, peer: self.peer, id: self.id, threadInfo: self.threadData, controllerInteraction: interfaceInteraction)
}
}
@ -64,12 +64,12 @@ private struct ShareGridTransaction {
let animated: Bool
}
private func preparedGridEntryTransition(context: AccountContext, from fromEntries: [ShareTopicEntry], to toEntries: [ShareTopicEntry], interfaceInteraction: ShareControllerInteraction) -> ShareGridTransaction {
private func preparedGridEntryTransition(environment: ShareControllerEnvironment, context: ShareControllerAccountContext, from fromEntries: [ShareTopicEntry], to toEntries: [ShareTopicEntry], interfaceInteraction: ShareControllerInteraction) -> ShareGridTransaction {
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices
let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(context: context, interfaceInteraction: interfaceInteraction), previousIndex: $0.2) }
let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, interfaceInteraction: interfaceInteraction)) }
let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(environment: environment, context: context, interfaceInteraction: interfaceInteraction), previousIndex: $0.2) }
let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(environment: environment, context: context, interfaceInteraction: interfaceInteraction)) }
return ShareGridTransaction(deletions: deletions, insertions: insertions, updates: updates, animated: false)
}
@ -157,8 +157,8 @@ final class ShareTopicsContainerNode: ASDisplayNode, ShareContentContainerNode {
}
private let sharedContext: SharedAccountContext
private let context: AccountContext
private let environment: ShareControllerEnvironment
private let context: ShareControllerAccountContext
private var theme: PresentationTheme
private let themePromise: Promise<PresentationTheme>
private let strings: PresentationStrings
@ -183,8 +183,8 @@ final class ShareTopicsContainerNode: ASDisplayNode, ShareContentContainerNode {
var backPressed: () -> Void = {}
init(sharedContext: SharedAccountContext, context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, peer: EnginePeer, topics: Signal<EngineChatList, NoError>, controllerInteraction: ShareControllerInteraction) {
self.sharedContext = sharedContext
init(environment: ShareControllerEnvironment, context: ShareControllerAccountContext, theme: PresentationTheme, strings: PresentationStrings, peer: EnginePeer, topics: Signal<EngineChatList, NoError>, controllerInteraction: ShareControllerInteraction) {
self.environment = environment
self.context = context
self.theme = theme
self.themePromise = Promise()
@ -245,7 +245,7 @@ final class ShareTopicsContainerNode: ASDisplayNode, ShareContentContainerNode {
strongSelf.entries = entries
let firstTime = previousEntries == nil
let transition = preparedGridEntryTransition(context: context, from: previousEntries ?? [], to: entries, interfaceInteraction: controllerInteraction)
let transition = preparedGridEntryTransition(environment: environment, context: context, from: previousEntries ?? [], to: entries, interfaceInteraction: controllerInteraction)
strongSelf.enqueueTransition(transition, firstTime: firstTime)
}
}))

View File

@ -173,9 +173,6 @@ static CGSize TGFitSize(CGSize size, CGSize maxSize) {
return [[MTSignal alloc] initWithGenerator:^id<MTDisposable>(MTSubscriber *subscriber)
{
bool preferAsFile = false;
#if DEBUG
preferAsFile = true;
#endif
CGSize maxSize = CGSizeMake(1280.0, 1280.0);
NSDictionary *imageOptions = @{

View File

@ -52,12 +52,12 @@ public enum PreparedShareItemError {
case fileTooBig(Int64)
}
private func preparedShareItem(account: Account, to peerId: PeerId, value: [String: Any]) -> Signal<PreparedShareItem, PreparedShareItemError> {
private func preparedShareItem(postbox: Postbox, network: Network, to peerId: PeerId, value: [String: Any]) -> Signal<PreparedShareItem, PreparedShareItemError> {
if let imageData = value["scaledImageData"] as? Data, let dimensions = value["scaledImageDimensions"] as? NSValue {
let diminsionsSize = dimensions.cgSizeValue
return .single(.preparing(false))
|> then(
standaloneUploadedImage(account: account, peerId: peerId, text: "", data: imageData, dimensions: PixelDimensions(width: Int32(diminsionsSize.width), height: Int32(diminsionsSize.height)))
standaloneUploadedImage(postbox: postbox, network: network, peerId: peerId, text: "", data: imageData, dimensions: PixelDimensions(width: Int32(diminsionsSize.width), height: Int32(diminsionsSize.height)))
|> mapError { _ -> PreparedShareItemError in
return .generic
}
@ -76,7 +76,7 @@ private func preparedShareItem(account: Account, to peerId: PeerId, value: [Stri
if let scaledImage = scalePhotoImage(image, dimensions: dimensions), let imageData = scaledImage.jpegData(compressionQuality: 0.52) {
return .single(.preparing(false))
|> then(
standaloneUploadedImage(account: account, peerId: peerId, text: "", data: imageData, dimensions: PixelDimensions(width: Int32(dimensions.width), height: Int32(dimensions.height)))
standaloneUploadedImage(postbox: postbox, network: network, peerId: peerId, text: "", data: imageData, dimensions: PixelDimensions(width: Int32(dimensions.width), height: Int32(dimensions.height)))
|> mapError { _ -> PreparedShareItemError in
return .generic
}
@ -146,7 +146,7 @@ private func preparedShareItem(account: Account, to peerId: PeerId, value: [Stri
let estimatedSize = TGMediaVideoConverter.estimatedSize(for: preset, duration: finalDuration, hasAudio: true)
let resource = LocalFileVideoMediaResource(randomId: Int64.random(in: Int64.min ... Int64.max), path: asset.url.path, adjustments: resourceAdjustments)
return standaloneUploadedFile(account: account, peerId: peerId, text: "", source: .resource(.standalone(resource: resource)), mimeType: "video/mp4", attributes: [.Video(duration: finalDuration, size: PixelDimensions(width: Int32(finalDimensions.width), height: Int32(finalDimensions.height)), flags: flags, preloadSize: nil)], hintFileIsLarge: estimatedSize > 10 * 1024 * 1024)
return standaloneUploadedFile(postbox: postbox, network: network, peerId: peerId, text: "", source: .resource(.standalone(resource: resource)), mimeType: "video/mp4", attributes: [.Video(duration: finalDuration, size: PixelDimensions(width: Int32(finalDimensions.width), height: Int32(finalDimensions.height)), flags: flags, preloadSize: nil)], hintFileIsLarge: estimatedSize > 10 * 1024 * 1024)
|> mapError { _ -> PreparedShareItemError in
return .generic
}
@ -217,7 +217,7 @@ private func preparedShareItem(account: Account, to peerId: PeerId, value: [Stri
mimeType = "animation/gif"
attributes = [.ImageSize(size: PixelDimensions(width: Int32(dimensions.width), height: Int32(dimensions.height))), .Animated, .FileName(fileName: fileName ?? "animation.gif")]
}
return standaloneUploadedFile(account: account, peerId: peerId, text: "", source: .data(data), mimeType: mimeType, attributes: attributes, hintFileIsLarge: data.count > 10 * 1024 * 1024)
return standaloneUploadedFile(postbox: postbox, network: network, peerId: peerId, text: "", source: .data(data), mimeType: mimeType, attributes: attributes, hintFileIsLarge: data.count > 10 * 1024 * 1024)
|> mapError { _ -> PreparedShareItemError in
return .generic
}
@ -236,7 +236,7 @@ private func preparedShareItem(account: Account, to peerId: PeerId, value: [Stri
let imageData = scaledImage.jpegData(compressionQuality: 0.54)!
return .single(.preparing(false))
|> then(
standaloneUploadedImage(account: account, peerId: peerId, text: "", data: imageData, dimensions: PixelDimensions(width: Int32(scaledImage.size.width), height: Int32(scaledImage.size.height)))
standaloneUploadedImage(postbox: postbox, network: network, peerId: peerId, text: "", data: imageData, dimensions: PixelDimensions(width: Int32(scaledImage.size.width), height: Int32(scaledImage.size.height)))
|> mapError { _ -> PreparedShareItemError in
return .generic
}
@ -259,7 +259,7 @@ private func preparedShareItem(account: Account, to peerId: PeerId, value: [Stri
let long = data.count > Int32(1.5 * 1024 * 1024)
return .single(.preparing(long))
|> then(
standaloneUploadedFile(account: account, peerId: peerId, text: "", source: .data(data), thumbnailData: thumbnailData, mimeType: mimeType, attributes: [.FileName(fileName: fileName ?? "file")], hintFileIsLarge: data.count > 10 * 1024 * 1024)
standaloneUploadedFile(postbox: postbox, network: network, peerId: peerId, text: "", source: .data(data), thumbnailData: thumbnailData, mimeType: mimeType, attributes: [.FileName(fileName: fileName ?? "file")], hintFileIsLarge: data.count > 10 * 1024 * 1024)
|> mapError { _ -> PreparedShareItemError in
return .generic
}
@ -290,7 +290,7 @@ private func preparedShareItem(account: Account, to peerId: PeerId, value: [Stri
let long = audioData.count > Int32(1.5 * 1024 * 1024)
return .single(.preparing(long))
|> then(
standaloneUploadedFile(account: account, peerId: peerId, text: "", source: .data(audioData), mimeType: mimeType, attributes: [.Audio(isVoice: isVoice, duration: Int(duration), title: title, performer: artist, waveform: waveform?.makeData()), .FileName(fileName: fileName)], hintFileIsLarge: audioData.count > 10 * 1024 * 1024)
standaloneUploadedFile(postbox: postbox, network: network, peerId: peerId, text: "", source: .data(audioData), mimeType: mimeType, attributes: [.Audio(isVoice: isVoice, duration: Int(duration), title: title, performer: artist, waveform: waveform?.makeData()), .FileName(fileName: fileName)], hintFileIsLarge: audioData.count > 10 * 1024 * 1024)
|> mapError { _ -> PreparedShareItemError in
return .generic
}
@ -345,7 +345,7 @@ private func preparedShareItem(account: Account, to peerId: PeerId, value: [Stri
}
}
public func preparedShareItems(account: Account, to peerId: PeerId, dataItems: [MTSignal], additionalText: String) -> Signal<PreparedShareItems, PreparedShareItemError> {
public func preparedShareItems(postbox: Postbox, network: Network, to peerId: PeerId, dataItems: [MTSignal]) -> Signal<PreparedShareItems, PreparedShareItemError> {
var dataSignals: Signal<[String: Any], PreparedShareItemError> = .complete()
for dataItem in dataItems {
let wrappedSignal: Signal<[String: Any], NoError> = Signal { subscriber in
@ -374,7 +374,7 @@ public func preparedShareItems(account: Account, to peerId: PeerId, dataItems: [
})
|> mapToSignal { items -> Signal<[PreparedShareItem], PreparedShareItemError> in
return combineLatest(items.map {
preparedShareItem(account: account, to: peerId, value: $0)
preparedShareItem(postbox: postbox, network: network, to: peerId, value: $0)
})
}
@ -384,21 +384,18 @@ public func preparedShareItems(account: Account, to peerId: PeerId, dataItems: [
var progresses: [Float] = []
for item in items {
switch item {
case let .preparing(long):
return .preparing(long)
case let .progress(value):
progresses.append(value)
case let .userInteractionRequired(value):
return .userInteractionRequired([value])
case let .done(content):
result.append(content)
progresses.append(1.0)
case let .preparing(long):
return .preparing(long)
case let .progress(value):
progresses.append(value)
case let .userInteractionRequired(value):
return .userInteractionRequired([value])
case let .done(content):
result.append(content)
progresses.append(1.0)
}
}
if result.count == items.count {
if !additionalText.isEmpty {
result.insert(PreparedShareItemContent.text(additionalText), at: 0)
}
return .done(result)
} else {
let value = progresses.reduce(0.0, +) / Float(progresses.count)
@ -414,8 +411,8 @@ public func preparedShareItems(account: Account, to peerId: PeerId, dataItems: [
})
}
public func sentShareItems(account: Account, to peerIds: [PeerId], threadIds: [PeerId: Int64], items: [PreparedShareItemContent], silently: Bool) -> Signal<Float, Void> {
var messages: [EnqueueMessage] = []
public func sentShareItems(accountPeerId: PeerId, postbox: Postbox, network: Network, stateManager: AccountStateManager, auxiliaryMethods: AccountAuxiliaryMethods, to peerIds: [PeerId], threadIds: [PeerId: Int64], items: [PreparedShareItemContent], silently: Bool, additionalText: String) -> Signal<Float, Void> {
var messages: [StandaloneSendEnqueueMessage] = []
var groupingKey: Int64?
var mediaTypes: (photo: Int, video: Int, music: Int, other: Int) = (0, 0, 0, 0)
if items.count > 1 {
@ -450,45 +447,82 @@ public func sentShareItems(account: Account, to peerIds: [PeerId], threadIds: [P
groupingKey = Int64.random(in: Int64.min ... Int64.max)
}
var attributes: [MessageAttribute] = []
if silently {
attributes.append(NotificationInfoMessageAttribute(flags: .muted))
}
var mediaMessages: [EnqueueMessage] = []
var mediaMessageCount = 0
var consumedText = false
for item in items {
switch item {
case let .text(text):
messages.append(.message(text: text, attributes: attributes, inlineStickers: [:], mediaReference: nil, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
case let .media(media):
switch media {
case let .media(reference):
let message: EnqueueMessage = .message(text: "", attributes: attributes, inlineStickers: [:], mediaReference: reference, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: groupingKey, correlationId: nil, bubbleUpEmojiOrStickersets: [])
messages.append(message)
mediaMessages.append(message)
}
if let _ = groupingKey, mediaMessages.count % 10 == 0 {
groupingKey = Int64.random(in: Int64.min ... Int64.max)
}
case let .text(text):
var message = StandaloneSendEnqueueMessage(
content: .text(text: StandaloneSendEnqueueMessage.Text(
string: text,
entities: []
)),
replyToMessageId: nil
)
message.isSilent = silently
messages.append(message)
case let .media(media):
switch media {
case let .media(reference):
var message = StandaloneSendEnqueueMessage(
content: .arbitraryMedia(
media: reference,
text: StandaloneSendEnqueueMessage.Text(
string: additionalText,
entities: []
)
),
replyToMessageId: nil
)
consumedText = true
message.isSilent = silently
message.groupingKey = groupingKey
messages.append(message)
mediaMessageCount += 1
}
if let _ = groupingKey, mediaMessageCount % 10 == 0 {
groupingKey = Int64.random(in: Int64.min ... Int64.max)
}
}
}
return enqueueMessagesToMultiplePeers(account: account, peerIds: peerIds, threadIds: threadIds, messages: messages)
|> castError(Void.self)
|> mapToSignal { messageIds -> Signal<Float, Void> in
return TelegramEngine(account: account).data.subscribe(EngineDataMap(
messageIds.map(TelegramEngine.EngineData.Item.Messages.Message.init)
))
|> castError(Void.self)
|> mapToSignal { messages -> Signal<Float, Void> in
for (_, message) in messages {
if let message = message, message.flags.contains(.Unsent) {
return .complete()
}
if !consumedText && !additionalText.isEmpty {
var message = StandaloneSendEnqueueMessage(
content: .text(text: StandaloneSendEnqueueMessage.Text(
string: additionalText,
entities: []
)),
replyToMessageId: nil
)
message.isSilent = silently
messages.append(message)
}
var peerSignals: Signal<Float, StandaloneSendMessagesError> = .single(0.0)
for peerId in peerIds {
peerSignals = peerSignals |> then(standaloneSendEnqueueMessages(
accountPeerId: accountPeerId,
postbox: postbox,
network: network,
stateManager: stateManager,
auxiliaryMethods: auxiliaryMethods,
peerId: peerId,
threadId: threadIds[peerId],
messages: messages
)
|> mapToSignal { status -> Signal<Float, StandaloneSendMessagesError> in
switch status {
case let .progress(progress):
//return .single(progress)
let _ = progress
return .complete()
case .done:
return .complete()
}
return .single(1.0)
}
|> take(1)
})
}
return peerSignals
|> mapError { _ -> Void in
return Void()
}
}

View File

@ -527,7 +527,7 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
})
})))
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .extracted(ChannelStatsContextExtractedContentSource(controller: controller, sourceNode: sourceNode, keepInPlace: false)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
let contextController = ContextController(presentationData: presentationData, source: .extracted(ChannelStatsContextExtractedContentSource(controller: controller, sourceNode: sourceNode, keepInPlace: false)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
controller.presentInGlobalOverlay(contextController)
}
return controller

View File

@ -838,7 +838,7 @@ private final class StickerPackContainer: ASDisplayNode {
}
})))
let contextController = ContextController(account: self.context.account, presentationData: self.presentationData, source: .reference(StickerPackContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
let contextController = ContextController(presentationData: self.presentationData, source: .reference(StickerPackContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
self.presentInGlobalOverlay(contextController, nil)
}

View File

@ -46,20 +46,29 @@ public final class AnimatedStickerNodeLocalFileSource: AnimatedStickerNodeSource
}
public final class AnimatedStickerResourceSource: AnimatedStickerNodeSource {
public let account: Account
public let postbox: Postbox
public let resource: MediaResource
public let fitzModifier: EmojiFitzModifier?
public let isVideo: Bool
public init(account: Account, resource: MediaResource, fitzModifier: EmojiFitzModifier? = nil, isVideo: Bool = false) {
self.account = account
public convenience init(account: Account, resource: MediaResource, fitzModifier: EmojiFitzModifier? = nil, isVideo: Bool = false) {
self.init(
postbox: account.postbox,
resource: resource,
fitzModifier: fitzModifier,
isVideo: isVideo
)
}
public init(postbox: Postbox, resource: MediaResource, fitzModifier: EmojiFitzModifier? = nil, isVideo: Bool = false) {
self.postbox = postbox
self.resource = resource
self.fitzModifier = fitzModifier
self.isVideo = isVideo
}
public func cachedDataPath(width: Int, height: Int) -> Signal<(String, Bool), NoError> {
return chatMessageAnimationData(mediaBox: self.account.postbox.mediaBox, resource: self.resource, fitzModifier: self.fitzModifier, isVideo: self.isVideo, width: width, height: height, synchronousLoad: false)
return chatMessageAnimationData(mediaBox: self.postbox.mediaBox, resource: self.resource, fitzModifier: self.fitzModifier, isVideo: self.isVideo, width: width, height: height, synchronousLoad: false)
|> filter { data in
return data.size != 0
}
@ -69,7 +78,7 @@ public final class AnimatedStickerResourceSource: AnimatedStickerNodeSource {
}
public func directDataPath(attemptSynchronously: Bool) -> Signal<String?, NoError> {
return self.account.postbox.mediaBox.resourceData(self.resource, attemptSynchronously: attemptSynchronously)
return self.postbox.mediaBox.resourceData(self.resource, attemptSynchronously: attemptSynchronously)
|> map { data -> String? in
if data.complete {
return data.path

View File

@ -596,7 +596,7 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
let items = self.contextMenuSpeedItems(scheduleTooltip: { change in
scheduledTooltip = change
})
let contextController = ContextController(account: self.context.account, presentationData: self.context.sharedContext.currentPresentationData.with { $0 }, source: .reference(HeaderContextReferenceContentSource(controller: controller, sourceNode: self.rateButton.referenceNode, shouldBeDismissed: self.dismissedPromise.get())), items: items, gesture: gesture)
let contextController = ContextController(presentationData: self.context.sharedContext.currentPresentationData.with { $0 }, source: .reference(HeaderContextReferenceContentSource(controller: controller, sourceNode: self.rateButton.referenceNode, shouldBeDismissed: self.dismissedPromise.get())), items: items, gesture: gesture)
contextController.dismissed = { [weak self] in
if let scheduledTooltip, let self, let rate = self.playbackBaseRate {
self.setRate?(rate, scheduledTooltip)

View File

@ -656,7 +656,7 @@ public final class MediaStreamComponent: CombinedComponent {
}
}
let contextController = ContextController(account: call.accountContext.account, presentationData: presentationData.withUpdated(theme: defaultDarkPresentationTheme), source: .reference(ReferenceContentSource(sourceView: anchorView)), items: .single(ContextController.Items(content: .list(items))), gesture: nil)
let contextController = ContextController(presentationData: presentationData.withUpdated(theme: defaultDarkPresentationTheme), source: .reference(ReferenceContentSource(sourceView: anchorView)), items: .single(ContextController.Items(content: .list(items))), gesture: nil)
/*contextController.passthroughTouchEvent = { sourceView, point in
guard let strongSelf = self else {
return .ignore

View File

@ -1799,7 +1799,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
dismissPromise.set(true)
}
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData.withUpdated(theme: strongSelf.darkTheme), source: .extracted(source), items: items |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
let contextController = ContextController(presentationData: strongSelf.presentationData.withUpdated(theme: strongSelf.darkTheme), source: .extracted(source), items: items |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
contextController.useComplexItemsTransitionAnimation = true
strongSelf.controller?.presentInGlobalOverlay(contextController)
}, getPeerVideo: { [weak self] endpointId, position in
@ -2488,7 +2488,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
private func openSettingsMenu(sourceNode: ASDisplayNode, gesture: ContextGesture?) {
let items: Signal<[ContextMenuItem], NoError> = self.contextMenuMainItems()
if let controller = self.controller {
let contextController = ContextController(account: self.context.account, presentationData: self.presentationData.withUpdated(theme: self.darkTheme), source: .reference(VoiceChatContextReferenceContentSource(controller: controller, sourceNode: self.optionsButton.referenceNode)), items: items |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
let contextController = ContextController(presentationData: self.presentationData.withUpdated(theme: self.darkTheme), source: .reference(VoiceChatContextReferenceContentSource(controller: controller, sourceNode: self.optionsButton.referenceNode)), items: items |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
controller.presentInGlobalOverlay(contextController)
}
}
@ -6311,7 +6311,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
let signal = Signal<TelegramMediaResource, UploadPeerPhotoError> { [weak self] subscriber in
let entityRenderer: LegacyPaintEntityRenderer? = adjustments.flatMap { adjustments in
if let paintingData = adjustments.paintingData, paintingData.hasAnimation {
return LegacyPaintEntityRenderer(account: account, adjustments: adjustments)
return LegacyPaintEntityRenderer(postbox: account.postbox, adjustments: adjustments)
} else {
return nil
}

View File

@ -685,12 +685,12 @@ public enum AccountNetworkState: Equatable {
}
public final class AccountAuxiliaryMethods {
public let fetchResource: (Account, MediaResource, Signal<[(Range<Int64>, MediaBoxFetchPriority)], NoError>, MediaResourceFetchParameters?) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError>?
public let fetchResource: (Postbox, MediaResource, Signal<[(Range<Int64>, MediaBoxFetchPriority)], NoError>, MediaResourceFetchParameters?) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError>?
public let fetchResourceMediaReferenceHash: (MediaResource) -> Signal<Data?, NoError>
public let prepareSecretThumbnailData: (MediaResourceData) -> (PixelDimensions, Data)?
public let backgroundUpload: (Postbox, Network, MediaResource) -> Signal<String?, NoError>
public init(fetchResource: @escaping (Account, MediaResource, Signal<[(Range<Int64>, MediaBoxFetchPriority)], NoError>, MediaResourceFetchParameters?) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError>?, fetchResourceMediaReferenceHash: @escaping (MediaResource) -> Signal<Data?, NoError>, prepareSecretThumbnailData: @escaping (MediaResourceData) -> (PixelDimensions, Data)?, backgroundUpload: @escaping (Postbox, Network, MediaResource) -> Signal<String?, NoError>) {
public init(fetchResource: @escaping (Postbox, MediaResource, Signal<[(Range<Int64>, MediaBoxFetchPriority)], NoError>, MediaResourceFetchParameters?) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError>?, fetchResourceMediaReferenceHash: @escaping (MediaResource) -> Signal<Data?, NoError>, prepareSecretThumbnailData: @escaping (MediaResourceData) -> (PixelDimensions, Data)?, backgroundUpload: @escaping (Postbox, Network, MediaResource) -> Signal<String?, NoError>) {
self.fetchResource = fetchResource
self.fetchResourceMediaReferenceHash = fetchResourceMediaReferenceHash
self.prepareSecretThumbnailData = prepareSecretThumbnailData
@ -1378,7 +1378,7 @@ public typealias TransformOutgoingMessageMedia = (_ postbox: Postbox, _ network:
public func setupAccount(_ account: Account, fetchCachedResourceRepresentation: FetchCachedResourceRepresentation? = nil, transformOutgoingMessageMedia: TransformOutgoingMessageMedia? = nil) {
account.postbox.mediaBox.fetchResource = { [weak account] resource, intervals, parameters -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> in
if let strongAccount = account {
if let result = strongAccount.auxiliaryMethods.fetchResource(strongAccount, resource, intervals, parameters) {
if let result = strongAccount.auxiliaryMethods.fetchResource(strongAccount.postbox, resource, intervals, parameters) {
return result
} else if let result = fetchResource(account: strongAccount, resource: resource, intervals: intervals, parameters: parameters) {
return result
@ -1475,6 +1475,9 @@ public func standaloneStateManager(
|> mapToSignal { phoneNumber in
Logger.shared.log("StandaloneStateManager", "received phone number")
let mediaReferenceRevalidationContext = MediaReferenceRevalidationContext()
let networkStatsContext = NetworkStatsContext(postbox: postbox)
return initializedNetwork(
accountId: id,
arguments: networkArguments,
@ -1492,6 +1495,31 @@ public func standaloneStateManager(
|> map { network -> AccountStateManager? in
Logger.shared.log("StandaloneStateManager", "received network")
postbox.mediaBox.fetchResource = { resource, intervals, parameters -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> in
if let result = auxiliaryMethods.fetchResource(
postbox,
resource,
intervals,
parameters
) {
return result
} else if let result = fetchResource(
accountPeerId: authorizedState.peerId,
postbox: postbox,
network: network,
mediaReferenceRevalidationContext: mediaReferenceRevalidationContext,
networkStatsContext: networkStatsContext,
isTestingEnvironment: authorizedState.isTestingEnvironment,
resource: resource,
intervals: intervals,
parameters: parameters
) {
return result
} else {
return .never()
}
}
return AccountStateManager(
accountPeerId: authorizedState.peerId,
accountManager: accountManager,

View File

@ -484,15 +484,15 @@ func _internal_setForumChannelPinnedTopics(account: Account, id: EnginePeer.Id,
}
}
func _internal_setChannelForumMode(account: Account, peerId: PeerId, isForum: Bool) -> Signal<Never, NoError> {
return account.postbox.transaction { transaction -> Api.InputChannel? in
func _internal_setChannelForumMode(postbox: Postbox, network: Network, stateManager: AccountStateManager, peerId: PeerId, isForum: Bool) -> Signal<Never, NoError> {
return postbox.transaction { transaction -> Api.InputChannel? in
return transaction.getPeer(peerId).flatMap(apiInputChannel)
}
|> mapToSignal { inputChannel -> Signal<Never, NoError> in
guard let inputChannel = inputChannel else {
return .complete()
}
return account.network.request(Api.functions.channels.toggleForum(channel: inputChannel, enabled: isForum ? .boolTrue : .boolFalse))
return network.request(Api.functions.channels.toggleForum(channel: inputChannel, enabled: isForum ? .boolTrue : .boolFalse))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.Updates?, NoError> in
return .single(nil)
@ -501,7 +501,7 @@ func _internal_setChannelForumMode(account: Account, peerId: PeerId, isForum: Bo
guard let result = result else {
return .complete()
}
account.stateManager.addUpdates(result)
stateManager.addUpdates(result)
return .complete()
}

View File

@ -104,6 +104,7 @@ public struct StandaloneSendEnqueueMessage {
public var replyToMessageId: MessageId?
public var forwardOptions: ForwardOptions?
public var isSilent: Bool = false
public var groupingKey: Int64? = nil
public init(
content: Content,
@ -114,11 +115,16 @@ public struct StandaloneSendEnqueueMessage {
}
}
public func standaloneSendEnqueueMessages(account: Account, peerId: PeerId, messages: [StandaloneSendEnqueueMessage]) -> Signal<StandaloneSendMessageStatus, StandaloneSendMessagesError> {
#if !DEBUG
error
#endif
public func standaloneSendEnqueueMessages(
accountPeerId: PeerId,
postbox: Postbox,
network: Network,
stateManager: AccountStateManager,
auxiliaryMethods: AccountAuxiliaryMethods,
peerId: PeerId,
threadId: Int64?,
messages: [StandaloneSendEnqueueMessage]
) -> Signal<StandaloneSendMessageStatus, StandaloneSendMessagesError> {
let signals: [Signal<PendingMessageUploadedContentResult, PendingMessageUploadError>] = messages.map { message in
var attributes: [MessageAttribute] = []
var text: String = ""
@ -167,7 +173,9 @@ public func standaloneSendEnqueueMessages(account: Account, peerId: PeerId, mess
attributes.append(NotificationInfoMessageAttribute(flags: .muted))
}
let content = messageContentToUpload(accountPeerId: account.peerId, network: account.network, postbox: account.postbox, auxiliaryMethods: account.auxiliaryMethods, transformOutgoingMessageMedia: account.transformOutgoingMessageMedia, messageMediaPreuploadManager: account.messageMediaPreuploadManager, revalidationContext: account.mediaReferenceRevalidationContext, forceReupload: false, isGrouped: false, passFetchProgress: true, forceNoBigParts: false, peerId: peerId, messageId: nil, attributes: attributes, text: text, media: media)
let content = messageContentToUpload(accountPeerId: accountPeerId, network: network, postbox: postbox, auxiliaryMethods: auxiliaryMethods, transformOutgoingMessageMedia: { _, _, _, _ in
return .single(nil)
}, messageMediaPreuploadManager: MessageMediaPreuploadManager(), revalidationContext: MediaReferenceRevalidationContext(), forceReupload: false, isGrouped: false, passFetchProgress: true, forceNoBigParts: false, peerId: peerId, messageId: nil, attributes: attributes, text: text, media: media)
let contentResult: Signal<PendingMessageUploadedContentResult, PendingMessageUploadError>
switch content {
case let .signal(value, _):
@ -197,31 +205,29 @@ public func standaloneSendEnqueueMessages(account: Account, peerId: PeerId, mess
}
if allDone {
var sendSignals: [Signal<Never, StandaloneSendMessagesError>] = []
sendSignals.removeAll()
for content in allResults {
var text: String = ""
switch content.content {
case let .text(text):
let _ = text
preconditionFailure()
case let .media(inputMedia, text):
let _ = inputMedia
let _ = text
preconditionFailure()
case let .forward(source):
let _ = source
preconditionFailure()
case let .chatContextResult(result):
let _ = result
preconditionFailure()
case let .secretMedia(inputFile, size, key):
let _ = inputFile
let _ = size
let _ = key
preconditionFailure()
case .messageScreenshot:
return .single(.done)
case let .text(textValue):
text = textValue
case let .media(_, textValue):
text = textValue
default:
break
}
sendSignals.append(sendUploadedMessageContent(
postbox: postbox,
network: network,
stateManager: stateManager,
accountPeerId: stateManager.accountPeerId,
peerId: peerId,
content: content,
text: text,
attributes: [],
threadId: threadId
))
}
return combineLatest(sendSignals)
@ -245,7 +251,9 @@ private func sendUploadedMessageContent(postbox: Postbox, network: Network, stat
var uniqueId: Int64 = 0
var forwardSourceInfoAttribute: ForwardSourceInfoAttribute?
var messageEntities: [Api.MessageEntity]?
var replyMessageId: Int32?
var replyMessageId: Int32? = threadId.flatMap { threadId in
makeThreadIdMessageId(peerId: peerId, threadId: threadId).id
}
var replyToStoryId: StoryId?
var scheduleTime: Int32?
var sendAsPeerId: PeerId?
@ -287,6 +295,10 @@ private func sendUploadedMessageContent(postbox: Postbox, network: Network, stat
}
}
if uniqueId == 0 {
uniqueId = Int64.random(in: Int64.min ... Int64.max)
}
if case .forward = content.content {
} else {
flags |= (1 << 7)

View File

@ -52,19 +52,19 @@ private func uploadedThumbnail(network: Network, postbox: Postbox, data: Data) -
}
}
public func standaloneUploadedImage(account: Account, peerId: PeerId, text: String, data: Data, thumbnailData: Data? = nil, dimensions: PixelDimensions) -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> {
return multipartUpload(network: account.network, postbox: account.postbox, source: .data(data), encrypt: peerId.namespace == Namespaces.Peer.SecretChat, tag: TelegramMediaResourceFetchTag(statsCategory: .image, userContentType: .image), hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: false)
public func standaloneUploadedImage(postbox: Postbox, network: Network, peerId: PeerId, text: String, data: Data, thumbnailData: Data? = nil, dimensions: PixelDimensions) -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> {
return multipartUpload(network: network, postbox: postbox, source: .data(data), encrypt: peerId.namespace == Namespaces.Peer.SecretChat, tag: TelegramMediaResourceFetchTag(statsCategory: .image, userContentType: .image), hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: false)
|> mapError { _ -> StandaloneUploadMediaError in return .generic }
|> mapToSignal { next -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> in
switch next {
case let .inputFile(inputFile):
return account.postbox.transaction { transaction -> Api.InputPeer? in
return postbox.transaction { transaction -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer)
}
|> mapError { _ -> StandaloneUploadMediaError in }
|> mapToSignal { inputPeer -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> in
if let inputPeer = inputPeer {
return account.network.request(Api.functions.messages.uploadMedia(peer: inputPeer, media: Api.InputMedia.inputMediaUploadedPhoto(flags: 0, file: inputFile, stickers: nil, ttlSeconds: nil)))
return network.request(Api.functions.messages.uploadMedia(peer: inputPeer, media: Api.InputMedia.inputMediaUploadedPhoto(flags: 0, file: inputFile, stickers: nil, ttlSeconds: nil)))
|> mapError { _ -> StandaloneUploadMediaError in return .generic }
|> mapToSignal { media -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> in
switch media {
@ -84,7 +84,7 @@ public func standaloneUploadedImage(account: Account, peerId: PeerId, text: Stri
}
}
case let .inputSecretFile(file, _, key):
return account.postbox.transaction { transaction -> Api.InputEncryptedChat? in
return postbox.transaction { transaction -> Api.InputEncryptedChat? in
if let peer = transaction.getPeer(peerId) as? TelegramSecretChat {
return Api.InputEncryptedChat.inputEncryptedChat(chatId: Int32(peer.id.id._internalGetInt64Value()), accessHash: peer.accessHash)
}
@ -95,7 +95,7 @@ public func standaloneUploadedImage(account: Account, peerId: PeerId, text: Stri
guard let inputChat = inputChat else {
return .fail(.generic)
}
return account.network.request(Api.functions.messages.uploadEncryptedFile(peer: inputChat, file: file))
return network.request(Api.functions.messages.uploadEncryptedFile(peer: inputChat, file: file))
|> mapError { _ -> StandaloneUploadMediaError in return .generic
}
|> mapToSignal { result -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> in
@ -113,15 +113,15 @@ public func standaloneUploadedImage(account: Account, peerId: PeerId, text: Stri
}
}
public func standaloneUploadedFile(account: Account, peerId: PeerId, text: String, source: MultipartUploadSource, thumbnailData: Data? = nil, mimeType: String, attributes: [TelegramMediaFileAttribute], hintFileIsLarge: Bool) -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> {
let upload = multipartUpload(network: account.network, postbox: account.postbox, source: source, encrypt: peerId.namespace == Namespaces.Peer.SecretChat, tag: TelegramMediaResourceFetchTag(statsCategory: statsCategoryForFileWithAttributes(attributes), userContentType: nil), hintFileSize: nil, hintFileIsLarge: hintFileIsLarge, forceNoBigParts: false)
public func standaloneUploadedFile(postbox: Postbox, network: Network, peerId: PeerId, text: String, source: MultipartUploadSource, thumbnailData: Data? = nil, mimeType: String, attributes: [TelegramMediaFileAttribute], hintFileIsLarge: Bool) -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> {
let upload = multipartUpload(network: network, postbox: postbox, source: source, encrypt: peerId.namespace == Namespaces.Peer.SecretChat, tag: TelegramMediaResourceFetchTag(statsCategory: statsCategoryForFileWithAttributes(attributes), userContentType: nil), hintFileSize: nil, hintFileIsLarge: hintFileIsLarge, forceNoBigParts: false)
|> mapError { _ -> StandaloneUploadMediaError in return .generic }
let uploadThumbnail: Signal<StandaloneUploadMediaThumbnailResult, StandaloneUploadMediaError>
if let thumbnailData = thumbnailData {
uploadThumbnail = .single(.pending)
|> then(
uploadedThumbnail(network: account.network, postbox: account.postbox, data: thumbnailData)
uploadedThumbnail(network: network, postbox: postbox, data: thumbnailData)
|> mapError { _ -> StandaloneUploadMediaError in return .generic }
|> map { result in
if let result = result {
@ -147,7 +147,7 @@ public func standaloneUploadedFile(account: Account, peerId: PeerId, text: Strin
default:
switch result {
case let .inputFile(inputFile):
return account.postbox.transaction { transaction -> Api.InputPeer? in
return postbox.transaction { transaction -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer)
}
|> mapError { _ -> StandaloneUploadMediaError in }
@ -158,7 +158,7 @@ public func standaloneUploadedFile(account: Account, peerId: PeerId, text: Strin
if let _ = thumbnailFile {
flags |= 1 << 2
}
return account.network.request(Api.functions.messages.uploadMedia(peer: inputPeer, media: Api.InputMedia.inputMediaUploadedDocument(flags: flags, file: inputFile, thumb: thumbnailFile, mimeType: mimeType, attributes: inputDocumentAttributesFromFileAttributes(attributes), stickers: nil, ttlSeconds: nil)))
return network.request(Api.functions.messages.uploadMedia(peer: inputPeer, media: Api.InputMedia.inputMediaUploadedDocument(flags: flags, file: inputFile, thumb: thumbnailFile, mimeType: mimeType, attributes: inputDocumentAttributesFromFileAttributes(attributes), stickers: nil, ttlSeconds: nil)))
|> mapError { _ -> StandaloneUploadMediaError in return .generic }
|> mapToSignal { media -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> in
switch media {
@ -178,7 +178,7 @@ public func standaloneUploadedFile(account: Account, peerId: PeerId, text: Strin
}
}
case let .inputSecretFile(file, _, key):
return account.postbox.transaction { transaction -> Api.InputEncryptedChat? in
return postbox.transaction { transaction -> Api.InputEncryptedChat? in
if let peer = transaction.getPeer(peerId) as? TelegramSecretChat {
return Api.InputEncryptedChat.inputEncryptedChat(chatId: Int32(peer.id.id._internalGetInt64Value()), accessHash: peer.accessHash)
}
@ -189,7 +189,7 @@ public func standaloneUploadedFile(account: Account, peerId: PeerId, text: Strin
guard let inputChat = inputChat else {
return .fail(.generic)
}
return account.network.request(Api.functions.messages.uploadEncryptedFile(peer: inputChat, file: file))
return network.request(Api.functions.messages.uploadEncryptedFile(peer: inputChat, file: file))
|> mapError { _ -> StandaloneUploadMediaError in return .generic }
|> mapToSignal { result -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> in
switch result {

View File

@ -22,8 +22,30 @@ private final class MediaResourceDataCopyFile : MediaResourceDataFetchCopyLocalI
}
}
public func fetchCloudMediaLocation(account: Account, resource: TelegramMediaResource, datacenterId: Int, size: Int64?, intervals: Signal<[(Range<Int64>, MediaBoxFetchPriority)], NoError>, parameters: MediaResourceFetchParameters?) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
return multipartFetch(accountPeerId: account.peerId, postbox: account.postbox, network: account.network, mediaReferenceRevalidationContext: account.mediaReferenceRevalidationContext, networkStatsContext: account.networkStatsContext, resource: resource, datacenterId: datacenterId, size: size, intervals: intervals, parameters: parameters)
func fetchCloudMediaLocation(
accountPeerId: PeerId,
postbox: Postbox,
network: Network,
mediaReferenceRevalidationContext: MediaReferenceRevalidationContext,
networkStatsContext: NetworkStatsContext,
resource: TelegramMediaResource,
datacenterId: Int,
size: Int64?,
intervals: Signal<[(Range<Int64>, MediaBoxFetchPriority)], NoError>,
parameters: MediaResourceFetchParameters?
) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
return multipartFetch(
accountPeerId: accountPeerId,
postbox: postbox,
network: network,
mediaReferenceRevalidationContext: mediaReferenceRevalidationContext,
networkStatsContext: networkStatsContext,
resource: resource,
datacenterId: datacenterId,
size: size,
intervals: intervals,
parameters: parameters
)
}
private func fetchLocalFileResource(path: String, move: Bool) -> Signal<MediaResourceDataFetchResult, NoError> {
@ -40,21 +62,76 @@ private func fetchLocalFileResource(path: String, move: Bool) -> Signal<MediaRes
}
func fetchResource(account: Account, resource: MediaResource, intervals: Signal<[(Range<Int64>, MediaBoxFetchPriority)], NoError>, parameters: MediaResourceFetchParameters?) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError>? {
return fetchResource(
accountPeerId: account.peerId,
postbox: account.postbox,
network: account.network,
mediaReferenceRevalidationContext: account.mediaReferenceRevalidationContext,
networkStatsContext: account.networkStatsContext,
isTestingEnvironment: account.testingEnvironment,
resource: resource,
intervals: intervals,
parameters: parameters
)
}
func fetchResource(
accountPeerId: PeerId,
postbox: Postbox,
network: Network,
mediaReferenceRevalidationContext: MediaReferenceRevalidationContext,
networkStatsContext: NetworkStatsContext,
isTestingEnvironment: Bool,
resource: MediaResource,
intervals: Signal<[(Range<Int64>, MediaBoxFetchPriority)], NoError>,
parameters: MediaResourceFetchParameters?
) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError>? {
if let _ = resource as? EmptyMediaResource {
return .single(.reset)
|> then(.never())
} else if let secretFileResource = resource as? SecretFileMediaResource {
return .single(.dataPart(resourceOffset: 0, data: Data(), range: 0 ..< 0, complete: false))
|> then(fetchSecretFileResource(account: account, resource: secretFileResource, intervals: intervals, parameters: parameters))
|> then(fetchSecretFileResource(
accountPeerId: accountPeerId,
postbox: postbox,
network: network,
mediaReferenceRevalidationContext: mediaReferenceRevalidationContext,
networkStatsContext: networkStatsContext,
resource: secretFileResource,
intervals: intervals,
parameters: parameters
))
} else if let cloudResource = resource as? TelegramMultipartFetchableResource {
return .single(.dataPart(resourceOffset: 0, data: Data(), range: 0 ..< 0, complete: false))
|> then(fetchCloudMediaLocation(account: account, resource: cloudResource, datacenterId: cloudResource.datacenterId, size: resource.size == 0 ? nil : resource.size, intervals: intervals, parameters: parameters))
|> then(fetchCloudMediaLocation(
accountPeerId: accountPeerId,
postbox: postbox,
network: network,
mediaReferenceRevalidationContext: mediaReferenceRevalidationContext,
networkStatsContext: networkStatsContext,
resource: cloudResource,
datacenterId: cloudResource.datacenterId,
size: resource.size == 0 ? nil : resource.size,
intervals: intervals,
parameters: parameters
))
} else if let webFileResource = resource as? MediaResourceWithWebFileReference {
return currentWebDocumentsHostDatacenterId(postbox: account.postbox, isTestingEnvironment: account.testingEnvironment)
return currentWebDocumentsHostDatacenterId(postbox: postbox, isTestingEnvironment: isTestingEnvironment)
|> castError(MediaResourceDataFetchError.self)
|> mapToSignal { datacenterId -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> in
return .single(.dataPart(resourceOffset: 0, data: Data(), range: 0 ..< 0, complete: false))
|> then(fetchCloudMediaLocation(account: account, resource: webFileResource, datacenterId: Int(datacenterId), size: resource.size == 0 ? nil : resource.size, intervals: intervals, parameters: parameters))
|> then(fetchCloudMediaLocation(
accountPeerId: accountPeerId,
postbox: postbox,
network: network,
mediaReferenceRevalidationContext: mediaReferenceRevalidationContext,
networkStatsContext: networkStatsContext,
resource: webFileResource,
datacenterId: Int(datacenterId),
size: resource.size == 0 ? nil : resource.size,
intervals: intervals,
parameters: parameters
))
}
} else if let localFileResource = resource as? LocalFileReferenceMediaResource {
return fetchLocalFileResource(path: localFileResource.localFilePath, move: localFileResource.isUniquelyReferencedTemporaryFile)
@ -63,7 +140,7 @@ func fetchResource(account: Account, resource: MediaResource, intervals: Signal<
return .single(.dataPart(resourceOffset: 0, data: Data(), range: 0 ..< 0, complete: false))
|> then(fetchHttpResource(url: httpReference.url))
} else if let wallpaperResource = resource as? WallpaperDataResource {
return getWallpaper(network: account.network, slug: wallpaperResource.slug)
return getWallpaper(network: network, slug: wallpaperResource.slug)
|> mapError { _ -> MediaResourceDataFetchError in
return .generic
}
@ -75,13 +152,24 @@ func fetchResource(account: Account, resource: MediaResource, intervals: Signal<
return .fail(.generic)
}
return .single(.dataPart(resourceOffset: 0, data: Data(), range: 0 ..< 0, complete: false))
|> then(fetchCloudMediaLocation(account: account, resource: cloudResource, datacenterId: cloudResource.datacenterId, size: resource.size == 0 ? nil : resource.size, intervals: intervals, parameters: MediaResourceFetchParameters(
tag: nil,
info: TelegramCloudMediaResourceFetchInfo(reference: .standalone(resource: file.file.resource), preferBackgroundReferenceRevalidation: false, continueInBackground: false),
location: nil,
contentType: .other,
isRandomAccessAllowed: true
)))
|> then(fetchCloudMediaLocation(
accountPeerId: accountPeerId,
postbox: postbox,
network: network,
mediaReferenceRevalidationContext: mediaReferenceRevalidationContext,
networkStatsContext: networkStatsContext,
resource: cloudResource,
datacenterId: cloudResource.datacenterId,
size: resource.size == 0 ? nil : resource.size,
intervals: intervals,
parameters: MediaResourceFetchParameters(
tag: nil,
info: TelegramCloudMediaResourceFetchInfo(reference: .standalone(resource: file.file.resource), preferBackgroundReferenceRevalidation: false, continueInBackground: false),
location: nil,
contentType: .other,
isRandomAccessAllowed: true
)
))
}
}
return nil

View File

@ -3,7 +3,28 @@ import Postbox
import SwiftSignalKit
import MtProtoKit
func fetchSecretFileResource(account: Account, resource: SecretFileMediaResource, intervals: Signal<[(Range<Int64>, MediaBoxFetchPriority)], NoError>, parameters: MediaResourceFetchParameters?) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
return multipartFetch(accountPeerId: account.peerId, postbox: account.postbox, network: account.network, mediaReferenceRevalidationContext: account.mediaReferenceRevalidationContext, networkStatsContext: account.networkStatsContext, resource: resource, datacenterId: resource.datacenterId, size: resource.size, intervals: intervals, parameters: parameters, encryptionKey: resource.key, decryptedSize: resource.decryptedSize)
func fetchSecretFileResource(
accountPeerId: PeerId,
postbox: Postbox,
network: Network,
mediaReferenceRevalidationContext: MediaReferenceRevalidationContext,
networkStatsContext: NetworkStatsContext,
resource: SecretFileMediaResource,
intervals: Signal<[(Range<Int64>, MediaBoxFetchPriority)], NoError>,
parameters: MediaResourceFetchParameters?
) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
return multipartFetch(
accountPeerId: accountPeerId,
postbox: postbox,
network: network,
mediaReferenceRevalidationContext: mediaReferenceRevalidationContext,
networkStatsContext: networkStatsContext,
resource: resource,
datacenterId: resource.datacenterId,
size: resource.size,
intervals: intervals,
parameters: parameters,
encryptionKey: resource.key,
decryptedSize: resource.decryptedSize
)
}

View File

@ -47,7 +47,7 @@ public extension TelegramEngine {
}
public func searchRemotePeers(query: String) -> Signal<([FoundPeer], [FoundPeer]), NoError> {
return _internal_searchPeers(account: self.account, query: query)
return _internal_searchPeers(accountPeerId: self.account.peerId, postbox: self.account.postbox, network: self.account.network, query: query)
}
public func searchLocalPeers(query: String) -> Signal<[EngineRenderedPeer], NoError> {

View File

@ -131,10 +131,10 @@ public extension TelegramEngine {
public struct Item {
}
private let account: Account
private let postbox: Postbox
init(account: Account) {
self.account = account
public init(postbox: Postbox) {
self.postbox = postbox
}
private func _subscribe(items: [AnyPostboxViewDataItem]) -> Signal<[Any], NoError> {
@ -144,7 +144,7 @@ public extension TelegramEngine {
keys.insert(key)
}
}
return self.account.postbox.combinedView(keys: Array(keys))
return self.postbox.combinedView(keys: Array(keys))
|> map { views -> [Any] in
var results: [Any] = []

View File

@ -5,10 +5,12 @@ import TelegramApi
public extension TelegramEngine {
final class HistoryImport {
private let account: Account
private let postbox: Postbox
private let network: Network
init(account: Account) {
self.account = account
public init(postbox: Postbox, network: Network) {
self.postbox = postbox
self.network = network
}
public struct Session {
@ -37,7 +39,7 @@ public extension TelegramEngine {
}
public func getInfo(header: String) -> Signal<ParsedInfo, GetInfoError> {
return self.account.network.request(Api.functions.messages.checkHistoryImport(importHead: header))
return self.network.request(Api.functions.messages.checkHistoryImport(importHead: header))
|> mapError { _ -> GetInfoError in
return .generic
}
@ -56,15 +58,16 @@ public extension TelegramEngine {
}
public func initSession(peerId: PeerId, file: TempBoxFile, mediaCount: Int32) -> Signal<Session, InitImportError> {
let account = self.account
return multipartUpload(network: self.account.network, postbox: self.account.postbox, source: .tempFile(file), encrypt: false, tag: nil, hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: true, useLargerParts: true, increaseParallelParts: true, useMultiplexedRequests: false, useCompression: true)
let postbox = self.postbox
let network = self.network
return multipartUpload(network: network, postbox: postbox, source: .tempFile(file), encrypt: false, tag: nil, hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: true, useLargerParts: true, increaseParallelParts: true, useMultiplexedRequests: false, useCompression: true)
|> mapError { _ -> InitImportError in
return .generic
}
|> mapToSignal { result -> Signal<Session, InitImportError> in
switch result {
case let .inputFile(inputFile):
return account.postbox.transaction { transaction -> Api.InputPeer? in
return postbox.transaction { transaction -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer)
}
|> castError(InitImportError.self)
@ -72,7 +75,7 @@ public extension TelegramEngine {
guard let inputPeer = inputPeer else {
return .fail(.generic)
}
return account.network.request(Api.functions.messages.initHistoryImport(peer: inputPeer, file: inputFile, mediaCount: mediaCount), automaticFloodWait: false)
return network.request(Api.functions.messages.initHistoryImport(peer: inputPeer, file: inputFile, mediaCount: mediaCount), automaticFloodWait: false)
|> mapError { error -> InitImportError in
if error.errorDescription == "CHAT_ADMIN_REQUIRED" {
return .chatAdminRequired
@ -123,8 +126,9 @@ public extension TelegramEngine {
forceNoBigParts = false
}
let account = self.account
return multipartUpload(network: self.account.network, postbox: self.account.postbox, source: .tempFile(file), encrypt: false, tag: nil, hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: forceNoBigParts, useLargerParts: true, useMultiplexedRequests: true)
let postbox = self.postbox
let network = self.network
return multipartUpload(network: network, postbox: postbox, source: .tempFile(file), encrypt: false, tag: nil, hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: forceNoBigParts, useLargerParts: true, useMultiplexedRequests: true)
|> mapError { _ -> UploadMediaError in
return .generic
}
@ -156,7 +160,7 @@ public extension TelegramEngine {
case .inputSecretFile:
return .fail(.generic)
}
return account.network.request(Api.functions.messages.uploadImportedMedia(peer: session.inputPeer, importId: session.id, fileName: fileName, media: inputMedia))
return network.request(Api.functions.messages.uploadImportedMedia(peer: session.inputPeer, importId: session.id, fileName: fileName, media: inputMedia))
|> mapError { error -> UploadMediaError in
switch error.errorDescription {
case "CHAT_ADMIN_REQUIRED":
@ -181,7 +185,7 @@ public extension TelegramEngine {
}
public func startImport(session: Session) -> Signal<Never, StartImportError> {
return self.account.network.request(Api.functions.messages.startHistoryImport(peer: session.inputPeer, importId: session.id))
return self.network.request(Api.functions.messages.startHistoryImport(peer: session.inputPeer, importId: session.id))
|> mapError { _ -> StartImportError in
return .generic
}
@ -209,8 +213,9 @@ public extension TelegramEngine {
}
public func checkPeerImport(peerId: PeerId) -> Signal<CheckPeerImportResult, CheckPeerImportError> {
let account = self.account
return self.account.postbox.transaction { transaction -> Peer? in
let postbox = self.postbox
let network = self.network
return postbox.transaction { transaction -> Peer? in
return transaction.getPeer(peerId)
}
|> castError(CheckPeerImportError.self)
@ -222,7 +227,7 @@ public extension TelegramEngine {
return .fail(.generic)
}
return account.network.request(Api.functions.messages.checkHistoryImportPeer(peer: inputPeer))
return network.request(Api.functions.messages.checkHistoryImportPeer(peer: inputPeer))
|> mapError { error -> CheckPeerImportError in
if error.errorDescription == "CHAT_ADMIN_REQUIRED" {
return .chatAdminRequired

View File

@ -3,8 +3,8 @@ import Postbox
import TelegramApi
import SwiftSignalKit
func _internal_exportMessageLink(account: Account, peerId: PeerId, messageId: MessageId, isThread: Bool = false) -> Signal<String?, NoError> {
return account.postbox.transaction { transaction -> (Peer, MessageId)? in
public func _internal_exportMessageLink(postbox: Postbox, network: Network, peerId: PeerId, messageId: MessageId, isThread: Bool = false) -> Signal<String?, NoError> {
return postbox.transaction { transaction -> (Peer, MessageId)? in
let peer: Peer? = transaction.getPeer(messageId.peerId)
if let peer = peer {
return (peer, messageId)
@ -22,7 +22,7 @@ func _internal_exportMessageLink(account: Account, peerId: PeerId, messageId: Me
if isThread {
flags |= 1 << 1
}
return account.network.request(Api.functions.channels.exportMessageLink(flags: flags, channel: input, id: sourceMessageId.id)) |> mapError { _ in return }
return network.request(Api.functions.channels.exportMessageLink(flags: flags, channel: input, id: sourceMessageId.id)) |> mapError { _ in return }
|> map { res in
switch res {
case let .exportedMessageLink(link, _):

View File

@ -217,7 +217,7 @@ public extension TelegramEngine {
}
public func exportMessageLink(peerId: PeerId, messageId: MessageId, isThread: Bool = false) -> Signal<String?, NoError> {
return _internal_exportMessageLink(account: self.account, peerId: peerId, messageId: messageId, isThread: isThread)
return _internal_exportMessageLink(postbox: self.account.postbox, network: self.account.network, peerId: peerId, messageId: messageId, isThread: isThread)
}
public func enqueueOutgoingMessage(

View File

@ -17,8 +17,8 @@ public enum CreateChannelMode {
case supergroup(isForum: Bool)
}
private func createChannel(account: Account, title: String, description: String?, username: String?, mode: CreateChannelMode, location: (latitude: Double, longitude: Double, address: String)? = nil, isForHistoryImport: Bool = false) -> Signal<PeerId, CreateChannelError> {
return account.postbox.transaction { transaction -> Signal<PeerId, CreateChannelError> in
private func createChannel(postbox: Postbox, network: Network, stateManager: AccountStateManager, title: String, description: String?, username: String?, mode: CreateChannelMode, location: (latitude: Double, longitude: Double, address: String)? = nil, isForHistoryImport: Bool = false) -> Signal<PeerId, CreateChannelError> {
return postbox.transaction { transaction -> Signal<PeerId, CreateChannelError> in
var flags: Int32 = 0
switch mode {
case .channel:
@ -43,7 +43,7 @@ private func createChannel(account: Account, title: String, description: String?
transaction.clearItemCacheCollection(collectionId: Namespaces.CachedItemCollection.cachedGroupCallDisplayAsPeers)
return account.network.request(Api.functions.channels.createChannel(flags: flags, title: title, about: description ?? "", geoPoint: geoPoint, address: address, ttlPeriod: nil), automaticFloodWait: false)
return network.request(Api.functions.channels.createChannel(flags: flags, title: title, about: description ?? "", geoPoint: geoPoint, address: address, ttlPeriod: nil), automaticFloodWait: false)
|> mapError { error -> CreateChannelError in
if error.errorCode == 406 {
return .serverProvided(error.errorDescription)
@ -58,9 +58,9 @@ private func createChannel(account: Account, title: String, description: String?
}
}
|> mapToSignal { updates -> Signal<PeerId, CreateChannelError> in
account.stateManager.addUpdates(updates)
stateManager.addUpdates(updates)
if let message = updates.messages.first, let peerId = apiMessagePeerId(message) {
return account.postbox.multiplePeersView([peerId])
return postbox.multiplePeersView([peerId])
|> filter { view in
return view.peers[peerId] != nil
}
@ -72,7 +72,7 @@ private func createChannel(account: Account, title: String, description: String?
|> timeout(5.0, queue: Queue.concurrentDefaultQueue(), alternate: .fail(.generic))
|> mapToSignal { peerId -> Signal<PeerId, CreateChannelError> in
if title.contains("*forum") {
return _internal_setChannelForumMode(account: account, peerId: peerId, isForum: true)
return _internal_setChannelForumMode(postbox: postbox, network: network, stateManager: stateManager, peerId: peerId, isForum: true)
|> castError(CreateChannelError.self)
|> map { _ -> PeerId in
}
@ -91,11 +91,11 @@ private func createChannel(account: Account, title: String, description: String?
}
func _internal_createChannel(account: Account, title: String, description: String?, username: String?) -> Signal<PeerId, CreateChannelError> {
return createChannel(account: account, title: title, description: description, username: nil, mode: .channel)
return createChannel(postbox: account.postbox, network: account.network, stateManager: account.stateManager, title: title, description: description, username: nil, mode: .channel)
}
func _internal_createSupergroup(account: Account, title: String, description: String?, username: String?, isForum: Bool, location: (latitude: Double, longitude: Double, address: String)? = nil, isForHistoryImport: Bool = false) -> Signal<PeerId, CreateChannelError> {
return createChannel(account: account, title: title, description: description, username: username, mode: .supergroup(isForum: isForum), location: location, isForHistoryImport: isForHistoryImport)
public func _internal_createSupergroup(postbox: Postbox, network: Network, stateManager: AccountStateManager, title: String, description: String?, username: String?, isForum: Bool, location: (latitude: Double, longitude: Double, address: String)? = nil, isForHistoryImport: Bool = false) -> Signal<PeerId, CreateChannelError> {
return createChannel(postbox: postbox, network: network, stateManager: stateManager, title: title, description: description, username: username, mode: .supergroup(isForum: isForum), location: location, isForHistoryImport: isForHistoryImport)
}
public enum DeleteChannelError {

View File

@ -12,17 +12,17 @@ func cachedRecentPeersEntryId() -> ItemCacheEntryId {
return ItemCacheEntryId(collectionId: 101, key: CachedRecentPeers.cacheKey())
}
func _internal_recentPeers(account: Account) -> Signal<RecentPeers, NoError> {
public func _internal_recentPeers(accountPeerId: EnginePeer.Id, postbox: Postbox) -> Signal<RecentPeers, NoError> {
let key = PostboxViewKey.cachedItem(cachedRecentPeersEntryId())
return account.postbox.combinedView(keys: [key])
return postbox.combinedView(keys: [key])
|> mapToSignal { views -> Signal<RecentPeers, NoError> in
if let value = (views.views[key] as? CachedItemView)?.value?.get(CachedRecentPeers.self) {
if value.enabled {
return account.postbox.multiplePeersView(value.ids)
return postbox.multiplePeersView(value.ids)
|> map { view -> RecentPeers in
var peers: [Peer] = []
for id in value.ids {
if let peer = view.peers[id], id != account.peerId {
if let peer = view.peers[id], id != accountPeerId {
peers.append(peer)
}
}
@ -44,7 +44,7 @@ public func _internal_getRecentPeers(transaction: Transaction) -> [PeerId] {
return entry.ids
}
func _internal_managedUpdatedRecentPeers(accountPeerId: PeerId, postbox: Postbox, network: Network) -> Signal<Void, NoError> {
public func _internal_managedUpdatedRecentPeers(accountPeerId: PeerId, postbox: Postbox, network: Network) -> Signal<Void, NoError> {
let key = PostboxViewKey.cachedItem(cachedRecentPeersEntryId())
let peersEnabled = postbox.combinedView(keys: [key])
|> map { views -> Bool in

View File

@ -35,7 +35,7 @@ public struct RecentlySearchedPeer: Equatable {
public let subpeerSummary: RecentlySearchedPeerSubpeerSummary?
}
func _internal_recentlySearchedPeers(postbox: Postbox) -> Signal<[RecentlySearchedPeer], NoError> {
public func _internal_recentlySearchedPeers(postbox: Postbox) -> Signal<[RecentlySearchedPeer], NoError> {
return postbox.combinedView(keys: [.orderedItemList(id: Namespaces.OrderedItemList.RecentlySearchedPeerIds)])
|> mapToSignal { view -> Signal<[RecentlySearchedPeer], NoError> in
var peerIds: [PeerId] = []

View File

@ -19,10 +19,8 @@ public struct FoundPeer: Equatable {
}
}
func _internal_searchPeers(account: Account, query: String) -> Signal<([FoundPeer], [FoundPeer]), NoError> {
let accountPeerId = account.peerId
let searchResult = account.network.request(Api.functions.contacts.search(q: query, limit: 20), automaticFloodWait: false)
public func _internal_searchPeers(accountPeerId: PeerId, postbox: Postbox, network: Network, query: String) -> Signal<([FoundPeer], [FoundPeer]), NoError> {
let searchResult = network.request(Api.functions.contacts.search(q: query, limit: 20), automaticFloodWait: false)
|> map(Optional.init)
|> `catch` { _ in
return Signal<Api.contacts.Found?, NoError>.single(nil)
@ -32,7 +30,7 @@ func _internal_searchPeers(account: Account, query: String) -> Signal<([FoundPee
if let result = result {
switch result {
case let .found(myResults, results, chats, users):
return account.postbox.transaction { transaction -> ([FoundPeer], [FoundPeer]) in
return postbox.transaction { transaction -> ([FoundPeer], [FoundPeer]) in
var subscribers: [PeerId: Int32] = [:]
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)

View File

@ -343,7 +343,7 @@ public extension TelegramEngine {
}
public func createSupergroup(title: String, description: String?, username: String? = nil, isForum: Bool = false, location: (latitude: Double, longitude: Double, address: String)? = nil, isForHistoryImport: Bool = false) -> Signal<PeerId, CreateChannelError> {
return _internal_createSupergroup(account: self.account, title: title, description: description, username: username, isForum: isForum, location: location, isForHistoryImport: isForHistoryImport)
return _internal_createSupergroup(postbox: self.account.postbox, network: self.account.network, stateManager: account.stateManager, title: title, description: description, username: username, isForum: isForum, location: location, isForHistoryImport: isForHistoryImport)
}
public func deleteChannel(peerId: PeerId) -> Signal<Void, DeleteChannelError> {
@ -502,7 +502,7 @@ public extension TelegramEngine {
}
public func recentPeers() -> Signal<RecentPeers, NoError> {
return _internal_recentPeers(account: self.account)
return _internal_recentPeers(accountPeerId: self.account.peerId, postbox: self.account.postbox)
}
public func managedUpdatedRecentPeers() -> Signal<Void, NoError> {
@ -926,7 +926,7 @@ public extension TelegramEngine {
}
public func ensurePeerIsLocallyAvailable(peer: EnginePeer) -> Signal<EnginePeer, NoError> {
return _internal_storedMessageFromSearchPeer(account: self.account, peer: peer._asPeer())
return _internal_storedMessageFromSearchPeer(postbox: self.account.postbox, peer: peer._asPeer())
|> map { result -> EnginePeer in
return EnginePeer(result)
}
@ -978,7 +978,7 @@ public extension TelegramEngine {
}
public func setChannelForumMode(id: EnginePeer.Id, isForum: Bool) -> Signal<Never, NoError> {
return _internal_setChannelForumMode(account: self.account, peerId: id, isForum: isForum)
return _internal_setChannelForumMode(postbox: self.account.postbox, network: self.account.network, stateManager: self.account.stateManager, peerId: id, isForum: isForum)
}
public func createForumChannelTopic(id: EnginePeer.Id, title: String, iconColor: Int32, iconFileId: Int64?) -> Signal<Int64, CreateForumChannelTopicError> {

View File

@ -193,7 +193,7 @@ public extension TelegramEngine {
}
}
func _internal_resolveInlineStickers(postbox: Postbox, network: Network, fileIds: [Int64]) -> Signal<[Int64: TelegramMediaFile], NoError> {
public func _internal_resolveInlineStickers(postbox: Postbox, network: Network, fileIds: [Int64]) -> Signal<[Int64: TelegramMediaFile], NoError> {
return postbox.transaction { transaction -> [Int64: TelegramMediaFile] in
var cachedFiles: [Int64: TelegramMediaFile] = [:]
for fileId in fileIds {

View File

@ -57,7 +57,7 @@ public final class TelegramEngine {
}()
public lazy var historyImport: HistoryImport = {
return HistoryImport(account: self.account)
return HistoryImport(postbox: self.account.postbox, network: self.account.network)
}()
public lazy var contacts: Contacts = {
@ -73,7 +73,7 @@ public final class TelegramEngine {
}()
public lazy var data: EngineData = {
return EngineData(account: self.account)
return EngineData(postbox: self.account.postbox)
}()
public lazy var orderedLists: OrderedLists = {

View File

@ -2,8 +2,8 @@ import Foundation
import Postbox
import SwiftSignalKit
func _internal_storedMessageFromSearchPeer(account: Account, peer: Peer) -> Signal<Peer, NoError> {
return account.postbox.transaction { transaction -> Peer in
public func _internal_storedMessageFromSearchPeer(postbox: Postbox, peer: Peer) -> Signal<Peer, NoError> {
return postbox.transaction { transaction -> Peer in
if transaction.getPeer(peer.id) == nil {
updatePeersCustom(transaction: transaction, peers: [peer], update: { _, updatedPeer in
return updatedPeer

View File

@ -379,6 +379,11 @@ swift_library(
"//submodules/TelegramUI/Components/PeerReportScreen",
"//submodules/Utils/VolumeButtons",
"//submodules/ChatContextQuery",
"//submodules/TelegramUI/Components/TelegramUIDeclareEncodables",
"//submodules/TelegramUI/Components/TelegramAccountAuxiliaryMethods",
"//submodules/TelegramUI/Components/PeerSelectionController",
"//submodules/TelegramUI/Components/Chat/AccessoryPanelNode",
"//submodules/TelegramUI/Components/Chat/ForwardAccessoryPanelNode",
] + select({
"@build_bazel_rules_apple//apple:ios_armv7": [],
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,

View File

@ -0,0 +1,20 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "AccessoryPanelNode",
module_name = "AccessoryPanelNode",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//submodules/AsyncDisplayKit",
"//submodules/TelegramPresentationData",
"//submodules/ChatPresentationInterfaceState",
],
visibility = [
"//visibility:public",
],
)

View File

@ -0,0 +1,23 @@
import Foundation
import UIKit
import AsyncDisplayKit
import TelegramPresentationData
import ChatPresentationInterfaceState
open class AccessoryPanelNode: ASDisplayNode {
open var originalFrameBeforeDismissed: CGRect?
open var dismiss: (() -> Void)?
open var interfaceInteraction: ChatPanelInterfaceInteraction?
open func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) {
}
open func updateState(size: CGSize, inset: CGFloat, interfaceState: ChatPresentationInterfaceState) {
}
open func animateIn() {
}
open func animateOut() {
}
}

View File

@ -0,0 +1,36 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "ForwardAccessoryPanelNode",
module_name = "ForwardAccessoryPanelNode",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//submodules/AsyncDisplayKit",
"//submodules/TelegramCore",
"//submodules/Postbox",
"//submodules/SSignalKit/SwiftSignalKit",
"//submodules/Display",
"//submodules/TelegramPresentationData",
"//submodules/TelegramUIPreferences",
"//submodules/AccountContext",
"//submodules/LocalizedPeerData",
"//submodules/AlertUI",
"//submodules/PresentationDataUtils",
"//submodules/TextFormat",
"//submodules/Markdown",
"//submodules/TelegramNotices",
"//submodules/ChatPresentationInterfaceState",
"//submodules/TelegramUI/Components/TextNodeWithEntities",
"//submodules/TelegramUI/Components/AnimationCache",
"//submodules/TelegramUI/Components/MultiAnimationRenderer",
"//submodules/TelegramUI/Components/Chat/AccessoryPanelNode",
],
visibility = [
"//visibility:public",
],
)

View File

@ -18,6 +18,7 @@ import ChatPresentationInterfaceState
import TextNodeWithEntities
import AnimationCache
import MultiAnimationRenderer
import AccessoryPanelNode
func textStringForForwardedMessage(_ message: Message, strings: PresentationStrings) -> (text: String, entities: [MessageTextEntity], isMedia: Bool) {
for media in message.media {
@ -81,9 +82,9 @@ func textStringForForwardedMessage(_ message: Message, strings: PresentationStri
return (message.text, message.textEntitiesAttribute?.entities ?? [], false)
}
final class ForwardAccessoryPanelNode: AccessoryPanelNode {
public final class ForwardAccessoryPanelNode: AccessoryPanelNode {
private let messageDisposable = MetaDisposable()
let messageIds: [MessageId]
public let messageIds: [MessageId]
private var messages: [Message] = []
private var authors: String?
private var sourcePeer: (peerId: PeerId, displayTitle: String)?
@ -106,7 +107,7 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode {
private var validLayout: (size: CGSize, inset: CGFloat, interfaceState: ChatPresentationInterfaceState)?
init(context: AccountContext, messageIds: [MessageId], theme: PresentationTheme, strings: PresentationStrings, fontSize: PresentationFontSize, nameDisplayOrder: PresentationPersonNameOrder, forwardOptionsState: ChatInterfaceForwardOptionsState?, animationCache: AnimationCache?, animationRenderer: MultiAnimationRenderer?) {
public init(context: AccountContext, messageIds: [MessageId], theme: PresentationTheme, strings: PresentationStrings, fontSize: PresentationFontSize, nameDisplayOrder: PresentationPersonNameOrder, forwardOptionsState: ChatInterfaceForwardOptionsState?, animationCache: AnimationCache?, animationRenderer: MultiAnimationRenderer?) {
self.context = context
self.messageIds = messageIds
self.theme = theme
@ -275,25 +276,25 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode {
self.messageDisposable.dispose()
}
override func didLoad() {
override public func didLoad() {
super.didLoad()
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
}
override func animateIn() {
override public func animateIn() {
self.iconNode.layer.animateScale(from: 0.001, to: 1.0, duration: 0.2)
}
override func animateOut() {
override public func animateOut() {
self.iconNode.layer.animateScale(from: 1.0, to: 0.001, duration: 0.2, removeOnCompletion: false)
}
override func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) {
override public func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) {
self.updateThemeAndStrings(theme: theme, strings: strings, forwardOptionsState: self.forwardOptionsState)
}
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, forwardOptionsState: ChatInterfaceForwardOptionsState?, force: Bool = false) {
public func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, forwardOptionsState: ChatInterfaceForwardOptionsState?, force: Bool = false) {
if force || self.theme !== theme || self.strings !== strings || self.forwardOptionsState != forwardOptionsState {
self.theme = theme
self.strings = strings
@ -327,11 +328,11 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode {
}
}
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
override public func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
return CGSize(width: constrainedSize.width, height: 45.0)
}
override func updateState(size: CGSize, inset: CGFloat, interfaceState: ChatPresentationInterfaceState) {
override public func updateState(size: CGSize, inset: CGFloat, interfaceState: ChatPresentationInterfaceState) {
self.validLayout = (size, inset, interfaceState)
let bounds = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: 45.0))
@ -360,7 +361,7 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode {
self.textNode.frame = CGRect(origin: CGPoint(x: leftInset + textLineInset, y: 25.0), size: textSize)
}
@objc func closePressed() {
@objc private func closePressed() {
guard let (peerId, peerDisplayTitle) = self.sourcePeer else {
return
}
@ -399,7 +400,7 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode {
}
private var previousTapTimestamp: Double?
@objc func tapGesture(_ recognizer: UITapGestureRecognizer) {
@objc private func tapGesture(_ recognizer: UITapGestureRecognizer) {
if case .ended = recognizer.state {
let timestamp = CFAbsoluteTimeGetCurrent()
if let previousTapTimestamp = self.previousTapTimestamp, previousTapTimestamp + 1.0 > timestamp {

View File

@ -2040,7 +2040,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
})))
}
let contextController = ContextController(account: strongSelf.context.account, presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: gallery, sourceView: sourceView, sourceRect: sourceRect)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
let contextController = ContextController(presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: gallery, sourceView: sourceView, sourceRect: sourceRect)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
strongSelf.interaction?.presentGlobalOverlayController(contextController, nil)
})
}

View File

@ -638,7 +638,6 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
let items = ContextController.Items(content: .list(itemList))
let controller = ContextController(
account: component.context.account,
presentationData: presentationData,
source: .extracted(LinkListContextExtractedContentSource(contentView: sourceView)),
items: .single(items),

View File

@ -24,6 +24,7 @@ swift_library(
"//submodules/TextFormat:TextFormat",
"//submodules/lottie-ios:Lottie",
"//submodules/GZip:GZip",
"//submodules/TelegramUIPreferences",
],
visibility = [
"//visibility:public",

View File

@ -14,6 +14,7 @@ import TextFormat
import Lottie
import GZip
import HierarchyTrackingLayer
import TelegramUIPreferences
public final class EmojiStatusComponent: Component {
public typealias EnvironmentType = Empty
@ -52,7 +53,9 @@ public final class EmojiStatusComponent: Component {
case image(image: UIImage?)
}
public let context: AccountContext
public let postbox: Postbox
public let energyUsageSettings: EnergyUsageSettings
public let resolveInlineStickers: ([Int64]) -> Signal<[Int64: TelegramMediaFile], NoError>
public let animationCache: AnimationCache
public let animationRenderer: MultiAnimationRenderer
public let content: Content
@ -61,7 +64,7 @@ public final class EmojiStatusComponent: Component {
public let action: (() -> Void)?
public let emojiFileUpdated: ((TelegramMediaFile?) -> Void)?
public init(
public convenience init(
context: AccountContext,
animationCache: AnimationCache,
animationRenderer: MultiAnimationRenderer,
@ -71,7 +74,37 @@ public final class EmojiStatusComponent: Component {
action: (() -> Void)?,
emojiFileUpdated: ((TelegramMediaFile?) -> Void)? = nil
) {
self.context = context
self.init(
postbox: context.account.postbox,
energyUsageSettings: context.sharedContext.energyUsageSettings,
resolveInlineStickers: { fileIds in
return context.engine.stickers.resolveInlineStickers(fileIds: fileIds)
},
animationCache: animationCache,
animationRenderer: animationRenderer,
content: content,
isVisibleForAnimations: isVisibleForAnimations,
useSharedAnimation: useSharedAnimation,
action: action,
emojiFileUpdated: emojiFileUpdated
)
}
public init(
postbox: Postbox,
energyUsageSettings: EnergyUsageSettings,
resolveInlineStickers: @escaping ([Int64]) -> Signal<[Int64: TelegramMediaFile], NoError>,
animationCache: AnimationCache,
animationRenderer: MultiAnimationRenderer,
content: Content,
isVisibleForAnimations: Bool,
useSharedAnimation: Bool = false,
action: (() -> Void)?,
emojiFileUpdated: ((TelegramMediaFile?) -> Void)? = nil
) {
self.postbox = postbox
self.energyUsageSettings = energyUsageSettings
self.resolveInlineStickers = resolveInlineStickers
self.animationCache = animationCache
self.animationRenderer = animationRenderer
self.content = content
@ -83,7 +116,9 @@ public final class EmojiStatusComponent: Component {
public func withVisibleForAnimations(_ isVisibleForAnimations: Bool) -> EmojiStatusComponent {
return EmojiStatusComponent(
context: self.context,
postbox: self.postbox,
energyUsageSettings: self.energyUsageSettings,
resolveInlineStickers: self.resolveInlineStickers,
animationCache: self.animationCache,
animationRenderer: self.animationRenderer,
content: self.content,
@ -95,7 +130,10 @@ public final class EmojiStatusComponent: Component {
}
public static func ==(lhs: EmojiStatusComponent, rhs: EmojiStatusComponent) -> Bool {
if lhs.context !== rhs.context {
if lhs.postbox !== rhs.postbox {
return false
}
if lhs.energyUsageSettings != rhs.energyUsageSettings {
return false
}
if lhs.animationCache !== rhs.animationCache {
@ -419,7 +457,15 @@ public final class EmojiStatusComponent: Component {
loopCount = value
}
animationLayer = InlineStickerItemLayer(
context: component.context,
context: .custom(InlineStickerItemLayer.Context.Custom(
postbox: component.postbox,
energyUsageSettings: {
return component.energyUsageSettings
},
resolveInlineStickers: { fileIds in
return component.resolveInlineStickers(fileIds)
}
)),
userLocation: .other,
attemptSynchronousLoad: false,
emoji: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: emojiFile.fileId.id, file: emojiFile),
@ -508,7 +554,7 @@ public final class EmojiStatusComponent: Component {
}*/
} else {
if self.emojiFileDisposable == nil {
self.emojiFileDisposable = (component.context.engine.stickers.resolveInlineStickers(fileIds: [emojiFileId])
self.emojiFileDisposable = (component.resolveInlineStickers([emojiFileId])
|> deliverOnMainQueue).start(next: { [weak self] result in
guard let strongSelf = self else {
return

View File

@ -24,6 +24,7 @@ swift_library(
"//submodules/TelegramUI/Components/VideoAnimationCache:VideoAnimationCache",
"//submodules/TelegramUI/Components/MultiAnimationRenderer:MultiAnimationRenderer",
"//submodules/ShimmerEffect:ShimmerEffect",
"//submodules/TelegramUIPreferences",
],
visibility = [
"//visibility:public",

View File

@ -15,6 +15,7 @@ import VideoAnimationCache
import MultiAnimationRenderer
import ShimmerEffect
import TextFormat
import TelegramUIPreferences
public func generateTopicIcon(title: String, backgroundColors: [UIColor], strokeColors: [UIColor], size: CGSize) -> UIImage? {
let realSize = size
@ -97,8 +98,20 @@ public extension AnimationCacheAnimationType {
}
public func animationCacheFetchFile(context: AccountContext, userLocation: MediaResourceUserLocation, userContentType: MediaResourceUserContentType, resource: MediaResourceReference, type: AnimationCacheAnimationType, keyframeOnly: Bool, customColor: UIColor?) -> (AnimationCacheFetchOptions) -> Disposable {
return animationCacheFetchFile(
postbox: context.account.postbox,
userLocation: userLocation,
userContentType: userContentType,
resource: resource,
type: type,
keyframeOnly: keyframeOnly,
customColor: customColor
)
}
public func animationCacheFetchFile(postbox: Postbox, userLocation: MediaResourceUserLocation, userContentType: MediaResourceUserContentType, resource: MediaResourceReference, type: AnimationCacheAnimationType, keyframeOnly: Bool, customColor: UIColor?) -> (AnimationCacheFetchOptions) -> Disposable {
return { options in
let source = AnimatedStickerResourceSource(account: context.account, resource: resource.resource, fitzModifier: nil, isVideo: false)
let source = AnimatedStickerResourceSource(postbox: postbox, resource: resource.resource, fitzModifier: nil, isVideo: false)
let dataDisposable = source.directDataPath(attemptSynchronously: false).start(next: { result in
guard let result = result else {
@ -119,7 +132,7 @@ public func animationCacheFetchFile(context: AccountContext, userLocation: Media
}
})
let fetchDisposable = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: userLocation, userContentType: userContentType, reference: resource).start()
let fetchDisposable = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: userContentType, reference: resource).start()
return ActionDisposable {
dataDisposable.dispose()
@ -129,6 +142,74 @@ public func animationCacheFetchFile(context: AccountContext, userLocation: Media
}
public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
public enum Context: Equatable {
public final class Custom: Equatable {
public let postbox: Postbox
public let energyUsageSettings: () -> EnergyUsageSettings
public let resolveInlineStickers: ([Int64]) -> Signal<[Int64: TelegramMediaFile], NoError>
public init(postbox: Postbox, energyUsageSettings: @escaping () -> EnergyUsageSettings, resolveInlineStickers: @escaping ([Int64]) -> Signal<[Int64: TelegramMediaFile], NoError>) {
self.postbox = postbox
self.energyUsageSettings = energyUsageSettings
self.resolveInlineStickers = resolveInlineStickers
}
public static func ==(lhs: Custom, rhs: Custom) -> Bool {
if lhs.postbox !== rhs.postbox {
return false
}
return true
}
}
case account(AccountContext)
case custom(Custom)
var postbox: Postbox {
switch self {
case let .account(account):
return account.account.postbox
case let .custom(custom):
return custom.postbox
}
}
var energyUsageSettings: EnergyUsageSettings {
switch self {
case let .account(account):
return account.sharedContext.energyUsageSettings
case let .custom(custom):
return custom.energyUsageSettings()
}
}
func resolveInlineStickers(fileIds: [Int64]) -> Signal<[Int64: TelegramMediaFile], NoError> {
switch self {
case let .account(account):
return account.engine.stickers.resolveInlineStickers(fileIds: fileIds)
case let .custom(custom):
return custom.resolveInlineStickers(fileIds)
}
}
public static func ==(lhs: Context, rhs: Context) -> Bool {
switch lhs {
case let .account(lhsContext):
if case let .account(rhsContext) = rhs, lhsContext === rhsContext {
return true
} else {
return false
}
case let .custom(custom):
if case .custom(custom) = rhs {
return true
} else {
return false
}
}
}
}
public static let queue = Queue()
public struct Key: Hashable {
@ -141,7 +222,7 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
}
}
private let context: AccountContext
private let context: InlineStickerItemLayer.Context
private let userLocation: MediaResourceUserLocation
private let emoji: ChatTextInputTextCustomEmojiAttribute
private let cache: AnimationCache
@ -189,7 +270,24 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
}
}
public init(context: AccountContext, userLocation: MediaResourceUserLocation, attemptSynchronousLoad: Bool, emoji: ChatTextInputTextCustomEmojiAttribute, file: TelegramMediaFile?, cache: AnimationCache, renderer: MultiAnimationRenderer, unique: Bool = false, placeholderColor: UIColor, pointSize: CGSize, dynamicColor: UIColor? = nil, loopCount: Int? = nil) {
public convenience init(context: AccountContext, userLocation: MediaResourceUserLocation, attemptSynchronousLoad: Bool, emoji: ChatTextInputTextCustomEmojiAttribute, file: TelegramMediaFile?, cache: AnimationCache, renderer: MultiAnimationRenderer, unique: Bool = false, placeholderColor: UIColor, pointSize: CGSize, dynamicColor: UIColor? = nil, loopCount: Int? = nil) {
self.init(
context: .account(context),
userLocation: userLocation,
attemptSynchronousLoad: attemptSynchronousLoad,
emoji: emoji,
file: file,
cache: cache,
renderer: renderer,
unique: unique,
placeholderColor: placeholderColor,
pointSize: pointSize,
dynamicColor: dynamicColor,
loopCount: loopCount
)
}
public init(context: InlineStickerItemLayer.Context, userLocation: MediaResourceUserLocation, attemptSynchronousLoad: Bool, emoji: ChatTextInputTextCustomEmojiAttribute, file: TelegramMediaFile?, cache: AnimationCache, renderer: MultiAnimationRenderer, unique: Bool = false, placeholderColor: UIColor, pointSize: CGSize, dynamicColor: UIColor? = nil, loopCount: Int? = nil) {
self.context = context
self.userLocation = userLocation
self.emoji = emoji
@ -211,7 +309,7 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
} else if let file = file {
self.updateFile(file: file, attemptSynchronousLoad: attemptSynchronousLoad)
} else {
self.infoDisposable = (context.engine.stickers.resolveInlineStickers(fileIds: [emoji.fileId])
self.infoDisposable = (context.resolveInlineStickers(fileIds: [emoji.fileId])
|> deliverOnMainQueue).start(next: { [weak self] files in
guard let strongSelf = self else {
return
@ -335,7 +433,7 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
let pointSize = self.pointSize
let placeholderColor = self.placeholderColor
let isThumbnailCancelled = Atomic<Bool>(value: false)
self.loadDisposable = self.renderer.loadFirstFrame(target: self, cache: self.cache, itemId: file.resource.id.stringRepresentation, size: self.pixelSize, fetch: animationCacheFetchFile(context: self.context, userLocation: self.userLocation, userContentType: .sticker, resource: .media(media: .standalone(media: file), resource: file.resource), type: AnimationCacheAnimationType(file: file), keyframeOnly: true, customColor: isTemplate ? .white : nil), completion: { [weak self] result, isFinal in
self.loadDisposable = self.renderer.loadFirstFrame(target: self, cache: self.cache, itemId: file.resource.id.stringRepresentation, size: self.pixelSize, fetch: animationCacheFetchFile(postbox: self.context.postbox, userLocation: self.userLocation, userContentType: .sticker, resource: .media(media: .standalone(media: file), resource: file.resource), type: AnimationCacheAnimationType(file: file), keyframeOnly: true, customColor: isTemplate ? .white : nil), completion: { [weak self] result, isFinal in
if !result {
MultiAnimationRendererImpl.firstFrameQueue.async {
let image = generateStickerPlaceholderImage(data: file.immediateThumbnailData, size: pointSize, scale: min(2.0, UIScreenScale), imageSize: file.dimensions?.cgSize ?? CGSize(width: 512.0, height: 512.0), backgroundColor: nil, foregroundColor: placeholderColor)
@ -377,10 +475,10 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
if file.isAnimatedSticker || file.isVideoSticker || file.isVideoEmoji {
let keyframeOnly = self.pixelSize.width >= 120.0
self.disposable = renderer.add(target: self, cache: self.cache, itemId: file.resource.id.stringRepresentation, unique: self.unique, size: self.pixelSize, fetch: animationCacheFetchFile(context: context, userLocation: self.userLocation, userContentType: .sticker, resource: .media(media: .standalone(media: file), resource: file.resource), type: AnimationCacheAnimationType(file: file), keyframeOnly: keyframeOnly, customColor: isTemplate ? .white : nil))
self.disposable = renderer.add(target: self, cache: self.cache, itemId: file.resource.id.stringRepresentation, unique: self.unique, size: self.pixelSize, fetch: animationCacheFetchFile(postbox: self.context.postbox, userLocation: self.userLocation, userContentType: .sticker, resource: .media(media: .standalone(media: file), resource: file.resource), type: AnimationCacheAnimationType(file: file), keyframeOnly: keyframeOnly, customColor: isTemplate ? .white : nil))
} else {
self.disposable = renderer.add(target: self, cache: self.cache, itemId: file.resource.id.stringRepresentation, unique: self.unique, size: self.pixelSize, fetch: { options in
let dataDisposable = context.account.postbox.mediaBox.resourceData(file.resource).start(next: { result in
let dataDisposable = context.postbox.mediaBox.resourceData(file.resource).start(next: { result in
guard result.complete else {
return
}
@ -388,7 +486,7 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
cacheStillSticker(path: result.path, width: Int(options.size.width), height: Int(options.size.height), writer: options.writer, customColor: isTemplate ? .white : nil)
})
let fetchDisposable = freeMediaFileResourceInteractiveFetched(account: context.account, userLocation: self.userLocation, fileReference: .customEmoji(media: file), resource: file.resource).start()
let fetchDisposable = freeMediaFileResourceInteractiveFetched(postbox: context.postbox, userLocation: self.userLocation, fileReference: .customEmoji(media: file), resource: file.resource).start()
return ActionDisposable {
dataDisposable.dispose()
@ -447,13 +545,26 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
public final class EmojiTextAttachmentView: UIView {
private let contentLayer: InlineStickerItemLayer
public init(context: AccountContext, userLocation: MediaResourceUserLocation, emoji: ChatTextInputTextCustomEmojiAttribute, file: TelegramMediaFile?, cache: AnimationCache, renderer: MultiAnimationRenderer, placeholderColor: UIColor, pointSize: CGSize) {
public convenience init(context: AccountContext, userLocation: MediaResourceUserLocation, emoji: ChatTextInputTextCustomEmojiAttribute, file: TelegramMediaFile?, cache: AnimationCache, renderer: MultiAnimationRenderer, placeholderColor: UIColor, pointSize: CGSize) {
self.init(
context: .account(context),
userLocation: userLocation,
emoji: emoji,
file: file,
cache: cache,
renderer: renderer,
placeholderColor: placeholderColor,
pointSize: pointSize
)
}
public init(context: InlineStickerItemLayer.Context, userLocation: MediaResourceUserLocation, emoji: ChatTextInputTextCustomEmojiAttribute, file: TelegramMediaFile?, cache: AnimationCache, renderer: MultiAnimationRenderer, placeholderColor: UIColor, pointSize: CGSize) {
self.contentLayer = InlineStickerItemLayer(context: context, userLocation: userLocation, attemptSynchronousLoad: true, emoji: emoji, file: file, cache: cache, renderer: renderer, placeholderColor: placeholderColor, pointSize: pointSize)
super.init(frame: CGRect())
self.layer.addSublayer(self.contentLayer)
self.contentLayer.isVisibleForAnimations = context.sharedContext.energyUsageSettings.loopEmoji
self.contentLayer.isVisibleForAnimations = context.energyUsageSettings.loopEmoji
}
required public init?(coder: NSCoder) {

View File

@ -244,13 +244,16 @@ public func presentedLegacyShortcutCamera(context: AccountContext, saveCapturedM
})
if let parentController = parentController {
parentController.present(ShareController(context: context, subject: .fromExternal({ peerIds, _, text, account, silently in
return legacyAssetPickerEnqueueMessages(context: context, account: account, signals: signals!)
guard let account = account as? ShareControllerAppAccountContext else {
return .single(.done)
}
return legacyAssetPickerEnqueueMessages(context: context, account: account.context.account, signals: signals!)
|> `catch` { _ -> Signal<[LegacyAssetPickerEnqueueMessage], ShareControllerError> in
return .single([])
}
|> mapToSignal { messages -> Signal<ShareControllerExternalStatus, ShareControllerError> in
let resultSignals = peerIds.map({ peerId in
return enqueueMessages(account: account, peerId: peerId, messages: messages.map { $0.message })
return enqueueMessages(account: account.context.account, peerId: peerId, messages: messages.map { $0.message })
|> castError(ShareControllerError.self)
|> mapToSignal { _ -> Signal<ShareControllerExternalStatus, ShareControllerError> in
return .complete()

View File

@ -7,6 +7,7 @@ import MetalKit
import Display
import SwiftSignalKit
import TelegramCore
import Postbox
public func mediaEditorGenerateGradientImage(size: CGSize, colors: [UIColor]) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(size, false, 1.0)
@ -54,7 +55,7 @@ final class MediaEditorComposer {
private let drawingImage: CIImage?
private var entities: [MediaEditorComposerEntity]
init(account: Account, values: MediaEditorValues, dimensions: CGSize, outputDimensions: CGSize, textScale: CGFloat) {
init(postbox: Postbox, values: MediaEditorValues, dimensions: CGSize, outputDimensions: CGSize, textScale: CGFloat) {
self.values = values
self.dimensions = dimensions
self.outputDimensions = outputDimensions
@ -79,7 +80,7 @@ final class MediaEditorComposer {
var entities: [MediaEditorComposerEntity] = []
for entity in values.entities {
entities.append(contentsOf: composerEntitiesForDrawingEntity(account: account, textScale: textScale, entity: entity.entity, colorSpace: colorSpace))
entities.append(contentsOf: composerEntitiesForDrawingEntity(postbox: postbox, textScale: textScale, entity: entity.entity, colorSpace: colorSpace))
}
self.entities = entities
@ -182,7 +183,7 @@ final class MediaEditorComposer {
}
}
public func makeEditorImageComposition(context: CIContext, account: Account, inputImage: UIImage, dimensions: CGSize, values: MediaEditorValues, time: CMTime, textScale: CGFloat, completion: @escaping (UIImage?) -> Void) {
public func makeEditorImageComposition(context: CIContext, postbox: Postbox, inputImage: UIImage, dimensions: CGSize, values: MediaEditorValues, time: CMTime, textScale: CGFloat, completion: @escaping (UIImage?) -> Void) {
let colorSpace = CGColorSpaceCreateDeviceRGB()
let inputImage = CIImage(image: inputImage, options: [.colorSpace: colorSpace])!
let gradientImage: CIImage
@ -199,7 +200,7 @@ public func makeEditorImageComposition(context: CIContext, account: Account, inp
var entities: [MediaEditorComposerEntity] = []
for entity in values.entities {
entities.append(contentsOf: composerEntitiesForDrawingEntity(account: account, textScale: textScale, entity: entity.entity, colorSpace: colorSpace))
entities.append(contentsOf: composerEntitiesForDrawingEntity(postbox: postbox, textScale: textScale, entity: entity.entity, colorSpace: colorSpace))
}
makeEditorImageFrameComposition(context: context, inputImage: inputImage, gradientImage: gradientImage, drawingImage: drawingImage, dimensions: dimensions, outputDimensions: dimensions, values: values, entities: entities, time: time, textScale: textScale, completion: { ciImage in

View File

@ -7,6 +7,7 @@ import MetalKit
import Display
import SwiftSignalKit
import TelegramCore
import Postbox
import AnimatedStickerNode
import TelegramAnimatedStickerNode
import YuvConversion
@ -60,7 +61,7 @@ private func prerenderTextTransformations(entity: DrawingEntity, image: UIImage,
return MediaEditorComposerStaticEntity(image: CIImage(image: newImage, options: [.colorSpace: colorSpace])!, position: position, scale: 1.0, rotation: 0.0, baseSize: nil, baseDrawingSize: CGSize(width: 1080, height: 1920), mirrored: false)
}
func composerEntitiesForDrawingEntity(account: Account, textScale: CGFloat, entity: DrawingEntity, colorSpace: CGColorSpace, tintColor: UIColor? = nil) -> [MediaEditorComposerEntity] {
func composerEntitiesForDrawingEntity(postbox: Postbox, textScale: CGFloat, entity: DrawingEntity, colorSpace: CGColorSpace, tintColor: UIColor? = nil) -> [MediaEditorComposerEntity] {
if let entity = entity as? DrawingStickerEntity {
let content: MediaEditorComposerStickerEntity.Content
switch entity.content {
@ -73,7 +74,7 @@ func composerEntitiesForDrawingEntity(account: Account, textScale: CGFloat, enti
case .dualVideoReference:
return []
}
return [MediaEditorComposerStickerEntity(account: account, content: content, position: entity.position, scale: entity.scale, rotation: entity.rotation, baseSize: entity.baseSize, mirrored: entity.mirrored, colorSpace: colorSpace, tintColor: tintColor, isStatic: entity.isExplicitlyStatic)]
return [MediaEditorComposerStickerEntity(postbox: postbox, content: content, position: entity.position, scale: entity.scale, rotation: entity.rotation, baseSize: entity.baseSize, mirrored: entity.mirrored, colorSpace: colorSpace, tintColor: tintColor, isStatic: entity.isExplicitlyStatic)]
} else if let renderImage = entity.renderImage, let image = CIImage(image: renderImage, options: [.colorSpace: colorSpace]) {
if let entity = entity as? DrawingBubbleEntity {
return [MediaEditorComposerStaticEntity(image: image, position: entity.position, scale: 1.0, rotation: entity.rotation, baseSize: entity.size, mirrored: false)]
@ -86,7 +87,7 @@ func composerEntitiesForDrawingEntity(account: Account, textScale: CGFloat, enti
entities.append(prerenderTextTransformations(entity: entity, image: renderImage, textScale: textScale, colorSpace: colorSpace))
if let renderSubEntities = entity.renderSubEntities {
for subEntity in renderSubEntities {
entities.append(contentsOf: composerEntitiesForDrawingEntity(account: account, textScale: textScale, entity: subEntity, colorSpace: colorSpace, tintColor: entity.color.toUIColor()))
entities.append(contentsOf: composerEntitiesForDrawingEntity(postbox: postbox, textScale: textScale, entity: subEntity, colorSpace: colorSpace, tintColor: entity.color.toUIColor()))
}
}
return entities
@ -146,7 +147,7 @@ private class MediaEditorComposerStickerEntity: MediaEditorComposerEntity {
}
}
let account: Account
let postbox: Postbox
let content: Content
let position: CGPoint
let scale: CGFloat
@ -181,8 +182,8 @@ private class MediaEditorComposerStickerEntity: MediaEditorComposerEntity {
var imagePixelBuffer: CVPixelBuffer?
let imagePromise = Promise<UIImage>()
init(account: Account, content: Content, position: CGPoint, scale: CGFloat, rotation: CGFloat, baseSize: CGSize, mirrored: Bool, colorSpace: CGColorSpace, tintColor: UIColor?, isStatic: Bool) {
self.account = account
init(postbox: Postbox, content: Content, position: CGPoint, scale: CGFloat, rotation: CGFloat, baseSize: CGSize, mirrored: Bool, colorSpace: CGColorSpace, tintColor: UIColor?, isStatic: Bool) {
self.postbox = postbox
self.content = content
self.position = position
self.scale = scale
@ -200,8 +201,8 @@ private class MediaEditorComposerStickerEntity: MediaEditorComposerEntity {
self.isAnimated = true
self.isVideoSticker = file.isVideoSticker || file.mimeType == "video/webm"
self.source = AnimatedStickerResourceSource(account: account, resource: file.resource, isVideo: isVideoSticker)
let pathPrefix = account.postbox.mediaBox.shortLivedResourceCachePathPrefix(file.resource.id)
self.source = AnimatedStickerResourceSource(postbox: postbox, resource: file.resource, isVideo: isVideoSticker)
let pathPrefix = postbox.mediaBox.shortLivedResourceCachePathPrefix(file.resource.id)
if let source = self.source {
let fitToSize: CGSize
if self.isStatic {
@ -251,7 +252,7 @@ private class MediaEditorComposerStickerEntity: MediaEditorComposerEntity {
}
} else {
self.isAnimated = false
self.disposables.add((chatMessageSticker(account: account, userLocation: .other, file: file, small: false, fetched: true, onlyFullSize: true, thumbnail: false, synchronousLoad: false, colorSpace: self.colorSpace)
self.disposables.add((chatMessageSticker(postbox: postbox, userLocation: .other, file: file, small: false, fetched: true, onlyFullSize: true, thumbnail: false, synchronousLoad: false, colorSpace: self.colorSpace)
|> deliverOn(self.queue)).start(next: { [weak self] generator in
if let self {
let context = generator(TransformImageArguments(corners: ImageCorners(), imageSize: baseSize, boundingSize: baseSize, intrinsicInsets: UIEdgeInsets()))
@ -276,7 +277,7 @@ private class MediaEditorComposerStickerEntity: MediaEditorComposerEntity {
private func setupVideoOutput() {
if case let .video(file) = self.content {
if let path = self.account.postbox.mediaBox.completedResourcePath(file.resource, pathExtension: "mp4") {
if let path = self.postbox.mediaBox.completedResourcePath(file.resource, pathExtension: "mp4") {
let url = URL(fileURLWithPath: path)
let asset = AVURLAsset(url: url)

View File

@ -3,6 +3,7 @@ import AVFoundation
import MetalKit
import SwiftSignalKit
import TelegramCore
import Postbox
enum ExportWriterStatus {
case unknown
@ -258,7 +259,7 @@ public final class MediaEditorVideoExport {
public private(set) var internalStatus: Status = .idle
private let account: Account
private let postbox: Postbox
private let subject: Subject
private let configuration: Configuration
private let textScale: CGFloat
@ -296,8 +297,8 @@ public final class MediaEditorVideoExport {
private let semaphore = DispatchSemaphore(value: 0)
public init(account: Account, subject: Subject, configuration: Configuration, outputPath: String, textScale: CGFloat = 1.0) {
self.account = account
public init(postbox: Postbox, subject: Subject, configuration: Configuration, outputPath: String, textScale: CGFloat = 1.0) {
self.postbox = postbox
self.subject = subject
self.configuration = configuration
self.outputPath = outputPath
@ -356,7 +357,7 @@ public final class MediaEditorVideoExport {
guard self.composer == nil else {
return
}
self.composer = MediaEditorComposer(account: self.account, values: self.configuration.values, dimensions: self.configuration.composerDimensions, outputDimensions: self.configuration.dimensions, textScale: self.textScale)
self.composer = MediaEditorComposer(postbox: self.postbox, values: self.configuration.values, dimensions: self.configuration.composerDimensions, outputDimensions: self.configuration.dimensions, textScale: self.textScale)
}
private func setupWithAsset(_ asset: AVAsset, additionalAsset: AVAsset?) {

View File

@ -3673,7 +3673,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
}
})))
let contextController = ContextController(account: self.context.account, presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(controller: self, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), gesture: nil)
let contextController = ContextController(presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(controller: self, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), gesture: nil)
self.present(contextController, in: .window(.root))
}
@ -3867,7 +3867,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
if let resultImage = mediaEditor.resultImage {
mediaEditor.seek(0.0, andPlay: false)
makeEditorImageComposition(context: self.node.ciContext, account: self.context.account, inputImage: resultImage, dimensions: storyDimensions, values: values, time: .zero, textScale: 2.0, completion: { resultImage in
makeEditorImageComposition(context: self.node.ciContext, postbox: self.context.account.postbox, inputImage: resultImage, dimensions: storyDimensions, values: values, time: .zero, textScale: 2.0, completion: { resultImage in
guard let resultImage else {
return
}
@ -4187,7 +4187,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
inputImage = UIImage()
}
makeEditorImageComposition(context: self.node.ciContext, account: self.context.account, inputImage: inputImage, dimensions: storyDimensions, values: mediaEditor.values, time: firstFrameTime, textScale: 2.0, completion: { [weak self] coverImage in
makeEditorImageComposition(context: self.node.ciContext, postbox: self.context.account.postbox, inputImage: inputImage, dimensions: storyDimensions, values: mediaEditor.values, time: firstFrameTime, textScale: 2.0, completion: { [weak self] coverImage in
if let self {
Logger.shared.log("MediaEditor", "Completed with video \(videoResult)")
self.completion(randomId, .video(video: videoResult, coverImage: coverImage, values: mediaEditor.values, duration: duration, dimensions: mediaEditor.values.resultDimensions), mediaAreas, caption, self.state.privacy, stickers, { [weak self] finished in
@ -4210,7 +4210,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
if let image = mediaEditor.resultImage {
self.saveDraft(id: randomId)
makeEditorImageComposition(context: self.node.ciContext, account: self.context.account, inputImage: image, dimensions: storyDimensions, values: mediaEditor.values, time: .zero, textScale: 2.0, completion: { [weak self] resultImage in
makeEditorImageComposition(context: self.node.ciContext, postbox: self.context.account.postbox, inputImage: image, dimensions: storyDimensions, values: mediaEditor.values, time: .zero, textScale: 2.0, completion: { [weak self] resultImage in
if let self, let resultImage {
Logger.shared.log("MediaEditor", "Completed with image \(resultImage)")
self.completion(randomId, .image(image: resultImage, dimensions: PixelDimensions(resultImage.size)), mediaAreas, caption, self.state.privacy, stickers, { [weak self] finished in
@ -4340,7 +4340,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
}
let configuration = recommendedVideoExportConfiguration(values: mediaEditor.values, duration: duration, forceFullHd: true, frameRate: 60.0)
let outputPath = NSTemporaryDirectory() + "\(Int64.random(in: 0 ..< .max)).mp4"
let videoExport = MediaEditorVideoExport(account: self.context.account, subject: exportSubject, configuration: configuration, outputPath: outputPath, textScale: 2.0)
let videoExport = MediaEditorVideoExport(postbox: self.context.account.postbox, subject: exportSubject, configuration: configuration, outputPath: outputPath, textScale: 2.0)
self.videoExport = videoExport
videoExport.start()
@ -4373,7 +4373,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
} else {
if let image = mediaEditor.resultImage {
Queue.concurrentDefaultQueue().async {
makeEditorImageComposition(context: self.node.ciContext, account: self.context.account, inputImage: image, dimensions: storyDimensions, values: mediaEditor.values, time: .zero, textScale: 2.0, completion: { resultImage in
makeEditorImageComposition(context: self.node.ciContext, postbox: self.context.account.postbox, inputImage: image, dimensions: storyDimensions, values: mediaEditor.values, time: .zero, textScale: 2.0, completion: { resultImage in
if let data = resultImage?.jpegData(compressionQuality: 0.8) {
let outputPath = NSTemporaryDirectory() + "\(Int64.random(in: 0 ..< .max)).jpg"
try? data.write(to: URL(fileURLWithPath: outputPath))

Some files were not shown because too many files have changed in this diff Show More