Various fixes

This commit is contained in:
Ilya Laktyushin 2024-07-25 21:44:05 +02:00
parent c1fc0da041
commit 4414753d7f
6 changed files with 79 additions and 50 deletions

View File

@ -12646,3 +12646,6 @@ Sorry for the inconvenience.";
"WebBrowser.Download.Confirmation" = "Do you want to download \"%@\"?"; "WebBrowser.Download.Confirmation" = "Do you want to download \"%@\"?";
"WebBrowser.Download.Download" = "Download"; "WebBrowser.Download.Download" = "Download";
"Story.Cover" = "Story Cover";
"Story.SaveCover" = "Save Cover";

View File

@ -623,7 +623,13 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU
if navigationResponse.canShowMIMEType { if navigationResponse.canShowMIMEType {
decisionHandler(.allow) decisionHandler(.allow)
} else if #available(iOS 14.5, *) { } else if #available(iOS 14.5, *) {
decisionHandler(.download) self.presentDownloadConfirmation(fileName: navigationResponse.response.suggestedFilename ?? "file", proceed: { download in
if download {
decisionHandler(.download)
} else {
decisionHandler(.cancel)
}
})
} else { } else {
decisionHandler(.cancel) decisionHandler(.cancel)
} }

View File

@ -499,6 +499,9 @@ public final class MediaEditor {
} else if case let .video(_, _, _, _, _, duration) = subject { } else if case let .video(_, _, _, _, _, duration) = subject {
self.playerPlaybackState = PlaybackState(duration: duration, position: 0.0, isPlaying: false, hasAudio: true) self.playerPlaybackState = PlaybackState(duration: duration, position: 0.0, isPlaying: false, hasAudio: true)
self.playerPlaybackStatePromise.set(.single(self.playerPlaybackState)) self.playerPlaybackStatePromise.set(.single(self.playerPlaybackState))
} else if case let .draft(mediaEditorDraft) = subject, mediaEditorDraft.isVideo {
self.playerPlaybackState = PlaybackState(duration: mediaEditorDraft.duration ?? 0.0, position: 0.0, isPlaying: false, hasAudio: true)
self.playerPlaybackStatePromise.set(.single(self.playerPlaybackState))
} }
} }

View File

