mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
Various improvements
This commit is contained in:
@@ -53,7 +53,7 @@ private class DetailsChatPlaceholderNode: ASDisplayNode, NavigationDetailsPlaceh
|
||||
self.presentationData = presentationData
|
||||
self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: self.presentationData.chatWallpaper, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: self.presentationInterfaceState.limitsConfiguration, fontSize: self.presentationData.chatFontSize, bubbleCorners: self.presentationData.chatBubbleCorners, accountPeerId: self.presentationInterfaceState.accountPeerId, mode: .standard(previewing: false), chatLocation: self.presentationInterfaceState.chatLocation, subject: nil, peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, importState: nil, threadData: nil, isGeneralThreadClosed: nil, replyMessage: nil, accountPeerColor: nil)
|
||||
|
||||
self.wallpaperBackgroundNode.update(wallpaper: presentationData.chatWallpaper)
|
||||
self.wallpaperBackgroundNode.update(wallpaper: presentationData.chatWallpaper, animated: false)
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, needsTiling: Bool, transition: ContainedViewLayoutTransition) {
|
||||
@@ -158,7 +158,7 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
|
||||
detailsPlaceholderNode = current
|
||||
} else {
|
||||
detailsPlaceholderNode = DetailsChatPlaceholderNode(context: self.context)
|
||||
detailsPlaceholderNode.wallpaperBackgroundNode.update(wallpaper: self.presentationData.chatWallpaper)
|
||||
detailsPlaceholderNode.wallpaperBackgroundNode.update(wallpaper: self.presentationData.chatWallpaper, animated: false)
|
||||
self.detailsPlaceholderNode = detailsPlaceholderNode
|
||||
}
|
||||
self.updateDetailsPlaceholderNode(detailsPlaceholderNode)
|
||||
@@ -275,9 +275,11 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
|
||||
|
||||
let context = self.context
|
||||
|
||||
var storyTarget: Stories.PendingTarget?
|
||||
var isPeerArchived = false
|
||||
var updatedTransitionOut: ((Stories.PendingTarget?, Bool) -> StoryCameraTransitionOut?)?
|
||||
let externalState = MediaEditorTransitionOutExternalState(
|
||||
storyTarget: nil,
|
||||
isPeerArchived: false,
|
||||
transitionOut: nil
|
||||
)
|
||||
|
||||
var presentImpl: ((ViewController) -> Void)?
|
||||
var returnToCameraImpl: (() -> Void)?
|
||||
@@ -297,7 +299,7 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
|
||||
}
|
||||
},
|
||||
transitionOut: { finished in
|
||||
if let transitionOut = (updatedTransitionOut ?? transitionOut)(finished ? storyTarget : nil, isPeerArchived), let destinationView = transitionOut.destinationView {
|
||||
if let transitionOut = (externalState.transitionOut ?? transitionOut)(finished ? externalState.storyTarget : nil, externalState.isPeerArchived), let destinationView = transitionOut.destinationView {
|
||||
return CameraScreen.TransitionOut(
|
||||
destinationView: destinationView,
|
||||
destinationRect: transitionOut.destinationRect,
|
||||
@@ -353,10 +355,9 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
|
||||
context: context,
|
||||
subject: subject,
|
||||
customTarget: customTarget,
|
||||
isEditing: false,
|
||||
transitionIn: transitionIn,
|
||||
transitionOut: { finished, isNew in
|
||||
if finished, let transitionOut = (updatedTransitionOut ?? transitionOut)(storyTarget, false), let destinationView = transitionOut.destinationView {
|
||||
if finished, let transitionOut = (externalState.transitionOut ?? transitionOut)(externalState.storyTarget, false), let destinationView = transitionOut.destinationView {
|
||||
return MediaEditorScreen.TransitionOut(
|
||||
destinationView: destinationView,
|
||||
destinationRect: transitionOut.destinationRect,
|
||||
@@ -371,20 +372,20 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}, completion: { [weak self] randomId, mediaResult, mediaAreas, caption, options, stickers, commit in
|
||||
guard let self, let mediaResult else {
|
||||
}, completion: { [weak self] result, commit in
|
||||
guard let self else {
|
||||
dismissCameraImpl?()
|
||||
commit({})
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let target: Stories.PendingTarget
|
||||
let targetPeerId: EnginePeer.Id
|
||||
if let customTarget {
|
||||
target = .peer(customTarget)
|
||||
targetPeerId = customTarget
|
||||
} else {
|
||||
if let sendAsPeerId = options.sendAsPeerId {
|
||||
if let sendAsPeerId = result.options.sendAsPeerId {
|
||||
target = .peer(sendAsPeerId)
|
||||
targetPeerId = sendAsPeerId
|
||||
} else {
|
||||
@@ -392,8 +393,8 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
|
||||
targetPeerId = context.account.peerId
|
||||
}
|
||||
}
|
||||
storyTarget = target
|
||||
|
||||
externalState.storyTarget = target
|
||||
|
||||
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: targetPeerId))
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self] peer in
|
||||
guard let self, let peer else {
|
||||
@@ -401,120 +402,16 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
|
||||
}
|
||||
|
||||
if case let .user(user) = peer {
|
||||
isPeerArchived = user.storiesHidden ?? false
|
||||
externalState.isPeerArchived = user.storiesHidden ?? false
|
||||
} else if case let .channel(channel) = peer {
|
||||
isPeerArchived = channel.storiesHidden ?? false
|
||||
externalState.isPeerArchived = channel.storiesHidden ?? false
|
||||
}
|
||||
|
||||
let context = self.context
|
||||
if let rootTabController = self.rootTabController {
|
||||
if let index = rootTabController.controllers.firstIndex(where: { $0 is ChatListController}) {
|
||||
rootTabController.selectedIndex = index
|
||||
}
|
||||
}
|
||||
|
||||
let completionImpl: () -> Void = { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
var chatListController: ChatListControllerImpl?
|
||||
|
||||
if isPeerArchived {
|
||||
var viewControllers = self.viewControllers
|
||||
|
||||
let archiveController = ChatListControllerImpl(context: context, location: .chatList(groupId: .archive), controlsHistoryPreload: false, hideNetworkActivityStatus: false, previewing: false, enableDebugActions: false)
|
||||
updatedTransitionOut = archiveController.storyCameraTransitionOut()
|
||||
chatListController = archiveController
|
||||
viewControllers.insert(archiveController, at: 1)
|
||||
self.setViewControllers(viewControllers, animated: false)
|
||||
} else {
|
||||
chatListController = self.chatListController as? ChatListControllerImpl
|
||||
}
|
||||
|
||||
if let chatListController {
|
||||
let _ = (chatListController.hasPendingStories
|
||||
|> filter { $0 }
|
||||
|> take(1)
|
||||
|> timeout(isPeerArchived ? 0.5 : 0.25, queue: .mainQueue(), alternate: .single(true))
|
||||
|> deliverOnMainQueue).startStandalone(completed: { [weak chatListController] in
|
||||
guard let chatListController else {
|
||||
return
|
||||
}
|
||||
|
||||
chatListController.scrollToStories(peerId: targetPeerId)
|
||||
Queue.mainQueue().justDispatch {
|
||||
commit({})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Queue.mainQueue().justDispatch {
|
||||
commit({})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let _ = self.chatListController as? ChatListControllerImpl {
|
||||
switch mediaResult {
|
||||
case let .image(image, dimensions):
|
||||
let tempFile = TempBox.shared.tempFile(fileName: "file")
|
||||
defer {
|
||||
TempBox.shared.dispose(tempFile)
|
||||
}
|
||||
if let imageData = compressImageToJPEG(image, quality: 0.7, tempFilePath: tempFile.path) {
|
||||
let entities = generateChatInputTextEntities(caption)
|
||||
Logger.shared.log("MediaEditor", "Calling uploadStory for image, randomId \(randomId)")
|
||||
let _ = (context.engine.messages.uploadStory(target: target, media: .image(dimensions: dimensions, data: imageData, stickers: stickers), mediaAreas: mediaAreas, text: caption.string, entities: entities, pin: options.pin, privacy: options.privacy, isForwardingDisabled: options.isForwardingDisabled, period: options.timeout, randomId: randomId)
|
||||
|> deliverOnMainQueue).startStandalone(next: { stableId in
|
||||
moveStorySource(engine: context.engine, peerId: context.account.peerId, from: randomId, to: Int64(stableId))
|
||||
})
|
||||
|
||||
completionImpl()
|
||||
}
|
||||
case let .video(content, firstFrameImage, values, duration, dimensions):
|
||||
let adjustments: VideoMediaResourceAdjustments
|
||||
if let valuesData = try? JSONEncoder().encode(values) {
|
||||
let data = MemoryBuffer(data: valuesData)
|
||||
let digest = MemoryBuffer(data: data.md5Digest())
|
||||
adjustments = VideoMediaResourceAdjustments(data: data, digest: digest, isStory: true)
|
||||
|
||||
let resource: TelegramMediaResource
|
||||
switch content {
|
||||
case let .imageFile(path):
|
||||
resource = LocalFileVideoMediaResource(randomId: Int64.random(in: .min ... .max), path: path, adjustments: adjustments)
|
||||
case let .videoFile(path):
|
||||
resource = LocalFileVideoMediaResource(randomId: Int64.random(in: .min ... .max), path: path, adjustments: adjustments)
|
||||
case let .asset(localIdentifier):
|
||||
resource = VideoLibraryMediaResource(localIdentifier: localIdentifier, conversion: .compress(adjustments))
|
||||
}
|
||||
let tempFile = TempBox.shared.tempFile(fileName: "file")
|
||||
defer {
|
||||
TempBox.shared.dispose(tempFile)
|
||||
}
|
||||
let imageData = firstFrameImage.flatMap { compressImageToJPEG($0, quality: 0.6, tempFilePath: tempFile.path) }
|
||||
let firstFrameFile = imageData.flatMap { data -> TempBoxFile? in
|
||||
let file = TempBox.shared.tempFile(fileName: "image.jpg")
|
||||
if let _ = try? data.write(to: URL(fileURLWithPath: file.path)) {
|
||||
return file
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
Logger.shared.log("MediaEditor", "Calling uploadStory for video, randomId \(randomId)")
|
||||
let entities = generateChatInputTextEntities(caption)
|
||||
let _ = (context.engine.messages.uploadStory(target: target, media: .video(dimensions: dimensions, duration: duration, resource: resource, firstFrameFile: firstFrameFile, stickers: stickers), mediaAreas: mediaAreas, text: caption.string, entities: entities, pin: options.pin, privacy: options.privacy, isForwardingDisabled: options.isForwardingDisabled, period: options.timeout, randomId: randomId)
|
||||
|> deliverOnMainQueue).startStandalone(next: { stableId in
|
||||
moveStorySource(engine: context.engine, peerId: context.account.peerId, from: randomId, to: Int64(stableId))
|
||||
})
|
||||
|
||||
completionImpl()
|
||||
}
|
||||
}
|
||||
}
|
||||
self.proceedWithStoryUpload(target: target, result: result, existingMedia: nil, forwardInfo: nil, externalState: externalState, commit: commit)
|
||||
|
||||
dismissCameraImpl?()
|
||||
})
|
||||
} as (Int64, MediaEditorScreen.Result?, [MediaArea], NSAttributedString, MediaEditorResultPrivacy, [TelegramMediaFile], @escaping (@escaping () -> Void) -> Void) -> Void
|
||||
} as (MediaEditorScreen.Result, @escaping (@escaping () -> Void) -> Void) -> Void
|
||||
)
|
||||
controller.cancelled = { showDraftTooltip in
|
||||
if showDraftTooltip {
|
||||
@@ -569,6 +466,138 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
|
||||
})
|
||||
}
|
||||
|
||||
public func proceedWithStoryUpload(target: Stories.PendingTarget, result: MediaEditorScreenResult, existingMedia: EngineMedia?, forwardInfo: Stories.PendingForwardInfo?, externalState: MediaEditorTransitionOutExternalState, commit: @escaping (@escaping () -> Void) -> Void) {
|
||||
guard let result = result as? MediaEditorScreen.Result else {
|
||||
return
|
||||
}
|
||||
let context = self.context
|
||||
let targetPeerId: EnginePeer.Id
|
||||
switch target {
|
||||
case let .peer(peerId):
|
||||
targetPeerId = peerId
|
||||
case .myStories:
|
||||
targetPeerId = context.account.peerId
|
||||
}
|
||||
|
||||
if let rootTabController = self.rootTabController {
|
||||
if let index = rootTabController.controllers.firstIndex(where: { $0 is ChatListController}) {
|
||||
rootTabController.selectedIndex = index
|
||||
}
|
||||
}
|
||||
|
||||
let completionImpl: () -> Void = { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
var chatListController: ChatListControllerImpl?
|
||||
|
||||
if externalState.isPeerArchived {
|
||||
var viewControllers = self.viewControllers
|
||||
|
||||
let archiveController = ChatListControllerImpl(context: context, location: .chatList(groupId: .archive), controlsHistoryPreload: false, hideNetworkActivityStatus: false, previewing: false, enableDebugActions: false)
|
||||
externalState.transitionOut = archiveController.storyCameraTransitionOut()
|
||||
chatListController = archiveController
|
||||
viewControllers.insert(archiveController, at: 1)
|
||||
self.setViewControllers(viewControllers, animated: false)
|
||||
} else {
|
||||
chatListController = self.chatListController as? ChatListControllerImpl
|
||||
externalState.transitionOut = chatListController?.storyCameraTransitionOut()
|
||||
}
|
||||
|
||||
if let chatListController {
|
||||
let _ = (chatListController.hasPendingStories
|
||||
|> filter { $0 }
|
||||
|> take(1)
|
||||
|> timeout(externalState.isPeerArchived ? 0.5 : 0.25, queue: .mainQueue(), alternate: .single(true))
|
||||
|> deliverOnMainQueue).startStandalone(completed: { [weak chatListController] in
|
||||
guard let chatListController else {
|
||||
return
|
||||
}
|
||||
|
||||
chatListController.scrollToStories(peerId: targetPeerId)
|
||||
Queue.mainQueue().justDispatch {
|
||||
commit({})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Queue.mainQueue().justDispatch {
|
||||
commit({})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let _ = self.chatListController as? ChatListControllerImpl {
|
||||
var media: EngineStoryInputMedia?
|
||||
|
||||
if let mediaResult = result.media {
|
||||
switch mediaResult {
|
||||
case let .image(image, dimensions):
|
||||
let tempFile = TempBox.shared.tempFile(fileName: "file")
|
||||
defer {
|
||||
TempBox.shared.dispose(tempFile)
|
||||
}
|
||||
if let imageData = compressImageToJPEG(image, quality: 0.7, tempFilePath: tempFile.path) {
|
||||
media = .image(dimensions: dimensions, data: imageData, stickers: result.stickers)
|
||||
}
|
||||
case let .video(content, firstFrameImage, values, duration, dimensions):
|
||||
let adjustments: VideoMediaResourceAdjustments
|
||||
if let valuesData = try? JSONEncoder().encode(values) {
|
||||
let data = MemoryBuffer(data: valuesData)
|
||||
let digest = MemoryBuffer(data: data.md5Digest())
|
||||
adjustments = VideoMediaResourceAdjustments(data: data, digest: digest, isStory: true)
|
||||
|
||||
let resource: TelegramMediaResource
|
||||
switch content {
|
||||
case let .imageFile(path):
|
||||
resource = LocalFileVideoMediaResource(randomId: Int64.random(in: .min ... .max), path: path, adjustments: adjustments)
|
||||
case let .videoFile(path):
|
||||
resource = LocalFileVideoMediaResource(randomId: Int64.random(in: .min ... .max), path: path, adjustments: adjustments)
|
||||
case let .asset(localIdentifier):
|
||||
resource = VideoLibraryMediaResource(localIdentifier: localIdentifier, conversion: .compress(adjustments))
|
||||
}
|
||||
let tempFile = TempBox.shared.tempFile(fileName: "file")
|
||||
defer {
|
||||
TempBox.shared.dispose(tempFile)
|
||||
}
|
||||
let imageData = firstFrameImage.flatMap { compressImageToJPEG($0, quality: 0.6, tempFilePath: tempFile.path) }
|
||||
let firstFrameFile = imageData.flatMap { data -> TempBoxFile? in
|
||||
let file = TempBox.shared.tempFile(fileName: "image.jpg")
|
||||
if let _ = try? data.write(to: URL(fileURLWithPath: file.path)) {
|
||||
return file
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
media = .video(dimensions: dimensions, duration: duration, resource: resource, firstFrameFile: firstFrameFile, stickers: result.stickers)
|
||||
}
|
||||
}
|
||||
} else if let existingMedia {
|
||||
media = .existing(media: existingMedia._asMedia())
|
||||
}
|
||||
|
||||
if let media {
|
||||
let _ = (context.engine.messages.uploadStory(
|
||||
target: target,
|
||||
media: media,
|
||||
mediaAreas: result.mediaAreas,
|
||||
text: result.caption.string,
|
||||
entities: generateChatInputTextEntities(result.caption),
|
||||
pin: result.options.pin,
|
||||
privacy: result.options.privacy,
|
||||
isForwardingDisabled: result.options.isForwardingDisabled,
|
||||
period: result.options.timeout,
|
||||
randomId: result.randomId,
|
||||
forwardInfo: forwardInfo
|
||||
)
|
||||
|> deliverOnMainQueue).startStandalone(next: { stableId in
|
||||
moveStorySource(engine: context.engine, peerId: context.account.peerId, from: result.randomId, to: Int64(stableId))
|
||||
})
|
||||
}
|
||||
completionImpl()
|
||||
}
|
||||
}
|
||||
|
||||
public func openSettings() {
|
||||
guard let rootTabController = self.rootTabController else {
|
||||
return
|
||||
@@ -581,3 +610,7 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension MediaEditorScreen.Result: MediaEditorScreenResult {
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user