mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Add story editing from stories grid
This commit is contained in:
parent
bd4de97bd8
commit
bb543f49ea
@ -3109,6 +3109,13 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
if controller.isEmbeddedEditor == true {
|
||||
mediaEditor.onFirstDisplay = { [weak self] in
|
||||
if let self {
|
||||
if let transitionInView = self.transitionInView {
|
||||
self.transitionInView = nil
|
||||
transitionInView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak transitionInView] _ in
|
||||
transitionInView?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
|
||||
if effectiveSubject.isPhoto {
|
||||
self.previewContainerView.layer.allowsGroupOpacity = true
|
||||
self.previewContainerView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, completion: { _ in
|
||||
@ -3765,6 +3772,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
|
||||
if let transitionOut = controller.transitionOut(finished, isNew), let destinationView = transitionOut.destinationView {
|
||||
var destinationTransitionView: UIView?
|
||||
var destinationTransitionRect: CGRect = .zero
|
||||
if !finished {
|
||||
if let transitionIn = controller.transitionIn, case let .gallery(galleryTransitionIn) = transitionIn, let sourceImage = galleryTransitionIn.sourceImage, isNew != true {
|
||||
let sourceSuperView = galleryTransitionIn.sourceView?.superview?.superview
|
||||
@ -3774,6 +3782,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
destinationTransitionOutView.frame = self.previewContainerView.convert(self.previewContainerView.bounds, to: sourceSuperView)
|
||||
sourceSuperView?.addSubview(destinationTransitionOutView)
|
||||
destinationTransitionView = destinationTransitionOutView
|
||||
destinationTransitionRect = galleryTransitionIn.sourceRect
|
||||
}
|
||||
if let view = self.componentHost.view as? MediaEditorScreenComponent.View {
|
||||
view.animateOut(to: .gallery)
|
||||
@ -3853,7 +3862,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
if let destinationTransitionView {
|
||||
self.previewContainerView.layer.allowsGroupOpacity = true
|
||||
self.previewContainerView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false)
|
||||
destinationTransitionView.layer.animateFrame(from: destinationTransitionView.frame, to: destinationView.convert(destinationView.bounds, to: destinationTransitionView.superview), duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { [weak destinationTransitionView] _ in
|
||||
destinationTransitionView.layer.animateFrame(from: destinationTransitionView.frame, to: destinationView.convert(destinationTransitionRect, to: destinationTransitionView.superview), duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { [weak destinationTransitionView] _ in
|
||||
destinationTransitionView?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ swift_library(
|
||||
"//submodules/UndoUI",
|
||||
"//submodules/TelegramUI/Components/PlainButtonComponent",
|
||||
"//submodules/Components/ComponentDisplayAdapters",
|
||||
"//submodules/TelegramUI/Components/MediaEditorScreen",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -33,6 +33,7 @@ import ShareController
|
||||
import UndoUI
|
||||
import PlainButtonComponent
|
||||
import ComponentDisplayAdapters
|
||||
import MediaEditorScreen
|
||||
|
||||
private let mediaBadgeBackgroundColor = UIColor(white: 0.0, alpha: 0.6)
|
||||
private let mediaBadgeTextColor = UIColor.white
|
||||
@ -1266,6 +1267,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
|
||||
|
||||
private let listDisposable = MetaDisposable()
|
||||
private var hiddenMediaDisposable: Disposable?
|
||||
private let updateDisposable = MetaDisposable()
|
||||
|
||||
private var numberOfItemsToRequest: Int = 50
|
||||
private var isRequestingView: Bool = false
|
||||
@ -1765,6 +1767,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
|
||||
self.hiddenMediaDisposable?.dispose()
|
||||
self.animationTimer?.invalidate()
|
||||
self.presentationDataDisposable?.dispose()
|
||||
self.updateDisposable.dispose()
|
||||
}
|
||||
|
||||
public func loadHole(anchor: SparseItemGrid.HoleAnchor, at location: SparseItemGrid.HoleLocation) -> Signal<Never, NoError> {
|
||||
@ -1858,16 +1861,54 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
|
||||
})))
|
||||
}
|
||||
|
||||
/*items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.StoryList_ItemAction_Edit, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let _ = self
|
||||
|
||||
|
||||
})
|
||||
})))*/
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.StoryList_ItemAction_Edit, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let _ = (self.context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: self.peerId)
|
||||
)
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self] peer in
|
||||
guard let self, let peer else {
|
||||
return
|
||||
}
|
||||
|
||||
var foundItemLayer: SparseItemGridLayer?
|
||||
var sourceImage: UIImage?
|
||||
self.itemGrid.forEachVisibleItem { gridItem in
|
||||
guard let itemLayer = gridItem.layer as? ItemLayer else {
|
||||
return
|
||||
}
|
||||
if let listItem = itemLayer.item, listItem.story.id == item.id {
|
||||
foundItemLayer = itemLayer
|
||||
if let contents = itemLayer.contents, CFGetTypeID(contents as CFTypeRef) == CGImage.typeID {
|
||||
sourceImage = UIImage(cgImage: contents as! CGImage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
guard let controller = MediaEditorScreen.makeEditStoryController(
|
||||
context: self.context,
|
||||
peer: peer,
|
||||
storyItem: item,
|
||||
videoPlaybackPosition: nil,
|
||||
repost: false,
|
||||
transitionIn: .gallery(MediaEditorScreen.TransitionIn.GalleryTransitionIn(sourceView: self.itemGrid.view, sourceRect: foundItemLayer?.frame ?? .zero, sourceImage: sourceImage)),
|
||||
transitionOut: MediaEditorScreen.TransitionOut(destinationView: self.itemGrid.view, destinationRect: foundItemLayer?.frame ?? .zero, destinationCornerRadius: 0.0),
|
||||
update: { [weak self] disposable in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.updateDisposable.set(disposable)
|
||||
}
|
||||
) else {
|
||||
return
|
||||
}
|
||||
self.parentController?.push(controller)
|
||||
})
|
||||
})
|
||||
})))
|
||||
}
|
||||
|
||||
if !item.isForwardingDisabled, case .everyone = item.privacy?.base {
|
||||
@ -1880,7 +1921,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
|
||||
let _ = (self.context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: self.peerId)
|
||||
)
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self] peer in
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self] peer in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
@ -4308,7 +4308,7 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
self.sendMessageContext.currentSpeechHolder = speechHolder
|
||||
}
|
||||
case .translate:
|
||||
self.sendMessageContext.performTranslateTextAction(view: self, text: text.string)
|
||||
self.sendMessageContext.performTranslateTextAction(view: self, text: text.string, entities: [])
|
||||
case .quote:
|
||||
break
|
||||
}
|
||||
@ -5359,13 +5359,9 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
|
||||
private let updateDisposable = MetaDisposable()
|
||||
func openStoryEditing(repost: Bool = false) {
|
||||
guard let component = self.component, let peerReference = PeerReference(component.slice.peer._asPeer()) else {
|
||||
guard let component = self.component else {
|
||||
return
|
||||
}
|
||||
let context = component.context
|
||||
let peerId = component.slice.peer.id
|
||||
let item = component.slice.item.storyItem
|
||||
let id = item.id
|
||||
|
||||
self.isEditingStory = true
|
||||
self.updateIsProgressPaused()
|
||||
@ -5376,277 +5372,39 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
videoPlaybackPosition = view.videoPlaybackPosition
|
||||
}
|
||||
|
||||
let subject: Signal<MediaEditorScreen.Subject?, NoError>
|
||||
subject = getStorySource(engine: component.context.engine, peerId: component.context.account.peerId, id: Int64(item.id))
|
||||
|> mapToSignal { source in
|
||||
if !repost, let source {
|
||||
return .single(.draft(source, Int64(item.id)))
|
||||
} else {
|
||||
let media = item.media._asMedia()
|
||||
return fetchMediaData(context: context, postbox: context.account.postbox, userLocation: .peer(peerReference.id), customUserContentType: .story, mediaReference: .story(peer: peerReference, id: item.id, media: media))
|
||||
|> mapToSignal { (value, isImage) -> Signal<MediaEditorScreen.Subject?, NoError> in
|
||||
guard case let .data(data) = value, data.complete else {
|
||||
return .complete()
|
||||
}
|
||||
if let image = UIImage(contentsOfFile: data.path) {
|
||||
return .single(nil)
|
||||
|> then(
|
||||
.single(.image(image, PixelDimensions(image.size), nil, .bottomRight))
|
||||
|> delay(0.1, queue: Queue.mainQueue())
|
||||
)
|
||||
} else {
|
||||
var duration: Double?
|
||||
if let file = media as? TelegramMediaFile {
|
||||
duration = file.duration
|
||||
}
|
||||
let symlinkPath = data.path + ".mp4"
|
||||
if fileSize(symlinkPath) == nil {
|
||||
let _ = try? FileManager.default.linkItem(atPath: data.path, toPath: symlinkPath)
|
||||
}
|
||||
return .single(nil)
|
||||
|> then(
|
||||
.single(.video(symlinkPath, nil, false, nil, nil, PixelDimensions(width: 720, height: 1280), duration ?? 0.0, [], .bottomRight))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let initialCaption: NSAttributedString?
|
||||
let initialPrivacy: EngineStoryPrivacy?
|
||||
let initialMediaAreas: [MediaArea]
|
||||
if repost {
|
||||
initialCaption = nil
|
||||
initialPrivacy = nil
|
||||
initialMediaAreas = []
|
||||
} else {
|
||||
initialCaption = chatInputStateStringWithAppliedEntities(item.text, entities: item.entities)
|
||||
initialPrivacy = item.privacy
|
||||
initialMediaAreas = item.mediaAreas
|
||||
}
|
||||
|
||||
let externalState = MediaEditorTransitionOutExternalState(
|
||||
storyTarget: nil,
|
||||
isForcedTarget: false,
|
||||
isPeerArchived: false,
|
||||
transitionOut: nil
|
||||
)
|
||||
|
||||
var updateProgressImpl: ((Float) -> Void)?
|
||||
let controller = MediaEditorScreen(
|
||||
context: context,
|
||||
mode: .storyEditor,
|
||||
subject: subject,
|
||||
isEditing: !repost,
|
||||
forwardSource: repost ? (component.slice.peer, item) : nil,
|
||||
initialCaption: initialCaption,
|
||||
initialPrivacy: initialPrivacy,
|
||||
initialMediaAreas: initialMediaAreas,
|
||||
initialVideoPosition: videoPlaybackPosition,
|
||||
guard let controller = MediaEditorScreen.makeEditStoryController(
|
||||
context: component.context,
|
||||
peer: component.slice.peer,
|
||||
storyItem: component.slice.item.storyItem,
|
||||
videoPlaybackPosition: videoPlaybackPosition,
|
||||
repost: repost,
|
||||
transitionIn: .noAnimation,
|
||||
transitionOut: { finished, isNew in
|
||||
if repost && finished {
|
||||
if let transitionOut = externalState.transitionOut?(externalState.storyTarget, externalState.isPeerArchived), let destinationView = transitionOut.destinationView {
|
||||
return MediaEditorScreen.TransitionOut(
|
||||
destinationView: destinationView,
|
||||
destinationRect: transitionOut.destinationRect,
|
||||
destinationCornerRadius: transitionOut.destinationCornerRadius
|
||||
)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
},
|
||||
completion: { [weak self] result, commit in
|
||||
transitionOut: nil,
|
||||
completed: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
let entities = generateChatInputTextEntities(result.caption)
|
||||
|
||||
if repost {
|
||||
let target: Stories.PendingTarget
|
||||
let targetPeerId: EnginePeer.Id
|
||||
if let sendAsPeerId = result.options.sendAsPeerId {
|
||||
target = .peer(sendAsPeerId)
|
||||
targetPeerId = sendAsPeerId
|
||||
} else {
|
||||
target = .myStories
|
||||
targetPeerId = context.account.peerId
|
||||
}
|
||||
externalState.storyTarget = target
|
||||
|
||||
self.component?.controller()?.dismiss(animated: false)
|
||||
|
||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: targetPeerId))
|
||||
|> deliverOnMainQueue).startStandalone(next: { peer in
|
||||
guard let peer else {
|
||||
return
|
||||
}
|
||||
|
||||
if case let .user(user) = peer {
|
||||
externalState.isPeerArchived = user.storiesHidden ?? false
|
||||
|
||||
} else if case let .channel(channel) = peer {
|
||||
externalState.isPeerArchived = channel.storiesHidden ?? false
|
||||
}
|
||||
|
||||
let forwardInfo = Stories.PendingForwardInfo(peerId: component.slice.peer.id, storyId: item.id, isModified: result.media != nil)
|
||||
|
||||
if let rootController = context.sharedContext.mainWindow?.viewController as? TelegramRootControllerInterface {
|
||||
var existingMedia: EngineMedia?
|
||||
if let _ = result.media {
|
||||
} else {
|
||||
existingMedia = item.media
|
||||
}
|
||||
rootController.proceedWithStoryUpload(target: target, result: result as! MediaEditorScreenResult, existingMedia: existingMedia, forwardInfo: forwardInfo, externalState: externalState, commit: commit)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
var updatedText: String?
|
||||
var updatedEntities: [MessageTextEntity]?
|
||||
if result.caption.string != item.text || entities != item.entities {
|
||||
updatedText = result.caption.string
|
||||
updatedEntities = entities
|
||||
}
|
||||
|
||||
if let mediaResult = result.media {
|
||||
switch mediaResult {
|
||||
case let .image(image, dimensions):
|
||||
updateProgressImpl?(0.0)
|
||||
|
||||
let tempFile = TempBox.shared.tempFile(fileName: "file")
|
||||
defer {
|
||||
TempBox.shared.dispose(tempFile)
|
||||
}
|
||||
if let imageData = compressImageToJPEG(image, quality: 0.7, tempFilePath: tempFile.path) {
|
||||
self.updateDisposable.set((context.engine.messages.editStory(peerId: peerId, id: id, media: .image(dimensions: dimensions, data: imageData, stickers: result.stickers), mediaAreas: result.mediaAreas, text: updatedText, entities: updatedEntities, privacy: nil)
|
||||
|> deliverOnMainQueue).startStrict(next: { [weak self] result in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
switch result {
|
||||
case let .progress(progress):
|
||||
updateProgressImpl?(progress)
|
||||
case .completed:
|
||||
Queue.mainQueue().after(0.1) {
|
||||
self.isEditingStory = false
|
||||
self.rewindCurrentItem()
|
||||
self.updateIsProgressPaused()
|
||||
self.state?.updated(transition: .easeInOut(duration: 0.2))
|
||||
|
||||
HapticFeedback().success()
|
||||
|
||||
commit({})
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
case let .video(content, firstFrameImage, values, duration, dimensions):
|
||||
updateProgressImpl?(0.0)
|
||||
|
||||
if let valuesData = try? JSONEncoder().encode(values) {
|
||||
let data = MemoryBuffer(data: valuesData)
|
||||
let digest = MemoryBuffer(data: data.md5Digest())
|
||||
let 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 firstFrameImageData = firstFrameImage.flatMap { compressImageToJPEG($0, quality: 0.6, tempFilePath: tempFile.path) }
|
||||
let firstFrameFile = firstFrameImageData.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
|
||||
}
|
||||
}
|
||||
|
||||
self.updateDisposable.set((context.engine.messages.editStory(peerId: peerId, id: id, media: .video(dimensions: dimensions, duration: duration, resource: resource, firstFrameFile: firstFrameFile, stickers: result.stickers), mediaAreas: result.mediaAreas, text: updatedText, entities: updatedEntities, privacy: nil)
|
||||
|> deliverOnMainQueue).startStrict(next: { [weak self] result in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
switch result {
|
||||
case let .progress(progress):
|
||||
updateProgressImpl?(progress)
|
||||
case .completed:
|
||||
Queue.mainQueue().after(0.1) {
|
||||
self.isEditingStory = false
|
||||
self.rewindCurrentItem()
|
||||
self.updateIsProgressPaused()
|
||||
self.state?.updated(transition: .easeInOut(duration: 0.2))
|
||||
|
||||
HapticFeedback().success()
|
||||
|
||||
commit({})
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
} else if updatedText != nil {
|
||||
let _ = (context.engine.messages.editStory(peerId: peerId, id: id, media: nil, mediaAreas: nil, text: updatedText, entities: updatedEntities, privacy: nil)
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self] result in
|
||||
switch result {
|
||||
case .completed:
|
||||
Queue.mainQueue().after(0.1) {
|
||||
if let self {
|
||||
self.isEditingStory = false
|
||||
self.rewindCurrentItem()
|
||||
self.updateIsProgressPaused()
|
||||
self.state?.updated(transition: .easeInOut(duration: 0.2))
|
||||
|
||||
HapticFeedback().success()
|
||||
}
|
||||
commit({})
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
})
|
||||
} else {
|
||||
self.isEditingStory = false
|
||||
self.rewindCurrentItem()
|
||||
self.updateIsProgressPaused()
|
||||
self.state?.updated(transition: .easeInOut(duration: 0.2))
|
||||
|
||||
HapticFeedback().success()
|
||||
|
||||
commit({})
|
||||
}
|
||||
self.component?.controller()?.dismiss(animated: false)
|
||||
},
|
||||
willDismiss: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.isEditingStory = false
|
||||
self.rewindCurrentItem()
|
||||
self.updateIsProgressPaused()
|
||||
self.state?.updated(transition: .easeInOut(duration: 0.2))
|
||||
},
|
||||
update: { [weak self] disposable in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.updateDisposable.set(disposable)
|
||||
}
|
||||
)
|
||||
controller.willDismiss = { [weak self] in
|
||||
self?.isEditingStory = false
|
||||
self?.rewindCurrentItem()
|
||||
self?.updateIsProgressPaused()
|
||||
self?.state?.updated(transition: .easeInOut(duration: 0.2))
|
||||
) else {
|
||||
return
|
||||
}
|
||||
controller.navigationPresentation = .flatModal
|
||||
self.component?.controller()?.push(controller)
|
||||
updateProgressImpl = { [weak controller, weak self] progress in
|
||||
controller?.updateEditProgress(progress, cancel: { [weak self] in
|
||||
self?.updateDisposable.set(nil)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private func presentSaveUpgradeScreen() {
|
||||
@ -7059,7 +6817,7 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
guard let self, let component = self.component else {
|
||||
return
|
||||
}
|
||||
self.sendMessageContext.performTranslateTextAction(view: self, text: component.slice.item.storyItem.text)
|
||||
self.sendMessageContext.performTranslateTextAction(view: self, text: component.slice.item.storyItem.text, entities: component.slice.item.storyItem.entities)
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
@ -1159,7 +1159,7 @@ final class StoryItemSetContainerSendMessage {
|
||||
controller.present(shareController, in: .window(.root))
|
||||
}
|
||||
|
||||
func performTranslateTextAction(view: StoryItemSetContainerComponent.View, text: String) {
|
||||
func performTranslateTextAction(view: StoryItemSetContainerComponent.View, text: String, entities: [MessageTextEntity]) {
|
||||
guard let component = view.component else {
|
||||
return
|
||||
}
|
||||
@ -1190,7 +1190,7 @@ final class StoryItemSetContainerSendMessage {
|
||||
|
||||
let _ = ApplicationSpecificNotice.incrementTranslationSuggestion(accountManager: component.context.sharedContext.accountManager, timestamp: Int32(Date().timeIntervalSince1970)).start()
|
||||
|
||||
let translateController = TranslateScreen(context: component.context, forceTheme: defaultDarkPresentationTheme, text: text, canCopy: true, fromLanguage: language, ignoredLanguages: translationSettings.ignoredLanguages)
|
||||
let translateController = TranslateScreen(context: component.context, forceTheme: defaultDarkPresentationTheme, text: text, entities: entities, canCopy: true, fromLanguage: language, ignoredLanguages: translationSettings.ignoredLanguages)
|
||||
translateController.pushController = { [weak view] c in
|
||||
guard let view, let component = view.component else {
|
||||
return
|
||||
@ -1762,7 +1762,7 @@ final class StoryItemSetContainerSendMessage {
|
||||
|
||||
self.sendMessages(view: view, peer: targetPeer, messages: enqueueMessages, silentPosting: silent, scheduleTime: scheduleTime)
|
||||
} else {
|
||||
let contactController = component.context.sharedContext.makeDeviceContactInfoController(context: component.context, subject: .filter(peer: peerAndContactData.0?._asPeer(), contactId: nil, contactData: contactData, completion: { [weak self, weak view] peer, contactData in
|
||||
let contactController = component.context.sharedContext.makeDeviceContactInfoController(context: ShareControllerAppAccountContext(context: component.context), environment: ShareControllerAppEnvironment(sharedContext: component.context.sharedContext), subject: .filter(peer: peerAndContactData.0?._asPeer(), contactId: nil, contactData: contactData, completion: { [weak self, weak view] peer, contactData in
|
||||
guard let self, let view else {
|
||||
return
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ swift_library(
|
||||
"//submodules/ComponentFlow:ComponentFlow",
|
||||
"//submodules/Components/ViewControllerComponent:ViewControllerComponent",
|
||||
"//submodules/Components/MultilineTextComponent:MultilineTextComponent",
|
||||
"//submodules/Components/MultilineTextWithEntitiesComponent:MultilineTextWithEntitiesComponent",
|
||||
"//submodules/Components/BundleIconComponent:BundleIconComponent",
|
||||
"//submodules/UndoUI:UndoUI",
|
||||
"//submodules/ActivityIndicator:ActivityIndicator",
|
||||
|
@ -11,6 +11,7 @@ import Speak
|
||||
import ComponentFlow
|
||||
import ViewControllerComponent
|
||||
import MultilineTextComponent
|
||||
import MultilineTextWithEntitiesComponent
|
||||
import BundleIconComponent
|
||||
import UndoUI
|
||||
|
||||
@ -35,15 +36,17 @@ private final class TranslateScreenComponent: CombinedComponent {
|
||||
|
||||
let context: AccountContext
|
||||
let text: String
|
||||
let entities: [MessageTextEntity]
|
||||
let fromLanguage: String?
|
||||
let toLanguage: String
|
||||
let copyTranslation: ((String) -> Void)?
|
||||
let changeLanguage: (String, String, @escaping (String, String) -> Void) -> Void
|
||||
let expand: () -> Void
|
||||
|
||||
init(context: AccountContext, text: String, fromLanguage: String?, toLanguage: String, copyTranslation: ((String) -> Void)?, changeLanguage: @escaping (String, String, @escaping (String, String) -> Void) -> Void, expand: @escaping () -> Void) {
|
||||
init(context: AccountContext, text: String, entities: [MessageTextEntity], fromLanguage: String?, toLanguage: String, copyTranslation: ((String) -> Void)?, changeLanguage: @escaping (String, String, @escaping (String, String) -> Void) -> Void, expand: @escaping () -> Void) {
|
||||
self.context = context
|
||||
self.text = text
|
||||
self.entities = entities
|
||||
self.fromLanguage = fromLanguage
|
||||
self.toLanguage = toLanguage
|
||||
self.copyTranslation = copyTranslation
|
||||
@ -58,6 +61,9 @@ private final class TranslateScreenComponent: CombinedComponent {
|
||||
if lhs.text != rhs.text {
|
||||
return false
|
||||
}
|
||||
if lhs.entities != rhs.entities {
|
||||
return false
|
||||
}
|
||||
if lhs.fromLanguage != rhs.fromLanguage {
|
||||
return false
|
||||
}
|
||||
@ -995,7 +1001,7 @@ public class TranslateScreen: ViewController {
|
||||
|
||||
public var wasDismissed: (() -> Void)?
|
||||
|
||||
public convenience init(context: AccountContext, forceTheme: PresentationTheme? = nil, text: String, canCopy: Bool, fromLanguage: String?, toLanguage: String? = nil, isExpanded: Bool = false, ignoredLanguages: [String]? = nil) {
|
||||
public convenience init(context: AccountContext, forceTheme: PresentationTheme? = nil, text: String, entities: [MessageTextEntity] = [], canCopy: Bool, fromLanguage: String?, toLanguage: String? = nil, isExpanded: Bool = false, ignoredLanguages: [String]? = nil) {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
var baseLanguageCode = presentationData.strings.baseLanguageCode
|
||||
@ -1024,7 +1030,7 @@ public class TranslateScreen: ViewController {
|
||||
var copyTranslationImpl: ((String) -> Void)?
|
||||
var changeLanguageImpl: ((String, String, @escaping (String, String) -> Void) -> Void)?
|
||||
var expandImpl: (() -> Void)?
|
||||
self.init(context: context, component: TranslateScreenComponent(context: context, text: text, fromLanguage: fromLanguage, toLanguage: toLanguage, copyTranslation: !canCopy ? nil : { text in
|
||||
self.init(context: context, component: TranslateScreenComponent(context: context, text: text, entities: entities, fromLanguage: fromLanguage, toLanguage: toLanguage, copyTranslation: !canCopy ? nil : { text in
|
||||
copyTranslationImpl?(text)
|
||||
}, changeLanguage: { fromLang, toLang, completion in
|
||||
changeLanguageImpl?(fromLang, toLang, completion)
|
||||
|
Loading…
x
Reference in New Issue
Block a user