@ -154,11 +154,15 @@ public extension MediaEditorScreen {
}) })
} else { } else {
var updatedText: String? var updatedText: String?
var updatedCoverTimestamp: Double?
var updatedEntities: [MessageTextEntity]? var updatedEntities: [MessageTextEntity]?
if result.caption.string != storyItem.text || entities != storyItem.entities { if result.caption.string != storyItem.text || entities != storyItem.entities {
updatedText = result.caption.string updatedText = result.caption.string
updatedEntities = entities updatedEntities = entities
} }
if let coverTimestamp = result.coverTimestamp {
updatedCoverTimestamp = coverTimestamp
}
if let mediaResult = result.media { if let mediaResult = result.media {
switch mediaResult { switch mediaResult {
@ -237,8 +241,22 @@ public extension MediaEditorScreen {
default: default:
break break
} }
} else if updatedText != nil { } else if updatedText != nil || updatedCoverTimestamp != nil {
let _ = (context.engine.messages.editStory(peerId: peer.id, id: storyItem.id, media: nil, mediaAreas: nil, text: updatedText, entities: updatedEntities, privacy: nil) var media: EngineStoryInputMedia?
if let updatedCoverTimestamp {
if case let .file(file) = storyItem.media {
var updatedAttributes: [TelegramMediaFileAttribute] = []
for attribute in file.attributes {
if case let .Video(duration, size, flags, preloadSize, _) = attribute {
updatedAttributes.append(.Video(duration: duration, size: size, flags: flags, preloadSize: preloadSize, coverTime: updatedCoverTimestamp))
} else {
updatedAttributes.append(attribute)
}
}
media = .existing(media: file.withUpdatedAttributes(updatedAttributes))
}
}
let _ = (context.engine.messages.editStory(peerId: peer.id, id: storyItem.id, media: media, mediaAreas: nil, text: updatedText, entities: updatedEntities, privacy: nil)
|> deliverOnMainQueue).startStandalone(next: { result in |> deliverOnMainQueue).startStandalone(next: { result in
switch result { switch result {
case .completed: case .completed:

View File

@ -19,41 +19,29 @@ private final class MediaCoverScreenComponent: Component {
let context: AccountContext let context: AccountContext
let mediaEditor: Signal<MediaEditor?, NoError> let mediaEditor: Signal<MediaEditor?, NoError>
let exclusive: Bool
init( init(
context: AccountContext, context: AccountContext,
mediaEditor: Signal<MediaEditor?, NoError> mediaEditor: Signal<MediaEditor?, NoError>,
exclusive: Bool
) { ) {
self.context = context self.context = context
self.mediaEditor = mediaEditor self.mediaEditor = mediaEditor
self.exclusive = exclusive
} }
static func ==(lhs: MediaCoverScreenComponent, rhs: MediaCoverScreenComponent) -> Bool { static func ==(lhs: MediaCoverScreenComponent, rhs: MediaCoverScreenComponent) -> Bool {
if lhs.context !== rhs.context { if lhs.context !== rhs.context {
return false return false
} }
if lhs.exclusive != rhs.exclusive {
return false
}
return true return true
} }
final class State: ComponentState { final class State: ComponentState {
enum ImageKey: Hashable {
case done
}
private var cachedImages: [ImageKey: UIImage] = [:]
func image(_ key: ImageKey) -> UIImage {
if let image = self.cachedImages[key] {
return image
} else {
var image: UIImage
switch key {
case .done:
image = generateTintedImage(image: UIImage(bundleImageName: "Media Editor/Done"), color: .white)!
}
cachedImages[key] = image
return image
}
}
var playerStateDisposable: Disposable? var playerStateDisposable: Disposable?
var playerState: MediaEditorPlayerState? var playerState: MediaEditorPlayerState?
@ -176,14 +164,6 @@ private final class MediaCoverScreenComponent: Component {
self.state?.updated() self.state?.updated()
} }
// override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
// let result = super.hitTest(point, with: event)
// if let controller = self.environment?.controller() as? MediaCoverScreen, [.erase, .restore].contains(controller.mode), result == self.previewContainerView {
// return nil
// }
// return result
// }
func update(component: MediaCoverScreenComponent, availableSize: CGSize, state: State, environment: Environment<ViewControllerComponentContainer.Environment>, transition: ComponentTransition) -> CGSize { func update(component: MediaCoverScreenComponent, availableSize: CGSize, state: State, environment: Environment<ViewControllerComponentContainer.Environment>, transition: ComponentTransition) -> CGSize {
let environment = environment[ViewControllerComponentContainer.Environment.self].value let environment = environment[ViewControllerComponentContainer.Environment.self].value
self.environment = environment self.environment = environment
@ -192,7 +172,6 @@ private final class MediaCoverScreenComponent: Component {
return .zero return .zero
} }
// let isFirstTime = self.component == nil
self.component = component self.component = component
self.state = state self.state = state
@ -217,9 +196,9 @@ private final class MediaCoverScreenComponent: Component {
controlsBottomInset = -75.0 controlsBottomInset = -75.0
} }
} }
let previewContainerFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - previewSize.width) / 2.0), y: environment.safeInsets.top), size: CGSize(width: previewSize.width, height: availableSize.height - environment.safeInsets.top - environment.safeInsets.bottom + controlsBottomInset)) let previewContainerFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - previewSize.width) / 2.0), y: topInset), size: CGSize(width: previewSize.width, height: availableSize.height - environment.safeInsets.top - environment.safeInsets.bottom + controlsBottomInset))
let buttonsContainerFrame = CGRect(origin: CGPoint(x: 0.0, y: availableSize.height - environment.safeInsets.bottom + controlsBottomInset - 31.0), size: CGSize(width: availableSize.width, height: environment.safeInsets.bottom - controlsBottomInset)) let buttonsContainerFrame = CGRect(origin: CGPoint(x: 0.0, y: availableSize.height - environment.safeInsets.bottom + controlsBottomInset), size: CGSize(width: availableSize.width, height: environment.safeInsets.bottom - controlsBottomInset))
let cancelButtonSize = self.cancelButton.update( let cancelButtonSize = self.cancelButton.update(
transition: transition, transition: transition,
@ -235,7 +214,7 @@ private final class MediaCoverScreenComponent: Component {
containerSize: CGSize(width: 120.0, height: 44.0) containerSize: CGSize(width: 120.0, height: 44.0)
) )
let cancelButtonFrame = CGRect( let cancelButtonFrame = CGRect(
origin: CGPoint(x: 16.0, y: 80.0), origin: CGPoint(x: 16.0, y: previewContainerFrame.minY + 28.0),
size: cancelButtonSize size: cancelButtonSize
) )
if let cancelButtonView = self.cancelButton.view { if let cancelButtonView = self.cancelButton.view {
@ -258,7 +237,7 @@ private final class MediaCoverScreenComponent: Component {
content: AnyComponentWithIdentity( content: AnyComponentWithIdentity(
id: AnyHashable(0), id: AnyHashable(0),
component: AnyComponent(ButtonTextContentComponent( component: AnyComponent(ButtonTextContentComponent(
text: "Save Cover", text: environment.strings.Story_SaveCover,
badge: 0, badge: 0,
textColor: environment.theme.list.itemCheckColors.foregroundColor, textColor: environment.theme.list.itemCheckColors.foregroundColor,
badgeBackground: .clear, badgeBackground: .clear,
@ -268,11 +247,16 @@ private final class MediaCoverScreenComponent: Component {
isEnabled: true, isEnabled: true,
displaysProgress: false, displaysProgress: false,
action: { [weak controller, weak self] in action: { [weak controller, weak self] in
guard let controller else {
return
}
if let playerState = self?.state?.playerState, let mediaEditor = self?.state?.mediaEditor, let image = mediaEditor.resultImage { if let playerState = self?.state?.playerState, let mediaEditor = self?.state?.mediaEditor, let image = mediaEditor.resultImage {
mediaEditor.setCoverImageTimestamp(playerState.position) mediaEditor.setCoverImageTimestamp(playerState.position)
controller?.completed(playerState.position, image) controller.completed(playerState.position, image)
}
if !controller.exclusive {
controller.requestDismiss(animated: true)
} }
controller?.requestDismiss(animated: true)
} }
) )
), ),
@ -280,7 +264,7 @@ private final class MediaCoverScreenComponent: Component {
containerSize: CGSize(width: availableSize.width - buttonSideInset * 2.0, height: 50.0) containerSize: CGSize(width: availableSize.width - buttonSideInset * 2.0, height: 50.0)
) )
let doneButtonFrame = CGRect( let doneButtonFrame = CGRect(
origin: CGPoint(x: floor((availableSize.width - doneButtonSize.width) / 2.0), y: availableSize.height - 99.0), origin: CGPoint(x: floor((availableSize.width - doneButtonSize.width) / 2.0), y: min(buttonsContainerFrame.minY, availableSize.height - doneButtonSize.height - buttonSideInset)),
size: doneButtonSize size: doneButtonSize
) )
if let doneButtonView = self.doneButton.view { if let doneButtonView = self.doneButton.view {
@ -292,12 +276,12 @@ private final class MediaCoverScreenComponent: Component {
let labelSize = self.label.update( let labelSize = self.label.update(
transition: transition, transition: transition,
component: AnyComponent(Text(text: "Story Cover", font: Font.semibold(17.0), color: UIColor(rgb: 0xffffff))), component: AnyComponent(Text(text: environment.strings.Story_Cover, font: Font.semibold(17.0), color: UIColor(rgb: 0xffffff))),
environment: {}, environment: {},
containerSize: CGSize(width: availableSize.width - 88.0, height: 44.0) containerSize: CGSize(width: availableSize.width - 88.0, height: 44.0)
) )
let labelFrame = CGRect( let labelFrame = CGRect(
origin: CGPoint(x: floorToScreenPixels((availableSize.width - labelSize.width) / 2.0), y: 80.0), origin: CGPoint(x: floorToScreenPixels((availableSize.width - labelSize.width) / 2.0), y: previewContainerFrame.minY + 28.0),
size: labelSize size: labelSize
) )
if let labelView = self.label.view { if let labelView = self.label.view {
@ -319,9 +303,11 @@ private final class MediaCoverScreenComponent: Component {
labelView.bounds = CGRect(origin: .zero, size: labelFrame.size) labelView.bounds = CGRect(origin: .zero, size: labelFrame.size)
transition.setPosition(view: labelView, position: labelFrame.center) transition.setPosition(view: labelView, position: labelFrame.center)
} }
let buttonCoverFrame = CGRect(origin: CGPoint(x: 0.0, y: doneButtonFrame.minY - buttonSideInset - 11.0), size: CGSize(width: previewContainerFrame.width, height: 100.0))
transition.setFrame(view: self.buttonsContainerView, frame: buttonsContainerFrame) transition.setFrame(view: self.buttonsContainerView, frame: buttonCoverFrame)
transition.setFrame(view: self.buttonsBackgroundView, frame: CGRect(origin: .zero, size: buttonsContainerFrame.size)) transition.setFrame(view: self.buttonsBackgroundView, frame: CGRect(origin: .zero, size: buttonCoverFrame.size))
transition.setFrame(view: self.previewContainerView, frame: previewContainerFrame) transition.setFrame(view: self.previewContainerView, frame: previewContainerFrame)
@ -371,7 +357,7 @@ private final class MediaCoverScreenComponent: Component {
containerSize: CGSize(width: previewSize.width - scrubberInset * 2.0, height: availableSize.height) containerSize: CGSize(width: previewSize.width - scrubberInset * 2.0, height: availableSize.height)
) )
let scrubberFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - scrubberSize.width) / 2.0), y: availableSize.height - environment.safeInsets.bottom - scrubberSize.height + controlsBottomInset + 3.0 - 40.0), size: scrubberSize) let scrubberFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - scrubberSize.width) / 2.0), y: min(previewContainerFrame.maxY, buttonCoverFrame.minY) - scrubberSize.height - 4.0), size: scrubberSize)
if let scrubberView = self.scrubber.view { if let scrubberView = self.scrubber.view {
var animateIn = false var animateIn = false
if scrubberView.superview == nil { if scrubberView.superview == nil {
@ -514,7 +500,8 @@ final class MediaCoverScreen: ViewController {
component: AnyComponent( component: AnyComponent(
MediaCoverScreenComponent( MediaCoverScreenComponent(
context: self.context, context: self.context,
mediaEditor: controller.mediaEditor mediaEditor: controller.mediaEditor,
exclusive: controller.exclusive
) )
), ),
environment: { environment: {

View File

@ -4740,6 +4740,9 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
coverController.completed = { [weak self] position, image in coverController.completed = { [weak self] position, image in
if let self { if let self {
self.controller?.currentCoverImage = image self.controller?.currentCoverImage = image
if exclusive {
self.requestCompletion()
}
} }
} }
self.controller?.present(coverController, in: .current) self.controller?.present(coverController, in: .current)
@ -5548,6 +5551,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
public let media: MediaResult? public let media: MediaResult?
public let mediaAreas: [MediaArea] public let mediaAreas: [MediaArea]
public let caption: NSAttributedString public let caption: NSAttributedString
public let coverTimestamp: Double?
public let options: MediaEditorResultPrivacy public let options: MediaEditorResultPrivacy
public let stickers: [TelegramMediaFile] public let stickers: [TelegramMediaFile]
public let randomId: Int64 public let randomId: Int64
@ -5556,6 +5560,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
self.media = nil self.media = nil
self.mediaAreas = [] self.mediaAreas = []
self.caption = NSAttributedString() self.caption = NSAttributedString()
self.coverTimestamp = nil
self.options = MediaEditorResultPrivacy(sendAsPeerId: nil, privacy: EngineStoryPrivacy(base: .everyone, additionallyIncludePeers: []), timeout: 0, isForwardingDisabled: false, pin: false) self.options = MediaEditorResultPrivacy(sendAsPeerId: nil, privacy: EngineStoryPrivacy(base: .everyone, additionallyIncludePeers: []), timeout: 0, isForwardingDisabled: false, pin: false)
self.stickers = [] self.stickers = []
self.randomId = 0 self.randomId = 0
@ -5565,6 +5570,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
media: MediaResult?, media: MediaResult?,
mediaAreas: [MediaArea] = [], mediaAreas: [MediaArea] = [],
caption: NSAttributedString = NSAttributedString(), caption: NSAttributedString = NSAttributedString(),
coverTimestamp: Double? = nil,
options: MediaEditorResultPrivacy = MediaEditorResultPrivacy(sendAsPeerId: nil, privacy: EngineStoryPrivacy(base: .everyone, additionallyIncludePeers: []), timeout: 0, isForwardingDisabled: false, pin: false), options: MediaEditorResultPrivacy = MediaEditorResultPrivacy(sendAsPeerId: nil, privacy: EngineStoryPrivacy(base: .everyone, additionallyIncludePeers: []), timeout: 0, isForwardingDisabled: false, pin: false),
stickers: [TelegramMediaFile] = [], stickers: [TelegramMediaFile] = [],
randomId: Int64 = 0 randomId: Int64 = 0
@ -5572,6 +5578,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
self.media = media self.media = media
self.mediaAreas = mediaAreas self.mediaAreas = mediaAreas
self.caption = caption self.caption = caption
self.coverTimestamp = coverTimestamp
self.options = options self.options = options
self.stickers = stickers self.stickers = stickers
self.randomId = randomId self.randomId = randomId
@ -6479,8 +6486,13 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
} }
} }
if self.isEmbeddedEditor && !(self.node.hasAnyChanges || hasEntityChanges) { var hasAnyChanges = self.node.hasAnyChanges
self.completion(MediaEditorScreen.Result(media: nil, mediaAreas: [], caption: caption, options: self.state.privacy, stickers: stickers, randomId: randomId), { [weak self] finished in if self.isEditingStoryCover {
hasAnyChanges = false
}
if self.isEmbeddedEditor && !(hasAnyChanges || hasEntityChanges) {
self.completion(MediaEditorScreen.Result(media: nil, mediaAreas: [], caption: caption, coverTimestamp: mediaEditor.values.coverImageTimestamp, options: self.state.privacy, stickers: stickers, randomId: randomId), { [weak self] finished in
self?.node.animateOut(finished: true, saveDraft: false, completion: { [weak self] in self?.node.animateOut(finished: true, saveDraft: false, completion: { [weak self] in
self?.dismiss() self?.dismiss()
Queue.mainQueue().justDispatch { Queue.mainQueue().justDispatch {
@ -6488,7 +6500,6 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
} }
}) })
}) })
return return
} }
@ -6754,7 +6765,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
makeEditorImageComposition(context: self.node.ciContext, postbox: self.context.account.postbox, inputImage: inputImage, dimensions: storyDimensions, values: mediaEditor.values, time: firstFrameTime, textScale: 2.0, completion: { [weak self] coverImage in makeEditorImageComposition(context: self.node.ciContext, postbox: self.context.account.postbox, inputImage: inputImage, dimensions: storyDimensions, values: mediaEditor.values, time: firstFrameTime, textScale: 2.0, completion: { [weak self] coverImage in
if let self { if let self {
Logger.shared.log("MediaEditor", "Completed with video \(videoResult)") Logger.shared.log("MediaEditor", "Completed with video \(videoResult)")
self.completion(MediaEditorScreen.Result(media: .video(video: videoResult, coverImage: coverImage, values: mediaEditor.values, duration: duration, dimensions: mediaEditor.values.resultDimensions), mediaAreas: mediaAreas, caption: caption, options: self.state.privacy, stickers: stickers, randomId: randomId), { [weak self] finished in self.completion(MediaEditorScreen.Result(media: .video(video: videoResult, coverImage: coverImage, values: mediaEditor.values, duration: duration, dimensions: mediaEditor.values.resultDimensions), mediaAreas: mediaAreas, caption: caption, coverTimestamp: mediaEditor.values.coverImageTimestamp, options: self.state.privacy, stickers: stickers, randomId: randomId), { [weak self] finished in
self?.node.animateOut(finished: true, saveDraft: false, completion: { [weak self] in self?.node.animateOut(finished: true, saveDraft: false, completion: { [weak self] in
self?.dismiss() self?.dismiss()
Queue.mainQueue().justDispatch { Queue.mainQueue().justDispatch {
@ -6777,7 +6788,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
makeEditorImageComposition(context: self.node.ciContext, postbox: self.context.account.postbox, inputImage: image, dimensions: storyDimensions, values: mediaEditor.values, time: .zero, textScale: 2.0, completion: { [weak self] resultImage in makeEditorImageComposition(context: self.node.ciContext, postbox: self.context.account.postbox, inputImage: image, dimensions: storyDimensions, values: mediaEditor.values, time: .zero, textScale: 2.0, completion: { [weak self] resultImage in
if let self, let resultImage { if let self, let resultImage {
Logger.shared.log("MediaEditor", "Completed with image \(resultImage)") Logger.shared.log("MediaEditor", "Completed with image \(resultImage)")
self.completion(MediaEditorScreen.Result(media: .image(image: resultImage, dimensions: PixelDimensions(resultImage.size)), mediaAreas: mediaAreas, caption: caption, options: self.state.privacy, stickers: stickers, randomId: randomId), { [weak self] finished in self.completion(MediaEditorScreen.Result(media: .image(image: resultImage, dimensions: PixelDimensions(resultImage.size)), mediaAreas: mediaAreas, caption: caption, coverTimestamp: nil, options: self.state.privacy, stickers: stickers, randomId: randomId), { [weak self] finished in
self?.node.animateOut(finished: true, saveDraft: false, completion: { [weak self] in self?.node.animateOut(finished: true, saveDraft: false, completion: { [weak self] in
self?.dismiss() self?.dismiss()
Queue.mainQueue().justDispatch { Queue.mainQueue().justDispatch {
@ -6925,6 +6936,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
media: .sticker(file: file, emoji: self.effectiveStickerEmoji()), media: .sticker(file: file, emoji: self.effectiveStickerEmoji()),
mediaAreas: [], mediaAreas: [],
caption: NSAttributedString(), caption: NSAttributedString(),
coverTimestamp: nil,
options: MediaEditorResultPrivacy(sendAsPeerId: nil, privacy: EngineStoryPrivacy(base: .everyone, additionallyIncludePeers: []), timeout: 0, isForwardingDisabled: false, pin: false), options: MediaEditorResultPrivacy(sendAsPeerId: nil, privacy: EngineStoryPrivacy(base: .everyone, additionallyIncludePeers: []), timeout: 0, isForwardingDisabled: false, pin: false),
stickers: [], stickers: [],
randomId: 0 randomId: 0