Postbox refactor waves 278-356: squash
Squashes 79 sequential refactor waves into a single commit. Highlights: - Drop `import Postbox` (and matching `//submodules/Postbox` BUILD deps) from a wide swath of consumer files: ChatList, ChatMessage*BubbleContentNode subclasses, ListMessageNode/ListMessageItem, GalleryData, ChatHistorySearchContainerNode, ChatPanelInterfaceInteraction, ChatControllerInteraction, ChatMessageStickerItemNode, ChatMessageReplyInfoNode, ChatMessageInstantVideoItemNode, ChatPresentationInterfaceState, BrowserMarkdown/Readability, MediaResources, LocalMediaResources, ICloudResources, FetchManager, ShareController, OpenChatMessage, GalleryController, GroupStickerSearchContainerNode, GroupStickerPackCurrentItem, ChatPinnedMessageTitlePanelNode, OverlayAudioPlayerController, PresentationThemeSettings, StatisticsUI/StoryIconNode, TextFormat/StringWithAppliedEntities, GalleryUI/VideoAdComponent, StickerPackPreviewUI, WallpaperPreviewMedia, WallpaperResources, YoutubeEmbedImplementation, InstantPageExternalMediaResource, PlatformRestrictionMatching, TelegramUIDeclareEncodables, ChatListNode/ChatListSearchContainerNode. - Add `TelegramEngine` facades: `Themes.wallpapers`, `Themes.themes`, `AccountData.addAppLogEvent`. - Add `EngineMessageHistoryEntryLocation` wrapper. - Add `EngineRaw*` escape-hatch typealiases (`EngineRawMessage`, `EngineRawPeer`, `EngineRawMedia`, `EngineRawMediaResource`, `EngineRawMediaResourceData`, `EngineRawItemCollectionItem`, `EngineRawItemCollectionInfo`) and `engineDeclareEncodable` forwarder. - Drop unused `account:`/`postbox:`/`network:` parameters from several public functions and delete the dead overloads/types/functions left over: `automaticThemeShouldSwitchNow`, `cancelFreeMediaFileInteractiveFetch`, `legacyEnqueueVideoMessage`, `TelegramMediaFileReference`, plus assorted dead public TelegramCore/AccountContext SecureId entry points. - Delete entire dead modules: `LegacyDataImport`, `TonBinding`, `SpotlightSupport`, `SvgRendering`, third-party `AppCenter`/`VectorPlus`/`SwiftColor`/`SwiftSVG`. - Drop orphan `//submodules/Postbox` BUILD deps across 3 cleanup rounds. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ea0f6a685c
commit
e918b353ec
252 changed files with 829 additions and 11680 deletions
|
|
@ -1,5 +1,4 @@
|
|||
import Foundation
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
import TelegramUIPreferences
|
||||
|
|
@ -13,7 +12,7 @@ public enum FetchManagerCategory: Int32 {
|
|||
}
|
||||
|
||||
public enum FetchManagerLocationKey: Comparable, Hashable {
|
||||
case messageId(MessageId)
|
||||
case messageId(EngineMessage.Id)
|
||||
case free
|
||||
|
||||
public static func <(lhs: FetchManagerLocationKey, rhs: FetchManagerLocationKey) -> Bool {
|
||||
|
|
@ -87,7 +86,7 @@ public struct FetchManagerPriorityKey: Comparable {
|
|||
}
|
||||
|
||||
public enum FetchManagerLocation: Hashable, CustomStringConvertible {
|
||||
case chat(PeerId)
|
||||
case chat(EnginePeer.Id)
|
||||
|
||||
public var description: String {
|
||||
switch self {
|
||||
|
|
@ -104,8 +103,8 @@ public enum FetchManagerForegroundDirection {
|
|||
|
||||
public enum FetchManagerPriority: Comparable {
|
||||
case userInitiated
|
||||
case foregroundPrefetch(direction: FetchManagerForegroundDirection, localOrder: MessageIndex)
|
||||
case backgroundPrefetch(locationOrder: HistoryPreloadIndex, localOrder: MessageIndex)
|
||||
case foregroundPrefetch(direction: FetchManagerForegroundDirection, localOrder: EngineMessage.Index)
|
||||
case backgroundPrefetch(locationOrder: HistoryPreloadIndex, localOrder: EngineMessage.Index)
|
||||
|
||||
public static func <(lhs: FetchManagerPriority, rhs: FetchManagerPriority) -> Bool {
|
||||
switch lhs {
|
||||
|
|
@ -160,11 +159,11 @@ public protocol FetchManager {
|
|||
var queue: Queue { get }
|
||||
|
||||
func interactivelyFetched(category: FetchManagerCategory, location: FetchManagerLocation, locationKey: FetchManagerLocationKey, mediaReference: AnyMediaReference?, resourceReference: MediaResourceReference, ranges: RangeSet<Int64>, statsCategory: MediaResourceStatsCategory, elevatedPriority: Bool, userInitiated: Bool, priority: FetchManagerPriority, storeToDownloadsPeerId: EnginePeer.Id?) -> Signal<Void, NoError>
|
||||
func cancelInteractiveFetches(category: FetchManagerCategory, location: FetchManagerLocation, locationKey: FetchManagerLocationKey, resource: MediaResource)
|
||||
func cancelInteractiveFetches(category: FetchManagerCategory, location: FetchManagerLocation, locationKey: FetchManagerLocationKey, resource: EngineRawMediaResource)
|
||||
func cancelInteractiveFetches(resourceId: String)
|
||||
func toggleInteractiveFetchPaused(resourceId: String, isPaused: Bool)
|
||||
func raisePriority(resourceId: String)
|
||||
func fetchStatus(category: FetchManagerCategory, location: FetchManagerLocation, locationKey: FetchManagerLocationKey, resource: MediaResource) -> Signal<MediaResourceStatus, NoError>
|
||||
func fetchStatus(category: FetchManagerCategory, location: FetchManagerLocation, locationKey: FetchManagerLocationKey, resource: EngineRawMediaResource) -> Signal<EngineMediaResourceStatus, NoError>
|
||||
}
|
||||
|
||||
public protocol PrefetchManager {
|
||||
|
|
|
|||
|
|
@ -24,10 +24,6 @@ public func freeMediaFileResourceInteractiveFetched(postbox: Postbox, userLocati
|
|||
return fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: MediaResourceUserContentType(file: fileReference.media), reference: fileReference.resourceReference(resource), range: range)
|
||||
}
|
||||
|
||||
public func cancelFreeMediaFileInteractiveFetch(account: Account, file: TelegramMediaFile) {
|
||||
account.postbox.mediaBox.cancelInteractiveResourceFetch(file.resource)
|
||||
}
|
||||
|
||||
private func fetchCategoryForFile(_ file: TelegramMediaFile) -> FetchManagerCategory {
|
||||
if file.isVoice || file.isInstantVideo {
|
||||
return .voice
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import TelegramCore
|
||||
|
||||
|
|
@ -10,13 +9,13 @@ public enum GalleryMediaSubject: Hashable {
|
|||
case pollDescription
|
||||
case pollOption(Data)
|
||||
case pollSolution
|
||||
case instantPageMedia(MediaId)
|
||||
case instantPageMedia(EngineMedia.Id)
|
||||
}
|
||||
|
||||
public enum GalleryControllerItemSource {
|
||||
case peerMessagesAtId(messageId: MessageId, chatLocation: ChatLocation, customTag: MemoryBuffer?, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>)
|
||||
case standaloneMessage(Message, GalleryMediaSubject?)
|
||||
case custom(messages: Signal<([Message], Int32, Bool), NoError>, messageId: MessageId, loadMore: (() -> Void)?)
|
||||
case peerMessagesAtId(messageId: EngineMessage.Id, chatLocation: ChatLocation, customTag: EngineMemoryBuffer?, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>)
|
||||
case standaloneMessage(EngineRawMessage, GalleryMediaSubject?)
|
||||
case custom(messages: Signal<([EngineRawMessage], Int32, Bool), NoError>, messageId: EngineMessage.Id, loadMore: (() -> Void)?)
|
||||
}
|
||||
|
||||
public final class GalleryControllerActionInteraction {
|
||||
|
|
@ -26,10 +25,10 @@ public final class GalleryControllerActionInteraction {
|
|||
public let openPeer: (EnginePeer) -> Void
|
||||
public let openHashtag: (String?, String) -> Void
|
||||
public let openBotCommand: (String) -> Void
|
||||
public let openAd: (MessageId) -> Void
|
||||
public let openAd: (EngineMessage.Id) -> Void
|
||||
public let addContact: (String) -> Void
|
||||
public let storeMediaPlaybackState: (MessageId, Double?, Double) -> Void
|
||||
public let editMedia: (MessageId, [UIView], @escaping () -> Void) -> Void
|
||||
public let storeMediaPlaybackState: (EngineMessage.Id, Double?, Double) -> Void
|
||||
public let editMedia: (EngineMessage.Id, [UIView], @escaping () -> Void) -> Void
|
||||
public let updateCanReadHistory: (Bool) -> Void
|
||||
public let sendSticker: ((FileMediaReference) -> Void)?
|
||||
|
||||
|
|
@ -40,10 +39,10 @@ public final class GalleryControllerActionInteraction {
|
|||
openPeer: @escaping (EnginePeer) -> Void,
|
||||
openHashtag: @escaping (String?, String) -> Void,
|
||||
openBotCommand: @escaping (String) -> Void,
|
||||
openAd: @escaping (MessageId) -> Void,
|
||||
openAd: @escaping (EngineMessage.Id) -> Void,
|
||||
addContact: @escaping (String) -> Void,
|
||||
storeMediaPlaybackState: @escaping (MessageId, Double?, Double) -> Void,
|
||||
editMedia: @escaping (MessageId, [UIView], @escaping () -> Void) -> Void,
|
||||
storeMediaPlaybackState: @escaping (EngineMessage.Id, Double?, Double) -> Void,
|
||||
editMedia: @escaping (EngineMessage.Id, [UIView], @escaping () -> Void) -> Void,
|
||||
updateCanReadHistory: @escaping (Bool) -> Void,
|
||||
sendSticker: ((FileMediaReference) -> Void)?
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
import Display
|
||||
|
|
@ -22,9 +21,9 @@ public final class OpenChatMessageParams {
|
|||
public let context: AccountContext
|
||||
public let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
|
||||
public let chatLocation: ChatLocation?
|
||||
public let chatFilterTag: MemoryBuffer?
|
||||
public let chatFilterTag: EngineMemoryBuffer?
|
||||
public let chatLocationContextHolder: Atomic<ChatLocationContextHolder?>?
|
||||
public let message: Message
|
||||
public let message: EngineRawMessage
|
||||
public let mediaSubject: GalleryMediaSubject?
|
||||
public let standalone: Bool
|
||||
public let copyProtected: Bool
|
||||
|
|
@ -34,21 +33,21 @@ public final class OpenChatMessageParams {
|
|||
public let modal: Bool
|
||||
public let dismissInput: () -> Void
|
||||
public let present: (ViewController, Any?, PresentationContextType) -> Void
|
||||
public let transitionNode: (MessageId, Media, Bool) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?
|
||||
public let transitionNode: (EngineMessage.Id, EngineRawMedia, Bool) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?
|
||||
public let addToTransitionSurface: (UIView) -> Void
|
||||
public let openUrl: (String) -> Void
|
||||
public let openPeer: (Peer, ChatControllerInteractionNavigateToPeer) -> Void
|
||||
public let callPeer: (PeerId, Bool) -> Void
|
||||
public let openConferenceCall: (Message) -> Void
|
||||
public let openPeer: (EngineRawPeer, ChatControllerInteractionNavigateToPeer) -> Void
|
||||
public let callPeer: (EnginePeer.Id, Bool) -> Void
|
||||
public let openConferenceCall: (EngineRawMessage) -> Void
|
||||
public let enqueueMessage: (EnqueueMessage) -> Void
|
||||
public let sendSticker: ((FileMediaReference, UIView?, CGRect?) -> Bool)?
|
||||
public let sendEmoji: ((String, ChatTextInputTextCustomEmojiAttribute) -> Void)?
|
||||
public let setupTemporaryHiddenMedia: (Signal<Any?, NoError>, Int, Media) -> Void
|
||||
public let chatAvatarHiddenMedia: (Signal<MessageId?, NoError>, Media) -> Void
|
||||
public let setupTemporaryHiddenMedia: (Signal<Any?, NoError>, Int, EngineRawMedia) -> Void
|
||||
public let chatAvatarHiddenMedia: (Signal<EngineMessage.Id?, NoError>, EngineRawMedia) -> Void
|
||||
public let actionInteraction: GalleryControllerActionInteraction?
|
||||
public let playlistLocation: PeerMessagesPlaylistLocation?
|
||||
public let gallerySource: GalleryControllerItemSource?
|
||||
public let centralItemUpdated: ((MessageId) -> Void)?
|
||||
public let centralItemUpdated: ((EngineMessage.Id) -> Void)?
|
||||
public let navigateToMessageContext: ((EngineMessage) -> Void)?
|
||||
public let getSourceRect: (() -> CGRect?)?
|
||||
public let blockInteraction: Promise<Bool>
|
||||
|
|
@ -57,9 +56,9 @@ public final class OpenChatMessageParams {
|
|||
context: AccountContext,
|
||||
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil,
|
||||
chatLocation: ChatLocation?,
|
||||
chatFilterTag: MemoryBuffer?,
|
||||
chatFilterTag: EngineMemoryBuffer?,
|
||||
chatLocationContextHolder: Atomic<ChatLocationContextHolder?>?,
|
||||
message: Message,
|
||||
message: EngineRawMessage,
|
||||
mediaSubject: GalleryMediaSubject? = nil,
|
||||
standalone: Bool,
|
||||
copyProtected: Bool = false,
|
||||
|
|
@ -69,21 +68,21 @@ public final class OpenChatMessageParams {
|
|||
modal: Bool = false,
|
||||
dismissInput: @escaping () -> Void,
|
||||
present: @escaping (ViewController, Any?, PresentationContextType) -> Void,
|
||||
transitionNode: @escaping (MessageId, Media, Bool) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?,
|
||||
transitionNode: @escaping (EngineMessage.Id, EngineRawMedia, Bool) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?,
|
||||
addToTransitionSurface: @escaping (UIView) -> Void,
|
||||
openUrl: @escaping (String) -> Void,
|
||||
openPeer: @escaping (Peer, ChatControllerInteractionNavigateToPeer) -> Void,
|
||||
callPeer: @escaping (PeerId, Bool) -> Void,
|
||||
openConferenceCall: @escaping (Message) -> Void,
|
||||
openPeer: @escaping (EngineRawPeer, ChatControllerInteractionNavigateToPeer) -> Void,
|
||||
callPeer: @escaping (EnginePeer.Id, Bool) -> Void,
|
||||
openConferenceCall: @escaping (EngineRawMessage) -> Void,
|
||||
enqueueMessage: @escaping (EnqueueMessage) -> Void,
|
||||
sendSticker: ((FileMediaReference, UIView?, CGRect?) -> Bool)?,
|
||||
sendEmoji: ((String, ChatTextInputTextCustomEmojiAttribute) -> Void)?,
|
||||
setupTemporaryHiddenMedia: @escaping (Signal<Any?, NoError>, Int, Media) -> Void,
|
||||
chatAvatarHiddenMedia: @escaping (Signal<MessageId?, NoError>, Media) -> Void,
|
||||
setupTemporaryHiddenMedia: @escaping (Signal<Any?, NoError>, Int, EngineRawMedia) -> Void,
|
||||
chatAvatarHiddenMedia: @escaping (Signal<EngineMessage.Id?, NoError>, EngineRawMedia) -> Void,
|
||||
actionInteraction: GalleryControllerActionInteraction? = nil,
|
||||
playlistLocation: PeerMessagesPlaylistLocation? = nil,
|
||||
gallerySource: GalleryControllerItemSource? = nil,
|
||||
centralItemUpdated: ((MessageId) -> Void)? = nil,
|
||||
centralItemUpdated: ((EngineMessage.Id) -> Void)? = nil,
|
||||
navigateToMessageContext: ((EngineMessage) -> Void)? = nil,
|
||||
getSourceRect: (() -> CGRect?)? = nil
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import Foundation
|
|||
import Display
|
||||
import SwiftSignalKit
|
||||
import TelegramCore
|
||||
import Postbox
|
||||
import TelegramPresentationData
|
||||
import AnimationCache
|
||||
import MultiAnimationRenderer
|
||||
|
|
@ -125,39 +124,6 @@ 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?, ChatSendMessageActionSheetController.SendParameters?) -> Void)? { get set }
|
||||
|
|
|
|||
|
|
@ -309,22 +309,6 @@ public struct PresentationGroupCallSummaryState: Equatable {
|
|||
}
|
||||
}
|
||||
|
||||
public struct PresentationGroupCallMemberState: Equatable {
|
||||
public var ssrc: UInt32
|
||||
public var muteState: GroupCallParticipantsContext.Participant.MuteState?
|
||||
public var speaking: Bool
|
||||
|
||||
public init(
|
||||
ssrc: UInt32,
|
||||
muteState: GroupCallParticipantsContext.Participant.MuteState?,
|
||||
speaking: Bool
|
||||
) {
|
||||
self.ssrc = ssrc
|
||||
self.muteState = muteState
|
||||
self.speaking = speaking
|
||||
}
|
||||
}
|
||||
|
||||
public enum PresentationGroupCallMuteAction: Equatable {
|
||||
case muted(isPushToTalkActive: Bool)
|
||||
case unmuted
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import Foundation
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
import TelegramUIPreferences
|
||||
|
|
@ -9,7 +8,7 @@ import MultiAnimationRenderer
|
|||
import Display
|
||||
|
||||
public enum StorySharingSubject {
|
||||
case messages([Message])
|
||||
case messages([EngineRawMessage])
|
||||
case gift(StarGift.UniqueGift)
|
||||
}
|
||||
|
||||
|
|
@ -110,11 +109,11 @@ public enum ShareControllerSubject {
|
|||
case url(String)
|
||||
case text(String)
|
||||
case quote(text: String, url: String)
|
||||
case messages([Message])
|
||||
case messages([EngineRawMessage])
|
||||
case image([ImageRepresentationWithReference])
|
||||
case media(AnyMediaReference, MediaParameters?)
|
||||
case mapMedia(TelegramMediaMap)
|
||||
case fromExternal(Int, ([PeerId], [PeerId: Int64], [PeerId: StarsAmount], String, ShareControllerAccountContext, Bool) -> Signal<ShareControllerExternalStatus, ShareControllerError>)
|
||||
case fromExternal(Int, ([EnginePeer.Id], [EnginePeer.Id: Int64], [EnginePeer.Id: StarsAmount], String, ShareControllerAccountContext, Bool) -> Signal<ShareControllerExternalStatus, ShareControllerError>)
|
||||
}
|
||||
|
||||
public struct ShareControllerAction {
|
||||
|
|
@ -151,12 +150,12 @@ public final class ShareControllerParams {
|
|||
public let subject: ShareControllerSubject
|
||||
public let presetText: String?
|
||||
public let preferredAction: ShareControllerPreferredAction
|
||||
public let showInChat: ((Message) -> Void)?
|
||||
public let showInChat: ((EngineRawMessage) -> Void)?
|
||||
public let fromForeignApp: Bool
|
||||
public let segmentedValues: [ShareControllerSegmentedValue]?
|
||||
public let externalShare: Bool
|
||||
public let immediateExternalShare: Bool
|
||||
public let immediatePeerId: PeerId?
|
||||
public let immediatePeerId: EnginePeer.Id?
|
||||
public let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
|
||||
public let forceTheme: PresentationTheme?
|
||||
public let forcedActionTitle: String?
|
||||
|
|
@ -165,8 +164,8 @@ public final class ShareControllerParams {
|
|||
|
||||
public let actionCompleted: (() -> Void)?
|
||||
public let dismissed: ((Bool) -> Void)?
|
||||
public let completed: (([PeerId]) -> Void)?
|
||||
public let enqueued: (([PeerId], [Int64]) -> Void)?
|
||||
public let completed: (([EnginePeer.Id]) -> Void)?
|
||||
public let enqueued: (([EnginePeer.Id], [Int64]) -> Void)?
|
||||
public let shareStory: (() -> Void)?
|
||||
public let debugAction: (() -> Void)?
|
||||
public let onMediaTimestampLinkCopied: ((Int32?) -> Void)?
|
||||
|
|
@ -177,12 +176,12 @@ public final class ShareControllerParams {
|
|||
subject: ShareControllerSubject,
|
||||
presetText: String? = nil,
|
||||
preferredAction: ShareControllerPreferredAction = .default,
|
||||
showInChat: ((Message) -> Void)? = nil,
|
||||
showInChat: ((EngineRawMessage) -> Void)? = nil,
|
||||
fromForeignApp: Bool = false,
|
||||
segmentedValues: [ShareControllerSegmentedValue]? = nil,
|
||||
externalShare: Bool = true,
|
||||
immediateExternalShare: Bool = false,
|
||||
immediatePeerId: PeerId? = nil,
|
||||
immediatePeerId: EnginePeer.Id? = nil,
|
||||
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil,
|
||||
forceTheme: PresentationTheme? = nil,
|
||||
forcedActionTitle: String? = nil,
|
||||
|
|
@ -190,8 +189,8 @@ public final class ShareControllerParams {
|
|||
collectibleItemInfo: TelegramCollectibleItemInfo? = nil,
|
||||
actionCompleted: (() -> Void)? = nil,
|
||||
dismissed: ((Bool) -> Void)? = nil,
|
||||
completed: (([PeerId]) -> Void)? = nil,
|
||||
enqueued: (([PeerId], [Int64]) -> Void)? = nil,
|
||||
completed: (([EnginePeer.Id]) -> Void)? = nil,
|
||||
enqueued: (([EnginePeer.Id], [Int64]) -> Void)? = nil,
|
||||
shareStory: (() -> Void)? = nil,
|
||||
debugAction: (() -> Void)? = nil,
|
||||
onMediaTimestampLinkCopied: ((Int32?) -> Void)? = nil,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ swift_library(
|
|||
deps = [
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
"//submodules/TelegramCore:TelegramCore",
|
||||
"//submodules/Postbox:Postbox",
|
||||
"//submodules/Display:Display",
|
||||
"//submodules/SSignalKit/SSignalKit",
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
|
|
|
|||
|
|
@ -643,7 +643,7 @@ public final class AvatarNode: ASDisplayNode {
|
|||
|
||||
let parameters: AvatarNodeParameters
|
||||
|
||||
if let peer = peer, let signal = peerAvatarImage(postbox: postbox, network: network, peerReference: PeerReference(peer), authorOfMessage: authorOfMessage, representation: representation, displayDimensions: displayDimensions, clipStyle: clipStyle, emptyColor: emptyColor, synchronousLoad: synchronousLoad, provideUnrounded: storeUnrounded, cutoutRect: cutoutRect) {
|
||||
if let peer = peer, let signal = peerAvatarImage(postbox: postbox, peerReference: PeerReference(peer), authorOfMessage: authorOfMessage, representation: representation, displayDimensions: displayDimensions, clipStyle: clipStyle, emptyColor: emptyColor, synchronousLoad: synchronousLoad, provideUnrounded: storeUnrounded, cutoutRect: cutoutRect) {
|
||||
self.contents = nil
|
||||
self.displaySuspended = true
|
||||
self.imageReady.set(self.imageNode.contentReady)
|
||||
|
|
|
|||
|
|
@ -27,11 +27,7 @@ public enum PeerAvatarImageType {
|
|||
case complete
|
||||
}
|
||||
|
||||
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>? {
|
||||
public func peerAvatarImageData(postbox: Postbox, peerReference: PeerReference?, authorOfMessage: MessageReference?, representation: TelegramMediaImageRepresentation?, synchronousLoad: Bool) -> Signal<(Data, PeerAvatarImageType)?, NoError>? {
|
||||
if let smallProfileImage = representation {
|
||||
let resourceData = postbox.mediaBox.resourceData(smallProfileImage.resource, attemptSynchronously: synchronousLoad)
|
||||
let imageData = resourceData
|
||||
|
|
@ -92,7 +88,6 @@ public func peerAvatarImageData(postbox: Postbox, network: Network, peerReferenc
|
|||
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,
|
||||
|
|
@ -105,7 +100,7 @@ public func peerAvatarCompleteImage(account: Account, peer: EnginePeer, forcePro
|
|||
)
|
||||
}
|
||||
|
||||
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> {
|
||||
public func peerAvatarCompleteImage(postbox: Postbox, 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
|
||||
|
|
@ -126,8 +121,8 @@ public func peerAvatarCompleteImage(postbox: Postbox, network: Network, peer: En
|
|||
thumbnailRepresentation = peer.profileImageRepresentations.first
|
||||
}
|
||||
|
||||
if let signal = peerAvatarImage(postbox: postbox, network: network, peerReference: PeerReference(peer), 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), authorOfMessage: nil, representation: peer.profileImageRepresentations.last, displayDimensions: size, emptyColor: nil, synchronousLoad: true) {
|
||||
if let signal = peerAvatarImage(postbox: postbox, peerReference: PeerReference(peer), authorOfMessage: nil,representation: thumbnailRepresentation, displayDimensions: size, clipStyle: clipStyle, blurred: blurred, inset: 0.0, emptyColor: nil, synchronousLoad: fullSize) {
|
||||
if fullSize, let fullSizeSignal = peerAvatarImage(postbox: postbox, peerReference: PeerReference(peer), 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 {
|
||||
|
|
@ -174,7 +169,6 @@ public func peerAvatarCompleteImage(postbox: Postbox, network: Network, peer: En
|
|||
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, cutoutRect: CGRect? = nil) -> Signal<(UIImage, UIImage)?, NoError>? {
|
||||
return peerAvatarImage(
|
||||
postbox: account.postbox,
|
||||
network: account.network,
|
||||
peerReference: peerReference,
|
||||
authorOfMessage: authorOfMessage,
|
||||
representation: representation,
|
||||
|
|
@ -189,8 +183,8 @@ public func peerAvatarImage(account: Account, peerReference: PeerReference?, aut
|
|||
)
|
||||
}
|
||||
|
||||
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, cutoutRect: CGRect? = nil) -> Signal<(UIImage, UIImage)?, NoError>? {
|
||||
if let imageData = peerAvatarImageData(postbox: postbox, network: network, peerReference: peerReference, authorOfMessage: authorOfMessage, representation: representation, synchronousLoad: synchronousLoad) {
|
||||
public func peerAvatarImage(postbox: Postbox, 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, cutoutRect: CGRect? = nil) -> Signal<(UIImage, UIImage)?, NoError>? {
|
||||
if let imageData = peerAvatarImageData(postbox: postbox, 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
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import AccountContext
|
||||
import InstantPageUI
|
||||
|
|
@ -211,7 +210,7 @@ private final class MarkdownConversionBudget {
|
|||
|
||||
private struct MarkdownPageResult {
|
||||
let blocks: [InstantPageBlock]
|
||||
let media: [MediaId: Media]
|
||||
let media: [EngineMedia.Id: EngineRawMedia]
|
||||
}
|
||||
|
||||
private enum MarkdownFormulaMode {
|
||||
|
|
@ -315,7 +314,7 @@ private struct MarkdownInlineContent {
|
|||
}
|
||||
|
||||
private struct MarkdownResolvedImage {
|
||||
let mediaId: MediaId
|
||||
let mediaId: EngineMedia.Id
|
||||
let inlineDimensions: PixelDimensions
|
||||
let caption: InstantPageCaption
|
||||
let linkUrl: String?
|
||||
|
|
@ -340,7 +339,7 @@ private final class MarkdownConversionContext {
|
|||
private var nextRemoteMediaId: Int64 = 0
|
||||
private var nextLocalMediaId: Int64 = 0
|
||||
|
||||
private(set) var media: [MediaId: Media] = [:]
|
||||
private(set) var media: [EngineMedia.Id: EngineRawMedia] = [:]
|
||||
|
||||
init(context: AccountContext, documentURL: URL, formulasByPlaceholder: [String: MarkdownFormulaDescriptor], budget: MarkdownConversionBudget) {
|
||||
self.context = context
|
||||
|
|
@ -426,14 +425,14 @@ private final class MarkdownConversionContext {
|
|||
}
|
||||
}
|
||||
|
||||
private func nextMediaId(namespace: Int32) -> MediaId {
|
||||
private func nextMediaId(namespace: Int32) -> EngineMedia.Id {
|
||||
switch namespace {
|
||||
case Namespaces.Media.LocalImage:
|
||||
self.nextLocalMediaId += 1
|
||||
return MediaId(namespace: namespace, id: self.nextLocalMediaId)
|
||||
return EngineMedia.Id(namespace: namespace, id: self.nextLocalMediaId)
|
||||
default:
|
||||
self.nextRemoteMediaId += 1
|
||||
return MediaId(namespace: namespace, id: self.nextRemoteMediaId)
|
||||
return EngineMedia.Id(namespace: namespace, id: self.nextRemoteMediaId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1028,7 +1027,7 @@ private func markdownWebpage(context: AccountContext, file: FileMediaReference,
|
|||
)
|
||||
|
||||
return TelegramMediaWebpage(
|
||||
webpageId: MediaId(namespace: 0, id: 0),
|
||||
webpageId: EngineMedia.Id(namespace: 0, id: 0),
|
||||
content: .Loaded(
|
||||
TelegramMediaWebpageLoadedContent(
|
||||
url: fileURL.absoluteString,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import Foundation
|
||||
import WebKit
|
||||
import AppBundle
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import InstantPageUI
|
||||
|
||||
|
|
@ -115,14 +114,14 @@ private func parseJson(_ input: [String: Any], url: String) -> TelegramMediaWebp
|
|||
let byline = input["byline"] as? String
|
||||
let excerpt = input["excerpt"] as? String
|
||||
|
||||
var media: [MediaId: Media] = [:]
|
||||
var media: [EngineMedia.Id: EngineRawMedia] = [:]
|
||||
let blocks = parseContent(input, url, &media)
|
||||
|
||||
guard !blocks.isEmpty else {
|
||||
return nil
|
||||
}
|
||||
return TelegramMediaWebpage(
|
||||
webpageId: MediaId(namespace: 0, id: 0),
|
||||
webpageId: EngineMedia.Id(namespace: 0, id: 0),
|
||||
content: .Loaded(
|
||||
TelegramMediaWebpageLoadedContent(
|
||||
url: url,
|
||||
|
|
@ -156,7 +155,7 @@ private func parseJson(_ input: [String: Any], url: String) -> TelegramMediaWebp
|
|||
)
|
||||
}
|
||||
|
||||
private func parseContent(_ input: [String: Any], _ url: String, _ media: inout [MediaId: Media]) -> [InstantPageBlock] {
|
||||
private func parseContent(_ input: [String: Any], _ url: String, _ media: inout [EngineMedia.Id: EngineRawMedia]) -> [InstantPageBlock] {
|
||||
let title = input["title"] as? String
|
||||
let byline = input["byline"] as? String
|
||||
let date = input["publishedTime"] as? String
|
||||
|
|
@ -185,7 +184,7 @@ private func parseRichText(_ input: String) -> RichText {
|
|||
return .plain(input)
|
||||
}
|
||||
|
||||
private func parseRichText(_ input: [String: Any], _ media: inout [MediaId: Media]) -> RichText {
|
||||
private func parseRichText(_ input: [String: Any], _ media: inout [EngineMedia.Id: EngineRawMedia]) -> RichText {
|
||||
var text: RichText
|
||||
if let string = input["content"] as? String {
|
||||
text = parseRichText(string)
|
||||
|
|
@ -204,7 +203,7 @@ private func parseRichText(_ input: [String: Any], _ media: inout [MediaId: Medi
|
|||
return text
|
||||
}
|
||||
|
||||
private func parseRichText(_ input: [Any], _ media: inout [MediaId: Media]) -> RichText {
|
||||
private func parseRichText(_ input: [Any], _ media: inout [EngineMedia.Id: EngineRawMedia]) -> RichText {
|
||||
var result: [RichText] = []
|
||||
|
||||
for item in input {
|
||||
|
|
@ -258,7 +257,7 @@ private func parseRichText(_ input: [Any], _ media: inout [MediaId: Media]) -> R
|
|||
} else {
|
||||
height = 0
|
||||
}
|
||||
let id = MediaId(namespace: Namespaces.Media.CloudFile, id: Int64(media.count))
|
||||
let id = EngineMedia.Id(namespace: Namespaces.Media.CloudFile, id: Int64(media.count))
|
||||
media[id] = TelegramMediaImage(
|
||||
imageId: id,
|
||||
representations: [
|
||||
|
|
@ -489,7 +488,7 @@ private func applyAnchor(_ input: RichText, item: [String: Any]) -> RichText {
|
|||
return .anchor(text: input, name: id)
|
||||
}
|
||||
|
||||
private func parseTable(_ input: [String: Any], _ media: inout [MediaId: Media]) -> InstantPageBlock {
|
||||
private func parseTable(_ input: [String: Any], _ media: inout [EngineMedia.Id: EngineRawMedia]) -> InstantPageBlock {
|
||||
let title = (input["title"] as? String) ?? ""
|
||||
return .table(
|
||||
title: trim(applyAnchor(parseRichText(title), item: input)),
|
||||
|
|
@ -499,7 +498,7 @@ private func parseTable(_ input: [String: Any], _ media: inout [MediaId: Media])
|
|||
)
|
||||
}
|
||||
|
||||
private func parseTableRows(_ input: [Any], _ media: inout [MediaId: Media]) -> [InstantPageTableRow] {
|
||||
private func parseTableRows(_ input: [Any], _ media: inout [EngineMedia.Id: EngineRawMedia]) -> [InstantPageTableRow] {
|
||||
var result: [InstantPageTableRow] = []
|
||||
for item in input {
|
||||
if let item = item as? [String: Any] {
|
||||
|
|
@ -514,7 +513,7 @@ private func parseTableRows(_ input: [Any], _ media: inout [MediaId: Media]) ->
|
|||
return result
|
||||
}
|
||||
|
||||
private func parseTableRow(_ input: [String: Any], _ media: inout [MediaId: Media]) -> InstantPageTableRow {
|
||||
private func parseTableRow(_ input: [String: Any], _ media: inout [EngineMedia.Id: EngineRawMedia]) -> InstantPageTableRow {
|
||||
var cells: [InstantPageTableCell] = []
|
||||
|
||||
if let content = input["content"] as? [Any] {
|
||||
|
|
@ -552,7 +551,7 @@ private func parseTableRow(_ input: [String: Any], _ media: inout [MediaId: Medi
|
|||
return InstantPageTableRow(cells: cells)
|
||||
}
|
||||
|
||||
private func parseDetails(_ item: [String: Any], _ url: String, _ media: inout [MediaId: Media]) -> InstantPageBlock? {
|
||||
private func parseDetails(_ item: [String: Any], _ url: String, _ media: inout [EngineMedia.Id: EngineRawMedia]) -> InstantPageBlock? {
|
||||
guard var content = item["contant"] as? [Any] else {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -576,7 +575,7 @@ private func parseDetails(_ item: [String: Any], _ url: String, _ media: inout [
|
|||
}
|
||||
|
||||
private let nonListCharacters = CharacterSet(charactersIn: "0123456789").inverted
|
||||
private func parseList(_ input: [String: Any], _ url: String, _ media: inout [MediaId: Media]) -> InstantPageBlock? {
|
||||
private func parseList(_ input: [String: Any], _ url: String, _ media: inout [EngineMedia.Id: EngineRawMedia]) -> InstantPageBlock? {
|
||||
guard let content = input["content"] as? [Any], let tag = input["tag"] as? String else {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -625,7 +624,7 @@ private func parseList(_ input: [String: Any], _ url: String, _ media: inout [Me
|
|||
return .list(items: items, ordered: ordered)
|
||||
}
|
||||
|
||||
private func parseImage(_ input: [String: Any], _ media: inout [MediaId: Media]) -> InstantPageBlock? {
|
||||
private func parseImage(_ input: [String: Any], _ media: inout [EngineMedia.Id: EngineRawMedia]) -> InstantPageBlock? {
|
||||
guard let src = input["src"] as? String else {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -654,7 +653,7 @@ private func parseImage(_ input: [String: Any], _ media: inout [MediaId: Media])
|
|||
height = 0
|
||||
}
|
||||
|
||||
let id = MediaId(namespace: Namespaces.Media.CloudImage, id: Int64(media.count))
|
||||
let id = EngineMedia.Id(namespace: Namespaces.Media.CloudImage, id: Int64(media.count))
|
||||
media[id] = TelegramMediaImage(
|
||||
imageId: id,
|
||||
representations: [
|
||||
|
|
@ -679,7 +678,7 @@ private func parseImage(_ input: [String: Any], _ media: inout [MediaId: Media])
|
|||
)
|
||||
}
|
||||
|
||||
private func parseVideo(_ input: [String: Any], _ media: inout [MediaId: Media]) -> InstantPageBlock? {
|
||||
private func parseVideo(_ input: [String: Any], _ media: inout [EngineMedia.Id: EngineRawMedia]) -> InstantPageBlock? {
|
||||
guard let src = input["src"] as? String else {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -709,7 +708,7 @@ private func parseVideo(_ input: [String: Any], _ media: inout [MediaId: Media])
|
|||
)
|
||||
}
|
||||
|
||||
private func parseFigure(_ input: [String: Any], _ media: inout [MediaId: Media]) -> InstantPageBlock? {
|
||||
private func parseFigure(_ input: [String: Any], _ media: inout [EngineMedia.Id: EngineRawMedia]) -> InstantPageBlock? {
|
||||
guard let content = input["content"] as? [Any] else {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -743,7 +742,7 @@ private func parseFigure(_ input: [String: Any], _ media: inout [MediaId: Media]
|
|||
return block
|
||||
}
|
||||
|
||||
private func parsePageBlocks(_ input: [Any], _ url: String, _ media: inout [MediaId: Media]) -> [InstantPageBlock] {
|
||||
private func parsePageBlocks(_ input: [Any], _ url: String, _ media: inout [EngineMedia.Id: EngineRawMedia]) -> [InstantPageBlock] {
|
||||
var result: [InstantPageBlock] = []
|
||||
for item in input {
|
||||
if let string = item as? String {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ import InstantPageUI
|
|||
import ChatInterfaceState
|
||||
import UndoUI
|
||||
import TextFormat
|
||||
import Postbox
|
||||
import TelegramAnimatedStickerNode
|
||||
import AnimationCache
|
||||
import MultiAnimationRenderer
|
||||
|
|
@ -63,12 +62,12 @@ final class ChatListSearchInteraction {
|
|||
let present: (ViewController, Any?) -> Void
|
||||
let dismissInput: () -> Void
|
||||
let getSelectedMessageIds: () -> Set<EngineMessage.Id>?
|
||||
let openStories: ((PeerId, ASDisplayNode) -> Void)?
|
||||
let openStories: ((EnginePeer.Id, ASDisplayNode) -> Void)?
|
||||
let switchToFilter: (ChatListSearchPaneKey) -> Void
|
||||
let dismissSearch: () -> Void
|
||||
let openAdInfo: (ASDisplayNode, AdPeer) -> Void
|
||||
|
||||
init(openPeer: @escaping (EnginePeer, EnginePeer?, Int64?, Bool) -> Void, openDisabledPeer: @escaping (EnginePeer, Int64?, ChatListDisabledPeerReason) -> Void, openMessage: @escaping (EnginePeer, Int64?, EngineMessage.Id, Bool) -> Void, openUrl: @escaping (String) -> Void, clearRecentSearch: @escaping () -> Void, addContact: @escaping (String) -> Void, toggleMessageSelection: @escaping (EngineMessage.Id, Bool) -> Void, messageContextAction: @escaping ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?, ChatListSearchPaneKey, (id: String, size: Int64, isFirstInList: Bool)?) -> Void), mediaMessageContextAction: @escaping ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void), peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, getSelectedMessageIds: @escaping () -> Set<EngineMessage.Id>?, openStories: ((PeerId, ASDisplayNode) -> Void)?, switchToFilter: @escaping (ChatListSearchPaneKey) -> Void, dismissSearch: @escaping () -> Void, openAdInfo: @escaping (ASDisplayNode, AdPeer) -> Void) {
|
||||
init(openPeer: @escaping (EnginePeer, EnginePeer?, Int64?, Bool) -> Void, openDisabledPeer: @escaping (EnginePeer, Int64?, ChatListDisabledPeerReason) -> Void, openMessage: @escaping (EnginePeer, Int64?, EngineMessage.Id, Bool) -> Void, openUrl: @escaping (String) -> Void, clearRecentSearch: @escaping () -> Void, addContact: @escaping (String) -> Void, toggleMessageSelection: @escaping (EngineMessage.Id, Bool) -> Void, messageContextAction: @escaping ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?, ChatListSearchPaneKey, (id: String, size: Int64, isFirstInList: Bool)?) -> Void), mediaMessageContextAction: @escaping ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void), peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, getSelectedMessageIds: @escaping () -> Set<EngineMessage.Id>?, openStories: ((EnginePeer.Id, ASDisplayNode) -> Void)?, switchToFilter: @escaping (ChatListSearchPaneKey) -> Void, dismissSearch: @escaping () -> Void, openAdInfo: @escaping (ASDisplayNode, AdPeer) -> Void) {
|
||||
self.openPeer = openPeer
|
||||
self.openDisabledPeer = openDisabledPeer
|
||||
self.openMessage = openMessage
|
||||
|
|
@ -215,14 +214,14 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
let interaction = ChatListSearchInteraction(openPeer: { peer, chatPeer, threadId, value in
|
||||
originalOpenPeer(peer, chatPeer, threadId, value)
|
||||
if peer.id.namespace != Namespaces.Peer.SecretChat {
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "search_global_open_peer", peerId: peer.id)
|
||||
context.engine.accountData.addAppLogEvent(type: "search_global_open_peer")
|
||||
}
|
||||
}, openDisabledPeer: { peer, threadId, reason in
|
||||
openDisabledPeer(peer, threadId, reason)
|
||||
}, openMessage: { peer, threadId, messageId, deactivateOnAction in
|
||||
originalOpenMessage(peer, threadId, messageId, deactivateOnAction)
|
||||
if peer.id.namespace != Namespaces.Peer.SecretChat {
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "search_global_open_message", peerId: peer.id, data: .dictionary(["msg_id": .number(Double(messageId.id))]))
|
||||
context.engine.accountData.addAppLogEvent(type: "search_global_open_message", data: .dictionary(["msg_id": .number(Double(messageId.id))]))
|
||||
}
|
||||
}, openUrl: { [weak self] url in
|
||||
let _ = openUserGeneratedUrl(context: context, peerId: nil, url: url, concealed: false, present: { c in
|
||||
|
|
@ -1396,16 +1395,16 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
return
|
||||
}
|
||||
|
||||
var resourceIds = Set<MediaResourceId>()
|
||||
var resourceIds = Set<EngineMediaResource.Id>()
|
||||
for message in messages {
|
||||
for media in message.media {
|
||||
if let file = media as? TelegramMediaFile {
|
||||
resourceIds.insert(file.resource.id)
|
||||
resourceIds.insert(EngineMediaResource.Id(file.resource.id))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let _ = (strongSelf.context.engine.resources.removeCachedResources(ids: resourceIds.map { EngineMediaResource.Id($0) }, force: true, notify: true)
|
||||
|
||||
let _ = (strongSelf.context.engine.resources.removeCachedResources(ids: Array(resourceIds), force: true, notify: true)
|
||||
|> deliverOnMainQueue).startStandalone(completed: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -2732,7 +2732,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||
}
|
||||
} else {
|
||||
if !finalQuery.isEmpty {
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "search_global_query")
|
||||
context.engine.accountData.addAppLogEvent(type: "search_global_query")
|
||||
}
|
||||
|
||||
let searchSignals: [Signal<(SearchMessagesResult, SearchMessagesState), NoError>]
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import UIKit
|
|||
import AsyncDisplayKit
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
import ItemListUI
|
||||
|
|
@ -2624,18 +2623,18 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||
}
|
||||
|
||||
if case .chatList = item.chatListLocation, itemPeer.peerId == item.context.account.peerId, let message = messages.first {
|
||||
var effectiveAuthor: Peer? = message.author?._asPeer()
|
||||
var effectiveAuthor: EngineRawPeer? = message.author?._asPeer()
|
||||
if let forwardInfo = message.forwardInfo {
|
||||
effectiveAuthor = forwardInfo.author
|
||||
if effectiveAuthor == nil, let authorSignature = forwardInfo.authorSignature {
|
||||
effectiveAuthor = TelegramUser(id: PeerId(namespace: Namespaces.Peer.Empty, id: PeerId.Id._internalFromInt64Value(Int64(authorSignature.persistentHashValue % 32))), accessHash: nil, firstName: authorSignature, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: nil, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil)
|
||||
effectiveAuthor = TelegramUser(id: EnginePeer.Id(namespace: Namespaces.Peer.Empty, id: EnginePeer.Id.Id._internalFromInt64Value(Int64(authorSignature.persistentHashValue % 32))), accessHash: nil, firstName: authorSignature, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: nil, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil)
|
||||
}
|
||||
}
|
||||
if let sourceAuthorInfo = message._asMessage().sourceAuthorInfo {
|
||||
if let originalAuthor = sourceAuthorInfo.originalAuthor, let peer = message.peers[originalAuthor] {
|
||||
effectiveAuthor = peer
|
||||
} else if let authorSignature = sourceAuthorInfo.originalAuthorName {
|
||||
effectiveAuthor = TelegramUser(id: PeerId(namespace: Namespaces.Peer.Empty, id: PeerId.Id._internalFromInt64Value(Int64(authorSignature.persistentHashValue % 32))), accessHash: nil, firstName: authorSignature, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: nil, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil)
|
||||
effectiveAuthor = TelegramUser(id: EnginePeer.Id(namespace: Namespaces.Peer.Empty, id: EnginePeer.Id.Id._internalFromInt64Value(Int64(authorSignature.persistentHashValue % 32))), accessHash: nil, firstName: authorSignature, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: nil, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2960,10 +2959,10 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||
case let .preview(dimensions, immediateThumbnailData, videoDuration):
|
||||
if let immediateThumbnailData {
|
||||
if let videoDuration {
|
||||
let thumbnailMedia = TelegramMediaFile(fileId: MediaId(namespace: 0, id: index), partialReference: nil, resource: EmptyMediaResource(), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: immediateThumbnailData, mimeType: "video/mp4", size: nil, attributes: [.Video(duration: Double(videoDuration), size: dimensions ?? PixelDimensions(width: 1, height: 1), flags: [], preloadSize: nil, coverTime: nil, videoCodec: nil)], alternativeRepresentations: [])
|
||||
let thumbnailMedia = TelegramMediaFile(fileId: EngineMedia.Id(namespace: 0, id: index), partialReference: nil, resource: EmptyMediaResource(), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: immediateThumbnailData, mimeType: "video/mp4", size: nil, attributes: [.Video(duration: Double(videoDuration), size: dimensions ?? PixelDimensions(width: 1, height: 1), flags: [], preloadSize: nil, coverTime: nil, videoCodec: nil)], alternativeRepresentations: [])
|
||||
contentImageSpecs.append(ContentImageSpec(message: message, media: .file(thumbnailMedia), size: fitSize))
|
||||
} else {
|
||||
let thumbnailMedia = TelegramMediaImage(imageId: MediaId(namespace: 0, id: index), representations: [], immediateThumbnailData: immediateThumbnailData, reference: nil, partialReference: nil, flags: [])
|
||||
let thumbnailMedia = TelegramMediaImage(imageId: EngineMedia.Id(namespace: 0, id: index), representations: [], immediateThumbnailData: immediateThumbnailData, reference: nil, partialReference: nil, flags: [])
|
||||
contentImageSpecs.append(ContentImageSpec(message: message, media: .image(thumbnailMedia), size: fitSize))
|
||||
}
|
||||
index += 1
|
||||
|
|
@ -3196,7 +3195,7 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||
textAttributedString = attributedText
|
||||
|
||||
let dateText: String
|
||||
var topIndex: MessageIndex?
|
||||
var topIndex: EngineMessage.Index?
|
||||
switch item.content {
|
||||
case .loading:
|
||||
break
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import ChatListSearchItemHeader
|
|||
import PremiumUI
|
||||
import AnimationCache
|
||||
import MultiAnimationRenderer
|
||||
import Postbox
|
||||
import ChatFolderLinkPreviewScreen
|
||||
import StoryContainerScreen
|
||||
import ChatListHeaderComponent
|
||||
|
|
@ -1239,7 +1238,7 @@ public final class ChatListNode: ListViewImpl {
|
|||
case .Header, .Hole:
|
||||
return nil
|
||||
case let .PeerId(value):
|
||||
return PeerId(value)
|
||||
return EnginePeer.Id(value)
|
||||
case .ThreadId, .GroupId, .ContactId, .ArchiveIntro, .EmptyIntro, .SectionHeader, .Notice, .additionalCategory, .TopPeer:
|
||||
return nil
|
||||
}
|
||||
|
|
@ -2618,7 +2617,7 @@ public final class ChatListNode: ListViewImpl {
|
|||
strongSelf.enqueueHistoryPreloadUpdate()
|
||||
}
|
||||
|
||||
var refreshStoryPeerIds: [PeerId] = []
|
||||
var refreshStoryPeerIds: [EnginePeer.Id] = []
|
||||
var isHiddenItemVisible = false
|
||||
if let range = range.visibleRange {
|
||||
let entryCount = chatListView.filteredEntries.count
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import TelegramCore
|
||||
import Display
|
||||
|
|
@ -71,18 +70,18 @@ public final class ChatPanelInterfaceInteraction {
|
|||
case editPrice
|
||||
}
|
||||
|
||||
public let setupReplyMessage: (MessageId?, EngineMessageReplyInnerSubject?, @escaping (ContainedViewLayoutTransition, @escaping () -> Void) -> Void) -> Void
|
||||
public let setupEditMessage: (MessageId?, @escaping (ContainedViewLayoutTransition) -> Void) -> Void
|
||||
public let beginMessageSelection: ([MessageId], @escaping (ContainedViewLayoutTransition) -> Void) -> Void
|
||||
public let setupReplyMessage: (EngineMessage.Id?, EngineMessageReplyInnerSubject?, @escaping (ContainedViewLayoutTransition, @escaping () -> Void) -> Void) -> Void
|
||||
public let setupEditMessage: (EngineMessage.Id?, @escaping (ContainedViewLayoutTransition) -> Void) -> Void
|
||||
public let beginMessageSelection: ([EngineMessage.Id], @escaping (ContainedViewLayoutTransition) -> Void) -> Void
|
||||
public let cancelMessageSelection: (ContainedViewLayoutTransition) -> Void
|
||||
public let deleteSelectedMessages: () -> Void
|
||||
public let reportSelectedMessages: () -> Void
|
||||
public let reportMessages: ([Message], ContextControllerProtocol?) -> Void
|
||||
public let blockMessageAuthor: (Message, ContextControllerProtocol?) -> Void
|
||||
public let deleteMessages: ([Message], ContextControllerProtocol?, @escaping (ContextMenuActionResult) -> Void) -> Void
|
||||
public let reportMessages: ([EngineRawMessage], ContextControllerProtocol?) -> Void
|
||||
public let blockMessageAuthor: (EngineRawMessage, ContextControllerProtocol?) -> Void
|
||||
public let deleteMessages: ([EngineRawMessage], ContextControllerProtocol?, @escaping (ContextMenuActionResult) -> Void) -> Void
|
||||
public let forwardSelectedMessages: () -> Void
|
||||
public let forwardCurrentForwardMessages: () -> Void
|
||||
public let forwardMessages: ([Message]) -> Void
|
||||
public let forwardMessages: ([EngineRawMessage]) -> Void
|
||||
public let updateForwardOptionsState: ((ChatInterfaceForwardOptionsState) -> ChatInterfaceForwardOptionsState) -> Void
|
||||
public let presentForwardOptions: (UIView) -> Void
|
||||
public let presentReplyOptions: (UIView) -> Void
|
||||
|
|
@ -90,7 +89,7 @@ public final class ChatPanelInterfaceInteraction {
|
|||
public let presentSuggestPostOptions: () -> Void
|
||||
public let shareSelectedMessages: () -> Void
|
||||
public let updateTextInputStateAndMode: (@escaping (ChatTextInputState, ChatInputMode) -> (ChatTextInputState, ChatInputMode)) -> Void
|
||||
public let updateInputModeAndDismissedButtonKeyboardMessageId: ((ChatPresentationInterfaceState) -> (ChatInputMode, MessageId?)) -> Void
|
||||
public let updateInputModeAndDismissedButtonKeyboardMessageId: ((ChatPresentationInterfaceState) -> (ChatInputMode, EngineMessage.Id?)) -> Void
|
||||
public let openStickers: () -> Void
|
||||
public let editMessage: () -> Void
|
||||
public let beginMessageSearch: (ChatSearchDomain, String) -> Void
|
||||
|
|
@ -100,17 +99,17 @@ public final class ChatPanelInterfaceInteraction {
|
|||
public let openSearchResults: () -> Void
|
||||
public let openCalendarSearch: () -> Void
|
||||
public let toggleMembersSearch: (Bool) -> Void
|
||||
public let navigateToMessage: (MessageId, Bool, Bool, ChatLoadingMessageSubject) -> Void
|
||||
public let navigateToChat: (PeerId) -> Void
|
||||
public let navigateToProfile: (PeerId) -> Void
|
||||
public let navigateToMessage: (EngineMessage.Id, Bool, Bool, ChatLoadingMessageSubject) -> Void
|
||||
public let navigateToChat: (EnginePeer.Id) -> Void
|
||||
public let navigateToProfile: (EnginePeer.Id) -> Void
|
||||
public let openPeerInfo: () -> Void
|
||||
public let togglePeerNotifications: () -> Void
|
||||
public let sendContextResult: (ChatContextResultCollection, ChatContextResult, ASDisplayNode, CGRect) -> Bool
|
||||
public let sendBotCommand: (Peer, String) -> Void
|
||||
public let sendBotCommand: (EngineRawPeer, String) -> Void
|
||||
public let sendShortcut: (Int32) -> Void
|
||||
public let openEditShortcuts: () -> Void
|
||||
public let sendBotStart: (String?) -> Void
|
||||
public let botSwitchChatWithPayload: (PeerId, String) -> Void
|
||||
public let botSwitchChatWithPayload: (EnginePeer.Id, String) -> Void
|
||||
public let beginMediaRecording: (Bool) -> Void
|
||||
public let finishMediaRecording: (ChatFinishMediaRecordingAction) -> Void
|
||||
public let stopMediaRecording: () -> Void
|
||||
|
|
@ -122,20 +121,20 @@ public final class ChatPanelInterfaceInteraction {
|
|||
public let displayVideoUnmuteTip: (CGPoint?) -> Void
|
||||
public let switchMediaRecordingMode: () -> Void
|
||||
public let setupMessageAutoremoveTimeout: () -> Void
|
||||
public let sendSticker: (FileMediaReference, Bool, UIView?, CGRect?, CALayer?, [ItemCollectionId]) -> Bool
|
||||
public let sendSticker: (FileMediaReference, Bool, UIView?, CGRect?, CALayer?, [EngineItemCollectionId]) -> Bool
|
||||
public let editSticker: (TelegramMediaFile) -> Void
|
||||
public let unblockPeer: () -> Void
|
||||
public let pinMessage: (MessageId, ContextControllerProtocol?) -> Void
|
||||
public let unpinMessage: (MessageId, Bool, ContextControllerProtocol?) -> Void
|
||||
public let pinMessage: (EngineMessage.Id, ContextControllerProtocol?) -> Void
|
||||
public let unpinMessage: (EngineMessage.Id, Bool, ContextControllerProtocol?) -> Void
|
||||
public let unpinAllMessages: () -> Void
|
||||
public let openPinnedList: (MessageId) -> Void
|
||||
public let openPinnedList: (EngineMessage.Id) -> Void
|
||||
public let shareAccountContact: () -> Void
|
||||
public let reportPeer: () -> Void
|
||||
public let presentPeerContact: () -> Void
|
||||
public let dismissReportPeer: () -> Void
|
||||
public let deleteChat: () -> Void
|
||||
public let beginCall: (Bool) -> Void
|
||||
public let toggleMessageStickerStarred: (MessageId) -> Void
|
||||
public let toggleMessageStickerStarred: (EngineMessage.Id) -> Void
|
||||
public let presentController: (ViewController, Any?) -> Void
|
||||
public let presentControllerInCurrent: (ViewController, Any?) -> Void
|
||||
public let getNavigationController: () -> NavigationController?
|
||||
|
|
@ -143,8 +142,8 @@ public final class ChatPanelInterfaceInteraction {
|
|||
public let navigateFeed: () -> Void
|
||||
public let openGrouping: () -> Void
|
||||
public let toggleSilentPost: () -> Void
|
||||
public let requestUnvoteInMessage: (MessageId) -> Void
|
||||
public let requestStopPollInMessage: (MessageId) -> Void
|
||||
public let requestUnvoteInMessage: (EngineMessage.Id) -> Void
|
||||
public let requestStopPollInMessage: (EngineMessage.Id) -> Void
|
||||
public let updateInputLanguage: (@escaping (String?) -> String?) -> Void
|
||||
public let unarchiveChat: () -> Void
|
||||
public let openLinkEditing: () -> Void
|
||||
|
|
@ -156,9 +155,9 @@ public final class ChatPanelInterfaceInteraction {
|
|||
public let openPeersNearby: () -> Void
|
||||
public let unarchivePeer: () -> Void
|
||||
public let scrollToTop: () -> Void
|
||||
public let viewReplies: (MessageId?, ChatReplyThreadMessage) -> Void
|
||||
public let viewReplies: (EngineMessage.Id?, ChatReplyThreadMessage) -> Void
|
||||
public let activatePinnedListPreview: (ASDisplayNode, ContextGesture) -> Void
|
||||
public let editMessageMedia: (MessageId, Bool) -> Void
|
||||
public let editMessageMedia: (EngineMessage.Id, Bool) -> Void
|
||||
public let joinGroupCall: (CachedChannelData.ActiveCall) -> Void
|
||||
public let presentInviteMembers: () -> Void
|
||||
public let presentGigagroupHelp: () -> Void
|
||||
|
|
@ -179,7 +178,7 @@ public final class ChatPanelInterfaceInteraction {
|
|||
public let addDoNotTranslateLanguage: (String) -> Void
|
||||
public let hideTranslationPanel: () -> Void
|
||||
public let openPremiumGift: () -> Void
|
||||
public let openSuggestPost: (Message?, OpenSuggestPostMode) -> Void
|
||||
public let openSuggestPost: (EngineRawMessage?, OpenSuggestPostMode) -> Void
|
||||
public let openPremiumRequiredForMessaging: () -> Void
|
||||
public let openStarsPurchase: (Int64?) -> Void
|
||||
public let openMessagePayment: () -> Void
|
||||
|
|
@ -190,7 +189,7 @@ public final class ChatPanelInterfaceInteraction {
|
|||
public let openBoostToUnrestrict: () -> Void
|
||||
public let updateRecordingTrimRange: (Double, Double, Bool, Bool) -> Void
|
||||
public let dismissAllTooltips: () -> Void
|
||||
public let editTodoMessage: (MessageId, Int32?, Bool) -> Void
|
||||
public let editTodoMessage: (EngineMessage.Id, Int32?, Bool) -> Void
|
||||
public let dismissUrlPreview: () -> Void
|
||||
public let dismissForwardMessages: () -> Void
|
||||
public let dismissSuggestPost: () -> Void
|
||||
|
|
@ -204,18 +203,18 @@ public final class ChatPanelInterfaceInteraction {
|
|||
public let statuses: ChatPanelInterfaceInteractionStatuses?
|
||||
|
||||
public init(
|
||||
setupReplyMessage: @escaping (MessageId?, EngineMessageReplyInnerSubject?, @escaping (ContainedViewLayoutTransition, @escaping () -> Void) -> Void) -> Void,
|
||||
setupEditMessage: @escaping (MessageId?, @escaping (ContainedViewLayoutTransition) -> Void) -> Void,
|
||||
beginMessageSelection: @escaping ([MessageId], @escaping (ContainedViewLayoutTransition) -> Void) -> Void,
|
||||
setupReplyMessage: @escaping (EngineMessage.Id?, EngineMessageReplyInnerSubject?, @escaping (ContainedViewLayoutTransition, @escaping () -> Void) -> Void) -> Void,
|
||||
setupEditMessage: @escaping (EngineMessage.Id?, @escaping (ContainedViewLayoutTransition) -> Void) -> Void,
|
||||
beginMessageSelection: @escaping ([EngineMessage.Id], @escaping (ContainedViewLayoutTransition) -> Void) -> Void,
|
||||
cancelMessageSelection: @escaping (ContainedViewLayoutTransition) -> Void,
|
||||
deleteSelectedMessages: @escaping () -> Void,
|
||||
reportSelectedMessages: @escaping () -> Void,
|
||||
reportMessages: @escaping ([Message], ContextControllerProtocol?) -> Void,
|
||||
blockMessageAuthor: @escaping (Message, ContextControllerProtocol?) -> Void,
|
||||
deleteMessages: @escaping ([Message], ContextControllerProtocol?, @escaping (ContextMenuActionResult) -> Void) -> Void,
|
||||
reportMessages: @escaping ([EngineRawMessage], ContextControllerProtocol?) -> Void,
|
||||
blockMessageAuthor: @escaping (EngineRawMessage, ContextControllerProtocol?) -> Void,
|
||||
deleteMessages: @escaping ([EngineRawMessage], ContextControllerProtocol?, @escaping (ContextMenuActionResult) -> Void) -> Void,
|
||||
forwardSelectedMessages: @escaping () -> Void,
|
||||
forwardCurrentForwardMessages: @escaping () -> Void,
|
||||
forwardMessages: @escaping ([Message]) -> Void,
|
||||
forwardMessages: @escaping ([EngineRawMessage]) -> Void,
|
||||
updateForwardOptionsState: @escaping ((ChatInterfaceForwardOptionsState) -> ChatInterfaceForwardOptionsState) -> Void,
|
||||
presentForwardOptions: @escaping (UIView) -> Void,
|
||||
presentReplyOptions: @escaping (UIView) -> Void,
|
||||
|
|
@ -223,7 +222,7 @@ public final class ChatPanelInterfaceInteraction {
|
|||
presentSuggestPostOptions: @escaping () -> Void,
|
||||
shareSelectedMessages: @escaping () -> Void,
|
||||
updateTextInputStateAndMode: @escaping ((ChatTextInputState, ChatInputMode) -> (ChatTextInputState, ChatInputMode)) -> Void,
|
||||
updateInputModeAndDismissedButtonKeyboardMessageId: @escaping ((ChatPresentationInterfaceState) -> (ChatInputMode, MessageId?)) -> Void,
|
||||
updateInputModeAndDismissedButtonKeyboardMessageId: @escaping ((ChatPresentationInterfaceState) -> (ChatInputMode, EngineMessage.Id?)) -> Void,
|
||||
openStickers: @escaping () -> Void,
|
||||
editMessage: @escaping () -> Void,
|
||||
beginMessageSearch: @escaping (ChatSearchDomain, String) -> Void,
|
||||
|
|
@ -233,17 +232,17 @@ public final class ChatPanelInterfaceInteraction {
|
|||
navigateMessageSearch: @escaping (ChatPanelSearchNavigationAction) -> Void,
|
||||
openCalendarSearch: @escaping () -> Void,
|
||||
toggleMembersSearch: @escaping (Bool) -> Void,
|
||||
navigateToMessage: @escaping (MessageId, Bool, Bool, ChatLoadingMessageSubject) -> Void,
|
||||
navigateToChat: @escaping (PeerId) -> Void,
|
||||
navigateToProfile: @escaping (PeerId) -> Void,
|
||||
navigateToMessage: @escaping (EngineMessage.Id, Bool, Bool, ChatLoadingMessageSubject) -> Void,
|
||||
navigateToChat: @escaping (EnginePeer.Id) -> Void,
|
||||
navigateToProfile: @escaping (EnginePeer.Id) -> Void,
|
||||
openPeerInfo: @escaping () -> Void,
|
||||
togglePeerNotifications: @escaping () -> Void,
|
||||
sendContextResult: @escaping (ChatContextResultCollection, ChatContextResult, ASDisplayNode, CGRect) -> Bool,
|
||||
sendBotCommand: @escaping (Peer, String) -> Void,
|
||||
sendBotCommand: @escaping (EngineRawPeer, String) -> Void,
|
||||
sendShortcut: @escaping (Int32) -> Void,
|
||||
openEditShortcuts: @escaping () -> Void,
|
||||
sendBotStart: @escaping (String?) -> Void,
|
||||
botSwitchChatWithPayload: @escaping (PeerId, String) -> Void,
|
||||
botSwitchChatWithPayload: @escaping (EnginePeer.Id, String) -> Void,
|
||||
beginMediaRecording: @escaping (Bool) -> Void,
|
||||
finishMediaRecording: @escaping (ChatFinishMediaRecordingAction) -> Void,
|
||||
stopMediaRecording: @escaping () -> Void,
|
||||
|
|
@ -255,20 +254,20 @@ public final class ChatPanelInterfaceInteraction {
|
|||
displayVideoUnmuteTip: @escaping (CGPoint?) -> Void,
|
||||
switchMediaRecordingMode: @escaping () -> Void,
|
||||
setupMessageAutoremoveTimeout: @escaping () -> Void,
|
||||
sendSticker: @escaping (FileMediaReference, Bool, UIView?, CGRect?, CALayer?, [ItemCollectionId]) -> Bool,
|
||||
sendSticker: @escaping (FileMediaReference, Bool, UIView?, CGRect?, CALayer?, [EngineItemCollectionId]) -> Bool,
|
||||
editSticker: @escaping (TelegramMediaFile) -> Void,
|
||||
unblockPeer: @escaping () -> Void,
|
||||
pinMessage: @escaping (MessageId, ContextControllerProtocol?) -> Void,
|
||||
unpinMessage: @escaping (MessageId, Bool, ContextControllerProtocol?) -> Void,
|
||||
pinMessage: @escaping (EngineMessage.Id, ContextControllerProtocol?) -> Void,
|
||||
unpinMessage: @escaping (EngineMessage.Id, Bool, ContextControllerProtocol?) -> Void,
|
||||
unpinAllMessages: @escaping () -> Void,
|
||||
openPinnedList: @escaping (MessageId) -> Void,
|
||||
openPinnedList: @escaping (EngineMessage.Id) -> Void,
|
||||
shareAccountContact: @escaping () -> Void,
|
||||
reportPeer: @escaping () -> Void,
|
||||
presentPeerContact: @escaping () -> Void,
|
||||
dismissReportPeer: @escaping () -> Void,
|
||||
deleteChat: @escaping () -> Void,
|
||||
beginCall: @escaping (Bool) -> Void,
|
||||
toggleMessageStickerStarred: @escaping (MessageId) -> Void,
|
||||
toggleMessageStickerStarred: @escaping (EngineMessage.Id) -> Void,
|
||||
presentController: @escaping (ViewController, Any?) -> Void,
|
||||
presentControllerInCurrent: @escaping (ViewController, Any?) -> Void,
|
||||
getNavigationController: @escaping () -> NavigationController?,
|
||||
|
|
@ -276,8 +275,8 @@ public final class ChatPanelInterfaceInteraction {
|
|||
navigateFeed: @escaping () -> Void,
|
||||
openGrouping: @escaping () -> Void,
|
||||
toggleSilentPost: @escaping () -> Void,
|
||||
requestUnvoteInMessage: @escaping (MessageId) -> Void,
|
||||
requestStopPollInMessage: @escaping (MessageId) -> Void,
|
||||
requestUnvoteInMessage: @escaping (EngineMessage.Id) -> Void,
|
||||
requestStopPollInMessage: @escaping (EngineMessage.Id) -> Void,
|
||||
updateInputLanguage: @escaping ((String?) -> String?) -> Void,
|
||||
unarchiveChat: @escaping () -> Void,
|
||||
openLinkEditing: @escaping () -> Void,
|
||||
|
|
@ -289,13 +288,13 @@ public final class ChatPanelInterfaceInteraction {
|
|||
displaySearchResultsTooltip: @escaping (ASDisplayNode, CGRect) -> Void,
|
||||
unarchivePeer: @escaping () -> Void,
|
||||
scrollToTop: @escaping () -> Void,
|
||||
viewReplies: @escaping (MessageId?, ChatReplyThreadMessage) -> Void,
|
||||
viewReplies: @escaping (EngineMessage.Id?, ChatReplyThreadMessage) -> Void,
|
||||
activatePinnedListPreview: @escaping (ASDisplayNode, ContextGesture) -> Void,
|
||||
joinGroupCall: @escaping (CachedChannelData.ActiveCall) -> Void,
|
||||
presentInviteMembers: @escaping () -> Void,
|
||||
presentGigagroupHelp: @escaping () -> Void,
|
||||
openMonoforum: @escaping () -> Void,
|
||||
editMessageMedia: @escaping (MessageId, Bool) -> Void,
|
||||
editMessageMedia: @escaping (EngineMessage.Id, Bool) -> Void,
|
||||
updateShowCommands: @escaping ((Bool) -> Bool) -> Void,
|
||||
updateShowSendAsPeers: @escaping ((Bool) -> Bool) -> Void,
|
||||
openInviteRequests: @escaping () -> Void,
|
||||
|
|
@ -312,14 +311,14 @@ public final class ChatPanelInterfaceInteraction {
|
|||
addDoNotTranslateLanguage: @escaping (String) -> Void,
|
||||
hideTranslationPanel: @escaping () -> Void,
|
||||
openPremiumGift: @escaping () -> Void,
|
||||
openSuggestPost: @escaping (Message?, OpenSuggestPostMode) -> Void,
|
||||
openSuggestPost: @escaping (EngineRawMessage?, OpenSuggestPostMode) -> Void,
|
||||
openPremiumRequiredForMessaging: @escaping () -> Void,
|
||||
openStarsPurchase: @escaping (Int64?) -> Void,
|
||||
openMessagePayment: @escaping () -> Void,
|
||||
openBoostToUnrestrict: @escaping () -> Void,
|
||||
updateRecordingTrimRange: @escaping (Double, Double, Bool, Bool) -> Void,
|
||||
dismissAllTooltips: @escaping () -> Void,
|
||||
editTodoMessage: @escaping (MessageId, Int32?, Bool) -> Void,
|
||||
editTodoMessage: @escaping (EngineMessage.Id, Int32?, Bool) -> Void,
|
||||
dismissUrlPreview: @escaping () -> Void,
|
||||
dismissForwardMessages: @escaping () -> Void,
|
||||
dismissSuggestPost: @escaping () -> Void,
|
||||
|
|
@ -472,7 +471,7 @@ public final class ChatPanelInterfaceInteraction {
|
|||
|
||||
public convenience init(
|
||||
updateTextInputStateAndMode: @escaping ((ChatTextInputState, ChatInputMode) -> (ChatTextInputState, ChatInputMode)) -> Void,
|
||||
updateInputModeAndDismissedButtonKeyboardMessageId: @escaping ((ChatPresentationInterfaceState) -> (ChatInputMode, MessageId?)) -> Void,
|
||||
updateInputModeAndDismissedButtonKeyboardMessageId: @escaping ((ChatPresentationInterfaceState) -> (ChatInputMode, EngineMessage.Id?)) -> Void,
|
||||
openLinkEditing: @escaping () -> Void
|
||||
) {
|
||||
self.init(setupReplyMessage: { _, _, _ in
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ swift_library(
|
|||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
"//submodules/Display:Display",
|
||||
"//submodules/Postbox:Postbox",
|
||||
"//submodules/TelegramCore:TelegramCore",
|
||||
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
||||
"//submodules/AccountContext:AccountContext",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import Foundation
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
import PassKit
|
||||
|
|
@ -19,20 +18,20 @@ import StoryContainerScreen
|
|||
public enum ChatMessageGalleryControllerData {
|
||||
case url(String)
|
||||
case pass(TelegramMediaFile)
|
||||
case instantPage(InstantPageGalleryController, Int, Media)
|
||||
case instantPage(InstantPageGalleryController, Int, EngineRawMedia)
|
||||
case map(TelegramMediaMap)
|
||||
case stickerPack(StickerPackReference, TelegramMediaFile?)
|
||||
case audio(TelegramMediaFile)
|
||||
case document(TelegramMediaFile, Bool)
|
||||
case gallery(Signal<GalleryController, NoError>)
|
||||
case secretGallery(SecretMediaPreviewController)
|
||||
case chatAvatars(AvatarGalleryController, Media)
|
||||
case chatAvatars(AvatarGalleryController, EngineRawMedia)
|
||||
case theme(TelegramMediaFile)
|
||||
case other(Media)
|
||||
case other(EngineRawMedia)
|
||||
case story(Signal<StoryContainerScreen, NoError>)
|
||||
}
|
||||
|
||||
private func instantPageBlockMedia(pageId: MediaId, block: InstantPageBlock, media: [MediaId: Media], counter: inout Int) -> [InstantPageGalleryEntry] {
|
||||
private func instantPageBlockMedia(pageId: EngineMedia.Id, block: InstantPageBlock, media: [EngineMedia.Id: EngineRawMedia], counter: inout Int) -> [InstantPageGalleryEntry] {
|
||||
switch block {
|
||||
case let .image(id, caption, _, _):
|
||||
if let m = media[id] {
|
||||
|
|
@ -64,7 +63,7 @@ private func instantPageBlockMedia(pageId: MediaId, block: InstantPageBlock, med
|
|||
return []
|
||||
}
|
||||
|
||||
public func instantPageGalleryMedia(webpageId: MediaId, page: InstantPage.Accessor, galleryMedia: Media) -> [InstantPageGalleryEntry] {
|
||||
public func instantPageGalleryMedia(webpageId: EngineMedia.Id, page: InstantPage.Accessor, galleryMedia: EngineRawMedia) -> [InstantPageGalleryEntry] {
|
||||
var result: [InstantPageGalleryEntry] = []
|
||||
var counter: Int = 0
|
||||
|
||||
|
|
@ -96,9 +95,9 @@ public func instantPageGalleryMedia(webpageId: MediaId, page: InstantPage.Access
|
|||
public func chatMessageGalleryControllerData(
|
||||
context: AccountContext,
|
||||
chatLocation: ChatLocation?,
|
||||
chatFilterTag: MemoryBuffer?,
|
||||
chatFilterTag: EngineMemoryBuffer?,
|
||||
chatLocationContextHolder: Atomic<ChatLocationContextHolder?>?,
|
||||
message: Message,
|
||||
message: EngineRawMessage,
|
||||
mediaSubject: GalleryMediaSubject? = nil,
|
||||
navigationController: NavigationController?,
|
||||
standalone: Bool,
|
||||
|
|
@ -113,10 +112,10 @@ public func chatMessageGalleryControllerData(
|
|||
standalone = true
|
||||
}
|
||||
|
||||
var galleryMedia: Media?
|
||||
var otherMedia: Media?
|
||||
var galleryMedia: EngineRawMedia?
|
||||
var otherMedia: EngineRawMedia?
|
||||
var instantPageMedia: (TelegramMediaWebpage, [InstantPageGalleryEntry])?
|
||||
if message.media.isEmpty, let entities = message.textEntitiesAttribute?.entities, entities.count == 1, let firstEntity = entities.first, case let .CustomEmoji(_, fileId) = firstEntity.type, let file = message.associatedMedia[MediaId(namespace: Namespaces.Media.CloudFile, id: fileId)] as? TelegramMediaFile {
|
||||
if message.media.isEmpty, let entities = message.textEntitiesAttribute?.entities, entities.count == 1, let firstEntity = entities.first, case let .CustomEmoji(_, fileId) = firstEntity.type, let file = message.associatedMedia[EngineMedia.Id(namespace: Namespaces.Media.CloudFile, id: fileId)] as? TelegramMediaFile {
|
||||
for attribute in file.attributes {
|
||||
if case let .CustomEmoji(_, _, _, reference) = attribute {
|
||||
if let reference = reference {
|
||||
|
|
@ -356,25 +355,11 @@ public func chatMessageGalleryControllerData(
|
|||
}
|
||||
|
||||
public enum ChatMessagePreviewControllerData {
|
||||
case instantPage(InstantPageGalleryController, Int, Media)
|
||||
case instantPage(InstantPageGalleryController, Int, EngineRawMedia)
|
||||
case gallery(GalleryController)
|
||||
}
|
||||
|
||||
public func chatMessagePreviewControllerData(context: AccountContext, chatLocation: ChatLocation?, chatFilterTag: MemoryBuffer?, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>?, message: Message, standalone: Bool, reverseMessageGalleryOrder: Bool, navigationController: NavigationController?) -> ChatMessagePreviewControllerData? {
|
||||
if let mediaData = chatMessageGalleryControllerData(context: context, chatLocation: chatLocation, chatFilterTag: chatFilterTag, chatLocationContextHolder: chatLocationContextHolder, message: message, navigationController: navigationController, standalone: standalone, reverseMessageGalleryOrder: reverseMessageGalleryOrder, mode: .default, source: nil, synchronousLoad: true, actionInteraction: nil) {
|
||||
switch mediaData {
|
||||
case .gallery:
|
||||
break
|
||||
case let .instantPage(gallery, centralIndex, galleryMedia):
|
||||
return .instantPage(gallery, centralIndex, galleryMedia)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
public func chatMediaListPreviewControllerData(context: AccountContext, chatLocation: ChatLocation?, chatFilterTag: MemoryBuffer?, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>?, message: Message, standalone: Bool, reverseMessageGalleryOrder: Bool, navigationController: NavigationController?) -> Signal<ChatMessagePreviewControllerData?, NoError> {
|
||||
public func chatMediaListPreviewControllerData(context: AccountContext, chatLocation: ChatLocation?, chatFilterTag: EngineMemoryBuffer?, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>?, message: EngineRawMessage, standalone: Bool, reverseMessageGalleryOrder: Bool, navigationController: NavigationController?) -> Signal<ChatMessagePreviewControllerData?, NoError> {
|
||||
if let mediaData = chatMessageGalleryControllerData(context: context, chatLocation: chatLocation, chatFilterTag: chatFilterTag, chatLocationContextHolder: chatLocationContextHolder, message: message, navigationController: navigationController, standalone: standalone, reverseMessageGalleryOrder: reverseMessageGalleryOrder, mode: .default, source: nil, synchronousLoad: true, actionInteraction: nil) {
|
||||
switch mediaData {
|
||||
case let .gallery(gallery):
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Postbox
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import WebKit
|
||||
|
|
@ -17,10 +16,10 @@ class ChatDocumentGalleryItem: GalleryItem {
|
|||
|
||||
let context: AccountContext
|
||||
let presentationData: PresentationData
|
||||
let message: Message
|
||||
let location: MessageHistoryEntryLocation?
|
||||
let message: EngineRawMessage
|
||||
let location: EngineMessageHistoryEntryLocation?
|
||||
|
||||
init(context: AccountContext, presentationData: PresentationData, message: Message, location: MessageHistoryEntryLocation?) {
|
||||
init(context: AccountContext, presentationData: PresentationData, message: EngineRawMessage, location: EngineMessageHistoryEntryLocation?) {
|
||||
self.context = context
|
||||
self.presentationData = presentationData
|
||||
self.message = message
|
||||
|
|
@ -104,7 +103,7 @@ class ChatDocumentGalleryItemNode: ZoomableContentGalleryItemNode, WKNavigationD
|
|||
|
||||
private var itemIsVisible = false
|
||||
|
||||
private var message: Message?
|
||||
private var message: EngineRawMessage?
|
||||
|
||||
private let footerContentNode: ChatItemGalleryFooterContentNode
|
||||
|
||||
|
|
@ -163,7 +162,7 @@ class ChatDocumentGalleryItemNode: ZoomableContentGalleryItemNode, WKNavigationD
|
|||
transition.updateFrame(node: self.statusNode, frame: CGRect(origin: CGPoint(), size: statusSize))
|
||||
}
|
||||
|
||||
fileprivate func setMessage(_ message: Message) {
|
||||
fileprivate func setMessage(_ message: EngineRawMessage) {
|
||||
self.footerContentNode.setMessage(message)
|
||||
}
|
||||
|
||||
|
|
@ -187,7 +186,7 @@ class ChatDocumentGalleryItemNode: ZoomableContentGalleryItemNode, WKNavigationD
|
|||
}
|
||||
}
|
||||
|
||||
private func setupStatus(context: AccountContext, resource: MediaResource) {
|
||||
private func setupStatus(context: AccountContext, resource: EngineRawMediaResource) {
|
||||
self.statusDisposable.set((context.engine.resources.status(resource: EngineMediaResource(resource))
|
||||
|> deliverOnMainQueue).start(next: { [weak self] status in
|
||||
if let strongSelf = self {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Postbox
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import WebKit
|
||||
|
|
@ -17,10 +16,10 @@ class ChatExternalFileGalleryItem: GalleryItem {
|
|||
|
||||
let context: AccountContext
|
||||
let presentationData: PresentationData
|
||||
let message: Message
|
||||
let location: MessageHistoryEntryLocation?
|
||||
|
||||
init(context: AccountContext, presentationData: PresentationData, message: Message, location: MessageHistoryEntryLocation?) {
|
||||
let message: EngineRawMessage
|
||||
let location: EngineMessageHistoryEntryLocation?
|
||||
|
||||
init(context: AccountContext, presentationData: PresentationData, message: EngineRawMessage, location: EngineMessageHistoryEntryLocation?) {
|
||||
self.context = context
|
||||
self.presentationData = presentationData
|
||||
self.message = message
|
||||
|
|
@ -78,7 +77,7 @@ class ChatExternalFileGalleryItemNode: GalleryItemNode {
|
|||
|
||||
private var itemIsVisible = false
|
||||
|
||||
private var message: Message?
|
||||
private var message: EngineRawMessage?
|
||||
|
||||
private let footerContentNode: ChatItemGalleryFooterContentNode
|
||||
|
||||
|
|
@ -164,7 +163,7 @@ class ChatExternalFileGalleryItemNode: GalleryItemNode {
|
|||
transition.updateFrame(node: self.statusNode, frame: CGRect(origin: CGPoint(), size: statusSize))
|
||||
}
|
||||
|
||||
fileprivate func setMessage(_ message: Message) {
|
||||
fileprivate func setMessage(_ message: EngineRawMessage) {
|
||||
self.message = message
|
||||
self.footerContentNode.setMessage(message)
|
||||
}
|
||||
|
|
@ -182,7 +181,7 @@ class ChatExternalFileGalleryItemNode: GalleryItemNode {
|
|||
}
|
||||
}
|
||||
|
||||
private func setupStatus(context: AccountContext, resource: MediaResource) {
|
||||
private func setupStatus(context: AccountContext, resource: EngineRawMediaResource) {
|
||||
self.statusDisposable.set((context.engine.resources.status(resource: EngineMediaResource(resource))
|
||||
|> deliverOnMainQueue).start(next: { [weak self] status in
|
||||
if let strongSelf = self {
|
||||
|
|
|
|||
|
|
@ -2949,7 +2949,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||
}
|
||||
|
||||
if swipeUpToClose {
|
||||
addAppLogEvent(postbox: self.context.account.postbox, type: "swipe_up_close", peerId: self.context.account.peerId)
|
||||
self.context.engine.accountData.addAppLogEvent(type: "swipe_up_close")
|
||||
|
||||
return false
|
||||
}
|
||||
|
|
@ -2957,7 +2957,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||
|
||||
if #available(iOS 15.0, *) {
|
||||
if let nativePictureInPictureContent = self.nativePictureInPictureContent as? NativePictureInPictureContentImpl {
|
||||
addAppLogEvent(postbox: self.context.account.postbox, type: "swipe_up_pip", peerId: self.context.account.peerId)
|
||||
self.context.engine.accountData.addAppLogEvent(type: "swipe_up_pip")
|
||||
nativePictureInPictureContent.beginPictureInPicture()
|
||||
return true
|
||||
}
|
||||
|
|
@ -2966,7 +2966,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||
}
|
||||
|
||||
override func maybePerformActionForSwipeDownDismiss() -> Bool {
|
||||
addAppLogEvent(postbox: self.context.account.postbox, type: "swipe_down_close", peerId: self.context.account.peerId)
|
||||
self.context.engine.accountData.addAppLogEvent(type: "swipe_down_close")
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
@ -3184,7 +3184,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||
self.activePictureInPictureController = nil
|
||||
self.activePictureInPictureNavigationController = nil
|
||||
|
||||
addAppLogEvent(postbox: self.context.account.postbox, type: "pip_close_btn", peerId: self.context.account.peerId)
|
||||
self.context.engine.accountData.addAppLogEvent(type: "pip_close_btn")
|
||||
}
|
||||
}, expand: { [weak self] completion in
|
||||
didExpand = true
|
||||
|
|
@ -3234,7 +3234,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||
|
||||
if #available(iOS 15.0, *) {
|
||||
if let nativePictureInPictureContent = self.nativePictureInPictureContent as? NativePictureInPictureContentImpl {
|
||||
addAppLogEvent(postbox: self.context.account.postbox, type: "pip_btn", peerId: self.context.account.peerId)
|
||||
self.context.engine.accountData.addAppLogEvent(type: "pip_btn")
|
||||
nativePictureInPictureContent.beginPictureInPicture()
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import SwiftSignalKit
|
|||
import ComponentFlow
|
||||
import MultilineTextComponent
|
||||
import MultilineTextWithEntitiesComponent
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
import ContextUI
|
||||
|
|
@ -111,7 +110,7 @@ final class VideoAdComponent: Component {
|
|||
|
||||
let titleString = component.message.author?.compactDisplayTitle ?? ""
|
||||
|
||||
var media: Media?
|
||||
var media: EngineRawMedia?
|
||||
if let photo = component.message.media.first as? TelegramMediaImage {
|
||||
media = photo
|
||||
} else if let file = component.message.media.first as? TelegramMediaFile {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ swift_library(
|
|||
],
|
||||
deps = [
|
||||
"//submodules/TelegramCore",
|
||||
"//submodules/Postbox",
|
||||
"//submodules/SSignalKit/SwiftSignalKit",
|
||||
"//submodules/Display",
|
||||
"//submodules/Pdf",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
import Display
|
||||
|
|
@ -13,9 +12,9 @@ public struct ICloudFileResourceId {
|
|||
|
||||
public var uniqueId: String {
|
||||
if self.thumbnail {
|
||||
return "icloud-thumb-\(persistentHash32(self.urlData))"
|
||||
return "icloud-thumb-\(enginePersistentHash32(self.urlData))"
|
||||
} else {
|
||||
return "icloud-\(persistentHash32(self.urlData))"
|
||||
return "icloud-\(enginePersistentHash32(self.urlData))"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -37,21 +36,21 @@ public class ICloudFileResource: TelegramMediaResource {
|
|||
self.thumbnail = thumbnail
|
||||
}
|
||||
|
||||
public required init(decoder: PostboxDecoder) {
|
||||
public required init(decoder: EnginePostboxDecoder) {
|
||||
self.urlData = decoder.decodeStringForKey("url", orElse: "")
|
||||
self.thumbnail = decoder.decodeBoolForKey("thumb", orElse: false)
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
public func encode(_ encoder: EnginePostboxEncoder) {
|
||||
encoder.encodeString(self.urlData, forKey: "url")
|
||||
encoder.encodeBool(self.thumbnail, forKey: "thumb")
|
||||
}
|
||||
|
||||
public var id: MediaResourceId {
|
||||
return MediaResourceId(ICloudFileResourceId(urlData: self.urlData, thumbnail: self.thumbnail).uniqueId)
|
||||
public var id: EngineRawMediaResourceId {
|
||||
return EngineRawMediaResourceId(ICloudFileResourceId(urlData: self.urlData, thumbnail: self.thumbnail).uniqueId)
|
||||
}
|
||||
|
||||
public func isEqual(to: MediaResource) -> Bool {
|
||||
|
||||
public func isEqual(to: EngineRawMediaResource) -> Bool {
|
||||
if let to = to as? ICloudFileResource {
|
||||
if self.urlData != to.urlData || self.thumbnail != to.thumbnail {
|
||||
return false
|
||||
|
|
@ -252,7 +251,7 @@ public func iCloudFileDescription(_ url: URL) -> Signal<ICloudFileDescription?,
|
|||
}
|
||||
}
|
||||
|
||||
private final class ICloudFileResourceCopyItem: MediaResourceDataFetchCopyLocalItem {
|
||||
private final class ICloudFileResourceCopyItem: EngineRawMediaResourceDataFetchCopyLocalItem {
|
||||
private let url: URL
|
||||
|
||||
init(url: URL) {
|
||||
|
|
@ -274,7 +273,7 @@ private final class ICloudFileResourceCopyItem: MediaResourceDataFetchCopyLocalI
|
|||
}
|
||||
}
|
||||
|
||||
public func fetchICloudFileResource(resource: ICloudFileResource) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
|
||||
public func fetchICloudFileResource(resource: ICloudFileResource) -> Signal<EngineMediaResourceDataFetchResult, EngineMediaResourceDataFetchError> {
|
||||
return Signal { subscriber in
|
||||
subscriber.putNext(.reset)
|
||||
|
||||
|
|
@ -306,7 +305,7 @@ public func fetchICloudFileResource(resource: ICloudFileResource) -> Signal<Medi
|
|||
|
||||
let complete = {
|
||||
if resource.thumbnail {
|
||||
let tempFile = TempBox.shared.tempFile(fileName: "thumb.jpg")
|
||||
let tempFile = EngineTempBox.shared.tempFile(fileName: "thumb.jpg")
|
||||
var data = Data()
|
||||
let fileExtension = url.pathExtension.lowercased()
|
||||
let isAudioFile = audioFileExtensions.contains(fileExtension)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import Foundation
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import PersistentStringHash
|
||||
|
||||
|
|
@ -7,9 +6,9 @@ public struct InstantPageExternalMediaResourceId {
|
|||
public let url: String
|
||||
|
||||
public var uniqueId: String {
|
||||
return "instantpage-media-\(persistentHash32(self.url))"
|
||||
return "instantpage-media-\(enginePersistentHash32(self.url))"
|
||||
}
|
||||
|
||||
|
||||
public var hashValue: Int {
|
||||
return self.uniqueId.hashValue
|
||||
}
|
||||
|
|
@ -17,28 +16,28 @@ public struct InstantPageExternalMediaResourceId {
|
|||
|
||||
public class InstantPageExternalMediaResource: TelegramMediaResource {
|
||||
public let url: String
|
||||
|
||||
|
||||
public var size: Int64? {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
public init(url: String) {
|
||||
self.url = url
|
||||
}
|
||||
|
||||
public required init(decoder: PostboxDecoder) {
|
||||
|
||||
public required init(decoder: EnginePostboxDecoder) {
|
||||
self.url = decoder.decodeStringForKey("u", orElse: "")
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
|
||||
public func encode(_ encoder: EnginePostboxEncoder) {
|
||||
encoder.encodeString(self.url, forKey: "u")
|
||||
}
|
||||
|
||||
public var id: MediaResourceId {
|
||||
return MediaResourceId(InstantPageExternalMediaResourceId(url: self.url).uniqueId)
|
||||
|
||||
public var id: EngineRawMediaResourceId {
|
||||
return EngineRawMediaResourceId(InstantPageExternalMediaResourceId(url: self.url).uniqueId)
|
||||
}
|
||||
|
||||
public func isEqual(to: MediaResource) -> Bool {
|
||||
|
||||
public func isEqual(to: EngineRawMediaResource) -> Bool {
|
||||
if let to = to as? InstantPageExternalMediaResource {
|
||||
return self.url == to.url
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||
|
||||
swift_library(
|
||||
name = "LegacyDataImport",
|
||||
module_name = "LegacyDataImport",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
deps = [
|
||||
"//submodules/TelegramCore:TelegramCore",
|
||||
"//submodules/SyncCore:SyncCore",
|
||||
"//submodules/Postbox:Postbox",
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/TelegramNotices:TelegramNotices",
|
||||
"//submodules/TelegramUIPreferences:TelegramUIPreferences",
|
||||
"//submodules/RadialStatusNode:RadialStatusNode",
|
||||
"//submodules/LegacyComponents:LegacyComponents",
|
||||
"//submodules/LegacyDataImport/Impl:LegacyDataImportImpl",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
|
||||
objc_library(
|
||||
name = "LegacyDataImportImpl",
|
||||
enable_modules = True,
|
||||
module_name = "LegacyDataImportImpl",
|
||||
srcs = glob([
|
||||
"Sources/**/*.m",
|
||||
"Sources/**/*.h",
|
||||
]),
|
||||
hdrs = glob([
|
||||
"PublicHeaders/**/*.h",
|
||||
]),
|
||||
includes = [
|
||||
"PublicHeaders",
|
||||
],
|
||||
sdk_frameworks = [
|
||||
"Foundation",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <LegacyDataImportImpl/TGProxyItem.h>
|
||||
#import <LegacyDataImportImpl/TGAutoDownloadPreferences.h>
|
||||
#import <LegacyDataImportImpl/TGPresentationAutoNightPreferences.h>
|
||||
|
||||
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef enum {
|
||||
TGNetworkTypeUnknown,
|
||||
TGNetworkTypeNone,
|
||||
TGNetworkTypeGPRS,
|
||||
TGNetworkTypeEdge,
|
||||
TGNetworkType3G,
|
||||
TGNetworkTypeLTE,
|
||||
TGNetworkTypeWiFi,
|
||||
} TGNetworkType;
|
||||
|
||||
typedef enum {
|
||||
TGAutoDownloadModeNone = 0,
|
||||
|
||||
TGAutoDownloadModeCellularContacts = 1 << 0,
|
||||
TGAutoDownloadModeWifiContacts = 1 << 1,
|
||||
|
||||
TGAutoDownloadModeCellularPrivateChats = 1 << 2,
|
||||
TGAutoDownloadModeWifiPrivateChats = 1 << 3,
|
||||
|
||||
TGAutoDownloadModeCellularGroups = 1 << 4,
|
||||
TGAutoDownloadModeWifiGroups = 1 << 5,
|
||||
|
||||
TGAutoDownloadModeCellularChannels = 1 << 6,
|
||||
TGAutoDownloadModeWifiChannels = 1 << 7,
|
||||
|
||||
TGAutoDownloadModeAutosavePhotosAll = TGAutoDownloadModeCellularContacts | TGAutoDownloadModeCellularPrivateChats | TGAutoDownloadModeCellularGroups | TGAutoDownloadModeCellularChannels,
|
||||
|
||||
TGAutoDownloadModeAllPrivateChats = TGAutoDownloadModeCellularContacts | TGAutoDownloadModeWifiContacts | TGAutoDownloadModeCellularPrivateChats | TGAutoDownloadModeWifiPrivateChats,
|
||||
TGAutoDownloadModeAllGroups = TGAutoDownloadModeCellularGroups | TGAutoDownloadModeWifiGroups | TGAutoDownloadModeCellularChannels | TGAutoDownloadModeWifiChannels,
|
||||
TGAutoDownloadModeAll = TGAutoDownloadModeCellularContacts | TGAutoDownloadModeWifiContacts | TGAutoDownloadModeCellularPrivateChats | TGAutoDownloadModeWifiPrivateChats | TGAutoDownloadModeCellularGroups | TGAutoDownloadModeWifiGroups | TGAutoDownloadModeCellularChannels | TGAutoDownloadModeWifiChannels
|
||||
} TGAutoDownloadMode;
|
||||
|
||||
typedef enum {
|
||||
TGAutoDownloadChatContact,
|
||||
TGAutoDownloadChatOtherPrivateChat,
|
||||
TGAutoDownloadChatGroup,
|
||||
TGAutoDownloadChatChannel
|
||||
} TGAutoDownloadChat;
|
||||
|
||||
@interface TGAutoDownloadPreferences : NSObject <NSCoding>
|
||||
|
||||
@property (nonatomic, readonly) bool disabled;
|
||||
|
||||
@property (nonatomic, readonly) TGAutoDownloadMode photos;
|
||||
@property (nonatomic, readonly) TGAutoDownloadMode videos;
|
||||
@property (nonatomic, readonly) int32_t maximumVideoSize;
|
||||
@property (nonatomic, readonly) TGAutoDownloadMode documents;
|
||||
@property (nonatomic, readonly) int32_t maximumDocumentSize;
|
||||
@property (nonatomic, readonly) TGAutoDownloadMode gifs;
|
||||
@property (nonatomic, readonly) TGAutoDownloadMode voiceMessages;
|
||||
@property (nonatomic, readonly) TGAutoDownloadMode videoMessages;
|
||||
|
||||
- (instancetype)updateDisabled:(bool)disabled;
|
||||
- (instancetype)updatePhotosMode:(TGAutoDownloadMode)mode;
|
||||
- (instancetype)updateVideosMode:(TGAutoDownloadMode)mode maximumSize:(int32_t)maximumSize;
|
||||
- (instancetype)updateDocumentsMode:(TGAutoDownloadMode)mode maximumSize:(int32_t)maximumSize;
|
||||
- (instancetype)updateGifsMode:(TGAutoDownloadMode)mode;
|
||||
- (instancetype)updateVoiceMessagesMode:(TGAutoDownloadMode)mode;
|
||||
- (instancetype)updateVideoMessagesMode:(TGAutoDownloadMode)mode;
|
||||
|
||||
+ (bool)shouldDownload:(TGAutoDownloadMode)mode inChat:(TGAutoDownloadChat)chat networkType:(TGNetworkType)networkType;
|
||||
- (bool)shouldDownloadPhotoInChat:(TGAutoDownloadChat)chat networkType:(TGNetworkType)networkType;
|
||||
- (bool)shouldDownloadVideoInChat:(TGAutoDownloadChat)chat networkType:(TGNetworkType)networkType;
|
||||
- (bool)shouldDownloadDocumentInChat:(TGAutoDownloadChat)chat networkType:(TGNetworkType)networkType;
|
||||
- (bool)shouldDownloadGifInChat:(TGAutoDownloadChat)chat networkType:(TGNetworkType)networkType;
|
||||
- (bool)shouldDownloadVoiceMessageInChat:(TGAutoDownloadChat)chat networkType:(TGNetworkType)networkType;
|
||||
- (bool)shouldDownloadVideoMessageInChat:(TGAutoDownloadChat)chat networkType:(TGNetworkType)networkType;
|
||||
|
||||
- (bool)isDefaultPreferences;
|
||||
|
||||
+ (instancetype)defaultPreferences;
|
||||
+ (instancetype)preferencesWithLegacyDownloadPrivatePhotos:(bool)privatePhotos groupPhotos:(bool)groupPhotos privateVoiceMessages:(bool)privateVoiceMessages groupVoiceMessages:(bool)groupVoiceMessages privateVideoMessages:(bool)privateVideoMessages groupVideoMessages:(bool)groupVideoMessages;
|
||||
|
||||
@end
|
||||
|
|
@ -1,250 +0,0 @@
|
|||
#import <LegacyDataImportImpl/TGAutoDownloadPreferences.h>
|
||||
|
||||
@implementation TGAutoDownloadPreferences
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_disabled = [aDecoder decodeBoolForKey:@"disabled"];
|
||||
_photos = [aDecoder decodeInt32ForKey:@"photos"];
|
||||
_videos = [aDecoder decodeInt32ForKey:@"videos"];
|
||||
_maximumVideoSize = [aDecoder decodeInt32ForKey:@"maxVideoSize"];
|
||||
_documents = [aDecoder decodeInt32ForKey:@"documents"];
|
||||
_maximumDocumentSize = [aDecoder decodeInt32ForKey:@"maxDocumentSize"];
|
||||
_voiceMessages = [aDecoder decodeInt32ForKey:@"voiceMessages"];
|
||||
_videoMessages = [aDecoder decodeInt32ForKey:@"videoMessages"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder
|
||||
{
|
||||
[aCoder encodeBool:_disabled forKey:@"disabled"];
|
||||
[aCoder encodeInt32:_photos forKey:@"photos"];
|
||||
[aCoder encodeInt32:_videos forKey:@"videos"];
|
||||
[aCoder encodeInt32:_maximumVideoSize forKey:@"maxVideoSize"];
|
||||
[aCoder encodeInt32:_documents forKey:@"documents"];
|
||||
[aCoder encodeInt32:_maximumDocumentSize forKey:@"maxDocumentSize"];
|
||||
[aCoder encodeInt32:_voiceMessages forKey:@"voiceMessages"];
|
||||
[aCoder encodeInt32:_videoMessages forKey:@"videoMessages"];
|
||||
}
|
||||
|
||||
+ (instancetype)defaultPreferences
|
||||
{
|
||||
TGAutoDownloadPreferences *preferences = [[TGAutoDownloadPreferences alloc] init];
|
||||
preferences->_photos = TGAutoDownloadModeAll;
|
||||
preferences->_videos = TGAutoDownloadModeNone;
|
||||
preferences->_maximumVideoSize = 10;
|
||||
preferences->_documents = TGAutoDownloadModeNone;
|
||||
preferences->_maximumDocumentSize = 10;
|
||||
preferences->_voiceMessages = TGAutoDownloadModeAll;
|
||||
preferences->_videoMessages = TGAutoDownloadModeAll;
|
||||
return preferences;
|
||||
}
|
||||
|
||||
+ (instancetype)preferencesWithLegacyDownloadPrivatePhotos:(bool)privatePhotos groupPhotos:(bool)groupPhotos privateVoiceMessages:(bool)privateVoiceMessages groupVoiceMessages:(bool)groupVoiceMessages privateVideoMessages:(bool)privateVideoMessages groupVideoMessages:(bool)groupVideoMessages
|
||||
{
|
||||
TGAutoDownloadPreferences *preferences = [[TGAutoDownloadPreferences alloc] init];
|
||||
|
||||
if (privatePhotos)
|
||||
preferences->_photos |= TGAutoDownloadModeAllPrivateChats;
|
||||
if (groupPhotos)
|
||||
preferences->_photos |= TGAutoDownloadModeAllGroups;
|
||||
|
||||
if (privateVoiceMessages)
|
||||
preferences->_voiceMessages |= TGAutoDownloadModeAllPrivateChats;
|
||||
if (groupVoiceMessages)
|
||||
preferences->_voiceMessages |= TGAutoDownloadModeAllGroups;
|
||||
|
||||
if (privateVideoMessages)
|
||||
preferences->_videoMessages |= TGAutoDownloadModeAllPrivateChats;
|
||||
if (groupVideoMessages)
|
||||
preferences->_videoMessages |= TGAutoDownloadModeAllGroups;
|
||||
|
||||
preferences->_maximumVideoSize = 10;
|
||||
preferences->_maximumDocumentSize = 10;
|
||||
|
||||
return preferences;
|
||||
}
|
||||
|
||||
- (instancetype)updateDisabled:(bool)disabled
|
||||
{
|
||||
TGAutoDownloadPreferences *preferences = [[TGAutoDownloadPreferences alloc] init];
|
||||
preferences->_disabled = disabled;
|
||||
preferences->_photos = _photos;
|
||||
preferences->_videos = _videos;
|
||||
preferences->_maximumVideoSize = _maximumVideoSize;
|
||||
preferences->_documents = _documents;
|
||||
preferences->_maximumDocumentSize = _maximumDocumentSize;
|
||||
preferences->_voiceMessages = _voiceMessages;
|
||||
preferences->_videoMessages = _videoMessages;
|
||||
return preferences;
|
||||
}
|
||||
|
||||
- (instancetype)updatePhotosMode:(TGAutoDownloadMode)mode
|
||||
{
|
||||
TGAutoDownloadPreferences *preferences = [[TGAutoDownloadPreferences alloc] init];
|
||||
preferences->_photos = mode;
|
||||
preferences->_videos = _videos;
|
||||
preferences->_maximumVideoSize = _maximumVideoSize;
|
||||
preferences->_documents = _documents;
|
||||
preferences->_maximumDocumentSize = _maximumDocumentSize;
|
||||
preferences->_voiceMessages = _voiceMessages;
|
||||
preferences->_videoMessages = _videoMessages;
|
||||
return preferences;
|
||||
}
|
||||
|
||||
- (instancetype)updateVideosMode:(TGAutoDownloadMode)mode maximumSize:(int32_t)maximumSize
|
||||
{
|
||||
TGAutoDownloadPreferences *preferences = [[TGAutoDownloadPreferences alloc] init];
|
||||
preferences->_photos = _photos;
|
||||
preferences->_videos = mode;
|
||||
preferences->_maximumVideoSize = maximumSize;
|
||||
preferences->_documents = _documents;
|
||||
preferences->_maximumDocumentSize = _maximumDocumentSize;
|
||||
preferences->_voiceMessages = _voiceMessages;
|
||||
preferences->_videoMessages = _videoMessages;
|
||||
return preferences;
|
||||
}
|
||||
|
||||
- (instancetype)updateDocumentsMode:(TGAutoDownloadMode)mode maximumSize:(int32_t)maximumSize
|
||||
{
|
||||
TGAutoDownloadPreferences *preferences = [[TGAutoDownloadPreferences alloc] init];
|
||||
preferences->_photos = _photos;
|
||||
preferences->_videos = _videos;
|
||||
preferences->_maximumVideoSize = _maximumVideoSize;
|
||||
preferences->_documents = mode;
|
||||
preferences->_maximumDocumentSize = maximumSize;
|
||||
preferences->_voiceMessages = _voiceMessages;
|
||||
preferences->_videoMessages = _videoMessages;
|
||||
return preferences;
|
||||
}
|
||||
|
||||
- (instancetype)updateVoiceMessagesMode:(TGAutoDownloadMode)mode
|
||||
{
|
||||
TGAutoDownloadPreferences *preferences = [[TGAutoDownloadPreferences alloc] init];
|
||||
preferences->_photos = _photos;
|
||||
preferences->_videos = _videos;
|
||||
preferences->_maximumVideoSize = _maximumVideoSize;
|
||||
preferences->_documents = _documents;
|
||||
preferences->_maximumDocumentSize = _maximumDocumentSize;
|
||||
preferences->_voiceMessages = mode;
|
||||
preferences->_videoMessages = _videoMessages;
|
||||
return preferences;
|
||||
}
|
||||
|
||||
- (instancetype)updateVideoMessagesMode:(TGAutoDownloadMode)mode
|
||||
{
|
||||
TGAutoDownloadPreferences *preferences = [[TGAutoDownloadPreferences alloc] init];
|
||||
preferences->_photos = _photos;
|
||||
preferences->_videos = _videos;
|
||||
preferences->_maximumVideoSize = _maximumVideoSize;
|
||||
preferences->_documents = _documents;
|
||||
preferences->_maximumDocumentSize = _maximumDocumentSize;
|
||||
preferences->_voiceMessages = _voiceMessages;
|
||||
preferences->_videoMessages = mode;
|
||||
return preferences;
|
||||
}
|
||||
|
||||
+ (bool)shouldDownload:(TGAutoDownloadMode)mode inChat:(TGAutoDownloadChat)chat networkType:(TGNetworkType)networkType
|
||||
{
|
||||
bool isWiFi = networkType == TGNetworkTypeWiFi;
|
||||
bool isCellular = !isWiFi && networkType != TGNetworkTypeNone;
|
||||
|
||||
bool shouldDownload = false;
|
||||
switch (chat)
|
||||
{
|
||||
case TGAutoDownloadChatContact:
|
||||
if (isCellular)
|
||||
shouldDownload = (mode & TGAutoDownloadModeCellularContacts) != 0;
|
||||
else if (isWiFi)
|
||||
shouldDownload = (mode & TGAutoDownloadModeWifiContacts) != 0;
|
||||
break;
|
||||
|
||||
case TGAutoDownloadChatOtherPrivateChat:
|
||||
if (isCellular)
|
||||
shouldDownload = (mode & TGAutoDownloadModeCellularPrivateChats) != 0;
|
||||
else if (isWiFi)
|
||||
shouldDownload = (mode & TGAutoDownloadModeWifiPrivateChats) != 0;
|
||||
break;
|
||||
|
||||
case TGAutoDownloadChatGroup:
|
||||
if (isCellular)
|
||||
shouldDownload = (mode & TGAutoDownloadModeCellularGroups) != 0;
|
||||
else if (isWiFi)
|
||||
shouldDownload = (mode & TGAutoDownloadModeWifiGroups) != 0;
|
||||
break;
|
||||
|
||||
case TGAutoDownloadChatChannel:
|
||||
if (isCellular)
|
||||
shouldDownload = (mode & TGAutoDownloadModeCellularChannels) != 0;
|
||||
else if (isWiFi)
|
||||
shouldDownload = (mode & TGAutoDownloadModeWifiChannels) != 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return shouldDownload;
|
||||
}
|
||||
|
||||
- (bool)shouldDownloadPhotoInChat:(TGAutoDownloadChat)chat networkType:(TGNetworkType)networkType
|
||||
{
|
||||
if (self.disabled)
|
||||
return false;
|
||||
|
||||
return [TGAutoDownloadPreferences shouldDownload:_photos inChat:chat networkType:networkType];
|
||||
}
|
||||
|
||||
- (bool)shouldDownloadVideoInChat:(TGAutoDownloadChat)chat networkType:(TGNetworkType)networkType
|
||||
{
|
||||
if (self.disabled)
|
||||
return false;
|
||||
|
||||
return [TGAutoDownloadPreferences shouldDownload:_videos inChat:chat networkType:networkType];
|
||||
}
|
||||
|
||||
- (bool)shouldDownloadDocumentInChat:(TGAutoDownloadChat)chat networkType:(TGNetworkType)networkType
|
||||
{
|
||||
if (self.disabled)
|
||||
return false;
|
||||
|
||||
return [TGAutoDownloadPreferences shouldDownload:_documents inChat:chat networkType:networkType];
|
||||
}
|
||||
|
||||
- (bool)shouldDownloadVoiceMessageInChat:(TGAutoDownloadChat)chat networkType:(TGNetworkType)networkType
|
||||
{
|
||||
if (self.disabled)
|
||||
return false;
|
||||
|
||||
return [TGAutoDownloadPreferences shouldDownload:_voiceMessages inChat:chat networkType:networkType];
|
||||
}
|
||||
|
||||
- (bool)shouldDownloadVideoMessageInChat:(TGAutoDownloadChat)chat networkType:(TGNetworkType)networkType
|
||||
{
|
||||
if (self.disabled)
|
||||
return false;
|
||||
|
||||
return [TGAutoDownloadPreferences shouldDownload:_videoMessages inChat:chat networkType:networkType];
|
||||
}
|
||||
|
||||
- (bool)isDefaultPreferences
|
||||
{
|
||||
return [self isEqual:[TGAutoDownloadPreferences defaultPreferences]];
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
if (object == self)
|
||||
return YES;
|
||||
|
||||
if (!object || ![object isKindOfClass:[self class]])
|
||||
return NO;
|
||||
|
||||
TGAutoDownloadPreferences *preferences = (TGAutoDownloadPreferences *)object;
|
||||
return preferences.photos == _photos && preferences.videos == _videos && preferences.documents == _documents && preferences.voiceMessages == _voiceMessages && preferences.videoMessages == _videoMessages && preferences.maximumVideoSize == _maximumVideoSize && preferences.maximumDocumentSize == _maximumDocumentSize && preferences.disabled == _disabled;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TGPresentationAutoNightModeDisabled,
|
||||
TGPresentationAutoNightModeBrightness,
|
||||
TGPresentationAutoNightModeScheduled,
|
||||
TGPresentationAutoNightModeSunsetSunrise
|
||||
} TGPresentationAutoNightMode;
|
||||
|
||||
@interface TGPresentationAutoNightPreferences : NSObject <NSCoding>
|
||||
|
||||
@property (nonatomic, readonly) TGPresentationAutoNightMode mode;
|
||||
|
||||
@property (nonatomic, readonly) CGFloat brightnessThreshold;
|
||||
|
||||
@property (nonatomic, readonly) int32_t scheduleStart;
|
||||
@property (nonatomic, readonly) int32_t scheduleEnd;
|
||||
|
||||
@property (nonatomic, readonly) CGFloat latitude;
|
||||
@property (nonatomic, readonly) CGFloat longitude;
|
||||
@property (nonatomic, readonly) NSString *cachedLocationName;
|
||||
|
||||
@property (nonatomic, readonly) int32_t preferredPalette;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
#import <LegacyDataImportImpl/TGPresentationAutoNightPreferences.h>
|
||||
|
||||
@implementation TGPresentationAutoNightPreferences
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_mode = [aDecoder decodeInt32ForKey:@"m"];
|
||||
_brightnessThreshold = [aDecoder decodeDoubleForKey:@"b"];
|
||||
_scheduleStart = [aDecoder decodeInt32ForKey:@"ss"];
|
||||
_scheduleEnd = [aDecoder decodeInt32ForKey:@"se"];
|
||||
_latitude = [aDecoder decodeDoubleForKey:@"lat"];
|
||||
_longitude = [aDecoder decodeDoubleForKey:@"lon"];
|
||||
_cachedLocationName = [aDecoder decodeObjectForKey:@"loc"];
|
||||
_preferredPalette = [aDecoder decodeInt32ForKey:@"p"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface TGProxyItem : NSObject <NSCoding>
|
||||
|
||||
@property (nonatomic, readonly) NSString *server;
|
||||
@property (nonatomic, readonly) int16_t port;
|
||||
@property (nonatomic, readonly) NSString *username;
|
||||
@property (nonatomic, readonly) NSString *password;
|
||||
@property (nonatomic, readonly) NSString *secret;
|
||||
|
||||
@property (nonatomic, readonly) bool isMTProxy;
|
||||
|
||||
- (instancetype)initWithServer:(NSString *)server port:(int16_t)port username:(NSString *)username password:(NSString *)password secret:(NSString *)secret;
|
||||
|
||||
@end
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
#import <LegacyDataImportImpl/TGProxyItem.h>
|
||||
|
||||
static bool TGObjectCompare(id obj1, id obj2) {
|
||||
if (obj1 == nil && obj2 == nil)
|
||||
return true;
|
||||
|
||||
return [obj1 isEqual:obj2];
|
||||
}
|
||||
|
||||
@implementation TGProxyItem
|
||||
|
||||
- (instancetype)initWithServer:(NSString *)server port:(int16_t)port username:(NSString *)username password:(NSString *)password secret:(NSString *)secret
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_server = server;
|
||||
_port = port;
|
||||
_username = username;
|
||||
_password = password;
|
||||
_secret = secret;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder
|
||||
{
|
||||
return [self initWithServer:[aDecoder decodeObjectForKey:@"server"] port:(int16_t)[aDecoder decodeInt32ForKey:@"port"] username:[aDecoder decodeObjectForKey:@"user"] password:[aDecoder decodeObjectForKey:@"pass"] secret:[aDecoder decodeObjectForKey:@"secret"]];
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder
|
||||
{
|
||||
[aCoder encodeObject:_server forKey:@"server"];
|
||||
[aCoder encodeInt32:_port forKey:@"port"];
|
||||
[aCoder encodeObject:_username forKey:@"user"];
|
||||
[aCoder encodeObject:_password forKey:@"pass"];
|
||||
[aCoder encodeObject:_secret forKey:@"secret"];
|
||||
}
|
||||
|
||||
- (bool)isMTProxy
|
||||
{
|
||||
return _secret.length > 0;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
if (object == self)
|
||||
return true;
|
||||
|
||||
if (!object || ![object isKindOfClass:[self class]])
|
||||
return false;
|
||||
|
||||
TGProxyItem *proxy = (TGProxyItem *)object;
|
||||
|
||||
if (![_server isEqualToString:proxy.server])
|
||||
return false;
|
||||
|
||||
if (_port != proxy.port)
|
||||
return false;
|
||||
|
||||
if (!TGObjectCompare(_username ?: @"", proxy.username ?: @""))
|
||||
return false;
|
||||
|
||||
if (!TGObjectCompare(_password ?: @"", proxy.password ?: @""))
|
||||
return false;
|
||||
|
||||
if (!TGObjectCompare(_secret ?: @"", proxy.secret ?: @""))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -1,250 +0,0 @@
|
|||
#import <LegacyDataImportImpl/TGAutoDownloadPreferences.h>
|
||||
|
||||
@implementation TGAutoDownloadPreferences
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_disabled = [aDecoder decodeBoolForKey:@"disabled"];
|
||||
_photos = [aDecoder decodeInt32ForKey:@"photos"];
|
||||
_videos = [aDecoder decodeInt32ForKey:@"videos"];
|
||||
_maximumVideoSize = [aDecoder decodeInt32ForKey:@"maxVideoSize"];
|
||||
_documents = [aDecoder decodeInt32ForKey:@"documents"];
|
||||
_maximumDocumentSize = [aDecoder decodeInt32ForKey:@"maxDocumentSize"];
|
||||
_voiceMessages = [aDecoder decodeInt32ForKey:@"voiceMessages"];
|
||||
_videoMessages = [aDecoder decodeInt32ForKey:@"videoMessages"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder
|
||||
{
|
||||
[aCoder encodeBool:_disabled forKey:@"disabled"];
|
||||
[aCoder encodeInt32:_photos forKey:@"photos"];
|
||||
[aCoder encodeInt32:_videos forKey:@"videos"];
|
||||
[aCoder encodeInt32:_maximumVideoSize forKey:@"maxVideoSize"];
|
||||
[aCoder encodeInt32:_documents forKey:@"documents"];
|
||||
[aCoder encodeInt32:_maximumDocumentSize forKey:@"maxDocumentSize"];
|
||||
[aCoder encodeInt32:_voiceMessages forKey:@"voiceMessages"];
|
||||
[aCoder encodeInt32:_videoMessages forKey:@"videoMessages"];
|
||||
}
|
||||
|
||||
+ (instancetype)defaultPreferences
|
||||
{
|
||||
TGAutoDownloadPreferences *preferences = [[TGAutoDownloadPreferences alloc] init];
|
||||
preferences->_photos = TGAutoDownloadModeAll;
|
||||
preferences->_videos = TGAutoDownloadModeNone;
|
||||
preferences->_maximumVideoSize = 10;
|
||||
preferences->_documents = TGAutoDownloadModeNone;
|
||||
preferences->_maximumDocumentSize = 10;
|
||||
preferences->_voiceMessages = TGAutoDownloadModeAll;
|
||||
preferences->_videoMessages = TGAutoDownloadModeAll;
|
||||
return preferences;
|
||||
}
|
||||
|
||||
+ (instancetype)preferencesWithLegacyDownloadPrivatePhotos:(bool)privatePhotos groupPhotos:(bool)groupPhotos privateVoiceMessages:(bool)privateVoiceMessages groupVoiceMessages:(bool)groupVoiceMessages privateVideoMessages:(bool)privateVideoMessages groupVideoMessages:(bool)groupVideoMessages
|
||||
{
|
||||
TGAutoDownloadPreferences *preferences = [[TGAutoDownloadPreferences alloc] init];
|
||||
|
||||
if (privatePhotos)
|
||||
preferences->_photos |= TGAutoDownloadModeAllPrivateChats;
|
||||
if (groupPhotos)
|
||||
preferences->_photos |= TGAutoDownloadModeAllGroups;
|
||||
|
||||
if (privateVoiceMessages)
|
||||
preferences->_voiceMessages |= TGAutoDownloadModeAllPrivateChats;
|
||||
if (groupVoiceMessages)
|
||||
preferences->_voiceMessages |= TGAutoDownloadModeAllGroups;
|
||||
|
||||
if (privateVideoMessages)
|
||||
preferences->_videoMessages |= TGAutoDownloadModeAllPrivateChats;
|
||||
if (groupVideoMessages)
|
||||
preferences->_videoMessages |= TGAutoDownloadModeAllGroups;
|
||||
|
||||
preferences->_maximumVideoSize = 10;
|
||||
preferences->_maximumDocumentSize = 10;
|
||||
|
||||
return preferences;
|
||||
}
|
||||
|
||||
- (instancetype)updateDisabled:(bool)disabled
|
||||
{
|
||||
TGAutoDownloadPreferences *preferences = [[TGAutoDownloadPreferences alloc] init];
|
||||
preferences->_disabled = disabled;
|
||||
preferences->_photos = _photos;
|
||||
preferences->_videos = _videos;
|
||||
preferences->_maximumVideoSize = _maximumVideoSize;
|
||||
preferences->_documents = _documents;
|
||||
preferences->_maximumDocumentSize = _maximumDocumentSize;
|
||||
preferences->_voiceMessages = _voiceMessages;
|
||||
preferences->_videoMessages = _videoMessages;
|
||||
return preferences;
|
||||
}
|
||||
|
||||
- (instancetype)updatePhotosMode:(TGAutoDownloadMode)mode
|
||||
{
|
||||
TGAutoDownloadPreferences *preferences = [[TGAutoDownloadPreferences alloc] init];
|
||||
preferences->_photos = mode;
|
||||
preferences->_videos = _videos;
|
||||
preferences->_maximumVideoSize = _maximumVideoSize;
|
||||
preferences->_documents = _documents;
|
||||
preferences->_maximumDocumentSize = _maximumDocumentSize;
|
||||
preferences->_voiceMessages = _voiceMessages;
|
||||
preferences->_videoMessages = _videoMessages;
|
||||
return preferences;
|
||||
}
|
||||
|
||||
- (instancetype)updateVideosMode:(TGAutoDownloadMode)mode maximumSize:(int32_t)maximumSize
|
||||
{
|
||||
TGAutoDownloadPreferences *preferences = [[TGAutoDownloadPreferences alloc] init];
|
||||
preferences->_photos = _photos;
|
||||
preferences->_videos = mode;
|
||||
preferences->_maximumVideoSize = maximumSize;
|
||||
preferences->_documents = _documents;
|
||||
preferences->_maximumDocumentSize = _maximumDocumentSize;
|
||||
preferences->_voiceMessages = _voiceMessages;
|
||||
preferences->_videoMessages = _videoMessages;
|
||||
return preferences;
|
||||
}
|
||||
|
||||
- (instancetype)updateDocumentsMode:(TGAutoDownloadMode)mode maximumSize:(int32_t)maximumSize
|
||||
{
|
||||
TGAutoDownloadPreferences *preferences = [[TGAutoDownloadPreferences alloc] init];
|
||||
preferences->_photos = _photos;
|
||||
preferences->_videos = _videos;
|
||||
preferences->_maximumVideoSize = _maximumVideoSize;
|
||||
preferences->_documents = mode;
|
||||
preferences->_maximumDocumentSize = maximumSize;
|
||||
preferences->_voiceMessages = _voiceMessages;
|
||||
preferences->_videoMessages = _videoMessages;
|
||||
return preferences;
|
||||
}
|
||||
|
||||
- (instancetype)updateVoiceMessagesMode:(TGAutoDownloadMode)mode
|
||||
{
|
||||
TGAutoDownloadPreferences *preferences = [[TGAutoDownloadPreferences alloc] init];
|
||||
preferences->_photos = _photos;
|
||||
preferences->_videos = _videos;
|
||||
preferences->_maximumVideoSize = _maximumVideoSize;
|
||||
preferences->_documents = _documents;
|
||||
preferences->_maximumDocumentSize = _maximumDocumentSize;
|
||||
preferences->_voiceMessages = mode;
|
||||
preferences->_videoMessages = _videoMessages;
|
||||
return preferences;
|
||||
}
|
||||
|
||||
- (instancetype)updateVideoMessagesMode:(TGAutoDownloadMode)mode
|
||||
{
|
||||
TGAutoDownloadPreferences *preferences = [[TGAutoDownloadPreferences alloc] init];
|
||||
preferences->_photos = _photos;
|
||||
preferences->_videos = _videos;
|
||||
preferences->_maximumVideoSize = _maximumVideoSize;
|
||||
preferences->_documents = _documents;
|
||||
preferences->_maximumDocumentSize = _maximumDocumentSize;
|
||||
preferences->_voiceMessages = _voiceMessages;
|
||||
preferences->_videoMessages = mode;
|
||||
return preferences;
|
||||
}
|
||||
|
||||
+ (bool)shouldDownload:(TGAutoDownloadMode)mode inChat:(TGAutoDownloadChat)chat networkType:(TGNetworkType)networkType
|
||||
{
|
||||
bool isWiFi = networkType == TGNetworkTypeWiFi;
|
||||
bool isCellular = !isWiFi && networkType != TGNetworkTypeNone;
|
||||
|
||||
bool shouldDownload = false;
|
||||
switch (chat)
|
||||
{
|
||||
case TGAutoDownloadChatContact:
|
||||
if (isCellular)
|
||||
shouldDownload = (mode & TGAutoDownloadModeCellularContacts) != 0;
|
||||
else if (isWiFi)
|
||||
shouldDownload = (mode & TGAutoDownloadModeWifiContacts) != 0;
|
||||
break;
|
||||
|
||||
case TGAutoDownloadChatOtherPrivateChat:
|
||||
if (isCellular)
|
||||
shouldDownload = (mode & TGAutoDownloadModeCellularPrivateChats) != 0;
|
||||
else if (isWiFi)
|
||||
shouldDownload = (mode & TGAutoDownloadModeWifiPrivateChats) != 0;
|
||||
break;
|
||||
|
||||
case TGAutoDownloadChatGroup:
|
||||
if (isCellular)
|
||||
shouldDownload = (mode & TGAutoDownloadModeCellularGroups) != 0;
|
||||
else if (isWiFi)
|
||||
shouldDownload = (mode & TGAutoDownloadModeWifiGroups) != 0;
|
||||
break;
|
||||
|
||||
case TGAutoDownloadChatChannel:
|
||||
if (isCellular)
|
||||
shouldDownload = (mode & TGAutoDownloadModeCellularChannels) != 0;
|
||||
else if (isWiFi)
|
||||
shouldDownload = (mode & TGAutoDownloadModeWifiChannels) != 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return shouldDownload;
|
||||
}
|
||||
|
||||
- (bool)shouldDownloadPhotoInChat:(TGAutoDownloadChat)chat networkType:(TGNetworkType)networkType
|
||||
{
|
||||
if (self.disabled)
|
||||
return false;
|
||||
|
||||
return [TGAutoDownloadPreferences shouldDownload:_photos inChat:chat networkType:networkType];
|
||||
}
|
||||
|
||||
- (bool)shouldDownloadVideoInChat:(TGAutoDownloadChat)chat networkType:(TGNetworkType)networkType
|
||||
{
|
||||
if (self.disabled)
|
||||
return false;
|
||||
|
||||
return [TGAutoDownloadPreferences shouldDownload:_videos inChat:chat networkType:networkType];
|
||||
}
|
||||
|
||||
- (bool)shouldDownloadDocumentInChat:(TGAutoDownloadChat)chat networkType:(TGNetworkType)networkType
|
||||
{
|
||||
if (self.disabled)
|
||||
return false;
|
||||
|
||||
return [TGAutoDownloadPreferences shouldDownload:_documents inChat:chat networkType:networkType];
|
||||
}
|
||||
|
||||
- (bool)shouldDownloadVoiceMessageInChat:(TGAutoDownloadChat)chat networkType:(TGNetworkType)networkType
|
||||
{
|
||||
if (self.disabled)
|
||||
return false;
|
||||
|
||||
return [TGAutoDownloadPreferences shouldDownload:_voiceMessages inChat:chat networkType:networkType];
|
||||
}
|
||||
|
||||
- (bool)shouldDownloadVideoMessageInChat:(TGAutoDownloadChat)chat networkType:(TGNetworkType)networkType
|
||||
{
|
||||
if (self.disabled)
|
||||
return false;
|
||||
|
||||
return [TGAutoDownloadPreferences shouldDownload:_videoMessages inChat:chat networkType:networkType];
|
||||
}
|
||||
|
||||
- (bool)isDefaultPreferences
|
||||
{
|
||||
return [self isEqual:[TGAutoDownloadPreferences defaultPreferences]];
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
if (object == self)
|
||||
return YES;
|
||||
|
||||
if (!object || ![object isKindOfClass:[self class]])
|
||||
return NO;
|
||||
|
||||
TGAutoDownloadPreferences *preferences = (TGAutoDownloadPreferences *)object;
|
||||
return preferences.photos == _photos && preferences.videos == _videos && preferences.documents == _documents && preferences.voiceMessages == _voiceMessages && preferences.videoMessages == _videoMessages && preferences.maximumVideoSize == _maximumVideoSize && preferences.maximumDocumentSize == _maximumDocumentSize && preferences.disabled == _disabled;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
#import <LegacyDataImportImpl/TGPresentationAutoNightPreferences.h>
|
||||
|
||||
@implementation TGPresentationAutoNightPreferences
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_mode = [aDecoder decodeInt32ForKey:@"m"];
|
||||
_brightnessThreshold = [aDecoder decodeDoubleForKey:@"b"];
|
||||
_scheduleStart = [aDecoder decodeInt32ForKey:@"ss"];
|
||||
_scheduleEnd = [aDecoder decodeInt32ForKey:@"se"];
|
||||
_latitude = [aDecoder decodeDoubleForKey:@"lat"];
|
||||
_longitude = [aDecoder decodeDoubleForKey:@"lon"];
|
||||
_cachedLocationName = [aDecoder decodeObjectForKey:@"loc"];
|
||||
_preferredPalette = [aDecoder decodeInt32ForKey:@"p"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
#import <LegacyDataImportImpl/TGProxyItem.h>
|
||||
|
||||
static bool TGObjectCompare(id obj1, id obj2) {
|
||||
if (obj1 == nil && obj2 == nil)
|
||||
return true;
|
||||
|
||||
return [obj1 isEqual:obj2];
|
||||
}
|
||||
|
||||
@implementation TGProxyItem
|
||||
|
||||
- (instancetype)initWithServer:(NSString *)server port:(int16_t)port username:(NSString *)username password:(NSString *)password secret:(NSString *)secret
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_server = server;
|
||||
_port = port;
|
||||
_username = username;
|
||||
_password = password;
|
||||
_secret = secret;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder
|
||||
{
|
||||
return [self initWithServer:[aDecoder decodeObjectForKey:@"server"] port:(int16_t)[aDecoder decodeInt32ForKey:@"port"] username:[aDecoder decodeObjectForKey:@"user"] password:[aDecoder decodeObjectForKey:@"pass"] secret:[aDecoder decodeObjectForKey:@"secret"]];
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder
|
||||
{
|
||||
[aCoder encodeObject:_server forKey:@"server"];
|
||||
[aCoder encodeInt32:_port forKey:@"port"];
|
||||
[aCoder encodeObject:_username forKey:@"user"];
|
||||
[aCoder encodeObject:_password forKey:@"pass"];
|
||||
[aCoder encodeObject:_secret forKey:@"secret"];
|
||||
}
|
||||
|
||||
- (bool)isMTProxy
|
||||
{
|
||||
return _secret.length > 0;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
if (object == self)
|
||||
return true;
|
||||
|
||||
if (!object || ![object isKindOfClass:[self class]])
|
||||
return false;
|
||||
|
||||
TGProxyItem *proxy = (TGProxyItem *)object;
|
||||
|
||||
if (![_server isEqualToString:proxy.server])
|
||||
return false;
|
||||
|
||||
if (_port != proxy.port)
|
||||
return false;
|
||||
|
||||
if (!TGObjectCompare(_username ?: @"", proxy.username ?: @""))
|
||||
return false;
|
||||
|
||||
if (!TGObjectCompare(_password ?: @"", proxy.password ?: @""))
|
||||
return false;
|
||||
|
||||
if (!TGObjectCompare(_secret ?: @"", proxy.secret ?: @""))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -1,197 +0,0 @@
|
|||
import Foundation
|
||||
|
||||
class LegacyBuffer: CustomStringConvertible {
|
||||
var data: UnsafeMutableRawPointer?
|
||||
var _size: UInt = 0
|
||||
private var capacity: UInt = 0
|
||||
private let freeWhenDone: Bool
|
||||
|
||||
var size: Int {
|
||||
return Int(self._size)
|
||||
}
|
||||
|
||||
deinit {
|
||||
if self.freeWhenDone {
|
||||
free(self.data)
|
||||
}
|
||||
}
|
||||
|
||||
init(memory: UnsafeMutableRawPointer?, size: Int, capacity: Int, freeWhenDone: Bool) {
|
||||
self.data = memory
|
||||
self._size = UInt(size)
|
||||
self.capacity = UInt(capacity)
|
||||
self.freeWhenDone = freeWhenDone
|
||||
}
|
||||
|
||||
init() {
|
||||
self.data = nil
|
||||
self._size = 0
|
||||
self.capacity = 0
|
||||
self.freeWhenDone = true
|
||||
}
|
||||
|
||||
convenience init(data: Data?) {
|
||||
self.init()
|
||||
|
||||
if let data = data {
|
||||
data.withUnsafeBytes { bytes in
|
||||
self.appendBytes(bytes, length: UInt(data.count))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func makeData() -> Data {
|
||||
return self.withUnsafeMutablePointer { pointer, size -> Data in
|
||||
if let pointer = pointer {
|
||||
return Data(bytes: pointer.assumingMemoryBound(to: UInt8.self), count: Int(size))
|
||||
} else {
|
||||
return Data()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var description: String {
|
||||
get {
|
||||
var string = ""
|
||||
if let data = self.data {
|
||||
var i: UInt = 0
|
||||
let bytes = data.assumingMemoryBound(to: UInt8.self)
|
||||
while i < _size && i < 8 {
|
||||
string += String(format: "%02x", Int(bytes.advanced(by: Int(i)).pointee))
|
||||
i += 1
|
||||
}
|
||||
if i < _size {
|
||||
string += "...\(_size)b"
|
||||
}
|
||||
} else {
|
||||
string += "<null>"
|
||||
}
|
||||
return string
|
||||
}
|
||||
}
|
||||
|
||||
func appendBytes(_ bytes: UnsafeRawPointer, length: UInt) {
|
||||
if self.capacity < self._size + length {
|
||||
self.capacity = self._size + length + 128
|
||||
if self.data == nil {
|
||||
self.data = malloc(Int(self.capacity))!
|
||||
}
|
||||
else {
|
||||
self.data = realloc(self.data, Int(self.capacity))!
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(self.data?.advanced(by: Int(self._size)), bytes, Int(length))
|
||||
self._size += length
|
||||
}
|
||||
|
||||
func appendBuffer(_ buffer: LegacyBuffer) {
|
||||
if self.capacity < self._size + buffer._size {
|
||||
self.capacity = self._size + buffer._size + 128
|
||||
if self.data == nil {
|
||||
self.data = malloc(Int(self.capacity))!
|
||||
}
|
||||
else {
|
||||
self.data = realloc(self.data, Int(self.capacity))!
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(self.data?.advanced(by: Int(self._size)), buffer.data, Int(buffer._size))
|
||||
}
|
||||
|
||||
func appendInt32(_ value: Int32) {
|
||||
var v = value
|
||||
self.appendBytes(&v, length: 4)
|
||||
}
|
||||
|
||||
func appendInt64(_ value: Int64) {
|
||||
var v = value
|
||||
self.appendBytes(&v, length: 8)
|
||||
}
|
||||
|
||||
func appendDouble(_ value: Double) {
|
||||
var v = value
|
||||
self.appendBytes(&v, length: 8)
|
||||
}
|
||||
|
||||
func withUnsafeMutablePointer<R>(_ f: (UnsafeMutableRawPointer?, UInt) -> R) -> R {
|
||||
return f(self.data, self._size)
|
||||
}
|
||||
}
|
||||
|
||||
class LegacyBufferReader {
|
||||
private let buffer: LegacyBuffer
|
||||
private(set) var offset: UInt = 0
|
||||
|
||||
init(_ buffer: LegacyBuffer) {
|
||||
self.buffer = buffer
|
||||
}
|
||||
|
||||
func reset() {
|
||||
self.offset = 0
|
||||
}
|
||||
|
||||
func skip(_ count: Int) {
|
||||
self.offset = min(self.buffer._size, self.offset + UInt(count))
|
||||
}
|
||||
|
||||
func readInt32() -> Int32? {
|
||||
if self.offset + 4 <= self.buffer._size {
|
||||
let value: Int32 = buffer.data!.advanced(by: Int(self.offset)).assumingMemoryBound(to: Int32.self).pointee
|
||||
self.offset += 4
|
||||
return value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func readInt64() -> Int64? {
|
||||
if self.offset + 8 <= self.buffer._size {
|
||||
let value: Int64 = buffer.data!.advanced(by: Int(self.offset)).assumingMemoryBound(to: Int64.self).pointee
|
||||
self.offset += 8
|
||||
return value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func readDouble() -> Double? {
|
||||
if self.offset + 8 <= self.buffer._size {
|
||||
let value: Double = buffer.data!.advanced(by: Int(self.offset)).assumingMemoryBound(to: Double.self).pointee
|
||||
self.offset += 8
|
||||
return value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func readBytesAsInt32(_ count: Int) -> Int32? {
|
||||
if count == 0 {
|
||||
return 0
|
||||
}
|
||||
guard count > 0, count <= 4, self.offset + UInt(count) <= self.buffer._size else {
|
||||
return nil
|
||||
}
|
||||
guard let bufferData = self.buffer.data else {
|
||||
return nil
|
||||
}
|
||||
var value: Int32 = 0
|
||||
memcpy(&value, bufferData.advanced(by: Int(self.offset)), count)
|
||||
self.offset += UInt(count)
|
||||
return value
|
||||
}
|
||||
|
||||
func readBuffer(_ count: Int) -> LegacyBuffer? {
|
||||
if count >= 0 && self.offset + UInt(count) <= self.buffer._size {
|
||||
let buffer = LegacyBuffer()
|
||||
buffer.appendBytes((self.buffer.data?.advanced(by: Int(self.offset)))!, length: UInt(count))
|
||||
self.offset += UInt(count)
|
||||
return buffer
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func withReadBufferNoCopy<T>(_ count: Int, _ f: (LegacyBuffer) -> T) -> T? {
|
||||
if count >= 0 && self.offset + UInt(count) <= self.buffer._size {
|
||||
return f(LegacyBuffer(memory: self.buffer.data!.advanced(by: Int(self.offset)), size: count, capacity: count, freeWhenDone: false))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
@ -1,780 +0,0 @@
|
|||
import Foundation
|
||||
import TelegramCore
|
||||
import SyncCore
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import LegacyComponents
|
||||
|
||||
private let reportedLayer_hash: Int32 = -717538193
|
||||
private let layer_hash: Int32 = 849537378
|
||||
private let seq_out_hash: Int32 = -737765753
|
||||
private let seq_in_hash: Int32 = -7646011
|
||||
|
||||
private let defaultPrime: Data = {
|
||||
let bytes: [UInt8] = [
|
||||
0xc7, 0x1c, 0xae, 0xb9, 0xc6, 0xb1, 0xc9, 0x04, 0x8e, 0x6c, 0x52, 0x2f,
|
||||
0x70, 0xf1, 0x3f, 0x73, 0x98, 0x0d, 0x40, 0x23, 0x8e, 0x3e, 0x21, 0xc1,
|
||||
0x49, 0x34, 0xd0, 0x37, 0x56, 0x3d, 0x93, 0x0f, 0x48, 0x19, 0x8a, 0x0a,
|
||||
0xa7, 0xc1, 0x40, 0x58, 0x22, 0x94, 0x93, 0xd2, 0x25, 0x30, 0xf4, 0xdb,
|
||||
0xfa, 0x33, 0x6f, 0x6e, 0x0a, 0xc9, 0x25, 0x13, 0x95, 0x43, 0xae, 0xd4,
|
||||
0x4c, 0xce, 0x7c, 0x37, 0x20, 0xfd, 0x51, 0xf6, 0x94, 0x58, 0x70, 0x5a,
|
||||
0xc6, 0x8c, 0xd4, 0xfe, 0x6b, 0x6b, 0x13, 0xab, 0xdc, 0x97, 0x46, 0x51,
|
||||
0x29, 0x69, 0x32, 0x84, 0x54, 0xf1, 0x8f, 0xaf, 0x8c, 0x59, 0x5f, 0x64,
|
||||
0x24, 0x77, 0xfe, 0x96, 0xbb, 0x2a, 0x94, 0x1d, 0x5b, 0xcd, 0x1d, 0x4a,
|
||||
0xc8, 0xcc, 0x49, 0x88, 0x07, 0x08, 0xfa, 0x9b, 0x37, 0x8e, 0x3c, 0x4f,
|
||||
0x3a, 0x90, 0x60, 0xbe, 0xe6, 0x7c, 0xf9, 0xa4, 0xa4, 0xa6, 0x95, 0x81,
|
||||
0x10, 0x51, 0x90, 0x7e, 0x16, 0x27, 0x53, 0xb5, 0x6b, 0x0f, 0x6b, 0x41,
|
||||
0x0d, 0xba, 0x74, 0xd8, 0xa8, 0x4b, 0x2a, 0x14, 0xb3, 0x14, 0x4e, 0x0e,
|
||||
0xf1, 0x28, 0x47, 0x54, 0xfd, 0x17, 0xed, 0x95, 0x0d, 0x59, 0x65, 0xb4,
|
||||
0xb9, 0xdd, 0x46, 0x58, 0x2d, 0xb1, 0x17, 0x8d, 0x16, 0x9c, 0x6b, 0xc4,
|
||||
0x65, 0xb0, 0xd6, 0xff, 0x9c, 0xa3, 0x92, 0x8f, 0xef, 0x5b, 0x9a, 0xe4,
|
||||
0xe4, 0x18, 0xfc, 0x15, 0xe8, 0x3e, 0xbe, 0xa0, 0xf8, 0x7f, 0xa9, 0xff,
|
||||
0x5e, 0xed, 0x70, 0x05, 0x0d, 0xed, 0x28, 0x49, 0xf4, 0x7b, 0xf9, 0x59,
|
||||
0xd9, 0x56, 0x85, 0x0c, 0xe9, 0x29, 0x85, 0x1f, 0x0d, 0x81, 0x15, 0xf6,
|
||||
0x35, 0xb1, 0x05, 0xee, 0x2e, 0x4e, 0x15, 0xd0, 0x4b, 0x24, 0x54, 0xbf,
|
||||
0x6f, 0x4f, 0xad, 0xf0, 0x34, 0xb1, 0x04, 0x03, 0x11, 0x9c, 0xd8, 0xe3,
|
||||
0xb9, 0x2f, 0xcc, 0x5b
|
||||
]
|
||||
var data = Data(count: bytes.count)
|
||||
data.withUnsafeMutableBytes { (dst: UnsafeMutablePointer<UInt8>) -> Void in
|
||||
for i in 0 ..< bytes.count {
|
||||
dst.advanced(by: i).pointee = bytes[i]
|
||||
}
|
||||
}
|
||||
return data
|
||||
}()
|
||||
|
||||
@objc(TGEncryptionKeyData) private final class TGEncryptionKeyData: NSObject, NSCoding {
|
||||
let keyId: Int64
|
||||
let key: Data
|
||||
let firstSeqOut: Int32
|
||||
|
||||
init?(coder aDecoder: NSCoder) {
|
||||
self.keyId = aDecoder.decodeInt64(forKey: "keyId")
|
||||
self.key = (aDecoder.decodeObject(forKey: "key") as? Data) ?? Data()
|
||||
self.firstSeqOut = aDecoder.decodeInt32(forKey: "firstSeqOut")
|
||||
}
|
||||
|
||||
func encode(with aCoder: NSCoder) {
|
||||
assertionFailure()
|
||||
}
|
||||
}
|
||||
|
||||
private struct SecretChatData {
|
||||
let accessHash: Int64
|
||||
let handshakeState: Int32
|
||||
let rekeyState: SecretChatRekeySessionState?
|
||||
}
|
||||
|
||||
private func readSecretChatParticipantData(accountPeerId: PeerId, data: Data) -> (SecretChatRole, PeerId)? {
|
||||
let reader = LegacyBufferReader(LegacyBuffer(data: data))
|
||||
|
||||
guard reader.readInt32() == Int32(bitPattern: 0xabcdef12) else {
|
||||
return nil
|
||||
}
|
||||
guard let formatVersion = reader.readInt32(), formatVersion >= 2 else {
|
||||
return nil
|
||||
}
|
||||
reader.skip(4)
|
||||
|
||||
guard let adminId = reader.readInt32() else {
|
||||
return nil
|
||||
}
|
||||
guard let count = reader.readInt32() else {
|
||||
return nil
|
||||
}
|
||||
var ids: [Int32] = []
|
||||
for _ in 0 ..< Int(count) {
|
||||
guard let id = reader.readInt32() else {
|
||||
return nil
|
||||
}
|
||||
reader.skip(4)
|
||||
reader.skip(4)
|
||||
ids.append(id)
|
||||
}
|
||||
|
||||
guard let otherPeerId = ids.first else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return (adminId == accountPeerId.id ? .creator : .participant, PeerId(namespace: Namespaces.Peer.CloudUser, id: otherPeerId))
|
||||
}
|
||||
|
||||
private func readSecretChatData(reader: LegacyBufferReader) -> SecretChatData? {
|
||||
guard let version = reader.readBytesAsInt32(1) else {
|
||||
return nil
|
||||
}
|
||||
if version != 3 {
|
||||
return nil
|
||||
}
|
||||
reader.skip(8)
|
||||
|
||||
guard let accessHash = reader.readInt64() else {
|
||||
return nil
|
||||
}
|
||||
guard let _ = reader.readInt64() else {
|
||||
return nil
|
||||
}
|
||||
guard let handshakeState = reader.readInt32() else {
|
||||
return nil
|
||||
}
|
||||
guard let currentRekeyExchangeId = reader.readInt64() else {
|
||||
return nil
|
||||
}
|
||||
guard let currentRekeyIsInitiatedByLocalClient = reader.readBytesAsInt32(1) else {
|
||||
return nil
|
||||
}
|
||||
guard let currentRekeyNumberLength = reader.readInt32() else {
|
||||
return nil
|
||||
}
|
||||
var currentRekeyNumber: Data?
|
||||
if currentRekeyNumberLength > 0 {
|
||||
guard let value = reader.readBuffer(Int(currentRekeyNumberLength))?.makeData() else {
|
||||
return nil
|
||||
}
|
||||
currentRekeyNumber = value
|
||||
}
|
||||
guard let currentRekeyKeyLength = reader.readInt32() else {
|
||||
return nil
|
||||
}
|
||||
var currentRekeyKey: Data?
|
||||
if currentRekeyKeyLength > 0 {
|
||||
guard let value = reader.readBuffer(Int(currentRekeyKeyLength))?.makeData() else {
|
||||
return nil
|
||||
}
|
||||
currentRekeyKey = value
|
||||
}
|
||||
guard let currentRekeyKeyId = reader.readInt64() else {
|
||||
return nil
|
||||
}
|
||||
|
||||
var rekeyState: SecretChatRekeySessionState?
|
||||
if currentRekeyExchangeId != 0 {
|
||||
let innerState: SecretChatRekeySessionData?
|
||||
if currentRekeyIsInitiatedByLocalClient != 0, let currentRekeyNumber = currentRekeyNumber {
|
||||
innerState = .requested(a: MemoryBuffer(data: currentRekeyNumber), config: SecretChatEncryptionConfig(g: 3, p: MemoryBuffer(data: defaultPrime), version: 0))
|
||||
} else if currentRekeyIsInitiatedByLocalClient == 0, let currentRekeyKey = currentRekeyKey, currentRekeyKeyId != 0 {
|
||||
innerState = .accepted(key: MemoryBuffer(data: currentRekeyKey), keyFingerprint: currentRekeyKeyId)
|
||||
} else {
|
||||
innerState = nil
|
||||
}
|
||||
if let innerState = innerState {
|
||||
rekeyState = SecretChatRekeySessionState(id: currentRekeyExchangeId, data: innerState)
|
||||
}
|
||||
}
|
||||
|
||||
return SecretChatData(accessHash: accessHash, handshakeState: handshakeState, rekeyState: rekeyState)
|
||||
}
|
||||
|
||||
let registeredAttachmentParsers: Bool = {
|
||||
let parsers: [(Int32, TGMediaAttachmentParser)] = [
|
||||
(TGActionMediaAttachmentType, TGActionMediaAttachment()),
|
||||
(TGImageMediaAttachmentType, TGImageMediaAttachment()),
|
||||
(TGLocationMediaAttachmentType, TGLocationMediaAttachment()),
|
||||
(TGVideoMediaAttachmentType, TGVideoMediaAttachment()),
|
||||
(Int32(bitPattern: 0xB90A5663), TGContactMediaAttachment()),
|
||||
(Int32(bitPattern: 0xE6C64318), TGDocumentMediaAttachment()),
|
||||
(TGAudioMediaAttachmentType, TGAudioMediaAttachment()),
|
||||
(Int32(bitPattern: 0x8C2E3CCE), TGMessageEntitiesAttachment()),
|
||||
(Int32(bitPattern: 0x944DE6B6), TGLocalMessageMetaMediaAttachment()),
|
||||
(TGAuthorSignatureMediaAttachmentType, TGAuthorSignatureMediaAttachment()),
|
||||
(TGInvoiceMediaAttachmentType, TGInvoiceMediaAttachment()),
|
||||
(TGGameAttachmentType, TGGameMediaAttachment()),
|
||||
(Int32(bitPattern: 0xA3F4C8F5), TGViaUserAttachment()),
|
||||
(TGBotContextResultAttachmentType, TGBotContextResultAttachment()),
|
||||
(TGReplyMarkupAttachmentType, TGReplyMarkupAttachment()),
|
||||
(TGWebPageMediaAttachmentType, TGWebPageMediaAttachment()),
|
||||
(TGReplyMessageMediaAttachmentType, TGReplyMessageMediaAttachment()),
|
||||
(TGAudioMediaAttachmentType, TGAudioMediaAttachment()),
|
||||
(Int32(bitPattern: 0xaa1050c1), TGForwardedMessageMediaAttachment())
|
||||
]
|
||||
for (id, parser) in parsers {
|
||||
TGMessage.registerMediaAttachmentParser(id, parser: parser)
|
||||
}
|
||||
return true
|
||||
}()
|
||||
|
||||
private func parseSecretChatData(peerId: PeerId, data: Data, unreadCount: Int32) -> (SecretChatData, [MessageId.Namespace: PeerReadState], Int32)? {
|
||||
let reader = LegacyBufferReader(LegacyBuffer(data: data))
|
||||
guard let magic = reader.readInt32() else {
|
||||
return nil
|
||||
}
|
||||
var version: Int32 = 1
|
||||
if magic == 0x7acde441 {
|
||||
guard let value = reader.readInt32() else {
|
||||
return nil
|
||||
}
|
||||
version = value
|
||||
}
|
||||
|
||||
if version < 2 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _ in 0 ..< 3 {
|
||||
guard let length = reader.readInt32() else {
|
||||
return nil
|
||||
}
|
||||
reader.skip(Int(length))
|
||||
}
|
||||
|
||||
guard let hasEncryptedData = reader.readBytesAsInt32(1), hasEncryptedData == 1 else {
|
||||
return nil
|
||||
}
|
||||
guard let secretChatData = readSecretChatData(reader: reader) else {
|
||||
return nil
|
||||
}
|
||||
reader.skip(4)
|
||||
reader.skip(4)
|
||||
reader.skip(8)
|
||||
reader.skip(4)
|
||||
reader.skip(4)
|
||||
reader.skip(4)
|
||||
reader.skip(4)
|
||||
guard let maxReadDate = reader.readInt32() else {
|
||||
return nil
|
||||
}
|
||||
guard let maxOutgoingReadDate = reader.readInt32() else {
|
||||
return nil
|
||||
}
|
||||
guard let messageDate = reader.readInt32() else {
|
||||
return nil
|
||||
}
|
||||
guard let minMessageDate = reader.readInt32() else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let readStates: [MessageId.Namespace: PeerReadState] = [
|
||||
Namespaces.Message.SecretIncoming: .indexBased(maxIncomingReadIndex: MessageIndex(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: 1), timestamp: maxReadDate), maxOutgoingReadIndex: MessageIndex.lowerBound(peerId: peerId), count: 0, markedUnread: false),
|
||||
Namespaces.Message.Local: .indexBased(maxIncomingReadIndex: MessageIndex.lowerBound(peerId: peerId), maxOutgoingReadIndex: MessageIndex(id: MessageId(peerId: peerId, namespace: Namespaces.Message.Local, id: 1), timestamp: maxOutgoingReadDate), count: 0, markedUnread: false)
|
||||
]
|
||||
return (secretChatData, readStates, max(messageDate, minMessageDate))
|
||||
}
|
||||
|
||||
private enum CustomPropertyKey {
|
||||
case string(String)
|
||||
case hash(Int32)
|
||||
}
|
||||
|
||||
private func loadLegacyPeerCustomProperyData(database: SqliteInterface, peerId: Int64, key: CustomPropertyKey) -> Data? {
|
||||
var propertiesData: Data?
|
||||
database.select("SELECT custom_properties FROM peers_v29 WHERE pid=\(peerId)", { cursor in
|
||||
propertiesData = cursor.getData(at: 0)
|
||||
return false
|
||||
})
|
||||
if let propertiesData = propertiesData {
|
||||
let keyHash: Int32
|
||||
switch key {
|
||||
case let .string(string):
|
||||
keyHash = HashFunctions.murMurHash32(string)
|
||||
case let .hash(hash):
|
||||
keyHash = hash
|
||||
}
|
||||
let reader = LegacyBufferReader(LegacyBuffer(data: propertiesData))
|
||||
|
||||
guard let _ = reader.readInt32() else {
|
||||
return nil
|
||||
}
|
||||
guard let count = reader.readInt32() else {
|
||||
return nil
|
||||
}
|
||||
for _ in 0 ..< Int(count) {
|
||||
guard let valueKey = reader.readInt32() else {
|
||||
return nil
|
||||
}
|
||||
guard let valueLength = reader.readInt32() else {
|
||||
return nil
|
||||
}
|
||||
if valueKey == keyHash {
|
||||
return reader.readBuffer(Int(valueLength))?.makeData()
|
||||
}
|
||||
reader.skip(Int(valueLength))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
private func loadLegacyPeerCustomProperyInt32(database: SqliteInterface, peerId: Int64, key: CustomPropertyKey) -> Int32? {
|
||||
guard let data = loadLegacyPeerCustomProperyData(database: database, peerId: peerId, key: key), data.count == 4 else {
|
||||
return nil
|
||||
}
|
||||
var result: Int32 = 0
|
||||
withUnsafeMutablePointer(to: &result, { bytes -> Void in
|
||||
data.copyBytes(to: UnsafeMutableRawPointer(bytes).assumingMemoryBound(to: UInt8.self), from: 0 ..< 4)
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
private func loadLegacyMessages(account: TemporaryAccount, basePath: String, accountPeerId: PeerId, peerId: PeerId, userPeerId: PeerId, database: SqliteInterface, conversationId: Int64, expectedTotalCount: Int32) -> Signal<Float, NoError> {
|
||||
return Signal { subscriber in
|
||||
subscriber.putNext(0.0)
|
||||
|
||||
var copyLocalFiles: [(MediaResource, String)] = []
|
||||
var messages: [StoreMessage] = []
|
||||
|
||||
Logger.shared.log("loadLegacyMessages", "begin peerId \(peerId) conversationId \(conversationId) count \(expectedTotalCount)")
|
||||
|
||||
database.select("CREATE INDEX IF NOT EXISTS random_ids_mid ON random_ids_v29 (mid)", { _ in
|
||||
return true
|
||||
})
|
||||
|
||||
var messageIndex: Int32 = -1
|
||||
let reportBase = max(1, expectedTotalCount / 100)
|
||||
|
||||
database.select("SELECT mid, message, media, from_id, dstate, date, flags, localMid, content_properties FROM messages_v29 WHERE cid=\(conversationId)", { cursor in
|
||||
messageIndex += 1
|
||||
|
||||
#if DEBUG
|
||||
//usleep(500000)
|
||||
#endif
|
||||
|
||||
if messageIndex % reportBase == 0 {
|
||||
subscriber.putNext(min(1.0, Float(messageIndex) / Float(expectedTotalCount)))
|
||||
}
|
||||
|
||||
let messageId = cursor.getInt32(at: 0)
|
||||
|
||||
//Logger.shared.log("loadLegacyMessages", "import message \(messageId)")
|
||||
|
||||
var globallyUniqueId: Int64?
|
||||
database.select("SELECT random_id FROM random_ids_v29 where mid=\(messageId)", { innerCursor in
|
||||
globallyUniqueId = innerCursor.getInt64(at: 0)
|
||||
return false
|
||||
})
|
||||
|
||||
let text = cursor.getString(at: 1)
|
||||
let fromId = cursor.getInt64(at: 3)
|
||||
let deliveryState = cursor.getInt32(at: 4)
|
||||
let timestamp = cursor.getInt32(at: 5)
|
||||
let autoremoveTimeout = cursor.getInt32(at: 7)
|
||||
let contentPropertiesData = cursor.getData(at: 8)
|
||||
|
||||
let parsedAuthorId: PeerId
|
||||
let parsedId: StoreMessageId
|
||||
var parsedFlags: StoreMessageFlags = []
|
||||
var parsedAttributes: [MessageAttribute] = []
|
||||
var parsedMedia: [Media] = []
|
||||
var parsedGroupingKey: Int64?
|
||||
|
||||
if fromId == accountPeerId.id {
|
||||
parsedAuthorId = accountPeerId
|
||||
parsedId = .Partial(peerId, Namespaces.Message.Local)
|
||||
} else {
|
||||
parsedAuthorId = userPeerId
|
||||
parsedId = .Partial(peerId, Namespaces.Message.SecretIncoming)
|
||||
parsedFlags.insert(.Incoming)
|
||||
}
|
||||
|
||||
if deliveryState != 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
if !contentPropertiesData.isEmpty {
|
||||
if let contentProperties = TGMessage.parseContentProperties(contentPropertiesData) {
|
||||
for (_, value) in contentProperties {
|
||||
if let value = value as? TGMessageGroupedIdContentProperty {
|
||||
parsedGroupingKey = value.groupedId
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Logger.shared.log("loadLegacyMessages", "message \(messageId) read content properties")
|
||||
|
||||
let media = cursor.getData(at: 2)
|
||||
if let mediaList = TGMessage.parseMediaAttachments(media) {
|
||||
for item in mediaList {
|
||||
if let item = item as? TGImageMediaAttachment {
|
||||
let mediaId = MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64())
|
||||
var representations: [TelegramMediaImageRepresentation] = []
|
||||
if let allSizes = item.imageInfo?.allSizes() as? [String: NSValue] {
|
||||
|
||||
for (imageUrl, sizeValue) in allSizes {
|
||||
var resource: TelegramMediaResource = LocalFileMediaResource(fileId: arc4random64())
|
||||
var resourcePath: String?
|
||||
if let (path, updatedResource) = pathAndResourceFromEncryptedFileUrl(basePath: basePath, url: imageUrl, type: .image) {
|
||||
resource = updatedResource
|
||||
copyLocalFiles.append((updatedResource, path))
|
||||
resourcePath = path
|
||||
} else if imageUrl.hasPrefix("file://"), let path = URL(string: imageUrl)?.path {
|
||||
copyLocalFiles.append((resource, path))
|
||||
resourcePath = path
|
||||
}
|
||||
|
||||
var dimensions = sizeValue.cgSizeValue
|
||||
if let resourcePath = resourcePath, let image = UIImage(contentsOfFile: resourcePath) {
|
||||
dimensions = image.size
|
||||
}
|
||||
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(dimensions), resource: resource, progressiveSizes: []))
|
||||
}
|
||||
}
|
||||
|
||||
if item.localImageId != 0 {
|
||||
let fullSizePath = basePath + "/Documents/files/image-local-\(String(item.localImageId, radix: 16))/image.jpg"
|
||||
if let image = UIImage(contentsOfFile: fullSizePath) {
|
||||
let resource: TelegramMediaResource = LocalFileMediaResource(fileId: arc4random64())
|
||||
copyLocalFiles.append((resource, fullSizePath))
|
||||
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(image.size), resource: resource, progressiveSizes: []))
|
||||
}
|
||||
}
|
||||
|
||||
parsedMedia.append(TelegramMediaImage(imageId: mediaId, representations: representations, immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: []))
|
||||
} else if let item = item as? TGVideoMediaAttachment {
|
||||
let mediaId = MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64())
|
||||
var representations: [TelegramMediaImageRepresentation] = []
|
||||
if let allSizes = item.thumbnailInfo?.allSizes() as? [String: NSValue] {
|
||||
for (imageUrl, sizeValue) in allSizes {
|
||||
var resource: TelegramMediaResource = LocalFileMediaResource(fileId: arc4random64())
|
||||
if let (path, updatedResource) = pathAndResourceFromEncryptedFileUrl(basePath: basePath, url: imageUrl, type: .image) {
|
||||
resource = updatedResource
|
||||
copyLocalFiles.append((updatedResource, path))
|
||||
} else if imageUrl.hasPrefix("file://"), let path = URL(string: imageUrl)?.path {
|
||||
copyLocalFiles.append((resource, path))
|
||||
}
|
||||
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(sizeValue.cgSizeValue), resource: resource, progressiveSizes: []))
|
||||
}
|
||||
}
|
||||
|
||||
var resource: TelegramMediaResource = LocalFileMediaResource(fileId: arc4random64())
|
||||
|
||||
var attributes: [TelegramMediaFileAttribute] = []
|
||||
attributes.append(.Video(duration: Int(item.duration), size: PixelDimensions(item.dimensions), flags: item.roundMessage ? .instantRoundVideo : []))
|
||||
|
||||
var size: Int32 = 0
|
||||
if let videoUrl = item.videoInfo?.url(withQuality: 1, actualQuality: nil, actualSize: &size) {
|
||||
if let path = pathFromLegacyLocalVideoUrl(basePath: basePath, url: videoUrl) {
|
||||
copyLocalFiles.append((resource, path))
|
||||
} else if let (path, updatedResource) = pathAndResourceFromEncryptedFileUrl(basePath: basePath, url: videoUrl, type: .video) {
|
||||
resource = updatedResource
|
||||
copyLocalFiles.append((updatedResource, path))
|
||||
} else if videoUrl.hasPrefix("file://"), let path = URL(string: videoUrl)?.path {
|
||||
copyLocalFiles.append((resource, path))
|
||||
}
|
||||
}
|
||||
parsedMedia.append(TelegramMediaFile(fileId: mediaId, partialReference: nil, resource: resource, previewRepresentations: representations, videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/mp4", size: size == 0 ? nil : Int(size), attributes: attributes))
|
||||
} else if let item = item as? TGAudioMediaAttachment {
|
||||
let mediaId = MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64())
|
||||
let representations: [TelegramMediaImageRepresentation] = []
|
||||
|
||||
var resource: TelegramMediaResource = LocalFileMediaResource(fileId: arc4random64())
|
||||
|
||||
var attributes: [TelegramMediaFileAttribute] = []
|
||||
attributes.append(.Audio(isVoice: true, duration: Int(item.duration), title: nil, performer: nil, waveform: nil))
|
||||
|
||||
let size: Int32 = item.fileSize
|
||||
let audioUrl = item.audioUri ?? ""
|
||||
|
||||
if let path = pathFromLegacyLocalVideoUrl(basePath: basePath, url: audioUrl) {
|
||||
copyLocalFiles.append((resource, path))
|
||||
} else if let (path, updatedResource) = pathAndResourceFromEncryptedFileUrl(basePath: basePath, url: audioUrl, type: .audio) {
|
||||
resource = updatedResource
|
||||
copyLocalFiles.append((updatedResource, path))
|
||||
} else if audioUrl.hasPrefix("file://"), let path = URL(string: audioUrl)?.path {
|
||||
copyLocalFiles.append((resource, path))
|
||||
}
|
||||
parsedMedia.append(TelegramMediaFile(fileId: mediaId, partialReference: nil, resource: resource, previewRepresentations: representations, videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: size == 0 ? nil : Int(size), attributes: attributes))
|
||||
} else if let item = item as? TGDocumentMediaAttachment {
|
||||
let mediaId = MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64())
|
||||
var representations: [TelegramMediaImageRepresentation] = []
|
||||
if let allSizes = (item.thumbnailInfo?.allSizes()) as? [String: NSValue] {
|
||||
for (imageUrl, sizeValue) in allSizes {
|
||||
var resource: TelegramMediaResource = LocalFileMediaResource(fileId: arc4random64())
|
||||
if let (path, updatedResource) = pathAndResourceFromEncryptedFileUrl(basePath: basePath, url: imageUrl, type: .image) {
|
||||
resource = updatedResource
|
||||
copyLocalFiles.append((updatedResource, path))
|
||||
} else if imageUrl.hasPrefix("file://"), let path = URL(string: imageUrl)?.path {
|
||||
copyLocalFiles.append((resource, path))
|
||||
} else if let updatedResource = resourceFromLegacyImageUrl(imageUrl) {
|
||||
resource = updatedResource
|
||||
copyLocalFiles.append((resource, pathFromLegacyImageUrl(basePath: basePath, url: imageUrl)))
|
||||
}
|
||||
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(sizeValue.cgSizeValue), resource: resource, progressiveSizes: []))
|
||||
}
|
||||
}
|
||||
|
||||
var resource: TelegramMediaResource = LocalFileMediaResource(fileId: arc4random64())
|
||||
|
||||
var attributes: [TelegramMediaFileAttribute] = []
|
||||
var fileName = "file"
|
||||
if let itemAttributes = item.attributes {
|
||||
for attribute in itemAttributes {
|
||||
if let attribute = attribute as? TGDocumentAttributeFilename {
|
||||
attributes.append(.FileName(fileName: attribute.filename ?? "file"))
|
||||
fileName = attribute.filename ?? "file"
|
||||
} else if let attribute = attribute as? TGDocumentAttributeAudio {
|
||||
let title = attribute.title ?? ""
|
||||
let performer = attribute.performer ?? ""
|
||||
var waveform: MemoryBuffer?
|
||||
if let data = attribute.waveform {
|
||||
waveform = MemoryBuffer(data: data.bitstream()!)
|
||||
}
|
||||
attributes.append(.Audio(isVoice: attribute.isVoice, duration: Int(attribute.duration), title: title.isEmpty ? nil : title, performer: performer.isEmpty ? nil : performer, waveform: waveform))
|
||||
} else if let _ = attribute as? TGDocumentAttributeAnimated {
|
||||
attributes.append(.Animated)
|
||||
} else if let attribute = attribute as? TGDocumentAttributeVideo {
|
||||
attributes.append(.Video(duration: Int(attribute.duration), size: PixelDimensions(attribute.size), flags: attribute.isRoundMessage ? .instantRoundVideo : []))
|
||||
} else if let attribute = attribute as? TGDocumentAttributeSticker {
|
||||
var packReference: StickerPackReference?
|
||||
if let reference = attribute.packReference as? TGStickerPackIdReference {
|
||||
packReference = .id(id: reference.packId, accessHash: reference.packAccessHash)
|
||||
} else if let reference = attribute.packReference as? TGStickerPackShortnameReference {
|
||||
packReference = .name(reference.shortName ?? "")
|
||||
}
|
||||
attributes.append(.Sticker(displayText: attribute.alt ?? "", packReference: packReference, maskData: nil))
|
||||
} else if let attribute = attribute as? TGDocumentAttributeImageSize {
|
||||
attributes.append(.ImageSize(size: PixelDimensions(attribute.size)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let documentUri = item.documentUri ?? ""
|
||||
|
||||
let size: Int32 = item.size
|
||||
if documentUri.hasPrefix("file://"), let path = URL(string: documentUri)?.path {
|
||||
copyLocalFiles.append((resource, path))
|
||||
} else if let (path, updatedResource) = pathAndResourceFromEncryptedFileUrl(basePath: basePath, url: documentUri, type: .document(fileName: fileName)) {
|
||||
resource = updatedResource
|
||||
copyLocalFiles.append((resource, path))
|
||||
} else if item.localDocumentId != 0 {
|
||||
copyLocalFiles.append((resource, pathFromLegacyFile(basePath: basePath, fileId: item.localDocumentId, isLocal: true, fileName: TGDocumentMediaAttachment.safeFileName(forFileName: fileName) ?? "")))
|
||||
} else if item.documentId != 0 {
|
||||
copyLocalFiles.append((resource, pathFromLegacyFile(basePath: basePath, fileId: item.documentId, isLocal: false, fileName: TGDocumentMediaAttachment.safeFileName(forFileName: fileName) ?? "")))
|
||||
}
|
||||
parsedMedia.append(TelegramMediaFile(fileId: mediaId, partialReference: nil, resource: resource, previewRepresentations: representations, videoThumbnails: [], immediateThumbnailData: nil, mimeType: item.mimeType ?? "application/octet-stream", size: size == 0 ? nil : Int(size), attributes: attributes))
|
||||
} else if let item = item as? TGActionMediaAttachment {
|
||||
if item.actionType == TGMessageActionEncryptedChatMessageLifetime, let actionData = item.actionData, let timeout = actionData["messageLifetime"] as? Int32 {
|
||||
|
||||
parsedMedia.append(TelegramMediaAction(action: .messageAutoremoveTimeoutUpdated(timeout)))
|
||||
}
|
||||
} else if let item = item as? TGContactMediaAttachment {
|
||||
parsedMedia.append(TelegramMediaContact(firstName: item.firstName ?? "", lastName: item.lastName ?? "", phoneNumber: item.phoneNumber ?? "", peerId: nil, vCardData: nil))
|
||||
} else if let item = item as? TGLocationMediaAttachment {
|
||||
var venue: MapVenue?
|
||||
if let v = item.venue {
|
||||
venue = MapVenue(title: v.title ?? "", address: v.address ?? "", provider: v.provider == "" ? nil : v.provider, id: v.venueId == "" ? nil : v.venueId, type: v.type == "" ? nil : v.type)
|
||||
}
|
||||
parsedMedia.append(TelegramMediaMap(latitude: item.latitude, longitude: item.longitude, heading: nil, accuracyRadius: nil, geoPlace: nil, venue: venue, liveBroadcastingTimeout: nil, liveProximityNotificationRadius: nil))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Logger.shared.log("loadLegacyMessages", "message \(messageId) read media")
|
||||
|
||||
if autoremoveTimeout != 0 {
|
||||
var countdownBeginTime: Int32?
|
||||
database.select("SELECT date FROM selfdestruct_v29 where mid=\(messageId)", { innerCursor in
|
||||
countdownBeginTime = innerCursor.getInt32(at: 0) - autoremoveTimeout
|
||||
return false
|
||||
})
|
||||
parsedAttributes.append(AutoremoveTimeoutMessageAttribute(timeout: autoremoveTimeout, countdownBeginTime: countdownBeginTime))
|
||||
}
|
||||
|
||||
let (parsedTags, parsedGlobalTags) = tagsForStoreMessage(incoming: parsedFlags.contains(.Incoming), attributes: parsedAttributes, media: parsedMedia, textEntities: nil, isPinned: false)
|
||||
messages.append(StoreMessage(id: parsedId, globallyUniqueId: globallyUniqueId, groupingKey: parsedGroupingKey, threadId: nil, timestamp: timestamp, flags: parsedFlags, tags: parsedTags, globalTags: parsedGlobalTags, localTags: [], forwardInfo: nil, authorId: parsedAuthorId, text: text, attributes: parsedAttributes, media: parsedMedia))
|
||||
|
||||
//Logger.shared.log("loadLegacyMessages", "message \(messageId) completed")
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
let disposable = (account.postbox.transaction { transaction -> Void in
|
||||
//Logger.shared.log("loadLegacyMessages", "conversation \(conversationId) storing messages")
|
||||
let _ = transaction.addMessages(messages, location: .UpperHistoryBlock)
|
||||
|
||||
//Logger.shared.log("loadLegacyMessages", "conversation \(conversationId) copying \(copyLocalFiles.count) files")
|
||||
|
||||
for (resource, path) in copyLocalFiles {
|
||||
account.postbox.mediaBox.copyResourceData(resource.id, fromTempPath: path)
|
||||
}
|
||||
|
||||
Logger.shared.log("loadLegacyMessages", "conversation \(conversationId) done")
|
||||
}).start(completed: {
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
|
||||
return disposable
|
||||
}
|
||||
}
|
||||
|
||||
private func importChannelBroadcastPreferences(account: TemporaryAccount, basePath: String, database: SqliteInterface) -> Signal<Never, NoError> {
|
||||
return deferred { () -> Signal<Never, NoError> in
|
||||
var peerIds: [Int64] = []
|
||||
database.select("SELECT cid FROM channel_conversations_v29", { cursor in
|
||||
peerIds.append(cursor.getInt64(at: 0))
|
||||
return true
|
||||
})
|
||||
var peerIdsWithMutedMessages: [Int64] = []
|
||||
for peerId in peerIds {
|
||||
if let data = loadLegacyPeerCustomProperyData(database: database, peerId: peerId, key: .hash(0x374BF349)), !data.isEmpty {
|
||||
let reader = LegacyBufferReader(LegacyBuffer(data: data))
|
||||
guard let version = reader.readBytesAsInt32(1) else {
|
||||
continue
|
||||
}
|
||||
guard let _ = reader.readBytesAsInt32(1) else {
|
||||
continue
|
||||
}
|
||||
if version >= 2 {
|
||||
guard let messagesMuted = reader.readBytesAsInt32(1) else {
|
||||
continue
|
||||
}
|
||||
if messagesMuted == 1 {
|
||||
peerIdsWithMutedMessages.append(peerId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
|
||||
func loadLegacySecretChats(account: TemporaryAccount, basePath: String, accountPeerId: PeerId, database: SqliteInterface) -> Signal<Float, NoError> {
|
||||
return deferred { () -> Signal<Float, NoError> in
|
||||
var peerIdToConversationId: [PeerId: Int64] = [:]
|
||||
database.select("SELECT encrypted_id, cid FROM encrypted_cids_v29", { cursor in
|
||||
peerIdToConversationId[PeerId(namespace: Namespaces.Peer.SecretChat, id: cursor.getInt32(at: 0))] = cursor.getInt64(at: 1)
|
||||
return true
|
||||
})
|
||||
var chatInfos: [(TelegramSecretChat, SecretChatState, Int32?, [MessageId.Namespace: PeerReadState], Int64)] = []
|
||||
for (peerId, conversationId) in peerIdToConversationId {
|
||||
database.select("SELECT chat_photo, unread_count, participants, date FROM convesations_v29 WHERE cid=\(conversationId)", { cursor in
|
||||
guard let (secretChatData, readStates, minMessageDate) = parseSecretChatData(peerId: peerId, data: cursor.getData(at: 0), unreadCount: cursor.getInt32(at: 1)) else {
|
||||
return false
|
||||
}
|
||||
guard let (role, userPeerId) = readSecretChatParticipantData(accountPeerId: accountPeerId, data: cursor.getData(at: 2)) else {
|
||||
return false
|
||||
}
|
||||
let chatMessageDate = cursor.getInt32(at: 3)
|
||||
let messageDate = min(minMessageDate, chatMessageDate)
|
||||
|
||||
let messageLifetime = loadLegacyPeerCustomProperyInt32(database: database, peerId: conversationId, key: .string("messageLifetime")) ?? 0
|
||||
|
||||
let state: SecretChatState
|
||||
var seqOut: Int32?
|
||||
|
||||
switch secretChatData.handshakeState {
|
||||
case 1: //requested
|
||||
guard let a = loadLegacyPeerCustomProperyData(database: database, peerId: conversationId, key: .string("a")), !a.isEmpty else {
|
||||
return false
|
||||
}
|
||||
state = SecretChatState(role: .creator, embeddedState: .handshake(.requested(g: 3, p: MemoryBuffer(data: defaultPrime), a: MemoryBuffer(data: a))), keychain: SecretChatKeychain(keys: []), keyFingerprint: nil, messageAutoremoveTimeout: nil)
|
||||
case 2: //accepting
|
||||
return false
|
||||
case 3: //terminated
|
||||
state = SecretChatState(role: .creator, embeddedState: .terminated, keychain: SecretChatKeychain(keys: []), keyFingerprint: nil, messageAutoremoveTimeout: nil)
|
||||
case 4:
|
||||
guard let sha1Fingerprint = loadLegacyPeerCustomProperyData(database: database, peerId: conversationId, key: .string("encryptionKeySha1")) else {
|
||||
return false
|
||||
}
|
||||
guard let sha256Fingerprint = loadLegacyPeerCustomProperyData(database: database, peerId: conversationId, key: .string("encryptionKeySha256")) else {
|
||||
return false
|
||||
}
|
||||
|
||||
guard let keysData = loadLegacyPeerCustomProperyData(database: database, peerId: conversationId, key: .string("encryptionKeys")) else {
|
||||
return false
|
||||
}
|
||||
guard let keysArray = NSKeyedUnarchiver.unarchiveObject(with: keysData) as? [TGEncryptionKeyData] else {
|
||||
return false
|
||||
}
|
||||
let parsedKeys: [SecretChatKey] = keysArray.map({ key in
|
||||
return SecretChatKey(fingerprint: key.keyId, key: MemoryBuffer(data: key.key), validity: .sequenceBasedIndexRange(fromCanonicalIndex: key.firstSeqOut), useCount: 1)
|
||||
})
|
||||
let requestedLayerValue = loadLegacyPeerCustomProperyInt32(database: database, peerId: conversationId, key: .hash(reportedLayer_hash)) ?? 0
|
||||
let appliedSeqInValue = loadLegacyPeerCustomProperyInt32(database: database, peerId: conversationId, key: .hash(seq_in_hash)) ?? 0
|
||||
guard let seqOutValue = loadLegacyPeerCustomProperyInt32(database: database, peerId: conversationId, key: .hash(seq_out_hash)) else {
|
||||
return false
|
||||
}
|
||||
seqOut = seqOutValue
|
||||
guard let activeLayerValue = loadLegacyPeerCustomProperyInt32(database: database, peerId: conversationId, key: .hash(layer_hash)) else {
|
||||
return false
|
||||
}
|
||||
guard let activeLayer = SecretChatSequenceBasedLayer(rawValue: activeLayerValue) else {
|
||||
return false
|
||||
}
|
||||
let rekeyState: SecretChatRekeySessionState? = secretChatData.rekeyState
|
||||
let embeddedState: SecretChatEmbeddedState = .sequenceBasedLayer(SecretChatSequenceBasedLayerState(layerNegotiationState: SecretChatLayerNegotiationState(activeLayer: activeLayer, locallyRequestedLayer: requestedLayerValue == 0 ? nil : requestedLayerValue, remotelyRequestedLayer: nil), rekeyState: rekeyState, baseIncomingOperationIndex: 0, baseOutgoingOperationIndex: 0, topProcessedCanonicalIncomingOperationIndex: appliedSeqInValue == 0 ? nil : max(0, appliedSeqInValue - 1)))
|
||||
state = SecretChatState(role: role, embeddedState: embeddedState, keychain: SecretChatKeychain(keys: parsedKeys), keyFingerprint: SecretChatKeyFingerprint(sha1: SecretChatKeySha1Fingerprint(digest: sha1Fingerprint), sha256: SecretChatKeySha256Fingerprint(digest: sha256Fingerprint)), messageAutoremoveTimeout: messageLifetime == 0 ? nil : messageLifetime)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
let secretChat = TelegramSecretChat(id: peerId, creationDate: messageDate, regularPeerId: userPeerId, accessHash: secretChatData.accessHash, role: role, embeddedState: state.embeddedState.peerState, messageAutoremoveTimeout: messageLifetime == 0 ? nil : messageLifetime)
|
||||
|
||||
chatInfos.append((secretChat, state, seqOut, readStates, conversationId))
|
||||
|
||||
return false
|
||||
})
|
||||
}
|
||||
var userPeers: [PeerId: Peer] = [:]
|
||||
var presences: [PeerId: PeerPresence] = [:]
|
||||
for info in chatInfos {
|
||||
if let (peer, presence) = loadLegacyUser(database: database, id: info.0.regularPeerId.id) {
|
||||
userPeers[peer.id] = peer
|
||||
presences[peer.id] = presence
|
||||
}
|
||||
}
|
||||
|
||||
let storedChats = account.postbox.transaction { transaction -> Void in
|
||||
updatePeers(transaction: transaction, peers: Array(userPeers.values), update: { _, updated in
|
||||
return updated
|
||||
})
|
||||
transaction.updatePeerPresencesInternal(presences: presences, merge: { _, updated in return updated })
|
||||
for (peer, state, seqOutValue, readStates, _) in chatInfos {
|
||||
if userPeers[peer.regularPeerId] == nil {
|
||||
continue
|
||||
}
|
||||
updatePeers(transaction: transaction, peers: [peer], update: { _, updated in
|
||||
return updated
|
||||
})
|
||||
transaction.setPeerChatState(peer.id, state: state)
|
||||
switch state.embeddedState {
|
||||
case .sequenceBasedLayer:
|
||||
if let seqOutValue = seqOutValue {
|
||||
transaction.operationLogResetIndices(peerId: peer.id, tag: OperationLogTags.SecretOutgoing, nextTagLocalIndex: seqOutValue + 1)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
transaction.resetIncomingReadStates([peer.id: readStates])
|
||||
}
|
||||
}
|
||||
|> ignoreValues
|
||||
|
||||
let _ = registeredAttachmentParsers
|
||||
|
||||
var countByConversationId: [Int64: Int32] = [:]
|
||||
var totalCount: Int32 = 0
|
||||
|
||||
for info in chatInfos {
|
||||
database.select("SELECT COUNT(*) FROM messages_v29 WHERE cid=\(info.4)", { cursor in
|
||||
let count = cursor.getInt32(at: 0)
|
||||
countByConversationId[info.4] = count
|
||||
totalCount += count
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
var storedMessagesSignals: Signal<Float, NoError> = .single(0.0)
|
||||
var cumulativeCount: Int32 = 0
|
||||
for info in chatInfos {
|
||||
let localBaseline = cumulativeCount
|
||||
let localCount = countByConversationId[info.4] ?? 0
|
||||
storedMessagesSignals = storedMessagesSignals
|
||||
|> then(
|
||||
loadLegacyMessages(account: account, basePath: basePath, accountPeerId: accountPeerId, peerId: info.0.id, userPeerId: info.0.regularPeerId, database: database, conversationId: info.4, expectedTotalCount: localCount)
|
||||
|> map { localProgress -> Float in
|
||||
if totalCount <= 0 {
|
||||
return 0.0
|
||||
}
|
||||
let globalCount = localBaseline + Int32(localProgress * Float(localCount))
|
||||
return Float(globalCount) / Float(totalCount)
|
||||
}
|
||||
)
|
||||
cumulativeCount += countByConversationId[info.4] ?? 0
|
||||
}
|
||||
|
||||
return storedChats
|
||||
|> map { _ -> Float in return 0.0 }
|
||||
|> then(storedMessagesSignals)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,245 +0,0 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import TelegramCore
|
||||
import SyncCore
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import MtProtoKit
|
||||
import LegacyDataImportImpl
|
||||
|
||||
public enum AccountImportError: Error {
|
||||
case generic
|
||||
}
|
||||
|
||||
public enum AccountImportProgressType {
|
||||
case generic
|
||||
case messages
|
||||
case media
|
||||
}
|
||||
|
||||
private func importedAccountData(basePath: String, documentsPath: String, accountManager: AccountManager, account: TemporaryAccount, database: SqliteInterface) -> Signal<(AccountImportProgressType, Float), AccountImportError> {
|
||||
return deferred { () -> Signal<(AccountImportProgressType, Float), AccountImportError> in
|
||||
let keychain = MTFileBasedKeychain(name: "Telegram", documentsPath: documentsPath)
|
||||
guard let masterDatacenterId = keychain.object(forKey: "defaultDatacenterId", group: "persistent") as? Int else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
let keychainContents = keychain.contents(forGroup: "persistent")
|
||||
|
||||
let importKeychain = account.postbox.transaction { transaction -> Void in
|
||||
for (key, value) in keychainContents {
|
||||
let data = NSKeyedArchiver.archivedData(withRootObject: value)
|
||||
transaction.setKeychainEntry(data, forKey: "persistent" + ":" + key)
|
||||
}
|
||||
}
|
||||
|> ignoreValues
|
||||
|> castError(AccountImportError.self)
|
||||
|
||||
let importData = importPreferencesData(documentsPath: documentsPath, masterDatacenterId: Int32(masterDatacenterId), account: account, database: database)
|
||||
|> mapToSignal { accountUserId -> Signal<(AccountImportProgressType, Float), AccountImportError> in
|
||||
return importDatabaseData(accountManager: accountManager, account: account, basePath: basePath, database: database, accountUserId: accountUserId)
|
||||
}
|
||||
|
||||
return importKeychain
|
||||
|> map { _ -> (AccountImportProgressType, Float) in return (.generic, 0.0) }
|
||||
|> then(importData)
|
||||
}
|
||||
}
|
||||
|
||||
private func importPreferencesData(documentsPath: String, masterDatacenterId: Int32, account: TemporaryAccount, database: SqliteInterface) -> Signal<Int32, AccountImportError> {
|
||||
return deferred { () -> Signal<Int32, AccountImportError> in
|
||||
let defaultsPath = documentsPath + "/standard.defaults"
|
||||
var parsedAccountUserId: Int32?
|
||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: defaultsPath)), let dict = NSKeyedUnarchiver.unarchiveObject(with: data) as? [String: Any], let id = dict["telegraphUserId"] as? Int {
|
||||
parsedAccountUserId = Int32(id)
|
||||
}
|
||||
if parsedAccountUserId == nil {
|
||||
if let id = UserDefaults.standard.object(forKey: "telegraphUserId") as? Int {
|
||||
parsedAccountUserId = Int32(id)
|
||||
}
|
||||
}
|
||||
|
||||
if let parsedAccountUserId = parsedAccountUserId {
|
||||
return account.postbox.transaction { transaction -> Int32 in
|
||||
transaction.setState(AuthorizedAccountState(isTestingEnvironment: false, masterDatacenterId: masterDatacenterId, peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: parsedAccountUserId), state: nil))
|
||||
return parsedAccountUserId
|
||||
}
|
||||
|> castError(AccountImportError.self)
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func importDatabaseData(accountManager: AccountManager, account: TemporaryAccount, basePath: String, database: SqliteInterface, accountUserId: Int32) -> Signal<(AccountImportProgressType, Float), AccountImportError> {
|
||||
return deferred { () -> Signal<(AccountImportProgressType, Float), AccountImportError> in
|
||||
var importedAccountUser: Signal<Never, AccountImportError> = .complete()
|
||||
if let (user, presence) = loadLegacyUser(database: database, id: accountUserId) {
|
||||
importedAccountUser = account.postbox.transaction { transaction -> Void in
|
||||
updatePeers(transaction: transaction, peers: [user], update: { _, updated in updated })
|
||||
transaction.updatePeerPresencesInternal(presences: [user.id: presence], merge: { _, updated in return updated })
|
||||
}
|
||||
|> ignoreValues
|
||||
|> castError(AccountImportError.self)
|
||||
}
|
||||
|
||||
let importedSecretChats = loadLegacySecretChats(account: account, basePath: basePath, accountPeerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: accountUserId), database: database)
|
||||
|> castError(AccountImportError.self)
|
||||
|
||||
/*let importedFiles = loadLegacyFiles(account: account, basePath: basePath, accountPeerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: accountUserId), database: database)
|
||||
|> castError(AccountImportError.self)*/
|
||||
|
||||
let importedLegacyPreferences = importLegacyPreferences(accountManager: accountManager, account: account, documentsPath: basePath + "/Documents", database: database)
|
||||
|> castError(AccountImportError.self)
|
||||
|
||||
return importedAccountUser
|
||||
|> map { _ -> (AccountImportProgressType, Float) in return (.generic, 0.0) }
|
||||
|> then(
|
||||
importedLegacyPreferences
|
||||
|> map { _ -> (AccountImportProgressType, Float) in return (.generic, 0.0) }
|
||||
)
|
||||
|> then(
|
||||
importedSecretChats
|
||||
|> map { value -> (AccountImportProgressType, Float) in return (.messages, value) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public enum ImportedLegacyAccountEvent {
|
||||
case progress(AccountImportProgressType, Float)
|
||||
case result(AccountRecordId?)
|
||||
}
|
||||
|
||||
public func importedLegacyAccount(basePath: String, accountManager: AccountManager, encryptionParameters: ValueBoxEncryptionParameters, present: @escaping (UIViewController) -> Void) -> Signal<ImportedLegacyAccountEvent, AccountImportError> {
|
||||
let queue = Queue()
|
||||
return deferred { () -> Signal<ImportedLegacyAccountEvent, AccountImportError> in
|
||||
let documentsPath = basePath + "/Documents"
|
||||
if FileManager.default.fileExists(atPath: documentsPath + "/importcompleted") {
|
||||
return .single(.result(nil))
|
||||
}
|
||||
|
||||
let unlockedDatabasePathAndKey: Signal<(String, Data?)?, AccountImportError>
|
||||
if FileManager.default.fileExists(atPath: documentsPath + "/tgdata.db.y") {
|
||||
let databasePath = documentsPath + "/tgdata.db.y"
|
||||
let unlockDatabase = Signal<(String, Data?)?, AccountImportError> { subscriber in
|
||||
let alertController = UIAlertController(title: nil, message: "Enter your passcode", preferredStyle: .alert)
|
||||
|
||||
let confirmAction = UIAlertAction(title: "Enter", style: .default) { _ in
|
||||
let passcode = alertController.textFields?[0].text
|
||||
|
||||
func checkPasscode(_ value: String) -> Bool {
|
||||
guard let database = SqliteInterface(databasePath: databasePath) else {
|
||||
return false
|
||||
}
|
||||
let key = value.data(using: .utf8)!
|
||||
if !database.unlock(password: hexString(key).data(using: .utf8)!) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
if checkPasscode(passcode ?? "") {
|
||||
subscriber.putNext((databasePath, (passcode ?? "").data(using: .utf8)!))
|
||||
subscriber.putCompletion()
|
||||
} else {
|
||||
let alertController = UIAlertController(title: nil, message: "Invalid passcode. Please try again.", preferredStyle: .alert)
|
||||
|
||||
let confirmAction = UIAlertAction(title: "OK", style: .default) { _ in
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
|
||||
alertController.addAction(confirmAction)
|
||||
|
||||
present(alertController)
|
||||
}
|
||||
}
|
||||
|
||||
let cancelAction = UIAlertAction(title: "Skip", style: .cancel) { _ in
|
||||
subscriber.putNext(nil)
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
|
||||
alertController.addTextField { textField in
|
||||
textField.placeholder = "Passcode"
|
||||
}
|
||||
|
||||
alertController.addAction(confirmAction)
|
||||
alertController.addAction(cancelAction)
|
||||
|
||||
present(alertController)
|
||||
return EmptyDisposable
|
||||
}
|
||||
|> runOn(Queue.mainQueue())
|
||||
|
||||
unlockedDatabasePathAndKey = (unlockDatabase
|
||||
|> mapToSignal { result -> Signal<(String, Data?)?, AccountImportError> in
|
||||
if let result = result {
|
||||
return .single(result)
|
||||
} else {
|
||||
let askAgain = Signal<(String, Data?)?, AccountImportError> { subscriber in
|
||||
let alertController = UIAlertController(title: "Warning", message: "If you continue without entering your passcode, all your secret chats will be lost.", preferredStyle: .alert)
|
||||
|
||||
let confirmAction = UIAlertAction(title: "Skip", style: .destructive) { _ in
|
||||
subscriber.putError(.generic)
|
||||
}
|
||||
|
||||
let cancelAction = UIAlertAction(title: "Try Again", style: .cancel) { _ in
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
|
||||
alertController.addAction(confirmAction)
|
||||
alertController.addAction(cancelAction)
|
||||
|
||||
present(alertController)
|
||||
return EmptyDisposable
|
||||
}
|
||||
|> runOn(Queue.mainQueue())
|
||||
return askAgain
|
||||
}
|
||||
})
|
||||
|> restart
|
||||
|> take(1)
|
||||
} else if FileManager.default.fileExists(atPath: documentsPath + "/tgdata.db") {
|
||||
unlockedDatabasePathAndKey = .single((documentsPath + "/tgdata.db", nil))
|
||||
} else {
|
||||
return .single(.result(nil))
|
||||
}
|
||||
|
||||
return unlockedDatabasePathAndKey
|
||||
|> mapToSignal { pathAndKey -> Signal<ImportedLegacyAccountEvent, AccountImportError> in
|
||||
guard let pathAndKey = pathAndKey else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
guard let database = SqliteInterface(databasePath: pathAndKey.0) else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
if let key = pathAndKey.1 {
|
||||
if !database.unlock(password: hexString(key).data(using: .utf8)!) {
|
||||
return .fail(.generic)
|
||||
}
|
||||
}
|
||||
|
||||
return temporaryAccount(manager: accountManager, rootPath: rootPathForBasePath(basePath), encryptionParameters: encryptionParameters)
|
||||
|> castError(AccountImportError.self)
|
||||
|> mapToSignal { account -> Signal<ImportedLegacyAccountEvent, AccountImportError> in
|
||||
let actions = importedAccountData(basePath: basePath, documentsPath: documentsPath, accountManager: accountManager, account: account, database: database)
|
||||
var result = actions
|
||||
|> map { typeAndProgress -> ImportedLegacyAccountEvent in
|
||||
return .progress(typeAndProgress.0, typeAndProgress.1)
|
||||
}
|
||||
#if DEBUG
|
||||
//result = result
|
||||
//|> then(.never())
|
||||
#endif
|
||||
|
||||
result = result
|
||||
|> then(.single(.result(account.id)))
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
|> runOn(queue)
|
||||
}
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
import Foundation
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import TelegramPresentationData
|
||||
import RadialStatusNode
|
||||
|
||||
public protocol LegacyDataImportSplash: WindowCoveringView {
|
||||
var progress: (AccountImportProgressType, Float) { get set }
|
||||
var serviceAction: (() -> Void)? { get set }
|
||||
}
|
||||
|
||||
private final class LegacyDataImportSplashImpl: WindowCoveringView, LegacyDataImportSplash {
|
||||
private let theme: PresentationTheme?
|
||||
private let strings: PresentationStrings?
|
||||
|
||||
public var progress: (AccountImportProgressType, Float) = (.generic, 0.0) {
|
||||
didSet {
|
||||
if self.progress.0 != oldValue.0 {
|
||||
if let size = self.validSize {
|
||||
switch self.progress.0 {
|
||||
case .generic:
|
||||
self.textNode.attributedText = NSAttributedString(string: self.strings?.AppUpgrade_Running ?? "Optimizing...", font: Font.regular(17.0), textColor: self.theme?.list.itemPrimaryTextColor ?? .black)
|
||||
case .media:
|
||||
self.textNode.attributedText = NSAttributedString(string: "Optimizing cache", font: Font.regular(17.0), textColor: self.theme?.list.itemPrimaryTextColor ?? .black)
|
||||
case .messages:
|
||||
self.textNode.attributedText = NSAttributedString(string: "Optimizing database", font: Font.regular(17.0), textColor: self.theme?.list.itemPrimaryTextColor ?? .black)
|
||||
}
|
||||
self.updateLayout(size)
|
||||
}
|
||||
}
|
||||
self.progressNode.transitionToState(.progress(color: self.theme?.list.itemAccentColor ?? UIColor(rgb: 0x007ee5), lineWidth: 2.0, value: CGFloat(max(0.025, self.progress.1)), cancelEnabled: false, animateRotation: true), animated: false, completion: {})
|
||||
}
|
||||
}
|
||||
|
||||
public var serviceAction: (() -> Void)?
|
||||
|
||||
private let progressNode: RadialStatusNode
|
||||
private let textNode: ImmediateTextNode
|
||||
|
||||
private var validSize: CGSize?
|
||||
|
||||
public init(theme: PresentationTheme?, strings: PresentationStrings?) {
|
||||
self.theme = theme
|
||||
self.strings = strings
|
||||
|
||||
self.progressNode = RadialStatusNode(backgroundNodeColor: theme?.list.plainBackgroundColor ?? .white)
|
||||
self.textNode = ImmediateTextNode()
|
||||
self.textNode.maximumNumberOfLines = 0
|
||||
self.textNode.textAlignment = .center
|
||||
self.textNode.attributedText = NSAttributedString(string: self.strings?.AppUpgrade_Running ?? "Optimizing...", font: Font.regular(17.0), textColor: self.theme?.list.itemPrimaryTextColor ?? .black)
|
||||
|
||||
super.init(frame: CGRect())
|
||||
|
||||
self.backgroundColor = self.theme?.list.plainBackgroundColor ?? .white
|
||||
|
||||
self.addSubnode(self.progressNode)
|
||||
self.progressNode.isUserInteractionEnabled = false
|
||||
self.addSubnode(self.textNode)
|
||||
self.textNode.isUserInteractionEnabled = false
|
||||
|
||||
self.addGestureRecognizer(UILongPressGestureRecognizer(target: self, action: #selector(self.longPressGesture(_:))))
|
||||
}
|
||||
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override public func updateLayout(_ size: CGSize) {
|
||||
self.validSize = size
|
||||
|
||||
let progressSize = CGSize(width: 60.0, height: 60.0)
|
||||
|
||||
let textSize = self.textNode.updateLayout(CGSize(width: size.width - 20.0, height: .greatestFiniteMagnitude))
|
||||
|
||||
let progressFrame = CGRect(origin: CGPoint(x: floor((size.width - progressSize.width) / 2.0), y: floor((size.height - progressSize.height - 15.0 - textSize.height) / 2.0)), size: progressSize)
|
||||
self.progressNode.frame = progressFrame
|
||||
self.textNode.frame = CGRect(origin: CGPoint(x: floor((size.width - textSize.width) / 2.0), y: progressFrame.maxY + 15.0), size: textSize)
|
||||
}
|
||||
|
||||
@objc private func longPressGesture(_ recognizer: UILongPressGestureRecognizer) {
|
||||
if case .began = recognizer.state {
|
||||
self.serviceAction?()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func makeLegacyDataImportSplash(theme: PresentationTheme?, strings: PresentationStrings?) -> LegacyDataImportSplash {
|
||||
return LegacyDataImportSplashImpl(theme: theme, strings: strings)
|
||||
}
|
||||
|
|
@ -1,189 +0,0 @@
|
|||
import Foundation
|
||||
import TelegramCore
|
||||
import SyncCore
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import LegacyComponents
|
||||
|
||||
private func importMediaFromMessageData(_ data: Data, basePath: String, copyLocalFiles: inout [(MediaResource, String)], cache: TGCache) {
|
||||
if let message = TGMessage(keyValueCoder: PSKeyValueDecoder(data: data)) {
|
||||
if let mediaAttachments = message.mediaAttachments {
|
||||
importMediaFromMediaList(mediaAttachments, basePath: basePath, copyLocalFiles: ©LocalFiles, cache: cache)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func importMediaFromMediaData(_ data: Data, basePath: String, copyLocalFiles: inout [(MediaResource, String)], cache: TGCache) {
|
||||
if let mediaAttachments = TGMessage.parseMediaAttachments(data) {
|
||||
importMediaFromMediaList(mediaAttachments, basePath: basePath, copyLocalFiles: ©LocalFiles, cache: cache)
|
||||
}
|
||||
}
|
||||
|
||||
private func importMediaFromMediaList(_ mediaAttachments: [Any], basePath: String, copyLocalFiles: inout [(MediaResource, String)], cache: TGCache) {
|
||||
for media in mediaAttachments {
|
||||
if let media = media as? TGDocumentMediaAttachment {
|
||||
var fileName = "file"
|
||||
if let itemAttributes = media.attributes {
|
||||
for attribute in itemAttributes {
|
||||
if let attribute = attribute as? TGDocumentAttributeFilename {
|
||||
fileName = attribute.filename ?? "file"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if media.documentId != 0 {
|
||||
let filePath = pathFromLegacyFile(basePath: basePath, fileId: media.documentId, isLocal: false, fileName: TGDocumentMediaAttachment.safeFileName(forFileName: fileName) ?? "")
|
||||
if FileManager.default.fileExists(atPath: filePath) {
|
||||
copyLocalFiles.append((CloudDocumentMediaResource(datacenterId: Int(media.datacenterId), fileId: media.documentId, accessHash: media.accessHash, size: nil, fileReference: nil, fileName: nil), filePath))
|
||||
}
|
||||
}
|
||||
} else if let media = media as? TGVideoMediaAttachment {
|
||||
if media.videoId != 0, let videoUrl = media.videoInfo?.url(withQuality: 1, actualQuality: nil, actualSize: nil) {
|
||||
if let (id, accessHash, datacenterId, path) = pathFromLegacyVideoUrl(basePath: basePath, url: videoUrl) {
|
||||
copyLocalFiles.append((CloudDocumentMediaResource(datacenterId: Int(datacenterId), fileId: id, accessHash: accessHash, size: nil, fileReference: nil, fileName: nil), path))
|
||||
}
|
||||
}
|
||||
} else if let media = media as? TGImageMediaAttachment {
|
||||
if let allSizes = media.imageInfo?.allSizes() as? [String: NSValue] {
|
||||
for (imageUrl, _) in allSizes {
|
||||
if let path = cache.path(forCachedData: imageUrl), let resource = resourceFromLegacyImageUrl(imageUrl), FileManager.default.fileExists(atPath: path) {
|
||||
copyLocalFiles.append((resource, path))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func makeMessageSortKey(tag: Int32, conversationId: Int64, space: Int8, timestamp: Int32, messageId: Int32) -> Data {
|
||||
let key = ValueBoxKey(length: 4 + 8 + 1 + 4 + 4)
|
||||
key.setInt32(0, value: tag.byteSwapped)
|
||||
key.setInt64(4, value: conversationId.byteSwapped)
|
||||
key.setInt8(4 + 8, value: space)
|
||||
key.setInt32(4 + 8 + 1, value: timestamp)
|
||||
key.setInt32(4 + 8 + 1 + 4, value: messageId.byteSwapped)
|
||||
return Data(bytes: key.memory, count: key.length)
|
||||
}
|
||||
|
||||
func loadLegacyFiles(account: TemporaryAccount, basePath: String, accountPeerId: PeerId, database: SqliteInterface) -> Signal<Float, NoError> {
|
||||
return Signal<Float, NoError> { subscriber in
|
||||
let _ = registeredAttachmentParsers
|
||||
|
||||
subscriber.putNext(0.0)
|
||||
|
||||
var channelIds: [Int64] = []
|
||||
database.select("SELECT DISTINCT cid FROM channel_message_tags_v29", { cursor in
|
||||
channelIds.append(cursor.getInt64(at: 0))
|
||||
return true
|
||||
})
|
||||
print(database.explain("SELECT DISTINCT cid FROM channel_message_tags_v29"))
|
||||
|
||||
var channelMessageIds: [(Int64, Int32)] = []
|
||||
|
||||
print(database.explain("SELECT mid FROM channel_message_tags_v29 WHERE tag_sort_key<100 AND tag_sort_key>0 ORDER BY tag_sort_key DESC LIMIT 4000"))
|
||||
|
||||
if !channelIds.isEmpty {
|
||||
/*
|
||||
TGSharedMediaCacheItemTypePhoto = 0,
|
||||
TGSharedMediaCacheItemTypeVideo = 1,
|
||||
TGSharedMediaCacheItemTypeFile = 2,
|
||||
TGSharedMediaCacheItemTypePhotoVideo = 3,
|
||||
TGSharedMediaCacheItemTypePhotoVideoFile = 4,
|
||||
TGSharedMediaCacheItemTypeAudio = 5,
|
||||
TGSharedMediaCacheItemTypeLink = 6,
|
||||
TGSharedMediaCacheItemTypeSticker = 7,
|
||||
TGSharedMediaCacheItemTypeGif = 8,
|
||||
TGSharedMediaCacheItemTypeVoiceVideoMessage = 9
|
||||
*/
|
||||
let tags: [Int32] = [
|
||||
2, // File
|
||||
5, // Audio
|
||||
3, // PhotoVideo
|
||||
]
|
||||
database.withStatement("SELECT mid FROM channel_message_tags_v29 WHERE tag_sort_key<? AND tag_sort_key>? ORDER BY tag_sort_key DESC LIMIT 4000", { select in
|
||||
for channelId in channelIds {
|
||||
for tag in tags {
|
||||
select([.data(makeMessageSortKey(tag: tag, conversationId: channelId, space: 0, timestamp: Int32.max - 1, messageId: 0)), .data(makeMessageSortKey(tag: tag, conversationId: channelId, space: 0, timestamp: 0, messageId: 0))], { cursor in
|
||||
channelMessageIds.append((channelId, cursor.getInt32(at: 0)))
|
||||
return true
|
||||
})
|
||||
select([.data(makeMessageSortKey(tag: tag, conversationId: channelId, space: 1, timestamp: Int32.max - 1, messageId: 0)), .data(makeMessageSortKey(tag: tag, conversationId: channelId, space: 1, timestamp: 0, messageId: 0))], { cursor in
|
||||
channelMessageIds.append((channelId, cursor.getInt32(at: 0)))
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var chatMessageIds: [Int32] = []
|
||||
let mediaTypes: [Int32] = [
|
||||
1, // video
|
||||
2, // image
|
||||
3, // file
|
||||
]
|
||||
for type in mediaTypes {
|
||||
database.select("SELECT mids FROM media_cache_v29 WHERE media_type=\(type) ORDER BY date DESC LIMIT 32000", { cursor in
|
||||
let midsData = cursor.getData(at: 0)
|
||||
let reader = LegacyBufferReader(LegacyBuffer(data: midsData))
|
||||
while true {
|
||||
if let mid = reader.readInt32() {
|
||||
chatMessageIds.append(mid)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
var copyLocalFiles: [(MediaResource, String)] = []
|
||||
|
||||
let totalCount = channelMessageIds.count + chatMessageIds.count
|
||||
let reportBase = max(1, totalCount / 100)
|
||||
|
||||
var itemIndex = -1
|
||||
|
||||
let cache = TGCache(cachesPath: basePath + "/Caches")!
|
||||
|
||||
if !channelMessageIds.isEmpty {
|
||||
database.withStatement("SELECT data FROM channel_messages_v29 WHERE cid=? AND mid=?", { select in
|
||||
for (peerId, messageId) in channelMessageIds {
|
||||
itemIndex += 1
|
||||
if itemIndex % reportBase == 0 {
|
||||
subscriber.putNext(Float(itemIndex) / Float(totalCount))
|
||||
}
|
||||
select([.int64(peerId), .int32(messageId)], { cursor in
|
||||
let data = cursor.getData(at: 0)
|
||||
importMediaFromMessageData(data, basePath: basePath, copyLocalFiles: ©LocalFiles, cache: cache)
|
||||
return true
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if !chatMessageIds.isEmpty {
|
||||
database.withStatement("SELECT media FROM messages_v29 WHERE mid=?", { select in
|
||||
for messageId in chatMessageIds {
|
||||
itemIndex += 1
|
||||
if itemIndex % reportBase == 0 {
|
||||
subscriber.putNext(Float(itemIndex) / Float(totalCount))
|
||||
}
|
||||
select([.int32(messageId)], { cursor in
|
||||
let data = cursor.getData(at: 0)
|
||||
importMediaFromMediaData(data, basePath: basePath, copyLocalFiles: ©LocalFiles, cache: cache)
|
||||
return true
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
for (resource, path) in copyLocalFiles {
|
||||
account.postbox.mediaBox.copyResourceData(resource.id, fromTempPath: path)
|
||||
}
|
||||
|
||||
subscriber.putCompletion()
|
||||
|
||||
return EmptyDisposable
|
||||
}
|
||||
}
|
||||
|
|
@ -1,438 +0,0 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import TelegramCore
|
||||
import SyncCore
|
||||
import SwiftSignalKit
|
||||
import MtProtoKit
|
||||
import TelegramUIPreferences
|
||||
import LegacyComponents
|
||||
import TelegramNotices
|
||||
import LegacyDataImportImpl
|
||||
|
||||
@objc(TGPresentationState) private final class TGPresentationState: NSObject, NSCoding {
|
||||
let pallete: Int32
|
||||
let userInfo: Int32
|
||||
let fontSize: Int32
|
||||
|
||||
init?(coder aDecoder: NSCoder) {
|
||||
self.pallete = aDecoder.decodeInt32(forKey: "p")
|
||||
self.userInfo = aDecoder.decodeInt32(forKey: "u")
|
||||
self.fontSize = aDecoder.decodeInt32(forKey: "f")
|
||||
}
|
||||
|
||||
func encode(with aCoder: NSCoder) {
|
||||
assertionFailure()
|
||||
}
|
||||
}
|
||||
|
||||
private enum PreferencesProvider {
|
||||
case dict([String: Any])
|
||||
case standard(UserDefaults)
|
||||
|
||||
subscript(_ key: String) -> Any? {
|
||||
get {
|
||||
switch self {
|
||||
case let .dict(dict):
|
||||
return dict[key]
|
||||
case let .standard(standard):
|
||||
return standard.object(forKey: key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func loadLegacyCustomProperyData(database: SqliteInterface, key: String) -> Data? {
|
||||
var result: Data?
|
||||
database.select("SELECT value FROM service_v29 WHERE key=\(HashFunctions.murMurHash32(key))", { cursor in
|
||||
result = cursor.getData(at: 0)
|
||||
return false
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
private func convertLegacyProxyPort(_ value: Int) -> Int32 {
|
||||
if value < 0 {
|
||||
return Int32(UInt16(bitPattern: Int16(clamping: value)))
|
||||
} else {
|
||||
return Int32(clamping: value)
|
||||
}
|
||||
}
|
||||
|
||||
func importLegacyPreferences(accountManager: AccountManager, account: TemporaryAccount, documentsPath: String, database: SqliteInterface) -> Signal<Never, NoError> {
|
||||
return deferred { () -> Signal<Never, NoError> in
|
||||
var presentationState: TGPresentationState?
|
||||
if let value = NSKeyedUnarchiver.unarchiveObject(withFile: documentsPath + "/presentation.dat") as? TGPresentationState {
|
||||
presentationState = value
|
||||
}
|
||||
|
||||
var autoNightPreferences: TGPresentationAutoNightPreferences?
|
||||
if let value = NSKeyedUnarchiver.unarchiveObject(withFile: documentsPath + "/autonight.dat") as? TGPresentationAutoNightPreferences {
|
||||
autoNightPreferences = value
|
||||
}
|
||||
|
||||
let autoDownloadPreferences: TGAutoDownloadPreferences? = NSKeyedUnarchiver.unarchiveObject(withFile: documentsPath + "/autoDownload.pref") as? TGAutoDownloadPreferences
|
||||
|
||||
let preferencesProvider: PreferencesProvider
|
||||
let defaultsPath = documentsPath + "/standard.defaults"
|
||||
|
||||
let standardPreferences = PreferencesProvider.standard(UserDefaults.standard)
|
||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: defaultsPath)), let dict = NSKeyedUnarchiver.unarchiveObject(with: data) as? [String: Any] {
|
||||
preferencesProvider = .dict(dict)
|
||||
} else {
|
||||
preferencesProvider = standardPreferences
|
||||
}
|
||||
|
||||
var showCallsTab: Bool?
|
||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: documentsPath + "/enablecalls.tab")), !data.isEmpty {
|
||||
showCallsTab = data.withUnsafeBytes { (bytes: UnsafePointer<Int8>) -> Bool in
|
||||
return bytes.pointee != 0
|
||||
}
|
||||
}
|
||||
|
||||
let parsedAutoplayGifs: Bool? = preferencesProvider["autoPlayAnimations"] as? Bool
|
||||
let soundEnabled: Bool? = preferencesProvider["soundEnabled"] as? Bool
|
||||
let vibrationEnabled: Bool? = preferencesProvider["vibrationEnabled"] as? Bool
|
||||
let bannerEnabled: Bool? = preferencesProvider["bannerEnabled"] as? Bool
|
||||
let callsDataUsageMode: Int? = preferencesProvider["callsDataUsageMode"] as? Int
|
||||
let callsDisableCallKit: Bool? = preferencesProvider["callsDisableCallKit"] as? Bool
|
||||
let callsUseProxy: Bool? = preferencesProvider["callsUseProxy"] as? Bool
|
||||
let contactsInhibitSync: Bool? = preferencesProvider["contactsInhibitSync"] as? Bool
|
||||
let stickersSuggestMode: Int? = preferencesProvider["stickersSuggestMode"] as? Int
|
||||
|
||||
let allowSecretWebpages: Bool? = preferencesProvider["allowSecretWebpages"] as? Bool
|
||||
let allowSecretWebpagesInitialized: Bool? = preferencesProvider["allowSecretWebpagesInitialized"] as? Bool
|
||||
let secretInlineBotsInitialized: Bool? = preferencesProvider["secretInlineBotsInitialized"] as? Bool
|
||||
|
||||
let musicPlayerOrderType: Int? = standardPreferences["musicPlayerOrderType_v1"] as? Int
|
||||
let musicPlayerRepeatType: Int? = standardPreferences["musicPlayerRepeatType_v1"] as? Int
|
||||
|
||||
let instantPageFontSize: Float? = standardPreferences["instantPage_fontMultiplier_v0"] as? Float
|
||||
let instantPageFontSerif: Int? = standardPreferences["instantPage_fontSerif_v0"] as? Int
|
||||
let instantPageTheme: Int? = standardPreferences["instantPage_theme_v0"] as? Int
|
||||
let instantPageAutoNightMode: Int? = standardPreferences["instantPage_autoNightTheme_v0"] as? Int
|
||||
|
||||
let proxyList = NSKeyedUnarchiver.unarchiveObject(withFile: documentsPath + "/proxies.data") as? [TGProxyItem]
|
||||
var selectedProxy: (ProxyServerSettings, Bool)?
|
||||
if let data = loadLegacyCustomProperyData(database: database, key: "socksProxyData"), let dict = NSKeyedUnarchiver.unarchiveObject(with: data) as? [String: Any], let host = dict["ip"] as? String, let port = dict["port"] as? Int {
|
||||
let inactive = (dict["inactive"] as? Bool) ?? true
|
||||
var connection: ProxyServerConnection?
|
||||
if let secretString = dict["secret"] as? String {
|
||||
let secret = MTProxySecret.parse(secretString)
|
||||
if let secret = secret {
|
||||
connection = .mtp(secret: secret.serialize())
|
||||
}
|
||||
} else {
|
||||
connection = .socks5(username: (dict["username"] as? String) ?? "", password: (dict["password"] as? String) ?? "")
|
||||
}
|
||||
if let connection = connection {
|
||||
selectedProxy = (ProxyServerSettings(host: host, port: convertLegacyProxyPort(port), connection: connection), !inactive)
|
||||
}
|
||||
}
|
||||
|
||||
var passcodeChallenge: PostboxAccessChallengeData?
|
||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: documentsPath + "/x.y")) {
|
||||
let reader = LegacyBufferReader(LegacyBuffer(data: data))
|
||||
if let mode = reader.readBytesAsInt32(1), let length = reader.readInt32(), let passwordData = reader.readBuffer(Int(length))?.makeData(), let passwordText = String(data: passwordData, encoding: .utf8) {
|
||||
var lockTimeout: Int32?
|
||||
if let value = UserDefaults.standard.object(forKey: "Passcode_lockTimeout") as? Int {
|
||||
if value == 0 {
|
||||
lockTimeout = nil
|
||||
} else {
|
||||
lockTimeout = max(60, Int32(clamping: value))
|
||||
}
|
||||
} else {
|
||||
lockTimeout = 1 * 60 * 60
|
||||
}
|
||||
|
||||
if mode == 3 {
|
||||
passcodeChallenge = .numericalPassword(value: passwordText)
|
||||
} else if mode == 4 {
|
||||
passcodeChallenge = PostboxAccessChallengeData.plaintextPassword(value: passwordText)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var passcodeEnableBiometrics: Bool = true
|
||||
if let value = UserDefaults.standard.object(forKey: "Passcode_useTouchId") as? Bool {
|
||||
passcodeEnableBiometrics = value
|
||||
}
|
||||
|
||||
var localization: TGLocalization?
|
||||
if let nativeDocumentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first {
|
||||
localization = NSKeyedUnarchiver.unarchiveObject(withFile: nativeDocumentsPath + "/localization") as? TGLocalization
|
||||
}
|
||||
|
||||
return accountManager.transaction { transaction -> Signal<Void, NoError> in
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.presentationThemeSettings, { current in
|
||||
var settings = (current as? PresentationThemeSettings) ?? PresentationThemeSettings.defaultSettings
|
||||
if let presentationState = presentationState {
|
||||
switch presentationState.pallete {
|
||||
case 1:
|
||||
settings.theme = .builtin(.day)
|
||||
|
||||
if presentationState.userInfo != 0 {
|
||||
//themeSpecificAccentColors: current.themeSpecificAccentColors
|
||||
//settings.themeAccentColor = presentationState.userInfo
|
||||
}
|
||||
settings.themeSpecificChatWallpapers[settings.theme.index] = .color(0xffffff)
|
||||
case 2:
|
||||
settings.theme = .builtin(.night)
|
||||
settings.themeSpecificChatWallpapers[settings.theme.index] = .color(0x000000)
|
||||
case 3:
|
||||
settings.theme = .builtin(.nightAccent)
|
||||
settings.themeSpecificChatWallpapers[settings.theme.index] = .color(0x18222d)
|
||||
default:
|
||||
settings.theme = .builtin(.dayClassic)
|
||||
settings.themeSpecificChatWallpapers[settings.theme.index] = .builtin(WallpaperSettings())
|
||||
}
|
||||
let fontSizeMap: [Int32: PresentationFontSize] = [
|
||||
14: .extraSmall,
|
||||
15: .small,
|
||||
16: .medium,
|
||||
17: .regular,
|
||||
19: .large,
|
||||
23: .extraLarge,
|
||||
26: .extraLargeX2
|
||||
]
|
||||
settings.fontSize = fontSizeMap[presentationState.fontSize] ?? .regular
|
||||
|
||||
if presentationState.userInfo != 0 {
|
||||
//themeSpecificAccentColors: current.themeSpecificAccentColors
|
||||
//settings.themeAccentColor = presentationState.userInfo
|
||||
}
|
||||
}
|
||||
|
||||
if let autoNightPreferences = autoNightPreferences {
|
||||
let nightTheme: PresentationBuiltinThemeReference
|
||||
switch autoNightPreferences.preferredPalette {
|
||||
case 1:
|
||||
nightTheme = .night
|
||||
default:
|
||||
nightTheme = .nightAccent
|
||||
}
|
||||
switch autoNightPreferences.mode {
|
||||
case TGPresentationAutoNightModeSunsetSunrise:
|
||||
settings.automaticThemeSwitchSetting = AutomaticThemeSwitchSetting(trigger: .timeBased(setting: .automatic(latitude: Double(autoNightPreferences.latitude), longitude: Double(autoNightPreferences.longitude), localizedName: autoNightPreferences.cachedLocationName)), theme: .builtin(nightTheme))
|
||||
case TGPresentationAutoNightModeScheduled:
|
||||
settings.automaticThemeSwitchSetting = AutomaticThemeSwitchSetting(trigger: .timeBased(setting: .manual(fromSeconds: autoNightPreferences.scheduleStart, toSeconds: autoNightPreferences.scheduleEnd)), theme: .builtin(nightTheme))
|
||||
case TGPresentationAutoNightModeBrightness:
|
||||
settings.automaticThemeSwitchSetting = AutomaticThemeSwitchSetting(trigger: .brightness(threshold: Double(autoNightPreferences.brightnessThreshold)), theme: .builtin(nightTheme))
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return settings
|
||||
})
|
||||
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings, { current in
|
||||
var settings: MediaAutoDownloadSettings = current as? MediaAutoDownloadSettings ?? .defaultSettings
|
||||
|
||||
if let preferences = autoDownloadPreferences, !preferences.isDefaultPreferences() {
|
||||
settings.cellular.enabled = !preferences.disabled
|
||||
settings.wifi.enabled = !preferences.disabled
|
||||
}
|
||||
|
||||
if let parsedAutoplayGifs = parsedAutoplayGifs {
|
||||
settings.autoplayGifs = parsedAutoplayGifs
|
||||
}
|
||||
|
||||
return settings
|
||||
})
|
||||
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.inAppNotificationSettings, { current in
|
||||
var settings: InAppNotificationSettings = current as? InAppNotificationSettings ?? .defaultSettings
|
||||
if let soundEnabled = soundEnabled {
|
||||
settings.playSounds = soundEnabled
|
||||
}
|
||||
if let vibrationEnabled = vibrationEnabled {
|
||||
settings.vibrate = vibrationEnabled
|
||||
}
|
||||
if let bannerEnabled = bannerEnabled {
|
||||
settings.displayPreviews = bannerEnabled
|
||||
}
|
||||
return settings
|
||||
})
|
||||
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.voiceCallSettings, { current in
|
||||
var settings: VoiceCallSettings = current as? VoiceCallSettings ?? .defaultSettings
|
||||
if let callsDataUsageMode = callsDataUsageMode {
|
||||
switch callsDataUsageMode {
|
||||
case 1:
|
||||
settings.dataSaving = .cellular
|
||||
case 2:
|
||||
settings.dataSaving = .always
|
||||
default:
|
||||
settings.dataSaving = .never
|
||||
}
|
||||
}
|
||||
if let callsDisableCallKit = callsDisableCallKit, callsDisableCallKit {
|
||||
settings.enableSystemIntegration = false
|
||||
}
|
||||
return settings
|
||||
})
|
||||
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.callListSettings, { current in
|
||||
var settings: CallListSettings = current as? CallListSettings ?? .defaultSettings
|
||||
if let showCallsTab = showCallsTab {
|
||||
settings.showTab = showCallsTab
|
||||
}
|
||||
return settings
|
||||
})
|
||||
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.presentationPasscodeSettings, { current in
|
||||
var settings: PresentationPasscodeSettings = current as? PresentationPasscodeSettings ?? .defaultSettings
|
||||
if let passcodeChallenge = passcodeChallenge {
|
||||
transaction.setAccessChallengeData(passcodeChallenge)
|
||||
settings.enableBiometrics = passcodeEnableBiometrics
|
||||
}
|
||||
return settings
|
||||
})
|
||||
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.stickerSettings, { current in
|
||||
var settings: StickerSettings = current as? StickerSettings ?? .defaultSettings
|
||||
if let stickersSuggestMode = stickersSuggestMode {
|
||||
switch stickersSuggestMode {
|
||||
case 1:
|
||||
settings.emojiStickerSuggestionMode = .installed
|
||||
case 2:
|
||||
settings.emojiStickerSuggestionMode = .none
|
||||
default:
|
||||
settings.emojiStickerSuggestionMode = .all
|
||||
}
|
||||
}
|
||||
return settings
|
||||
})
|
||||
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.musicPlaybackSettings, { current in
|
||||
var settings: MusicPlaybackSettings = current as? MusicPlaybackSettings ?? .defaultSettings
|
||||
if let musicPlayerOrderType = musicPlayerOrderType {
|
||||
switch musicPlayerOrderType {
|
||||
case 1:
|
||||
settings.order = .reversed
|
||||
case 2:
|
||||
settings.order = .random
|
||||
default:
|
||||
settings.order = .regular
|
||||
}
|
||||
}
|
||||
if let musicPlayerRepeatType = musicPlayerRepeatType {
|
||||
switch musicPlayerRepeatType {
|
||||
case 1:
|
||||
settings.looping = .all
|
||||
case 2:
|
||||
settings.looping = .item
|
||||
default:
|
||||
settings.looping = .none
|
||||
}
|
||||
}
|
||||
return settings
|
||||
})
|
||||
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.instantPagePresentationSettings, { current in
|
||||
let settings: InstantPagePresentationSettings = current as? InstantPagePresentationSettings ?? .defaultSettings
|
||||
if let instantPageFontSize = instantPageFontSize {
|
||||
switch instantPageFontSize {
|
||||
case 0.85:
|
||||
settings.fontSize = .small
|
||||
case 1.15:
|
||||
settings.fontSize = .large
|
||||
case 1.30:
|
||||
settings.fontSize = .xlarge
|
||||
case 1.50:
|
||||
settings.fontSize = .xxlarge
|
||||
default:
|
||||
settings.fontSize = .standard
|
||||
}
|
||||
}
|
||||
if let instantPageFontSerif = instantPageFontSerif {
|
||||
settings.forceSerif = instantPageFontSerif == 1
|
||||
}
|
||||
if let instantPageTheme = instantPageTheme {
|
||||
switch instantPageTheme {
|
||||
case 1:
|
||||
settings.themeType = .sepia
|
||||
case 2:
|
||||
settings.themeType = .gray
|
||||
case 3:
|
||||
settings.themeType = .dark
|
||||
default:
|
||||
settings.themeType = .light
|
||||
}
|
||||
}
|
||||
if let instantPageAutoNightMode = instantPageAutoNightMode {
|
||||
settings.autoNightMode = instantPageAutoNightMode == 1
|
||||
}
|
||||
return settings
|
||||
})
|
||||
|
||||
if let localization = localization {
|
||||
transaction.updateSharedData(SharedDataKeys.localizationSettings, { _ in
|
||||
var entries: [LocalizationEntry] = []
|
||||
for (key, value) in localization.dict() {
|
||||
entries.append(LocalizationEntry.string(key: key, value: value))
|
||||
}
|
||||
return LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: localization.code, localizedName: "", localization: Localization(version: 0, entries: entries), customPluralizationCode: nil), secondaryComponent: nil)
|
||||
})
|
||||
}
|
||||
|
||||
transaction.updateSharedData(SharedDataKeys.proxySettings, { current in
|
||||
var settings: ProxySettings = current as? ProxySettings ?? .defaultSettings
|
||||
if let callsUseProxy = callsUseProxy {
|
||||
settings.useForCalls = callsUseProxy
|
||||
}
|
||||
|
||||
if let proxyList = proxyList {
|
||||
for item in proxyList {
|
||||
let connection: ProxyServerConnection?
|
||||
if item.isMTProxy, let secret = item.secret {
|
||||
let parsedSecret = MTProxySecret.parse(secret)
|
||||
if let parsedSecret = parsedSecret {
|
||||
connection = .mtp(secret: parsedSecret.serialize())
|
||||
} else {
|
||||
connection = nil
|
||||
}
|
||||
} else if !item.isMTProxy {
|
||||
connection = .socks5(username: item.username ?? "", password: item.password ?? "")
|
||||
} else {
|
||||
connection = nil
|
||||
}
|
||||
if let connection = connection {
|
||||
settings.servers.append(ProxyServerSettings(host: item.server, port: convertLegacyProxyPort(Int(item.port)), connection: connection))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let (server, active) = selectedProxy {
|
||||
if !settings.servers.contains(server) {
|
||||
settings.servers.insert(server, at: 0)
|
||||
}
|
||||
settings.activeServer = server
|
||||
settings.enabled = active
|
||||
}
|
||||
|
||||
return settings
|
||||
})
|
||||
|
||||
if let secretInlineBotsInitialized = secretInlineBotsInitialized, secretInlineBotsInitialized {
|
||||
ApplicationSpecificNotice.setSecretChatInlineBotUsage(transaction: transaction)
|
||||
}
|
||||
|
||||
if let allowSecretWebpagesInitialized = allowSecretWebpagesInitialized, allowSecretWebpagesInitialized, let allowSecretWebpages = allowSecretWebpages {
|
||||
ApplicationSpecificNotice.setSecretChatLinkPreviews(transaction: transaction, value: allowSecretWebpages)
|
||||
}
|
||||
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
transaction.updatePreferencesEntry(key: PreferencesKeys.contactsSettings, { current in
|
||||
var settings = current as? ContactsSettings ?? ContactsSettings.defaultSettings
|
||||
if let contactsInhibitSync = contactsInhibitSync, contactsInhibitSync {
|
||||
settings.synchronizeContacts = false
|
||||
}
|
||||
return settings
|
||||
})
|
||||
}
|
||||
}
|
||||
|> switchToLatest
|
||||
|> ignoreValues
|
||||
}
|
||||
}
|
||||
|
|
@ -1,137 +0,0 @@
|
|||
import Foundation
|
||||
import TelegramCore
|
||||
import SyncCore
|
||||
import SwiftSignalKit
|
||||
import LegacyComponents
|
||||
|
||||
func resourceFromLegacyImageUrl(_ fileRef: String) -> TelegramMediaResource? {
|
||||
if fileRef.isEmpty {
|
||||
return nil
|
||||
}
|
||||
let components = fileRef.components(separatedBy: "_")
|
||||
if components.count != 4 {
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let datacenterId = Int32(components[0]) else {
|
||||
return nil
|
||||
}
|
||||
guard let volumeId = Int64(components[1]) else {
|
||||
return nil
|
||||
}
|
||||
guard let localId = Int32(components[2]) else {
|
||||
return nil
|
||||
}
|
||||
guard let secret = Int64(components[3]) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return CloudFileMediaResource(datacenterId: Int(datacenterId), volumeId: volumeId, localId: localId, secret: secret, size: nil, fileReference: nil)
|
||||
}
|
||||
|
||||
func pathFromLegacyImageUrl(basePath: String, url: String) -> String {
|
||||
let cache = TGCache(cachesPath: basePath + "/Caches")!
|
||||
return cache.path(forCachedData: url)
|
||||
}
|
||||
|
||||
func pathFromLegacyVideoUrl(basePath: String, url: String) -> (id: Int64, accessHash: Int64, datacenterId: Int32, path: String)? {
|
||||
if !url.hasPrefix("video:") {
|
||||
return nil
|
||||
}
|
||||
//[videoInfo addVideoWithQuality:1 url:[[NSString alloc] initWithFormat:@"video:%lld:%lld:%d:%d", videoMedia.videoId, videoMedia.accessHash, concreteResult.document.datacenterId, concreteResult.document.size] size:concreteResult.document.size];
|
||||
let components = url.components(separatedBy: ":")
|
||||
if components.count != 5 {
|
||||
return nil
|
||||
}
|
||||
guard let videoId = Int64(components[1]) else {
|
||||
return nil
|
||||
}
|
||||
guard let accessHash = Int64(components[2]) else {
|
||||
return nil
|
||||
}
|
||||
guard let datacenterId = Int32(components[3]) else {
|
||||
return nil
|
||||
}
|
||||
let documentsPath = basePath + "/Documents"
|
||||
let videoPath = documentsPath + "/video/remote\(String(videoId, radix: 16)).mov"
|
||||
return (videoId, accessHash, datacenterId, videoPath)
|
||||
}
|
||||
|
||||
func pathFromLegacyLocalVideoUrl(basePath: String, url: String) -> String? {
|
||||
let documentsPath = basePath + "/Documents"
|
||||
if !url.hasPrefix("local-video:") {
|
||||
return nil
|
||||
}
|
||||
let videoPath = documentsPath + "/video/" + String(url[url.index(url.startIndex, offsetBy: "local-video:".count)...])
|
||||
return videoPath
|
||||
}
|
||||
|
||||
func pathFromLegacyFile(basePath: String, fileId: Int64, isLocal: Bool, fileName: String) -> String {
|
||||
let documentsPath = basePath + "/Documents"
|
||||
let filePath = documentsPath + "/files/" + (isLocal ? "local" : "") + "\(String(fileId, radix: 16))/\(fileName)"
|
||||
return filePath
|
||||
}
|
||||
|
||||
enum EncryptedFileType {
|
||||
case image
|
||||
case video
|
||||
case document(fileName: String)
|
||||
case audio
|
||||
}
|
||||
|
||||
func pathAndResourceFromEncryptedFileUrl(basePath: String, url: String, type: EncryptedFileType) -> (String, TelegramMediaResource)? {
|
||||
let cache = TGCache(cachesPath: basePath + "/Caches")!
|
||||
|
||||
if url.hasPrefix("encryptedThumbnail:") {
|
||||
let path = cache.path(forCachedData: url)!
|
||||
return (path, LocalFileMediaResource(fileId: arc4random64()))
|
||||
}
|
||||
|
||||
if !url.hasPrefix("mt-encrypted-file://?") {
|
||||
return nil
|
||||
}
|
||||
guard let dict = TGStringUtils.argumentDictionary(inUrlString: String(url[url.index(url.startIndex, offsetBy: "mt-encrypted-file://?".count)...])) else {
|
||||
return nil
|
||||
}
|
||||
guard let idString = dict["id"] as? String, let id = Int64(idString) else {
|
||||
return nil
|
||||
}
|
||||
guard let datacenterIdString = dict["dc"] as? String, let datacenterId = Int32(datacenterIdString) else {
|
||||
return nil
|
||||
}
|
||||
guard let accessHashString = dict["accessHash"] as? String, let accessHash = Int64(accessHashString) else {
|
||||
return nil
|
||||
}
|
||||
guard let sizeString = dict["size"] as? String, let size = Int32(sizeString) else {
|
||||
return nil
|
||||
}
|
||||
guard let decryptedSizeString = dict["decryptedSize"] as? String, let decryptedSize = Int32(decryptedSizeString) else {
|
||||
return nil
|
||||
}
|
||||
guard let keyFingerprintString = dict["fingerprint"] as? String, let _ = Int32(keyFingerprintString) else {
|
||||
return nil
|
||||
}
|
||||
guard let keyString = dict["key"] as? String else {
|
||||
return nil
|
||||
}
|
||||
let keyData = dataWithHexString(keyString)
|
||||
guard keyData.count == 64 else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let resource = SecretFileMediaResource(fileId: id, accessHash: accessHash, containerSize: size, decryptedSize: decryptedSize, datacenterId: Int(datacenterId), key: SecretFileEncryptionKey(aesKey: keyData.subdata(in: 0 ..< 32), aesIv: keyData.subdata(in: 32 ..< 64)))
|
||||
|
||||
let filePath: String
|
||||
switch type {
|
||||
case .video:
|
||||
filePath = basePath + "Documents/video/remote\(String(id, radix: 16)).mov"
|
||||
case .image:
|
||||
filePath = cache.path(forCachedData: url)
|
||||
case let .document(fileName):
|
||||
filePath = basePath + "Documents/files/\(String(id, radix: 16))/\(TGDocumentMediaAttachment.safeFileName(forFileName: fileName)!)"
|
||||
case .audio:
|
||||
filePath = basePath + "Documents/audio/\(String(id, radix: 16))"
|
||||
}
|
||||
|
||||
return (filePath, resource)
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import TelegramCore
|
||||
import SyncCore
|
||||
import SwiftSignalKit
|
||||
|
||||
func loadLegacyUser(database: SqliteInterface, id: Int32) -> (TelegramUser, TelegramUserPresence)? {
|
||||
var result: (TelegramUser, TelegramUserPresence)?
|
||||
database.select("SELECT uid, first_name, last_name, phone_number, access_hash, photo_small, photo_big, last_seen, username FROM users_v29 WHERE uid=\(id)", { cursor in
|
||||
let accessHash = cursor.getInt64(at: 4)
|
||||
let firstName = cursor.getString(at: 1)
|
||||
let lastName = cursor.getString(at: 2)
|
||||
let username = cursor.getString(at: 8)
|
||||
let phone = cursor.getString(at: 3)
|
||||
|
||||
let photoSmall = cursor.getString(at: 5)
|
||||
let photoBig = cursor.getString(at: 6)
|
||||
var photo: [TelegramMediaImageRepresentation] = []
|
||||
if let resource = resourceFromLegacyImageUrl(photoSmall) {
|
||||
photo.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 80, height: 80), resource: resource, progressiveSizes: []))
|
||||
}
|
||||
if let resource = resourceFromLegacyImageUrl(photoBig) {
|
||||
photo.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 600, height: 600), resource: resource, progressiveSizes: []))
|
||||
}
|
||||
|
||||
let user = TelegramUser(id: EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: cursor.getInt32(at: 0)), accessHash: accessHash == 0 ? nil : .personal(accessHash), firstName: firstName.isEmpty ? nil : firstName, lastName: lastName.isEmpty ? nil : lastName, username: username.isEmpty ? nil : username, phone: phone.isEmpty ? nil : phone, photo: photo, botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
|
||||
let status: UserPresenceStatus
|
||||
let lastSeen = cursor.getInt32(at: 7)
|
||||
if lastSeen == -2 {
|
||||
status = .recently
|
||||
} else if lastSeen == -3 {
|
||||
status = .lastWeek
|
||||
} else if lastSeen == -4 {
|
||||
status = .lastMonth
|
||||
} else if lastSeen <= 0 {
|
||||
status = .none
|
||||
} else {
|
||||
status = .present(until: lastSeen)
|
||||
}
|
||||
|
||||
let presence = TelegramUserPresence(status: status, lastActivity: 0)
|
||||
result = (user, presence)
|
||||
return false
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
|
@ -361,48 +361,6 @@ public func legacyEnqueueGifMessage(account: Account, data: Data, correlationId:
|
|||
} |> runOn(Queue.concurrentDefaultQueue())
|
||||
}
|
||||
|
||||
public func legacyEnqueueVideoMessage(account: Account, data: Data, correlationId: Int64? = nil) -> Signal<EnqueueMessage, Void> {
|
||||
return Signal { subscriber in
|
||||
if let previewImage = UIImage(data: data) {
|
||||
let dimensions = previewImage.size
|
||||
var previewRepresentations: [TelegramMediaImageRepresentation] = []
|
||||
|
||||
let thumbnailSize = dimensions.aspectFitted(CGSize(width: 320.0, height: 320.0))
|
||||
let thumbnailImage = TGScaleImageToPixelSize(previewImage, thumbnailSize)!
|
||||
if let thumbnailData = thumbnailImage.jpegData(compressionQuality: 0.4) {
|
||||
let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
|
||||
account.postbox.mediaBox.storeResourceData(resource.id, data: thumbnailData)
|
||||
previewRepresentations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(thumbnailSize), resource: resource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false))
|
||||
}
|
||||
|
||||
var randomId: Int64 = 0
|
||||
arc4random_buf(&randomId, 8)
|
||||
let tempFilePath = NSTemporaryDirectory() + "\(randomId).mp4"
|
||||
|
||||
let _ = try? FileManager.default.removeItem(atPath: tempFilePath)
|
||||
let _ = try? data.write(to: URL(fileURLWithPath: tempFilePath), options: [.atomic])
|
||||
|
||||
let resource = LocalFileGifMediaResource(randomId: Int64.random(in: Int64.min ... Int64.max), path: tempFilePath)
|
||||
let fileName: String = "video.mp4"
|
||||
|
||||
let finalDimensions = TGMediaVideoConverter.dimensions(for: dimensions, adjustments: nil, preset: TGMediaVideoConversionPresetAnimation)
|
||||
|
||||
var fileAttributes: [TelegramMediaFileAttribute] = []
|
||||
fileAttributes.append(.Video(duration: 0.0, size: PixelDimensions(finalDimensions), flags: [.supportsStreaming], preloadSize: nil, coverTime: nil, videoCodec: nil))
|
||||
fileAttributes.append(.FileName(fileName: fileName))
|
||||
fileAttributes.append(.Animated)
|
||||
|
||||
let media = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: Int64.random(in: Int64.min ... Int64.max)), partialReference: nil, resource: resource, previewRepresentations: previewRepresentations, videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/mp4", size: nil, attributes: fileAttributes, alternativeRepresentations: [])
|
||||
subscriber.putNext(.message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: media), threadId: nil, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: nil, correlationId: correlationId, bubbleUpEmojiOrStickersets: []))
|
||||
subscriber.putCompletion()
|
||||
} else {
|
||||
subscriber.putError(Void())
|
||||
}
|
||||
|
||||
return EmptyDisposable
|
||||
} |> runOn(Queue.concurrentDefaultQueue())
|
||||
}
|
||||
|
||||
public struct LegacyAssetPickerEnqueueMessage {
|
||||
public var message: EnqueueMessage
|
||||
public var uniqueId: String?
|
||||
|
|
|
|||
|
|
@ -4,34 +4,33 @@ import AsyncDisplayKit
|
|||
import Display
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramPresentationData
|
||||
import AccountContext
|
||||
import TelegramUIPreferences
|
||||
import ItemListUI
|
||||
|
||||
public final class ListMessageItemInteraction {
|
||||
public let openMessage: (Message, ChatControllerInteractionOpenMessageMode) -> Bool
|
||||
public let openMessageContextMenu: (Message, Bool, ASDisplayNode, CGRect, UIGestureRecognizer?) -> Void
|
||||
public let toggleMessagesSelection: ([MessageId], Bool) -> Void
|
||||
public let toggleMediaPlayback: ((Message) -> Void)?
|
||||
let openUrl: (String, Bool, Bool?, Message?) -> Void
|
||||
let openInstantPage: (Message, ChatMessageItemAssociatedData?) -> Void
|
||||
let longTap: (ChatControllerInteractionLongTapAction, Message?) -> Void
|
||||
let getHiddenMedia: () -> [MessageId: [Media]]
|
||||
public let openMessage: (EngineRawMessage, ChatControllerInteractionOpenMessageMode) -> Bool
|
||||
public let openMessageContextMenu: (EngineRawMessage, Bool, ASDisplayNode, CGRect, UIGestureRecognizer?) -> Void
|
||||
public let toggleMessagesSelection: ([EngineMessage.Id], Bool) -> Void
|
||||
public let toggleMediaPlayback: ((EngineRawMessage) -> Void)?
|
||||
let openUrl: (String, Bool, Bool?, EngineRawMessage?) -> Void
|
||||
let openInstantPage: (EngineRawMessage, ChatMessageItemAssociatedData?) -> Void
|
||||
let longTap: (ChatControllerInteractionLongTapAction, EngineRawMessage?) -> Void
|
||||
let getHiddenMedia: () -> [EngineMessage.Id: [EngineRawMedia]]
|
||||
|
||||
public var searchTextHighightState: String?
|
||||
public var preferredStoryHighQuality: Bool = false
|
||||
|
||||
public init(
|
||||
openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool,
|
||||
openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect, UIGestureRecognizer?) -> Void,
|
||||
toggleMediaPlayback: ((Message) -> Void)?,
|
||||
toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void,
|
||||
openUrl: @escaping (String, Bool, Bool?, Message?) -> Void,
|
||||
openInstantPage: @escaping (Message, ChatMessageItemAssociatedData?) -> Void,
|
||||
longTap: @escaping (ChatControllerInteractionLongTapAction, Message?) -> Void,
|
||||
getHiddenMedia: @escaping () -> [MessageId: [Media]]
|
||||
openMessage: @escaping (EngineRawMessage, ChatControllerInteractionOpenMessageMode) -> Bool,
|
||||
openMessageContextMenu: @escaping (EngineRawMessage, Bool, ASDisplayNode, CGRect, UIGestureRecognizer?) -> Void,
|
||||
toggleMediaPlayback: ((EngineRawMessage) -> Void)?,
|
||||
toggleMessagesSelection: @escaping ([EngineMessage.Id], Bool) -> Void,
|
||||
openUrl: @escaping (String, Bool, Bool?, EngineRawMessage?) -> Void,
|
||||
openInstantPage: @escaping (EngineRawMessage, ChatMessageItemAssociatedData?) -> Void,
|
||||
longTap: @escaping (ChatControllerInteractionLongTapAction, EngineRawMessage?) -> Void,
|
||||
getHiddenMedia: @escaping () -> [EngineMessage.Id: [EngineRawMedia]]
|
||||
) {
|
||||
self.openMessage = openMessage
|
||||
self.openMessageContextMenu = openMessageContextMenu
|
||||
|
|
@ -51,7 +50,7 @@ public final class ListMessageItemInteraction {
|
|||
openUrl: { _, _, _, _ in
|
||||
}, openInstantPage: { _, _ in
|
||||
}, longTap: { _, _ in
|
||||
}, getHiddenMedia: { () -> [MessageId : [Media]] in
|
||||
}, getHiddenMedia: { () -> [EngineMessage.Id : [EngineRawMedia]] in
|
||||
return [:]
|
||||
})
|
||||
}
|
||||
|
|
@ -67,7 +66,7 @@ public final class ListMessageItem: ListViewItem, ItemListItem {
|
|||
let context: AccountContext
|
||||
let chatLocation: ChatLocation
|
||||
let interaction: ListMessageItemInteraction
|
||||
let message: Message?
|
||||
let message: EngineRawMessage?
|
||||
let translateToLanguage: String?
|
||||
public let selection: ChatHistoryMessageSelection
|
||||
public let selectionSide: ListMessageItemSelectionSide
|
||||
|
|
@ -94,7 +93,7 @@ public final class ListMessageItem: ListViewItem, ItemListItem {
|
|||
context: AccountContext,
|
||||
chatLocation: ChatLocation,
|
||||
interaction: ListMessageItemInteraction,
|
||||
message: Message?,
|
||||
message: EngineRawMessage?,
|
||||
translateToLanguage: String? = nil,
|
||||
selection: ChatHistoryMessageSelection,
|
||||
selectionSide: ListMessageItemSelectionSide = .right,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import Foundation
|
|||
import UIKit
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import AccountContext
|
||||
|
||||
public class ListMessageNode: ListViewItemNode {
|
||||
|
|
@ -28,7 +28,7 @@ public class ListMessageNode: ListViewItemNode {
|
|||
}
|
||||
}
|
||||
|
||||
public func transitionNode(id: MessageId, media: Media, adjustRect: Bool) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? {
|
||||
public func transitionNode(id: EngineMessage.Id, media: EngineRawMedia, adjustRect: Bool) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ swift_library(
|
|||
],
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/Postbox:Postbox",
|
||||
"//submodules/TelegramCore:TelegramCore",
|
||||
"//submodules/ImageCompression:ImageCompression",
|
||||
"//submodules/PersistentStringHash:PersistentStringHash",
|
||||
|
|
|
|||
|
|
@ -1,27 +1,26 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import PersistentStringHash
|
||||
|
||||
public final class VideoMediaResourceAdjustments: PostboxCoding, Equatable {
|
||||
public let data: MemoryBuffer
|
||||
public let digest: MemoryBuffer
|
||||
public final class VideoMediaResourceAdjustments: EnginePostboxCoding, Equatable {
|
||||
public let data: EngineMemoryBuffer
|
||||
public let digest: EngineMemoryBuffer
|
||||
public let isStory: Bool
|
||||
|
||||
public init(data: MemoryBuffer, digest: MemoryBuffer, isStory: Bool = false) {
|
||||
public init(data: EngineMemoryBuffer, digest: EngineMemoryBuffer, isStory: Bool = false) {
|
||||
self.data = data
|
||||
self.digest = digest
|
||||
self.isStory = isStory
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
public init(decoder: EnginePostboxDecoder) {
|
||||
self.data = decoder.decodeBytesForKey("d")!
|
||||
self.digest = decoder.decodeBytesForKey("h")!
|
||||
self.isStory = decoder.decodeBoolForKey("s", orElse: false)
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
public func encode(_ encoder: EnginePostboxEncoder) {
|
||||
encoder.encodeBytes(self.data, forKey: "d")
|
||||
encoder.encodeBytes(self.digest, forKey: "h")
|
||||
encoder.encodeBool(self.isStory, forKey: "s")
|
||||
|
|
@ -34,7 +33,7 @@ public final class VideoMediaResourceAdjustments: PostboxCoding, Equatable {
|
|||
|
||||
public struct VideoLibraryMediaResourceId {
|
||||
public let localIdentifier: String
|
||||
public let adjustmentsDigest: MemoryBuffer?
|
||||
public let adjustmentsDigest: EngineMemoryBuffer?
|
||||
|
||||
public var uniqueId: String {
|
||||
if let adjustmentsDigest = self.adjustmentsDigest {
|
||||
|
|
@ -49,11 +48,11 @@ public struct VideoLibraryMediaResourceId {
|
|||
}
|
||||
}
|
||||
|
||||
public enum VideoLibraryMediaResourceConversion: PostboxCoding, Equatable {
|
||||
public enum VideoLibraryMediaResourceConversion: EnginePostboxCoding, Equatable {
|
||||
case passthrough
|
||||
case compress(VideoMediaResourceAdjustments?)
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
public init(decoder: EnginePostboxDecoder) {
|
||||
switch decoder.decodeInt32ForKey("v", orElse: 0) {
|
||||
case 0:
|
||||
self = .passthrough
|
||||
|
|
@ -64,7 +63,7 @@ public enum VideoLibraryMediaResourceConversion: PostboxCoding, Equatable {
|
|||
}
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
public func encode(_ encoder: EnginePostboxEncoder) {
|
||||
switch self {
|
||||
case .passthrough:
|
||||
encoder.encodeInt32(0, forKey: "v")
|
||||
|
|
@ -113,28 +112,28 @@ public final class VideoLibraryMediaResource: TelegramMediaResource {
|
|||
self.conversion = conversion
|
||||
}
|
||||
|
||||
public required init(decoder: PostboxDecoder) {
|
||||
public required init(decoder: EnginePostboxDecoder) {
|
||||
self.localIdentifier = decoder.decodeStringForKey("i", orElse: "")
|
||||
self.conversion = (decoder.decodeObjectForKey("conv", decoder: { VideoLibraryMediaResourceConversion(decoder: $0) }) as? VideoLibraryMediaResourceConversion) ?? .compress(nil)
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
public func encode(_ encoder: EnginePostboxEncoder) {
|
||||
encoder.encodeString(self.localIdentifier, forKey: "i")
|
||||
encoder.encodeObject(self.conversion, forKey: "conv")
|
||||
}
|
||||
|
||||
public var id: MediaResourceId {
|
||||
var adjustmentsDigest: MemoryBuffer?
|
||||
public var id: EngineRawMediaResourceId {
|
||||
var adjustmentsDigest: EngineMemoryBuffer?
|
||||
switch self.conversion {
|
||||
case .passthrough:
|
||||
break
|
||||
case let .compress(adjustments):
|
||||
adjustmentsDigest = adjustments?.digest
|
||||
}
|
||||
return MediaResourceId(VideoLibraryMediaResourceId(localIdentifier: self.localIdentifier, adjustmentsDigest: adjustmentsDigest).uniqueId)
|
||||
return EngineRawMediaResourceId(VideoLibraryMediaResourceId(localIdentifier: self.localIdentifier, adjustmentsDigest: adjustmentsDigest).uniqueId)
|
||||
}
|
||||
|
||||
public func isEqual(to: MediaResource) -> Bool {
|
||||
public func isEqual(to: EngineRawMediaResource) -> Bool {
|
||||
if let to = to as? VideoLibraryMediaResource {
|
||||
return self.localIdentifier == to.localIdentifier && self.conversion == to.conversion
|
||||
} else {
|
||||
|
|
@ -180,7 +179,7 @@ public final class LocalFileVideoMediaResource: TelegramMediaResource {
|
|||
self.adjustments = adjustments
|
||||
}
|
||||
|
||||
public required init(decoder: PostboxDecoder) {
|
||||
public required init(decoder: EnginePostboxDecoder) {
|
||||
self.randomId = decoder.decodeInt64ForKey("i", orElse: 0)
|
||||
let paths = decoder.decodeStringArrayForKey("ps")
|
||||
if !paths.isEmpty {
|
||||
|
|
@ -191,7 +190,7 @@ public final class LocalFileVideoMediaResource: TelegramMediaResource {
|
|||
self.adjustments = decoder.decodeObjectForKey("a", decoder: { VideoMediaResourceAdjustments(decoder: $0) }) as? VideoMediaResourceAdjustments
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
public func encode(_ encoder: EnginePostboxEncoder) {
|
||||
encoder.encodeInt64(self.randomId, forKey: "i")
|
||||
encoder.encodeStringArray(self.paths, forKey: "ps")
|
||||
if let adjustments = self.adjustments {
|
||||
|
|
@ -201,11 +200,11 @@ public final class LocalFileVideoMediaResource: TelegramMediaResource {
|
|||
}
|
||||
}
|
||||
|
||||
public var id: MediaResourceId {
|
||||
return MediaResourceId(LocalFileVideoMediaResourceId(randomId: self.randomId).uniqueId)
|
||||
public var id: EngineRawMediaResourceId {
|
||||
return EngineRawMediaResourceId(LocalFileVideoMediaResourceId(randomId: self.randomId).uniqueId)
|
||||
}
|
||||
|
||||
public func isEqual(to: MediaResource) -> Bool {
|
||||
public func isEqual(to: EngineRawMediaResource) -> Bool {
|
||||
if let to = to as? LocalFileVideoMediaResource {
|
||||
return self.randomId == to.randomId && self.paths == to.paths && self.adjustments == to.adjustments
|
||||
} else {
|
||||
|
|
@ -245,7 +244,7 @@ public final class LocalFileAudioMediaResource: TelegramMediaResource {
|
|||
self.trimRange = trimRange
|
||||
}
|
||||
|
||||
public required init(decoder: PostboxDecoder) {
|
||||
public required init(decoder: EnginePostboxDecoder) {
|
||||
self.randomId = decoder.decodeInt64ForKey("i", orElse: 0)
|
||||
self.path = decoder.decodeStringForKey("p", orElse: "")
|
||||
|
||||
|
|
@ -256,7 +255,7 @@ public final class LocalFileAudioMediaResource: TelegramMediaResource {
|
|||
}
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
public func encode(_ encoder: EnginePostboxEncoder) {
|
||||
encoder.encodeInt64(self.randomId, forKey: "i")
|
||||
encoder.encodeString(self.path, forKey: "p")
|
||||
|
||||
|
|
@ -269,11 +268,11 @@ public final class LocalFileAudioMediaResource: TelegramMediaResource {
|
|||
}
|
||||
}
|
||||
|
||||
public var id: MediaResourceId {
|
||||
return MediaResourceId(LocalFileAudioMediaResourceId(randomId: self.randomId).uniqueId)
|
||||
public var id: EngineRawMediaResourceId {
|
||||
return EngineRawMediaResourceId(LocalFileAudioMediaResourceId(randomId: self.randomId).uniqueId)
|
||||
}
|
||||
|
||||
public func isEqual(to: MediaResource) -> Bool {
|
||||
public func isEqual(to: EngineRawMediaResource) -> Bool {
|
||||
if let to = to as? LocalFileAudioMediaResource {
|
||||
return self.randomId == to.randomId && self.path == to.path && self.trimRange == to.trimRange
|
||||
} else {
|
||||
|
|
@ -327,7 +326,7 @@ public class PhotoLibraryMediaResource: TelegramMediaResource {
|
|||
self.forceHd = forceHd
|
||||
}
|
||||
|
||||
public required init(decoder: PostboxDecoder) {
|
||||
public required init(decoder: EnginePostboxDecoder) {
|
||||
self.localIdentifier = decoder.decodeStringForKey("i", orElse: "")
|
||||
self.uniqueId = decoder.decodeInt64ForKey("uid", orElse: 0)
|
||||
self.width = decoder.decodeOptionalInt32ForKey("w")
|
||||
|
|
@ -337,7 +336,7 @@ public class PhotoLibraryMediaResource: TelegramMediaResource {
|
|||
self.forceHd = decoder.decodeBoolForKey("hd", orElse: false)
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
public func encode(_ encoder: EnginePostboxEncoder) {
|
||||
encoder.encodeString(self.localIdentifier, forKey: "i")
|
||||
encoder.encodeInt64(self.uniqueId, forKey: "uid")
|
||||
if let width = self.width {
|
||||
|
|
@ -363,11 +362,11 @@ public class PhotoLibraryMediaResource: TelegramMediaResource {
|
|||
encoder.encodeBool(self.forceHd, forKey: "hd")
|
||||
}
|
||||
|
||||
public var id: MediaResourceId {
|
||||
return MediaResourceId(PhotoLibraryMediaResourceId(localIdentifier: self.localIdentifier, resourceId: self.uniqueId).uniqueId)
|
||||
public var id: EngineRawMediaResourceId {
|
||||
return EngineRawMediaResourceId(PhotoLibraryMediaResourceId(localIdentifier: self.localIdentifier, resourceId: self.uniqueId).uniqueId)
|
||||
}
|
||||
|
||||
public func isEqual(to: MediaResource) -> Bool {
|
||||
public func isEqual(to: EngineRawMediaResource) -> Bool {
|
||||
if let to = to as? PhotoLibraryMediaResource {
|
||||
if self.localIdentifier != to.localIdentifier {
|
||||
return false
|
||||
|
|
@ -426,21 +425,21 @@ public final class LocalFileGifMediaResource: TelegramMediaResource {
|
|||
self.path = path
|
||||
}
|
||||
|
||||
public required init(decoder: PostboxDecoder) {
|
||||
public required init(decoder: EnginePostboxDecoder) {
|
||||
self.randomId = decoder.decodeInt64ForKey("i", orElse: 0)
|
||||
self.path = decoder.decodeStringForKey("p", orElse: "")
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
public func encode(_ encoder: EnginePostboxEncoder) {
|
||||
encoder.encodeInt64(self.randomId, forKey: "i")
|
||||
encoder.encodeString(self.path, forKey: "p")
|
||||
}
|
||||
|
||||
public var id: MediaResourceId {
|
||||
return MediaResourceId(LocalFileGifMediaResourceId(randomId: self.randomId).uniqueId)
|
||||
public var id: EngineRawMediaResourceId {
|
||||
return EngineRawMediaResourceId(LocalFileGifMediaResourceId(randomId: self.randomId).uniqueId)
|
||||
}
|
||||
|
||||
public func isEqual(to: MediaResource) -> Bool {
|
||||
public func isEqual(to: EngineRawMediaResource) -> Bool {
|
||||
if let to = to as? LocalFileGifMediaResource {
|
||||
return self.randomId == to.randomId && self.path == to.path
|
||||
} else {
|
||||
|
|
@ -475,21 +474,21 @@ public class BundleResource: TelegramMediaResource {
|
|||
self.path = path
|
||||
}
|
||||
|
||||
public required init(decoder: PostboxDecoder) {
|
||||
public required init(decoder: EnginePostboxDecoder) {
|
||||
self.nameHash = decoder.decodeInt64ForKey("h", orElse: 0)
|
||||
self.path = decoder.decodeStringForKey("p", orElse: "")
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
public func encode(_ encoder: EnginePostboxEncoder) {
|
||||
encoder.encodeInt64(self.nameHash, forKey: "h")
|
||||
encoder.encodeString(self.path, forKey: "p")
|
||||
}
|
||||
|
||||
public var id: MediaResourceId {
|
||||
return MediaResourceId(BundleResourceId(nameHash: self.nameHash).uniqueId)
|
||||
public var id: EngineRawMediaResourceId {
|
||||
return EngineRawMediaResourceId(BundleResourceId(nameHash: self.nameHash).uniqueId)
|
||||
}
|
||||
|
||||
public func isEqual(to: MediaResource) -> Bool {
|
||||
public func isEqual(to: EngineRawMediaResource) -> Bool {
|
||||
if let to = to as? BundleResource {
|
||||
return self.nameHash == to.nameHash
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ swift_library(
|
|||
],
|
||||
deps = [
|
||||
"//submodules/TelegramCore:TelegramCore",
|
||||
"//submodules/Postbox:Postbox",
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/TelegramUIPreferences:TelegramUIPreferences",
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
|
||||
public final class CachedStickerAJpegRepresentation: CachedMediaResourceRepresentation {
|
||||
public final class CachedStickerAJpegRepresentation: EngineRawCachedMediaResourceRepresentation {
|
||||
public let size: CGSize?
|
||||
public let keepDuration: CachedMediaRepresentationKeepDuration = .general
|
||||
public let keepDuration: EngineCachedMediaRepresentationKeepDuration = .general
|
||||
|
||||
public var uniqueId: String {
|
||||
if let size = self.size {
|
||||
|
|
@ -19,7 +19,7 @@ public final class CachedStickerAJpegRepresentation: CachedMediaResourceRepresen
|
|||
self.size = size
|
||||
}
|
||||
|
||||
public func isEqual(to: CachedMediaResourceRepresentation) -> Bool {
|
||||
public func isEqual(to: EngineRawCachedMediaResourceRepresentation) -> Bool {
|
||||
if let to = to as? CachedStickerAJpegRepresentation {
|
||||
return self.size == to.size
|
||||
} else {
|
||||
|
|
@ -33,8 +33,8 @@ public enum CachedScaledImageRepresentationMode: Int32 {
|
|||
case aspectFit = 1
|
||||
}
|
||||
|
||||
public final class CachedScaledImageRepresentation: CachedMediaResourceRepresentation {
|
||||
public let keepDuration: CachedMediaRepresentationKeepDuration = .general
|
||||
public final class CachedScaledImageRepresentation: EngineRawCachedMediaResourceRepresentation {
|
||||
public let keepDuration: EngineCachedMediaRepresentationKeepDuration = .general
|
||||
|
||||
public let size: CGSize
|
||||
public let mode: CachedScaledImageRepresentationMode
|
||||
|
|
@ -48,7 +48,7 @@ public final class CachedScaledImageRepresentation: CachedMediaResourceRepresent
|
|||
self.mode = mode
|
||||
}
|
||||
|
||||
public func isEqual(to: CachedMediaResourceRepresentation) -> Bool {
|
||||
public func isEqual(to: EngineRawCachedMediaResourceRepresentation) -> Bool {
|
||||
if let to = to as? CachedScaledImageRepresentation {
|
||||
return self.size == to.size && self.mode == to.mode
|
||||
} else {
|
||||
|
|
@ -57,8 +57,8 @@ public final class CachedScaledImageRepresentation: CachedMediaResourceRepresent
|
|||
}
|
||||
}
|
||||
|
||||
public final class CachedVideoFirstFrameRepresentation: CachedMediaResourceRepresentation {
|
||||
public let keepDuration: CachedMediaRepresentationKeepDuration = .general
|
||||
public final class CachedVideoFirstFrameRepresentation: EngineRawCachedMediaResourceRepresentation {
|
||||
public let keepDuration: EngineCachedMediaRepresentationKeepDuration = .general
|
||||
|
||||
public var uniqueId: String {
|
||||
return "first-frame"
|
||||
|
|
@ -67,7 +67,7 @@ public final class CachedVideoFirstFrameRepresentation: CachedMediaResourceRepre
|
|||
public init() {
|
||||
}
|
||||
|
||||
public func isEqual(to: CachedMediaResourceRepresentation) -> Bool {
|
||||
public func isEqual(to: EngineRawCachedMediaResourceRepresentation) -> Bool {
|
||||
if to is CachedVideoFirstFrameRepresentation {
|
||||
return true
|
||||
} else {
|
||||
|
|
@ -76,8 +76,8 @@ public final class CachedVideoFirstFrameRepresentation: CachedMediaResourceRepre
|
|||
}
|
||||
}
|
||||
|
||||
public final class CachedVideoPrefixFirstFrameRepresentation: CachedMediaResourceRepresentation {
|
||||
public let keepDuration: CachedMediaRepresentationKeepDuration = .general
|
||||
public final class CachedVideoPrefixFirstFrameRepresentation: EngineRawCachedMediaResourceRepresentation {
|
||||
public let keepDuration: EngineCachedMediaRepresentationKeepDuration = .general
|
||||
|
||||
public var uniqueId: String {
|
||||
return "prefix-first-frame"
|
||||
|
|
@ -89,7 +89,7 @@ public final class CachedVideoPrefixFirstFrameRepresentation: CachedMediaResourc
|
|||
self.prefixLength = prefixLength
|
||||
}
|
||||
|
||||
public func isEqual(to: CachedMediaResourceRepresentation) -> Bool {
|
||||
public func isEqual(to: EngineRawCachedMediaResourceRepresentation) -> Bool {
|
||||
if let to = to as? CachedVideoPrefixFirstFrameRepresentation {
|
||||
if self.prefixLength != to.prefixLength {
|
||||
return false
|
||||
|
|
@ -101,8 +101,8 @@ public final class CachedVideoPrefixFirstFrameRepresentation: CachedMediaResourc
|
|||
}
|
||||
}
|
||||
|
||||
public final class CachedScaledVideoFirstFrameRepresentation: CachedMediaResourceRepresentation {
|
||||
public let keepDuration: CachedMediaRepresentationKeepDuration = .general
|
||||
public final class CachedScaledVideoFirstFrameRepresentation: EngineRawCachedMediaResourceRepresentation {
|
||||
public let keepDuration: EngineCachedMediaRepresentationKeepDuration = .general
|
||||
|
||||
public let size: CGSize
|
||||
|
||||
|
|
@ -114,7 +114,7 @@ public final class CachedScaledVideoFirstFrameRepresentation: CachedMediaResourc
|
|||
self.size = size
|
||||
}
|
||||
|
||||
public func isEqual(to: CachedMediaResourceRepresentation) -> Bool {
|
||||
public func isEqual(to: EngineRawCachedMediaResourceRepresentation) -> Bool {
|
||||
if let to = to as? CachedScaledVideoFirstFrameRepresentation {
|
||||
return self.size == to.size
|
||||
} else {
|
||||
|
|
@ -123,8 +123,8 @@ public final class CachedScaledVideoFirstFrameRepresentation: CachedMediaResourc
|
|||
}
|
||||
}
|
||||
|
||||
public final class CachedBlurredWallpaperRepresentation: CachedMediaResourceRepresentation {
|
||||
public let keepDuration: CachedMediaRepresentationKeepDuration = .general
|
||||
public final class CachedBlurredWallpaperRepresentation: EngineRawCachedMediaResourceRepresentation {
|
||||
public let keepDuration: EngineCachedMediaRepresentationKeepDuration = .general
|
||||
|
||||
public var uniqueId: String {
|
||||
return "blurred-wallpaper"
|
||||
|
|
@ -133,7 +133,7 @@ public final class CachedBlurredWallpaperRepresentation: CachedMediaResourceRepr
|
|||
public init() {
|
||||
}
|
||||
|
||||
public func isEqual(to: CachedMediaResourceRepresentation) -> Bool {
|
||||
public func isEqual(to: EngineRawCachedMediaResourceRepresentation) -> Bool {
|
||||
if to is CachedBlurredWallpaperRepresentation {
|
||||
return true
|
||||
} else {
|
||||
|
|
@ -142,8 +142,8 @@ public final class CachedBlurredWallpaperRepresentation: CachedMediaResourceRepr
|
|||
}
|
||||
}
|
||||
|
||||
public final class CachedAlbumArtworkRepresentation: CachedMediaResourceRepresentation {
|
||||
public let keepDuration: CachedMediaRepresentationKeepDuration = .general
|
||||
public final class CachedAlbumArtworkRepresentation: EngineRawCachedMediaResourceRepresentation {
|
||||
public let keepDuration: EngineCachedMediaRepresentationKeepDuration = .general
|
||||
|
||||
public let size: CGSize?
|
||||
|
||||
|
|
@ -159,7 +159,7 @@ public final class CachedAlbumArtworkRepresentation: CachedMediaResourceRepresen
|
|||
self.size = size
|
||||
}
|
||||
|
||||
public func isEqual(to: CachedMediaResourceRepresentation) -> Bool {
|
||||
public func isEqual(to: EngineRawCachedMediaResourceRepresentation) -> Bool {
|
||||
if let to = to as? CachedAlbumArtworkRepresentation {
|
||||
return self.size == to.size
|
||||
} else {
|
||||
|
|
@ -168,8 +168,8 @@ public final class CachedAlbumArtworkRepresentation: CachedMediaResourceRepresen
|
|||
}
|
||||
}
|
||||
|
||||
public final class CachedEmojiThumbnailRepresentation: CachedMediaResourceRepresentation {
|
||||
public let keepDuration: CachedMediaRepresentationKeepDuration = .general
|
||||
public final class CachedEmojiThumbnailRepresentation: EngineRawCachedMediaResourceRepresentation {
|
||||
public let keepDuration: EngineCachedMediaRepresentationKeepDuration = .general
|
||||
|
||||
public let outline: Bool
|
||||
|
||||
|
|
@ -181,7 +181,7 @@ public final class CachedEmojiThumbnailRepresentation: CachedMediaResourceRepres
|
|||
self.outline = outline
|
||||
}
|
||||
|
||||
public func isEqual(to: CachedMediaResourceRepresentation) -> Bool {
|
||||
public func isEqual(to: EngineRawCachedMediaResourceRepresentation) -> Bool {
|
||||
if let to = to as? CachedEmojiThumbnailRepresentation {
|
||||
return self.outline == to.outline
|
||||
} else {
|
||||
|
|
@ -190,8 +190,8 @@ public final class CachedEmojiThumbnailRepresentation: CachedMediaResourceRepres
|
|||
}
|
||||
}
|
||||
|
||||
public final class CachedEmojiRepresentation: CachedMediaResourceRepresentation {
|
||||
public let keepDuration: CachedMediaRepresentationKeepDuration = .general
|
||||
public final class CachedEmojiRepresentation: EngineRawCachedMediaResourceRepresentation {
|
||||
public let keepDuration: EngineCachedMediaRepresentationKeepDuration = .general
|
||||
|
||||
public let tile: UInt8
|
||||
public let outline: Bool
|
||||
|
|
@ -205,7 +205,7 @@ public final class CachedEmojiRepresentation: CachedMediaResourceRepresentation
|
|||
self.outline = outline
|
||||
}
|
||||
|
||||
public func isEqual(to: CachedMediaResourceRepresentation) -> Bool {
|
||||
public func isEqual(to: EngineRawCachedMediaResourceRepresentation) -> Bool {
|
||||
if let to = to as? CachedEmojiRepresentation {
|
||||
return self.tile == to.tile && self.outline == to.outline
|
||||
} else {
|
||||
|
|
@ -239,8 +239,8 @@ public enum EmojiFitzModifier: Int32, Equatable {
|
|||
}
|
||||
}
|
||||
|
||||
public final class CachedAnimatedStickerFirstFrameRepresentation: CachedMediaResourceRepresentation {
|
||||
public let keepDuration: CachedMediaRepresentationKeepDuration = .general
|
||||
public final class CachedAnimatedStickerFirstFrameRepresentation: EngineRawCachedMediaResourceRepresentation {
|
||||
public let keepDuration: EngineCachedMediaRepresentationKeepDuration = .general
|
||||
|
||||
public let width: Int32
|
||||
public let height: Int32
|
||||
|
|
@ -261,7 +261,7 @@ public final class CachedAnimatedStickerFirstFrameRepresentation: CachedMediaRes
|
|||
}
|
||||
}
|
||||
|
||||
public func isEqual(to: CachedMediaResourceRepresentation) -> Bool {
|
||||
public func isEqual(to: EngineRawCachedMediaResourceRepresentation) -> Bool {
|
||||
if let other = to as? CachedAnimatedStickerFirstFrameRepresentation {
|
||||
if other.width != self.width {
|
||||
return false
|
||||
|
|
@ -279,8 +279,8 @@ public final class CachedAnimatedStickerFirstFrameRepresentation: CachedMediaRes
|
|||
}
|
||||
}
|
||||
|
||||
public final class CachedAnimatedStickerRepresentation: CachedMediaResourceRepresentation {
|
||||
public let keepDuration: CachedMediaRepresentationKeepDuration = .shortLived
|
||||
public final class CachedAnimatedStickerRepresentation: EngineRawCachedMediaResourceRepresentation {
|
||||
public let keepDuration: EngineCachedMediaRepresentationKeepDuration = .shortLived
|
||||
|
||||
public let width: Int32
|
||||
public let height: Int32
|
||||
|
|
@ -301,7 +301,7 @@ public final class CachedAnimatedStickerRepresentation: CachedMediaResourceRepre
|
|||
self.fitzModifier = fitzModifier
|
||||
}
|
||||
|
||||
public func isEqual(to: CachedMediaResourceRepresentation) -> Bool {
|
||||
public func isEqual(to: EngineRawCachedMediaResourceRepresentation) -> Bool {
|
||||
if let other = to as? CachedAnimatedStickerRepresentation {
|
||||
if other.width != self.width {
|
||||
return false
|
||||
|
|
@ -319,8 +319,8 @@ public final class CachedAnimatedStickerRepresentation: CachedMediaResourceRepre
|
|||
}
|
||||
}
|
||||
|
||||
public final class CachedVideoStickerRepresentation: CachedMediaResourceRepresentation {
|
||||
public let keepDuration: CachedMediaRepresentationKeepDuration = .shortLived
|
||||
public final class CachedVideoStickerRepresentation: EngineRawCachedMediaResourceRepresentation {
|
||||
public let keepDuration: EngineCachedMediaRepresentationKeepDuration = .shortLived
|
||||
|
||||
public let width: Int32
|
||||
public let height: Int32
|
||||
|
|
@ -336,7 +336,7 @@ public final class CachedVideoStickerRepresentation: CachedMediaResourceRepresen
|
|||
self.height = height
|
||||
}
|
||||
|
||||
public func isEqual(to: CachedMediaResourceRepresentation) -> Bool {
|
||||
public func isEqual(to: EngineRawCachedMediaResourceRepresentation) -> Bool {
|
||||
if let other = to as? CachedVideoStickerRepresentation {
|
||||
if other.width != self.width {
|
||||
return false
|
||||
|
|
@ -351,8 +351,8 @@ public final class CachedVideoStickerRepresentation: CachedMediaResourceRepresen
|
|||
}
|
||||
}
|
||||
|
||||
public final class CachedPreparedPatternWallpaperRepresentation: CachedMediaResourceRepresentation {
|
||||
public let keepDuration: CachedMediaRepresentationKeepDuration = .general
|
||||
public final class CachedPreparedPatternWallpaperRepresentation: EngineRawCachedMediaResourceRepresentation {
|
||||
public let keepDuration: EngineCachedMediaRepresentationKeepDuration = .general
|
||||
|
||||
public var uniqueId: String {
|
||||
return "prepared-pattern-wallpaper"
|
||||
|
|
@ -361,7 +361,7 @@ public final class CachedPreparedPatternWallpaperRepresentation: CachedMediaReso
|
|||
public init() {
|
||||
}
|
||||
|
||||
public func isEqual(to: CachedMediaResourceRepresentation) -> Bool {
|
||||
public func isEqual(to: EngineRawCachedMediaResourceRepresentation) -> Bool {
|
||||
if to is CachedPreparedPatternWallpaperRepresentation {
|
||||
return true
|
||||
} else {
|
||||
|
|
@ -371,8 +371,8 @@ public final class CachedPreparedPatternWallpaperRepresentation: CachedMediaReso
|
|||
}
|
||||
|
||||
|
||||
public final class CachedPreparedSvgRepresentation: CachedMediaResourceRepresentation {
|
||||
public let keepDuration: CachedMediaRepresentationKeepDuration = .general
|
||||
public final class CachedPreparedSvgRepresentation: EngineRawCachedMediaResourceRepresentation {
|
||||
public let keepDuration: EngineCachedMediaRepresentationKeepDuration = .general
|
||||
|
||||
public var uniqueId: String {
|
||||
return "prepared-svg"
|
||||
|
|
@ -381,7 +381,7 @@ public final class CachedPreparedSvgRepresentation: CachedMediaResourceRepresent
|
|||
public init() {
|
||||
}
|
||||
|
||||
public func isEqual(to: CachedMediaResourceRepresentation) -> Bool {
|
||||
public func isEqual(to: EngineRawCachedMediaResourceRepresentation) -> Bool {
|
||||
if to is CachedPreparedSvgRepresentation {
|
||||
return true
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ func presentLegacySecureIdAttachmentMenu(context: AccountContext, present: @esca
|
|||
|> runOn(.mainQueue())
|
||||
|> delay(0.1, queue: .mainQueue())).start()
|
||||
|
||||
let _ = (processedLegacySecureIdAttachmentItems(postbox: context.account.postbox, signal: signal)
|
||||
let _ = (processedLegacySecureIdAttachmentItems(signal: signal)
|
||||
|> mapToSignal { resources -> Signal<([TelegramMediaResource], SecureIdRecognizedDocumentData?), NoError> in
|
||||
switch type {
|
||||
case .generic, .idCard:
|
||||
|
|
@ -116,7 +116,7 @@ private enum AttachmentItem {
|
|||
case iCloud(URL)
|
||||
}
|
||||
|
||||
private func processedLegacySecureIdAttachmentItems(postbox: Postbox, signal: SSignal) -> Signal<[TelegramMediaResource], NoError> {
|
||||
private func processedLegacySecureIdAttachmentItems(signal: SSignal) -> Signal<[TelegramMediaResource], NoError> {
|
||||
let nativeSignal = Signal<AttachmentItem?, NoError> { subscriber in
|
||||
let disposable = signal.start(next: { next in
|
||||
if let dict = next as? [String: Any], let image = dict["image"] as? UIImage {
|
||||
|
|
|
|||
|
|
@ -844,24 +844,6 @@ private func chatMessageVideoDatas(postbox: Postbox, userLocation: MediaResource
|
|||
return signal
|
||||
}
|
||||
|
||||
public func rawMessagePhoto(postbox: Postbox, userLocation: MediaResourceUserLocation, photoReference: ImageMediaReference) -> Signal<UIImage?, NoError> {
|
||||
return chatMessagePhotoDatas(postbox: postbox, userLocation: userLocation, photoReference: photoReference, autoFetchFullSize: true)
|
||||
|> map { value -> UIImage? in
|
||||
let thumbnailData = value._0
|
||||
let fullSizeData = value._1
|
||||
let fullSizeComplete = value._3
|
||||
if let fullSizeData = fullSizeData {
|
||||
if fullSizeComplete {
|
||||
return UIImage(data: fullSizeData)?.precomposed()
|
||||
}
|
||||
}
|
||||
if let thumbnailData = thumbnailData {
|
||||
return UIImage(data: thumbnailData)?.precomposed()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public func chatMessagePhoto(postbox: Postbox, userLocation: MediaResourceUserLocation, userContentType customUserContentType: MediaResourceUserContentType? = nil, photoReference: ImageMediaReference, synchronousLoad: Bool = false, highQuality: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||
return chatMessagePhotoInternal(photoData: chatMessagePhotoDatas(postbox: postbox, userLocation: userLocation, customUserContentType: customUserContentType, photoReference: photoReference, tryAdditionalRepresentations: true, synchronousLoad: synchronousLoad), synchronousLoad: synchronousLoad)
|
||||
|> map { _, _, generate in
|
||||
|
|
@ -1766,79 +1748,6 @@ public func mediaGridMessagePhoto(account: Account, userLocation: MediaResourceU
|
|||
}
|
||||
}
|
||||
|
||||
public func gifPaneVideoThumbnail(account: Account, videoReference: FileMediaReference) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||
if let smallestRepresentation = smallestImageRepresentation(videoReference.media.previewRepresentations) {
|
||||
let thumbnailResource = smallestRepresentation.resource
|
||||
|
||||
let thumbnail = Signal<MediaResourceData, NoError> { subscriber in
|
||||
let data = account.postbox.mediaBox.resourceData(thumbnailResource).start(next: { data in
|
||||
subscriber.putNext(data)
|
||||
}, completed: {
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
let fetched = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: .other, reference: videoReference.resourceReference(thumbnailResource)).start()
|
||||
return ActionDisposable {
|
||||
data.dispose()
|
||||
fetched.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
return thumbnail
|
||||
|> map { data in
|
||||
let thumbnailData = try? Data(contentsOf: URL(fileURLWithPath: data.path))
|
||||
return { arguments in
|
||||
guard let context = DrawingContext(size: arguments.drawingSize, clear: true) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let drawingRect = arguments.drawingRect
|
||||
let fittedSize = arguments.imageSize.aspectFilled(arguments.boundingSize).fitted(arguments.imageSize)
|
||||
let fittedRect = CGRect(origin: CGPoint(x: drawingRect.origin.x + (drawingRect.size.width - fittedSize.width) / 2.0, y: drawingRect.origin.y + (drawingRect.size.height - fittedSize.height) / 2.0), size: fittedSize)
|
||||
|
||||
var thumbnailImage: CGImage?
|
||||
if let thumbnailData = thumbnailData, let imageSource = CGImageSourceCreateWithData(thumbnailData as CFData, nil), let image = CGImageSourceCreateImageAtIndex(imageSource, 0, nil) {
|
||||
thumbnailImage = image
|
||||
}
|
||||
|
||||
var blurredThumbnailImage: UIImage?
|
||||
if let thumbnailImage = thumbnailImage {
|
||||
let thumbnailSize = CGSize(width: thumbnailImage.width, height: thumbnailImage.height)
|
||||
let thumbnailContextSize = thumbnailSize.aspectFitted(CGSize(width: 150.0, height: 150.0))
|
||||
if let thumbnailContext = DrawingContext(size: thumbnailContextSize, scale: 1.0) {
|
||||
thumbnailContext.withFlippedContext { c in
|
||||
c.interpolationQuality = .none
|
||||
c.draw(thumbnailImage, in: CGRect(origin: CGPoint(), size: thumbnailContextSize))
|
||||
}
|
||||
imageFastBlur(Int32(thumbnailContextSize.width), Int32(thumbnailContextSize.height), Int32(thumbnailContext.bytesPerRow), thumbnailContext.bytes)
|
||||
|
||||
blurredThumbnailImage = thumbnailContext.generateImage()
|
||||
}
|
||||
}
|
||||
|
||||
context.withFlippedContext { c in
|
||||
c.setBlendMode(.copy)
|
||||
if arguments.boundingSize != arguments.imageSize {
|
||||
c.fill(arguments.drawingRect)
|
||||
}
|
||||
|
||||
c.setBlendMode(.copy)
|
||||
if let blurredThumbnailImage = blurredThumbnailImage, let cgImage = blurredThumbnailImage.cgImage {
|
||||
c.interpolationQuality = .low
|
||||
drawImage(context: c, image: cgImage, orientation: .up, in: fittedRect)
|
||||
c.setBlendMode(.normal)
|
||||
}
|
||||
}
|
||||
|
||||
addCorners(context, arguments: arguments)
|
||||
|
||||
return context
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .never()
|
||||
}
|
||||
}
|
||||
|
||||
public func mediaGridMessageVideo(postbox: Postbox, userLocation: MediaResourceUserLocation, userContentType customUserContentType: MediaResourceUserContentType? = nil, videoReference: FileMediaReference, hlsFiles: [(playlist: TelegramMediaFile, video: TelegramMediaFile)] = [], onlyFullSize: Bool = false, useLargeThumbnail: Bool = false, synchronousLoad: Bool = false, autoFetchFullSizeThumbnail: Bool = false, overlayColor: UIColor? = nil, nilForEmptyResult: Bool = false, useMiniThumbnailIfAvailable: Bool = false, blurred: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||
return internalMediaGridMessageVideo(postbox: postbox, userLocation: userLocation, customUserContentType: customUserContentType, videoReference: videoReference, hlsFiles: hlsFiles, onlyFullSize: onlyFullSize, useLargeThumbnail: useLargeThumbnail, synchronousLoad: synchronousLoad, autoFetchFullSizeThumbnail: autoFetchFullSizeThumbnail, overlayColor: overlayColor, nilForEmptyResult: nilForEmptyResult, useMiniThumbnailIfAvailable: useMiniThumbnailIfAvailable)
|
||||
|> map {
|
||||
|
|
@ -2703,25 +2612,6 @@ public func chatMessageImageFile(account: Account, userLocation: MediaResourceUs
|
|||
}
|
||||
}
|
||||
|
||||
public func preloadedBotIcon(account: Account, fileReference: FileMediaReference) -> Signal<Bool, NoError> {
|
||||
let signal = Signal<Bool, NoError> { subscriber in
|
||||
let fetched = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: MediaResourceUserContentType(file: fileReference.media), reference: fileReference.resourceReference(fileReference.media.resource)).start()
|
||||
let dataDisposable = account.postbox.mediaBox.resourceData(fileReference.media.resource, option: .incremental(waitUntilFetchStatus: false)).start(next: { data in
|
||||
if data.complete {
|
||||
subscriber.putNext(true)
|
||||
subscriber.putCompletion()
|
||||
} else {
|
||||
subscriber.putNext(false)
|
||||
}
|
||||
})
|
||||
return ActionDisposable {
|
||||
fetched.dispose()
|
||||
dataDisposable.dispose()
|
||||
}
|
||||
}
|
||||
return signal
|
||||
}
|
||||
|
||||
public func instantPageImageFile(account: Account, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference, fetched: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||
return chatMessageFileDatas(account: account, userLocation: userLocation, fileReference: fileReference, progressive: false, fetched: fetched)
|
||||
|> map { value in
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import Foundation
|
||||
import TelegramCore
|
||||
import Postbox
|
||||
|
||||
public extension Message {
|
||||
public extension EngineRawMessage {
|
||||
func isRestricted(platform: String, contentSettings: ContentSettings) -> Bool {
|
||||
return self.restrictionReason(platform: platform, contentSettings: contentSettings) != nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent {
|
|||
jsonString += "]}}"
|
||||
|
||||
if let data = jsonString.data(using: .utf8), let json = JSON(data: data) {
|
||||
addAppLogEvent(postbox: strongSelf.context.account.postbox, type: "premium_gift.promo_screen_show", data: json)
|
||||
strongSelf.context.engine.accountData.addAppLogEvent(type: "premium_gift.promo_screen_show", data: json)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -568,7 +568,7 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent {
|
|||
controller?.dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
addAppLogEvent(postbox: accountContext.account.postbox, type: "premium_gift.promo_screen_tap", data: ["item": perk.identifier])
|
||||
accountContext.engine.accountData.addAppLogEvent(type: "premium_gift.promo_screen_tap", data: ["item": perk.identifier])
|
||||
}
|
||||
))
|
||||
i += 1
|
||||
|
|
@ -900,7 +900,7 @@ private final class PremiumGiftScreenComponent: CombinedComponent {
|
|||
let (currency, amount) = product.storeProduct.priceCurrencyAndAmount
|
||||
let duration = product.months
|
||||
|
||||
addAppLogEvent(postbox: self.context.account.postbox, type: "premium_gift.promo_screen_accept")
|
||||
self.context.engine.accountData.addAppLogEvent(type: "premium_gift.promo_screen_accept")
|
||||
|
||||
self.inProgress = true
|
||||
self.updateInProgress(true)
|
||||
|
|
@ -968,7 +968,7 @@ private final class PremiumGiftScreenComponent: CombinedComponent {
|
|||
}
|
||||
|
||||
if let errorText = errorText {
|
||||
addAppLogEvent(postbox: strongSelf.context.account.postbox, type: "premium_gift.promo_screen_fail")
|
||||
strongSelf.context.engine.accountData.addAppLogEvent(type: "premium_gift.promo_screen_fail")
|
||||
|
||||
let alertController = textAlertController(context: strongSelf.context, title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
|
||||
strongSelf.present(alertController)
|
||||
|
|
|
|||
|
|
@ -1682,7 +1682,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
|||
jsonString += "]}}"
|
||||
|
||||
if let context = screenContext.context, let data = jsonString.data(using: .utf8), let json = JSON(data: data) {
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "premium.promo_screen_show", data: json)
|
||||
context.engine.accountData.addAppLogEvent(type: "premium.promo_screen_show", data: json)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -2260,7 +2260,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
|||
}
|
||||
updateIsFocused(true)
|
||||
|
||||
addAppLogEvent(postbox: accountContext.account.postbox, type: "premium.promo_screen_tap", data: ["item": perk.identifier])
|
||||
accountContext.engine.accountData.addAppLogEvent(type: "premium.promo_screen_tap", data: ["item": perk.identifier])
|
||||
},
|
||||
highlighting: accountContext != nil ? .default : .disabled
|
||||
))))
|
||||
|
|
@ -3262,7 +3262,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
|||
}
|
||||
|
||||
if let context = self.screenContext.context {
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "premium.promo_screen_accept")
|
||||
context.engine.accountData.addAppLogEvent(type: "premium.promo_screen_accept")
|
||||
}
|
||||
|
||||
self.inProgress = true
|
||||
|
|
@ -3316,7 +3316,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
|||
self.updated(transition: .immediate)
|
||||
|
||||
if let context = self.screenContext.context {
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "premium.promo_screen_fail")
|
||||
context.engine.accountData.addAppLogEvent(type: "premium.promo_screen_fail")
|
||||
}
|
||||
|
||||
let errorText = presentationData.strings.Premium_Purchase_ErrorUnknown
|
||||
|
|
@ -3368,7 +3368,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
|||
|
||||
if let errorText = errorText {
|
||||
if let context = self.screenContext.context {
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "premium.promo_screen_fail")
|
||||
context.engine.accountData.addAppLogEvent(type: "premium.promo_screen_fail")
|
||||
}
|
||||
|
||||
let alertController = textAlertController(sharedContext: self.screenContext.sharedContext, title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
|
||||
|
|
|
|||
|
|
@ -296,15 +296,15 @@ func deleteAccountDataController(context: AccountContext, mode: DeleteAccountDat
|
|||
|
||||
switch mode {
|
||||
case .peers:
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_cloud_cancel")
|
||||
context.engine.accountData.addAppLogEvent(type: "deactivate.step_cloud_cancel")
|
||||
case .groups:
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_groups_cancel")
|
||||
context.engine.accountData.addAppLogEvent(type: "deactivate.step_groups_cancel")
|
||||
case .messages:
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_messages_cancel")
|
||||
context.engine.accountData.addAppLogEvent(type: "deactivate.step_messages_cancel")
|
||||
case .phone:
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_phone_cancel")
|
||||
context.engine.accountData.addAppLogEvent(type: "deactivate.step_phone_cancel")
|
||||
case .password:
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_2fa_cancel")
|
||||
context.engine.accountData.addAppLogEvent(type: "deactivate.step_2fa_cancel")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -437,10 +437,10 @@ func deleteAccountDataController(context: AccountContext, mode: DeleteAccountDat
|
|||
let controller = deleteAccountDataController(context: context, mode: nextMode, twoStepAuthData: twoStepAuthData)
|
||||
replaceTopControllerImpl?(controller)
|
||||
} else {
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_confirmation_show")
|
||||
context.engine.accountData.addAppLogEvent(type: "deactivate.step_confirmation_show")
|
||||
|
||||
presentControllerImpl?(textAlertController(context: context, title: presentationData.strings.DeleteAccount_ConfirmationAlertTitle, text: presentationData.strings.DeleteAccount_ConfirmationAlertText, actions: [TextAlertAction(type: .destructiveAction, title: presentationData.strings.DeleteAccount_ConfirmationAlertDelete, action: {
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.final")
|
||||
context.engine.accountData.addAppLogEvent(type: "deactivate.final")
|
||||
|
||||
invokeAppLogEventsSynchronization(postbox: context.account.postbox)
|
||||
|
||||
|
|
@ -473,7 +473,7 @@ func deleteAccountDataController(context: AccountContext, mode: DeleteAccountDat
|
|||
})
|
||||
})
|
||||
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_confirmation_cancel")
|
||||
context.engine.accountData.addAppLogEvent(type: "deactivate.step_confirmation_cancel")
|
||||
|
||||
dismissImpl?()
|
||||
})], actionLayout: .vertical))
|
||||
|
|
@ -581,15 +581,15 @@ func deleteAccountDataController(context: AccountContext, mode: DeleteAccountDat
|
|||
|
||||
switch mode {
|
||||
case .peers:
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_cloud_show")
|
||||
context.engine.accountData.addAppLogEvent(type: "deactivate.step_cloud_show")
|
||||
case .groups:
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_groups_show")
|
||||
context.engine.accountData.addAppLogEvent(type: "deactivate.step_groups_show")
|
||||
case .messages:
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_messages_show")
|
||||
context.engine.accountData.addAppLogEvent(type: "deactivate.step_messages_show")
|
||||
case .phone:
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_phone_show")
|
||||
context.engine.accountData.addAppLogEvent(type: "deactivate.step_phone_show")
|
||||
case .password:
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_2fa_show")
|
||||
context.engine.accountData.addAppLogEvent(type: "deactivate.step_2fa_show")
|
||||
}
|
||||
|
||||
return controller
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ public func deleteAccountOptionsController(context: AccountContext, navigationCo
|
|||
let supportPeerDisposable = MetaDisposable()
|
||||
|
||||
let arguments = DeleteAccountOptionsArguments(changePhoneNumber: {
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_phone_change_tap")
|
||||
context.engine.accountData.addAppLogEvent(type: "deactivate.options_phone_change_tap")
|
||||
|
||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.engine.account.peerId))
|
||||
|> deliverOnMainQueue).start(next: { accountPeer in
|
||||
|
|
@ -195,7 +195,7 @@ public func deleteAccountOptionsController(context: AccountContext, navigationCo
|
|||
dismissImpl?()
|
||||
})
|
||||
}, addAccount: {
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_add_account_tap")
|
||||
context.engine.accountData.addAppLogEvent(type: "deactivate.options_add_account_tap")
|
||||
|
||||
let _ = (activeAccountsAndPeers(context: context)
|
||||
|> take(1)
|
||||
|
|
@ -233,11 +233,11 @@ public func deleteAccountOptionsController(context: AccountContext, navigationCo
|
|||
}
|
||||
})
|
||||
}, setupPrivacy: {
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_privacy_tap")
|
||||
context.engine.accountData.addAppLogEvent(type: "deactivate.options_privacy_tap")
|
||||
|
||||
replaceTopControllerImpl?(makePrivacyAndSecurityController(context: context), false)
|
||||
}, setupTwoStepAuth: {
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_2fa_tap")
|
||||
context.engine.accountData.addAppLogEvent(type: "deactivate.options_2fa_tap")
|
||||
|
||||
if let data = twoStepAuthData {
|
||||
switch data {
|
||||
|
|
@ -263,7 +263,7 @@ public func deleteAccountOptionsController(context: AccountContext, navigationCo
|
|||
let controller = twoStepVerificationUnlockSettingsController(context: context, mode: .access(intro: false, data: twoStepAuthData.flatMap({ Signal<TwoStepVerificationUnlockSettingsControllerData, NoError>.single(.access(configuration: $0)) })))
|
||||
replaceTopControllerImpl?(controller, false)
|
||||
}, setPasscode: {
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_passcode_tap")
|
||||
context.engine.accountData.addAppLogEvent(type: "deactivate.options_passcode_tap")
|
||||
|
||||
let _ = passcodeOptionsAccessController(context: context, pushController: { controller in
|
||||
replaceTopControllerImpl?(controller, false)
|
||||
|
|
@ -276,18 +276,18 @@ public func deleteAccountOptionsController(context: AccountContext, navigationCo
|
|||
})
|
||||
dismissImpl?()
|
||||
}, clearCache: {
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_clear_cache_tap")
|
||||
context.engine.accountData.addAppLogEvent(type: "deactivate.options_clear_cache_tap")
|
||||
|
||||
pushControllerImpl?(StorageUsageScreen(context: context, makeStorageUsageExceptionsScreen: { category in
|
||||
return storageUsageExceptionsScreen(context: context, category: category)
|
||||
}))
|
||||
dismissImpl?()
|
||||
}, clearSyncedContacts: {
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_clear_contacts_tap")
|
||||
context.engine.accountData.addAppLogEvent(type: "deactivate.options_clear_contacts_tap")
|
||||
|
||||
replaceTopControllerImpl?(dataPrivacyController(context: context), false)
|
||||
}, deleteChats: {
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_delete_chats_tap")
|
||||
context.engine.accountData.addAppLogEvent(type: "deactivate.options_delete_chats_tap")
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
|
|
@ -325,7 +325,7 @@ public func deleteAccountOptionsController(context: AccountContext, navigationCo
|
|||
|
||||
openFaq(resolvedUrlPromise)
|
||||
}, contactSupport: { [weak navigationController] in
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_support_tap")
|
||||
context.engine.accountData.addAppLogEvent(type: "deactivate.options_support_tap")
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
|
|
@ -394,7 +394,7 @@ public func deleteAccountOptionsController(context: AccountContext, navigationCo
|
|||
]
|
||||
)
|
||||
alertController.dismissed = { _ in
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_support_cancel")
|
||||
context.engine.accountData.addAppLogEvent(type: "deactivate.options_support_cancel")
|
||||
}
|
||||
presentControllerImpl?(alertController, nil)
|
||||
}, deleteAccount: {
|
||||
|
|
@ -464,7 +464,7 @@ public func deleteAccountOptionsController(context: AccountContext, navigationCo
|
|||
let _ = controller?.dismiss()
|
||||
}
|
||||
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_show")
|
||||
context.engine.accountData.addAppLogEvent(type: "deactivate.options_show")
|
||||
|
||||
return controller
|
||||
}
|
||||
|
|
|
|||
|
|
@ -363,10 +363,10 @@ public func themePickerController(context: AccountContext, focusOnItemTag: Theme
|
|||
var selectAccentColorImpl: ((TelegramBaseTheme?, PresentationThemeAccentColor?) -> Void)?
|
||||
var openAccentColorPickerImpl: ((PresentationThemeReference, Bool) -> Void)?
|
||||
|
||||
let _ = telegramWallpapers(postbox: context.account.postbox, network: context.account.network).start()
|
||||
let _ = context.engine.themes.wallpapers().start()
|
||||
|
||||
let cloudThemes = Promise<[TelegramTheme]>()
|
||||
let updatedCloudThemes = telegramThemes(postbox: context.account.postbox, network: context.account.network, accountManager: context.sharedContext.accountManager)
|
||||
let updatedCloudThemes = context.engine.themes.themes(accountManager: context.sharedContext.accountManager)
|
||||
cloudThemes.set(updatedCloudThemes)
|
||||
|
||||
let removedThemeIndexesPromise = Promise<Set<Int64>>(Set())
|
||||
|
|
|
|||
|
|
@ -565,7 +565,7 @@ public func themeAutoNightSettingsController(context: AccountContext) -> ViewCon
|
|||
})
|
||||
|
||||
let cloudThemes = Promise<[TelegramTheme]>()
|
||||
let updatedCloudThemes = telegramThemes(postbox: context.account.postbox, network: context.account.network, accountManager: context.sharedContext.accountManager)
|
||||
let updatedCloudThemes = context.engine.themes.themes(accountManager: context.sharedContext.accountManager)
|
||||
cloudThemes.set(updatedCloudThemes)
|
||||
|
||||
let signal = combineLatest(context.sharedContext.presentationData |> deliverOnMainQueue, sharedData |> deliverOnMainQueue, cloudThemes.get() |> deliverOnMainQueue, stagingSettingsPromise.get() |> deliverOnMainQueue)
|
||||
|
|
|
|||
|
|
@ -284,7 +284,7 @@ public final class ThemePreviewController: ViewController {
|
|||
switch theme {
|
||||
case let .cloud(info):
|
||||
resolvedWallpaper = info.resolvedWallpaper
|
||||
return telegramThemes(postbox: context.account.postbox, network: context.account.network, accountManager: context.sharedContext.accountManager)
|
||||
return context.engine.themes.themes(accountManager: context.sharedContext.accountManager)
|
||||
|> take(1)
|
||||
|> map { themes -> Bool in
|
||||
if let _ = themes.first(where: { $0.id == info.theme.id }) {
|
||||
|
|
@ -317,7 +317,7 @@ public final class ThemePreviewController: ViewController {
|
|||
}, scale: 1.0)
|
||||
let themeThumbnailData = themeThumbnail?.jpegData(compressionQuality: 0.6)
|
||||
|
||||
return telegramThemes(postbox: context.account.postbox, network: context.account.network, accountManager: context.sharedContext.accountManager)
|
||||
return context.engine.themes.themes(accountManager: context.sharedContext.accountManager)
|
||||
|> take(1)
|
||||
|> mapToSignal { themes -> Signal<(PresentationThemeReference, Bool), NoError> in
|
||||
let similarTheme = themes.first(where: { $0.isCreator && $0.title == info.title })
|
||||
|
|
|
|||
|
|
@ -520,7 +520,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
|||
var selectAccentColorImpl: ((PresentationThemeAccentColor?) -> Void)?
|
||||
var openAccentColorPickerImpl: ((PresentationThemeReference, Bool) -> Void)?
|
||||
|
||||
let _ = telegramWallpapers(postbox: context.account.postbox, network: context.account.network).start()
|
||||
let _ = context.engine.themes.wallpapers().start()
|
||||
|
||||
let currentAppIcon: PresentationAppIcon?
|
||||
var appIcons = context.sharedContext.applicationBindings.getAvailableAlternateIcons()
|
||||
|
|
@ -540,7 +540,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
|||
currentAppIconName.set(currentAppIcon?.name ?? "Blue")
|
||||
|
||||
let cloudThemes = Promise<[TelegramTheme]>()
|
||||
let updatedCloudThemes = telegramThemes(postbox: context.account.postbox, network: context.account.network, accountManager: context.sharedContext.accountManager)
|
||||
let updatedCloudThemes = context.engine.themes.themes(accountManager: context.sharedContext.accountManager)
|
||||
cloudThemes.set(updatedCloudThemes)
|
||||
|
||||
let removedThemeIndexesPromise = Promise<Set<Int64>>(Set())
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||
|
||||
swift_library(
|
||||
name = "SpotlightSupport",
|
||||
module_name = "SpotlightSupport",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/SyncCore:SyncCore",
|
||||
"//submodules/TelegramCore:TelegramCore",
|
||||
"//submodules/Display:Display",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
|
|
@ -4,7 +4,6 @@ import Display
|
|||
import AsyncDisplayKit
|
||||
import ComponentFlow
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import PhotoResources
|
||||
import AvatarStoryIndicatorComponent
|
||||
|
|
@ -15,7 +14,7 @@ final class StoryIconNode: ASDisplayNode {
|
|||
private let imageNode = TransformImageNode()
|
||||
private let storyIndicator = ComponentView<Empty>()
|
||||
|
||||
init(context: AccountContext, theme: PresentationTheme, peer: Peer, storyItem: EngineStoryItem) {
|
||||
init(context: AccountContext, theme: PresentationTheme, peer: EngineRawPeer, storyItem: EngineStoryItem) {
|
||||
self.imageNode.displaysAsynchronously = false
|
||||
|
||||
super.init()
|
||||
|
|
@ -29,7 +28,7 @@ final class StoryIconNode: ASDisplayNode {
|
|||
self.imageNode.frame = bounds.insetBy(dx: 3.0, dy: 3.0)
|
||||
self.frame = bounds
|
||||
|
||||
let media: Media?
|
||||
let media: EngineRawMedia?
|
||||
switch storyItem.media {
|
||||
case let .image(image):
|
||||
media = image
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ swift_library(
|
|||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
"//submodules/Display:Display",
|
||||
"//submodules/Postbox:Postbox",
|
||||
"//submodules/TelegramCore:TelegramCore",
|
||||
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
||||
"//submodules/AccountContext:AccountContext",
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import Foundation
|
|||
import UIKit
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
import AccountContext
|
||||
|
|
@ -802,19 +801,19 @@ private final class StickerPackContainer: ASDisplayNode {
|
|||
private func emojiSuggestionPeekContent(itemLayer: CALayer, file: TelegramMediaFile) -> Signal<(UIView, CGRect, PeekControllerContent)?, NoError> {
|
||||
let context = self.context
|
||||
|
||||
var collectionId: ItemCollectionId?
|
||||
var collectionId: EngineItemCollectionId?
|
||||
for attribute in file.attributes {
|
||||
if case let .CustomEmoji(_, _, _, packReference) = attribute {
|
||||
switch packReference {
|
||||
case let .id(id, _):
|
||||
collectionId = ItemCollectionId(namespace: Namespaces.ItemCollection.CloudEmojiPacks, id: id)
|
||||
collectionId = EngineItemCollectionId(namespace: Namespaces.ItemCollection.CloudEmojiPacks, id: id)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var bubbleUpEmojiOrStickersets: [ItemCollectionId] = []
|
||||
var bubbleUpEmojiOrStickersets: [EngineItemCollectionId] = []
|
||||
if let collectionId {
|
||||
bubbleUpEmojiOrStickersets.append(collectionId)
|
||||
}
|
||||
|
|
@ -859,9 +858,9 @@ private final class StickerPackContainer: ASDisplayNode {
|
|||
case let .CustomEmoji(_, _, displayText, stickerPackReference):
|
||||
text = displayText
|
||||
|
||||
var packId: ItemCollectionId?
|
||||
var packId: EngineItemCollectionId?
|
||||
if case let .id(id, _) = stickerPackReference {
|
||||
packId = ItemCollectionId(namespace: Namespaces.ItemCollection.CloudEmojiPacks, id: id)
|
||||
packId = EngineItemCollectionId(namespace: Namespaces.ItemCollection.CloudEmojiPacks, id: id)
|
||||
}
|
||||
emojiAttribute = ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: packId, fileId: file.fileId.id, file: file)
|
||||
break loop
|
||||
|
|
@ -1468,12 +1467,12 @@ private final class StickerPackContainer: ASDisplayNode {
|
|||
}
|
||||
|
||||
if installedCount == self.currentStickerPacks.count {
|
||||
var removedPacks: Signal<[(info: ItemCollectionInfo, index: Int, items: [ItemCollectionItem])], NoError> = .single([])
|
||||
var removedPacks: Signal<[(info: EngineRawItemCollectionInfo, index: Int, items: [EngineRawItemCollectionItem])], NoError> = .single([])
|
||||
for (info, _, _) in self.currentStickerPacks {
|
||||
removedPacks = removedPacks
|
||||
|> mapToSignal { current -> Signal<[(info: ItemCollectionInfo, index: Int, items: [ItemCollectionItem])], NoError> in
|
||||
|> mapToSignal { current -> Signal<[(info: EngineRawItemCollectionInfo, index: Int, items: [EngineRawItemCollectionItem])], NoError> in
|
||||
return self.context.engine.stickers.removeStickerPackInteractively(id: info.id, option: .delete)
|
||||
|> map { result -> [(info: ItemCollectionInfo, index: Int, items: [ItemCollectionItem])] in
|
||||
|> map { result -> [(info: EngineRawItemCollectionInfo, index: Int, items: [EngineRawItemCollectionItem])] in
|
||||
if let result = result {
|
||||
return current + [(info, result.0, result.1)]
|
||||
} else {
|
||||
|
|
@ -2968,13 +2967,6 @@ public final class StickerPackScreenImpl: ViewController, StickerPackScreen {
|
|||
}
|
||||
return .single(result)
|
||||
}
|
||||
|> mapToSignal { peer -> Signal<Peer?, NoError> in
|
||||
if let peer = peer {
|
||||
return .single(peer._asPeer())
|
||||
} else {
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
|
|
@ -2982,7 +2974,7 @@ public final class StickerPackScreenImpl: ViewController, StickerPackScreen {
|
|||
if let peer {
|
||||
if let parentNavigationController = strongSelf.parentNavigationController {
|
||||
strongSelf.controllerNode.dismiss()
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: parentNavigationController, context: strongSelf.context, chatLocation: .peer(EnginePeer(peer)), keepStack: .always, animated: true))
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: parentNavigationController, context: strongSelf.context, chatLocation: .peer(peer), keepStack: .always, animated: true))
|
||||
}
|
||||
} else {
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, title: nil, text: strongSelf.presentationData.strings.Resolve_ErrorNotFound, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
|
|
|
|||
|
|
@ -260,74 +260,6 @@ public func chatMessageAnimatedStickerBackingData(postbox: Postbox, fileReferenc
|
|||
}
|
||||
}
|
||||
|
||||
public func chatMessageLegacySticker(account: Account, userLocation: MediaResourceUserLocation, file: TelegramMediaFile, small: Bool, fitSize: CGSize, fetched: Bool = false, onlyFullSize: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||
let signal = chatMessageStickerDatas(postbox: account.postbox, userLocation: userLocation, file: file, small: small, fetched: fetched, onlyFullSize: onlyFullSize, synchronousLoad: false)
|
||||
return signal |> map { value in
|
||||
let fullSizeData = value._1
|
||||
let fullSizeComplete = value._2
|
||||
return { preArguments in
|
||||
var fullSizeImage: (UIImage, UIImage)?
|
||||
if let fullSizeData = fullSizeData, fullSizeComplete {
|
||||
if let image = imageFromAJpeg(data: fullSizeData) {
|
||||
fullSizeImage = image
|
||||
}
|
||||
}
|
||||
|
||||
if let fullSizeImage = fullSizeImage {
|
||||
var updatedFitSize = fitSize
|
||||
if updatedFitSize.width.isEqual(to: 1.0) {
|
||||
updatedFitSize = fullSizeImage.0.size
|
||||
}
|
||||
|
||||
let contextSize = fullSizeImage.0.size.aspectFitted(updatedFitSize)
|
||||
|
||||
let arguments = TransformImageArguments(corners: preArguments.corners, imageSize: contextSize, boundingSize: contextSize, intrinsicInsets: preArguments.intrinsicInsets)
|
||||
|
||||
guard let context = DrawingContext(size: arguments.drawingSize, clear: true) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let thumbnailImage: CGImage? = nil
|
||||
|
||||
var blurredThumbnailImage: UIImage?
|
||||
if let thumbnailImage = thumbnailImage {
|
||||
let thumbnailSize = CGSize(width: thumbnailImage.width, height: thumbnailImage.height)
|
||||
let thumbnailContextSize = thumbnailSize.aspectFitted(CGSize(width: 150.0, height: 150.0))
|
||||
if let thumbnailContext = DrawingContext(size: thumbnailContextSize, scale: 1.0) {
|
||||
thumbnailContext.withFlippedContext { c in
|
||||
c.interpolationQuality = .none
|
||||
c.draw(thumbnailImage, in: CGRect(origin: CGPoint(), size: thumbnailContextSize))
|
||||
}
|
||||
imageFastBlur(Int32(thumbnailContextSize.width), Int32(thumbnailContextSize.height), Int32(thumbnailContext.bytesPerRow), thumbnailContext.bytes)
|
||||
|
||||
blurredThumbnailImage = thumbnailContext.generateImage()
|
||||
}
|
||||
}
|
||||
|
||||
context.withFlippedContext { c in
|
||||
c.setBlendMode(.copy)
|
||||
if let blurredThumbnailImage = blurredThumbnailImage {
|
||||
c.interpolationQuality = .low
|
||||
c.draw(blurredThumbnailImage.cgImage!, in: arguments.drawingRect)
|
||||
}
|
||||
|
||||
if let cgImage = fullSizeImage.0.cgImage, let cgImageAlpha = fullSizeImage.1.cgImage {
|
||||
c.setBlendMode(.normal)
|
||||
c.interpolationQuality = .medium
|
||||
|
||||
let mask = CGImage(maskWidth: cgImageAlpha.width, height: cgImageAlpha.height, bitsPerComponent: cgImageAlpha.bitsPerComponent, bitsPerPixel: cgImageAlpha.bitsPerPixel, bytesPerRow: cgImageAlpha.bytesPerRow, provider: cgImageAlpha.dataProvider!, decode: nil, shouldInterpolate: true)
|
||||
|
||||
c.draw(cgImage.masking(mask!)!, in: arguments.drawingRect)
|
||||
}
|
||||
}
|
||||
|
||||
return context
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func chatMessageSticker(account: Account, userLocation: MediaResourceUserLocation, file: TelegramMediaFile, small: Bool, fetched: Bool = false, onlyFullSize: Bool = false, thumbnail: Bool = false, synchronousLoad: Bool = false, colorSpace: CGColorSpace? = nil) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||
return chatMessageSticker(postbox: account.postbox, userLocation: userLocation, file: file, small: small, fetched: fetched, onlyFullSize: onlyFullSize, thumbnail: thumbnail, synchronousLoad: synchronousLoad, colorSpace: colorSpace)
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||
|
||||
swift_library(
|
||||
name = "SvgRendering",
|
||||
module_name = "SvgRendering",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
deps = [
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
|
|
@ -2,7 +2,6 @@ import Foundation
|
|||
import UIKit
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
import TelegramPresentationData
|
||||
|
|
|
|||
|
|
@ -5,10 +5,6 @@ import TelegramApi
|
|||
import MtProtoKit
|
||||
|
||||
|
||||
public enum ChatContextResultMessageDecodingError: Error {
|
||||
case generic
|
||||
}
|
||||
|
||||
public enum ChatContextResultMessage: PostboxCoding, Equatable, Codable {
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case data
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
import Foundation
|
||||
|
||||
public enum CloudMediaResourceLocation: Equatable {
|
||||
case photo(id: Int64, accessHash: Int64, fileReference: Data, thumbSize: String)
|
||||
case file(id: Int64, accessHash: Int64, fileReference: Data, thumbSize: String)
|
||||
case peerPhoto(peer: PeerReference, fullSize: Bool, volumeId: Int64, localId: Int64)
|
||||
case stickerPackThumbnail(packReference: StickerPackReference, volumeId: Int64, localId: Int64)
|
||||
}
|
||||
|
|
@ -1321,16 +1321,6 @@ public func authorizeWithPasskey(accountManager: AccountManager<TelegramAccountM
|
|||
}
|
||||
}
|
||||
|
||||
public enum PasswordRecoveryRequestError {
|
||||
case limitExceeded
|
||||
case generic
|
||||
}
|
||||
|
||||
public enum PasswordRecoveryOption {
|
||||
case none
|
||||
case email(pattern: String)
|
||||
}
|
||||
|
||||
public enum PasswordRecoveryError {
|
||||
case invalidCode
|
||||
case limitExceeded
|
||||
|
|
@ -1586,18 +1576,6 @@ public func signUpWithName(accountManager: AccountManager<TelegramAccountManager
|
|||
|> switchToLatest
|
||||
}
|
||||
|
||||
public enum AuthorizationStateReset {
|
||||
case empty
|
||||
}
|
||||
|
||||
public func resetAuthorizationState(account: UnauthorizedAccount, to value: AuthorizationStateReset) -> Signal<Void, NoError> {
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
if let state = transaction.getState() as? UnauthorizedAccountState {
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: state.isTestingEnvironment, masterDatacenterId: state.masterDatacenterId, contents: .empty))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func togglePreviousCodeEntry(account: UnauthorizedAccount) -> Signal<Never, NoError> {
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
if let state = transaction.getState() as? UnauthorizedAccountState {
|
||||
|
|
|
|||
|
|
@ -671,7 +671,7 @@ final class MediaReferenceRevalidationContext {
|
|||
}
|
||||
|> map { [$0] }
|
||||
} else {
|
||||
signal = telegramWallpapers(postbox: postbox, network: network, forceUpdate: true)
|
||||
signal = _internal_telegramWallpapers(postbox: postbox, network: network, forceUpdate: true)
|
||||
|> last
|
||||
|> mapError { _ -> RevalidateMediaReferenceError in
|
||||
}
|
||||
|
|
@ -697,7 +697,7 @@ final class MediaReferenceRevalidationContext {
|
|||
|
||||
func themes(postbox: Postbox, network: Network, background: Bool) -> Signal<[TelegramTheme], RevalidateMediaReferenceError> {
|
||||
return self.genericItem(key: .themes, background: background, request: { next, error in
|
||||
return (telegramThemes(postbox: postbox, network: network, accountManager: nil, forceUpdate: true)
|
||||
return (_internal_telegramThemes(postbox: postbox, network: network, accountManager: nil, forceUpdate: true)
|
||||
|> take(1)
|
||||
|> mapError { _ -> RevalidateMediaReferenceError in
|
||||
}).start(next: { value in
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ final class NetworkStatsContext {
|
|||
for (targetKey, averageStats) in self.averageTargetStats {
|
||||
if averageStats.count >= 1000 || averageStats.size >= 4 * 1024 * 1024 {
|
||||
if let postbox = self.postbox {
|
||||
addAppLogEvent(postbox: postbox, type: "download", data: .dictionary([
|
||||
_internal_addAppLogEvent(postbox: postbox, type: "download", data: .dictionary([
|
||||
"n": .number(Double(targetKey.networkType.rawValue)),
|
||||
"d": .number(Double(targetKey.datacenterId)),
|
||||
"b": .number(averageStats.networkBps / Double(averageStats.count)),
|
||||
|
|
|
|||
|
|
@ -408,37 +408,6 @@ public func enqueueMessages(account: Account, peerId: PeerId, messages: [Enqueue
|
|||
}
|
||||
}
|
||||
|
||||
public func enqueueMessagesToMultiplePeers(account: Account, peerIds: [PeerId], threadIds: [PeerId: Int64], messages: [EnqueueMessage]) -> Signal<[MessageId], NoError> {
|
||||
let signal: Signal<[(Bool, EnqueueMessage)], NoError>
|
||||
if let transformOutgoingMessageMedia = account.transformOutgoingMessageMedia {
|
||||
signal = opportunisticallyTransformOutgoingMedia(network: account.network, postbox: account.postbox, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messages: messages, userInteractive: true)
|
||||
} else {
|
||||
signal = .single(messages.map { (false, $0) })
|
||||
}
|
||||
return signal
|
||||
|> mapToSignal { messages -> Signal<[MessageId], NoError> in
|
||||
return account.postbox.transaction { transaction -> [MessageId] in
|
||||
var messageIds: [MessageId] = []
|
||||
for peerId in peerIds {
|
||||
var replyToMessageId: EngineMessageReplySubject?
|
||||
if let threadIds = threadIds[peerId] {
|
||||
replyToMessageId = EngineMessageReplySubject(messageId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadIds)), quote: nil, innerSubject: nil)
|
||||
}
|
||||
var messages = messages
|
||||
if let replyToMessageId = replyToMessageId {
|
||||
messages = messages.map { ($0.0, $0.1.withUpdatedReplyToMessageId(replyToMessageId)) }
|
||||
}
|
||||
for id in enqueueMessages(transaction: transaction, account: account, peerId: peerId, messages: messages, disableAutoremove: false, transformGroupingKeysWithPeerId: true) {
|
||||
if let id = id {
|
||||
messageIds.append(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
return messageIds
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func resendMessages(account: Account, messageIds: [MessageId]) -> Signal<Void, NoError> {
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
var removeMessageIds: [MessageId] = []
|
||||
|
|
|
|||
|
|
@ -8,12 +8,6 @@ public enum StandaloneUploadMediaError {
|
|||
case generic
|
||||
}
|
||||
|
||||
public struct StandaloneUploadSecretFile {
|
||||
let file: Api.InputEncryptedFile
|
||||
let size: Int32
|
||||
let key: SecretFileEncryptionKey
|
||||
}
|
||||
|
||||
public enum StandaloneUploadMediaThumbnailResult {
|
||||
case pending
|
||||
case file(Api.InputFile)
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
import Foundation
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import MtProtoKit
|
||||
|
||||
|
||||
public func updateContentPrivacySettings(postbox: Postbox, _ f: @escaping (ContentPrivacySettings) -> ContentPrivacySettings) -> Signal<Void, NoError> {
|
||||
return postbox.transaction { transaction -> Void in
|
||||
var updated: ContentPrivacySettings?
|
||||
transaction.updatePreferencesEntry(key: PreferencesKeys.contentPrivacySettings, { current in
|
||||
if let current = current?.get(ContentPrivacySettings.self) {
|
||||
updated = f(current)
|
||||
return PreferencesEntry(updated)
|
||||
} else {
|
||||
updated = f(ContentPrivacySettings.defaultSettings)
|
||||
return PreferencesEntry(updated)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -24,7 +24,7 @@ extension SplitTest {
|
|||
public func addEvent(_ event: Self.Event, data: JSON = []) {
|
||||
if let bucket = self.bucket {
|
||||
//TODO: merge additional data
|
||||
addAppLogEvent(postbox: self.postbox, type: event.rawValue, data: ["bucket": bucket])
|
||||
_internal_addAppLogEvent(postbox: self.postbox, type: event.rawValue, data: ["bucket": bucket])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1423,10 +1423,6 @@ private final class CallSessionManagerContext {
|
|||
}
|
||||
}
|
||||
|
||||
public enum CallRequestError {
|
||||
case generic
|
||||
}
|
||||
|
||||
public final class CallSessionManager {
|
||||
public static func getStableIncomingUUID(stableId: Int64) -> UUID {
|
||||
return StableIncomingUUIDs.shared.with { impl in
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import SwiftSignalKit
|
|||
import MtProtoKit
|
||||
|
||||
|
||||
public func addAppLogEvent(postbox: Postbox, time: Double = Date().timeIntervalSince1970, type: String, peerId: PeerId? = nil, data: JSON = .dictionary([:])) {
|
||||
func _internal_addAppLogEvent(postbox: Postbox, time: Double = Date().timeIntervalSince1970, type: String, peerId: PeerId? = nil, data: JSON = .dictionary([:])) {
|
||||
let tag: PeerOperationLogTag = OperationLogTags.SynchronizeAppLogEvents
|
||||
let peerId = PeerId(0)
|
||||
let _ = (postbox.transaction { transaction in
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
import Foundation
|
||||
import Postbox
|
||||
|
||||
public struct ArchivedStickerPacksInfoId {
|
||||
public let rawValue: MemoryBuffer
|
||||
public let id: Int32
|
||||
|
||||
init(_ rawValue: MemoryBuffer) {
|
||||
self.rawValue = rawValue
|
||||
assert(rawValue.length == 4)
|
||||
var idValue: Int32 = 0
|
||||
memcpy(&idValue, rawValue.memory, 4)
|
||||
self.id = idValue
|
||||
}
|
||||
|
||||
init(_ id: Int32) {
|
||||
self.id = id
|
||||
var idValue: Int32 = id
|
||||
self.rawValue = MemoryBuffer(memory: malloc(4)!, capacity: 4, length: 4, freeWhenDone: true)
|
||||
memcpy(self.rawValue.memory, &idValue, 4)
|
||||
}
|
||||
}
|
||||
|
||||
public final class ArchivedStickerPacksInfo: Codable {
|
||||
public let count: Int32
|
||||
|
||||
init(count: Int32) {
|
||||
self.count = count
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
self.count = try container.decode(Int32.self, forKey: "c")
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
try container.encode(self.count, forKey: "c")
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,5 @@
|
|||
import Postbox
|
||||
|
||||
public enum AutodownloadPreset {
|
||||
case low
|
||||
case medium
|
||||
case high
|
||||
}
|
||||
|
||||
public struct AutodownloadPresetSettings: Codable {
|
||||
public let disabled: Bool
|
||||
public let photoSizeMax: Int64
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
import Foundation
|
||||
import Postbox
|
||||
|
||||
public class LocalMediaPlaybackInfoAttribute: MessageAttribute {
|
||||
public let data: Data
|
||||
|
||||
public init(data: Data) {
|
||||
self.data = data
|
||||
}
|
||||
|
||||
required public init(decoder: PostboxDecoder) {
|
||||
self.data = decoder.decodeDataForKey("d") ?? Data()
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeData(self.data, forKey: "d")
|
||||
}
|
||||
}
|
||||
|
|
@ -114,23 +114,6 @@ public func newSessionReviews(postbox: Postbox) -> Signal<[NewSessionReview], No
|
|||
}
|
||||
}
|
||||
|
||||
public func addNewSessionReview(postbox: Postbox, item: NewSessionReview) -> Signal<Never, NoError> {
|
||||
return postbox.transaction { transaction -> Void in
|
||||
guard let entry = CodableEntry(item) else {
|
||||
return
|
||||
}
|
||||
transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.NewSessionReviews, item: OrderedItemListEntry(id: NewSessionReview.Id(id: item.id).rawValue, contents: entry), removeTailIfCountExceeds: 200)
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
|
||||
public func clearNewSessionReviews(postbox: Postbox) -> Signal<Never, NoError> {
|
||||
return postbox.transaction { transaction -> Void in
|
||||
transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.NewSessionReviews, items: [])
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
|
||||
public func removeNewSessionReviews(postbox: Postbox, ids: [Int64]) -> Signal<Never, NoError> {
|
||||
return postbox.transaction { transaction -> Void in
|
||||
for id in ids {
|
||||
|
|
|
|||
|
|
@ -653,34 +653,6 @@ public enum TelegramMediaFileAttribute: PostboxCoding, Equatable {
|
|||
}
|
||||
}
|
||||
|
||||
public enum TelegramMediaFileReference: PostboxCoding, Equatable {
|
||||
case cloud(fileId: Int64, accessHash: Int64, fileReference: Data?)
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
switch decoder.decodeInt32ForKey("_v", orElse: 0) {
|
||||
case 0:
|
||||
self = .cloud(fileId: decoder.decodeInt64ForKey("i", orElse: 0), accessHash: decoder.decodeInt64ForKey("h", orElse: 0), fileReference: decoder.decodeBytesForKey("fr")?.makeData())
|
||||
default:
|
||||
self = .cloud(fileId: 0, accessHash: 0, fileReference: nil)
|
||||
assertionFailure()
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
switch self {
|
||||
case let .cloud(imageId, accessHash, fileReference):
|
||||
encoder.encodeInt32(0, forKey: "_v")
|
||||
encoder.encodeInt64(imageId, forKey: "i")
|
||||
encoder.encodeInt64(accessHash, forKey: "h")
|
||||
if let fileReference = fileReference {
|
||||
encoder.encodeBytes(MemoryBuffer(data: fileReference), forKey: "fr")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "fr")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum TelegramMediaFileDecodingError: Error {
|
||||
case generic
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,6 @@
|
|||
import Foundation
|
||||
import Postbox
|
||||
|
||||
public enum VoiceCallP2PMode: Int32 {
|
||||
case never = 0
|
||||
case contacts = 1
|
||||
case always = 2
|
||||
}
|
||||
|
||||
public struct VoipConfiguration: Codable, Equatable {
|
||||
public var serializedData: String?
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,10 @@ public extension TelegramEngine {
|
|||
return _internal_acceptTermsOfService(account: self.account, id: id)
|
||||
}
|
||||
|
||||
public func addAppLogEvent(time: Double = Date().timeIntervalSince1970, type: String, data: JSON = .dictionary([:])) {
|
||||
_internal_addAppLogEvent(postbox: self.account.postbox, time: time, type: type, peerId: nil, data: data)
|
||||
}
|
||||
|
||||
public func requestChangeAccountPhoneNumberVerification(apiId: Int32, apiHash: String, phoneNumber: String, pushNotificationConfiguration: AuthorizationCodePushNotificationConfiguration?, firebaseSecretStream: Signal<[String: String], NoError>) -> Signal<ChangeAccountPhoneNumberData, RequestChangeAccountPhoneNumberVerificationError> {
|
||||
return _internal_requestChangeAccountPhoneNumberVerification(account: self.account, apiId: apiId, apiHash: apiHash, phoneNumber: phoneNumber, pushNotificationConfiguration: pushNotificationConfiguration, firebaseSecretStream: firebaseSecretStream)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -337,13 +337,6 @@ func _internal_requestTwoStepVerificationPasswordRecoveryCode(network: Network)
|
|||
}
|
||||
}
|
||||
|
||||
public enum RecoverTwoStepVerificationPasswordError {
|
||||
case generic
|
||||
case codeExpired
|
||||
case limitExceeded
|
||||
case invalidCode
|
||||
}
|
||||
|
||||
func _internal_cachedTwoStepPasswordToken(postbox: Postbox) -> Signal<TemporaryTwoStepPasswordToken?, NoError> {
|
||||
return postbox.transaction { transaction -> TemporaryTwoStepPasswordToken? in
|
||||
let key = ValueBoxKey(length: 1)
|
||||
|
|
|
|||
|
|
@ -3415,10 +3415,6 @@ func _internal_revokeConferenceInviteLink(account: Account, reference: InternalG
|
|||
}
|
||||
}
|
||||
|
||||
public enum ConfirmAddConferenceParticipantError {
|
||||
case generic
|
||||
}
|
||||
|
||||
func _internal_pollConferenceCallBlockchain(network: Network, reference: InternalGroupCallReference, subChainId: Int, offset: Int, limit: Int) -> Signal<(blocks: [Data], nextOffset: Int)?, NoError> {
|
||||
return network.request(Api.functions.phone.getGroupCallChainBlocks(call: reference.apiInputGroupCall, subChainId: Int32(subChainId), offset: Int32(offset), limit: Int32(limit)))
|
||||
|> map(Optional.init)
|
||||
|
|
|
|||
|
|
@ -202,10 +202,6 @@ func _internal_sendAppStoreReceipt(postbox: Postbox, network: Network, stateMana
|
|||
}
|
||||
}
|
||||
|
||||
public enum RestoreAppStoreReceiptError {
|
||||
case generic
|
||||
}
|
||||
|
||||
func _internal_canPurchasePremium(postbox: Postbox, network: Network, purpose: AppStoreTransactionPurpose) -> Signal<Bool, NoError> {
|
||||
return apiInputStorePaymentPurpose(postbox: postbox, purpose: purpose)
|
||||
|> mapToSignal { purpose -> Signal<Bool, NoError> in
|
||||
|
|
|
|||
|
|
@ -4,18 +4,6 @@ import SwiftSignalKit
|
|||
import TelegramApi
|
||||
|
||||
|
||||
public struct ChatListFilteringConfiguration: Equatable {
|
||||
public let isEnabled: Bool
|
||||
|
||||
public init(appConfiguration: AppConfiguration) {
|
||||
var isEnabled = false
|
||||
if let data = appConfiguration.data, let value = data["dialog_filters_enabled"] as? Bool, value {
|
||||
isEnabled = true
|
||||
}
|
||||
self.isEnabled = isEnabled
|
||||
}
|
||||
}
|
||||
|
||||
public struct ChatListFilterPeerCategories: OptionSet, Hashable {
|
||||
public var rawValue: Int32
|
||||
|
||||
|
|
|
|||
|
|
@ -3,17 +3,6 @@ import Postbox
|
|||
import TelegramApi
|
||||
import SwiftSignalKit
|
||||
|
||||
public enum ResolvePeerByNameOptionCached {
|
||||
case none
|
||||
case cached
|
||||
case cachedIfLaterThan(timestamp: Int32)
|
||||
}
|
||||
|
||||
public enum ResolvePeerByNameOptionRemote {
|
||||
case updateIfEarlierThan(timestamp: Int32)
|
||||
case update
|
||||
}
|
||||
|
||||
public enum ResolvePeerIdByNameResult {
|
||||
case progress
|
||||
case result(PeerId?)
|
||||
|
|
|
|||
|
|
@ -276,44 +276,6 @@ public func deleteSecureIdValues(network: Network, keys: Set<SecureIdValueKey>)
|
|||
}
|
||||
}
|
||||
|
||||
public func dropSecureId(network: Network, currentPassword: String) -> Signal<Void, AuthorizationPasswordVerificationError> {
|
||||
return _internal_twoStepAuthData(network)
|
||||
|> mapError { _ -> AuthorizationPasswordVerificationError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { authData -> Signal<Void, AuthorizationPasswordVerificationError> in
|
||||
let checkPassword: Api.InputCheckPasswordSRP
|
||||
if let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData {
|
||||
let kdfResult = passwordKDF(encryptionProvider: network.encryptionProvider, password: currentPassword, derivation: currentPasswordDerivation, srpSessionData: srpSessionData)
|
||||
if let kdfResult = kdfResult {
|
||||
checkPassword = .inputCheckPasswordSRP(.init(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1)))
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
} else {
|
||||
checkPassword = .inputCheckPasswordEmpty
|
||||
}
|
||||
|
||||
let settings = network.request(Api.functions.account.getPasswordSettings(password: checkPassword), automaticFloodWait: false)
|
||||
|> mapError { error in
|
||||
return AuthorizationPasswordVerificationError.generic
|
||||
}
|
||||
|
||||
return settings
|
||||
|> mapToSignal { value -> Signal<Void, AuthorizationPasswordVerificationError> in
|
||||
switch value {
|
||||
case .passwordSettings:
|
||||
var flags: Int32 = 0
|
||||
flags |= (1 << 2)
|
||||
return network.request(Api.functions.account.updatePasswordSettings(password: .inputCheckPasswordEmpty, newSettings: .passwordInputSettings(.init(flags: flags, newAlgo: nil, newPasswordHash: nil, hint: nil, email: nil, newSecureSettings: nil))), automaticFloodWait: false)
|
||||
|> map { _ in }
|
||||
|> mapError { _ in
|
||||
return AuthorizationPasswordVerificationError.generic
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum GetAllSecureIdValuesError {
|
||||
case generic
|
||||
|
|
|
|||
|
|
@ -15,10 +15,6 @@ public struct SecureIdValueAccessContext: Equatable {
|
|||
}
|
||||
}
|
||||
|
||||
public func generateSecureIdValueEmptyAccessContext() -> SecureIdValueAccessContext? {
|
||||
return SecureIdValueAccessContext(secret: Data(), id: 0)
|
||||
}
|
||||
|
||||
public func generateSecureIdValueAccessContext() -> SecureIdValueAccessContext? {
|
||||
guard let secret = generateSecureSecretData() else {
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -12,6 +12,14 @@ public extension TelegramEngine {
|
|||
public func getChatThemes(accountManager: AccountManager<TelegramAccountManagerTypes>, forceUpdate: Bool = false, onlyCached: Bool = false) -> Signal<[TelegramTheme], NoError> {
|
||||
return _internal_getChatThemes(accountManager: accountManager, network: self.account.network, forceUpdate: forceUpdate, onlyCached: onlyCached)
|
||||
}
|
||||
|
||||
public func themes(accountManager: AccountManager<TelegramAccountManagerTypes>, forceUpdate: Bool = false) -> Signal<[TelegramTheme], NoError> {
|
||||
return _internal_telegramThemes(postbox: self.account.postbox, network: self.account.network, accountManager: accountManager, forceUpdate: forceUpdate)
|
||||
}
|
||||
|
||||
public func wallpapers(forceUpdate: Bool = false) -> Signal<[TelegramWallpaper], NoError> {
|
||||
return _internal_telegramWallpapers(postbox: self.account.postbox, network: self.account.network, forceUpdate: forceUpdate)
|
||||
}
|
||||
|
||||
public func setChatTheme(peerId: PeerId, chatTheme: ChatTheme?) -> Signal<Void, NoError> {
|
||||
return _internal_setChatTheme(account: self.account, peerId: peerId, chatTheme: chatTheme)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ public typealias EngineMemoryBuffer = MemoryBuffer
|
|||
public typealias EnginePostboxDecoder = PostboxDecoder
|
||||
public typealias EnginePostboxEncoder = PostboxEncoder
|
||||
public typealias EngineAdaptedPostboxDecoder = AdaptedPostboxDecoder
|
||||
public typealias EngineAdaptedPostboxEncoder = AdaptedPostboxEncoder
|
||||
public typealias EngineItemCollectionId = ItemCollectionId
|
||||
public typealias EngineStoryId = StoryId
|
||||
public typealias EngineFetchResourceSourceType = FetchResourceSourceType
|
||||
|
|
@ -18,6 +19,7 @@ public typealias EngineValueBoxEncryptionParameters = ValueBoxEncryptionParamete
|
|||
public typealias EngineMessageAndThreadId = MessageAndThreadId
|
||||
public typealias EnginePeerStoryStats = PeerStoryStats
|
||||
public typealias EngineMessageHistoryAnchorIndex = MessageHistoryAnchorIndex
|
||||
public typealias EngineMessageHistoryEntryLocation = MessageHistoryEntryLocation
|
||||
public typealias EngineChatListTotalUnreadStateCategory = ChatListTotalUnreadStateCategory
|
||||
public typealias EngineChatListTotalUnreadStateStats = ChatListTotalUnreadStateStats
|
||||
public typealias EngineChatListTotalUnreadState = ChatListTotalUnreadState
|
||||
|
|
@ -28,8 +30,28 @@ public typealias EngineCachedMediaResourceRepresentationResult = CachedMediaReso
|
|||
public typealias EngineMediaResourceDataFetchResult = MediaResourceDataFetchResult
|
||||
public typealias EngineMediaResourceDataFetchError = MediaResourceDataFetchError
|
||||
public typealias EngineMediaResourceStatus = MediaResourceStatus
|
||||
public typealias EnginePostboxCoding = PostboxCoding
|
||||
public typealias EngineRawItemCollectionInfo = ItemCollectionInfo
|
||||
public typealias EngineRawItemCollectionItem = ItemCollectionItem
|
||||
public typealias EngineRawMedia = Media
|
||||
public typealias EngineRawMessage = Message
|
||||
public typealias EngineRawPeer = Peer
|
||||
public typealias EngineRawMediaResource = MediaResource
|
||||
public typealias EngineRawMediaResourceId = MediaResourceId
|
||||
public typealias EngineRawMediaResourceData = MediaResourceData
|
||||
public typealias EngineRawMediaResourceDataFetchCopyLocalItem = MediaResourceDataFetchCopyLocalItem
|
||||
public typealias EngineRawCachedMediaResourceRepresentation = CachedMediaResourceRepresentation
|
||||
public typealias EngineCachedMediaRepresentationKeepDuration = CachedMediaRepresentationKeepDuration
|
||||
public typealias EngineCachedPeerData = CachedPeerData
|
||||
|
||||
public func engineFileSize(_ path: String, useTotalFileAllocatedSize: Bool = false) -> Int64? {
|
||||
return fileSize(path, useTotalFileAllocatedSize: useTotalFileAllocatedSize)
|
||||
}
|
||||
|
||||
public func enginePersistentHash32(_ string: String) -> Int32 {
|
||||
return persistentHash32(string)
|
||||
}
|
||||
|
||||
public func engineDeclareEncodable(_ type: Any.Type, f: @escaping (EnginePostboxDecoder) -> EnginePostboxCoding) {
|
||||
declareEncodable(type, f: f)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ let telegramThemeFormat = "ios"
|
|||
let telegramThemeFileExtension = "tgios-theme"
|
||||
#endif
|
||||
|
||||
public func telegramThemes(postbox: Postbox, network: Network, accountManager: AccountManager<TelegramAccountManagerTypes>?, forceUpdate: Bool = false) -> Signal<[TelegramTheme], NoError> {
|
||||
func _internal_telegramThemes(postbox: Postbox, network: Network, accountManager: AccountManager<TelegramAccountManagerTypes>?, forceUpdate: Bool = false) -> Signal<[TelegramTheme], NoError> {
|
||||
let fetch: ([TelegramTheme]?, Int64?) -> Signal<[TelegramTheme], NoError> = { current, hash in
|
||||
network.request(Api.functions.account.getThemes(format: telegramThemeFormat, hash: hash ?? 0))
|
||||
|> retryRequest
|
||||
|
|
@ -145,7 +145,7 @@ private func saveUnsaveTheme(account: Account, accountManager: AccountManager<Te
|
|||
return .complete()
|
||||
}
|
||||
|> mapToSignal { _ -> Signal<Void, NoError> in
|
||||
return telegramThemes(postbox: account.postbox, network: account.network, accountManager: accountManager, forceUpdate: true)
|
||||
return _internal_telegramThemes(postbox: account.postbox, network: account.network, accountManager: accountManager, forceUpdate: true)
|
||||
|> take(1)
|
||||
|> mapToSignal { _ -> Signal<Void, NoError> in
|
||||
return .complete()
|
||||
|
|
@ -542,7 +542,7 @@ func managedThemesUpdates(accountManager: AccountManager<TelegramAccountManagerT
|
|||
}
|
||||
transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudThemes, items: updatedEntries)
|
||||
} else {
|
||||
let _ = (telegramThemes(postbox: postbox, network: network, accountManager: accountManager, forceUpdate: true)
|
||||
let _ = (_internal_telegramThemes(postbox: postbox, network: network, accountManager: accountManager, forceUpdate: true)
|
||||
|> take(1)).start()
|
||||
}
|
||||
}.start()
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue