diff --git a/submodules/StickerPeekUI/Sources/StickerPreviewPeekContent.swift b/submodules/StickerPeekUI/Sources/StickerPreviewPeekContent.swift index 2e6b1ad411..ef2701a5e5 100644 --- a/submodules/StickerPeekUI/Sources/StickerPreviewPeekContent.swift +++ b/submodules/StickerPeekUI/Sources/StickerPreviewPeekContent.swift @@ -417,11 +417,11 @@ final class PremiumStickerPackAccessoryNode: SparseNode, PeekControllerAccessory private func topItems(selectedEmoji: [String] = [], recommendedEmoji: [String], count: Int) -> [String] { var defaultItems: [String] = [ - "👍", "👎", "❤", "🔥", "🥰", "👏", "😁" + "👍", "👎", "❤", "🔥", "🥰", "👏", "😁", "😎" ] if !recommendedEmoji.isEmpty, let firstEmoji = recommendedEmoji.first { - defaultItems.removeLast() - defaultItems.append(firstEmoji) + defaultItems.remove(at: defaultItems.count - 2) + defaultItems.insert(firstEmoji, at: defaultItems.count - 1) } var result = selectedEmoji.filter { !defaultItems.contains($0) } result.append(contentsOf: defaultItems) @@ -468,7 +468,7 @@ final class EmojiStickerAccessoryNode: SparseNode, PeekControllerAccessoryNode { subject: .stickerAlt, hasTrending: false, topReactionItems: [], - topEmojiItems: topItems(selectedEmoji: selectedItems, recommendedEmoji: recommendedEmoji, count: 7), + topEmojiItems: topItems(selectedEmoji: selectedItems, recommendedEmoji: recommendedEmoji, count: 8), areUnicodeEmojiEnabled: true, areCustomEmojiEnabled: false, chatPeerId: context.account.peerId, diff --git a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift index cf097e1d81..75b78c450d 100644 --- a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift +++ b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift @@ -88,7 +88,6 @@ final class MediaEditorScreenComponent: Component { let selectedEntity: DrawingEntity? let entityViewForEntity: (DrawingEntity) -> DrawingEntityView? let openDrawing: (DrawingScreenType) -> Void - let openTools: () -> Void let cutoutUndo: () -> Void init( @@ -105,7 +104,6 @@ final class MediaEditorScreenComponent: Component { selectedEntity: DrawingEntity?, entityViewForEntity: @escaping (DrawingEntity) -> DrawingEntityView?, openDrawing: @escaping (DrawingScreenType) -> Void, - openTools: @escaping () -> Void, cutoutUndo: @escaping () -> Void ) { self.context = context @@ -121,7 +119,6 @@ final class MediaEditorScreenComponent: Component { self.selectedEntity = selectedEntity self.entityViewForEntity = entityViewForEntity self.openDrawing = openDrawing - self.openTools = openTools self.cutoutUndo = cutoutUndo } @@ -726,7 +723,6 @@ final class MediaEditorScreenComponent: Component { let isTablet = environment.metrics.isTablet let openDrawing = component.openDrawing - let openTools = component.openTools let cutoutUndo = component.cutoutUndo let buttonSideInset: CGFloat @@ -766,8 +762,8 @@ final class MediaEditorScreenComponent: Component { size: CGSize(width: 33.0, height: 33.0) ) ), - action: { [weak self] in - guard let environment = self?.environment, let controller = environment.controller() as? MediaEditorScreen else { + action: { [weak controller] in + guard let controller else { return } guard !controller.node.recording.isActive else { @@ -811,8 +807,8 @@ final class MediaEditorScreenComponent: Component { icon: doneButtonIcon, title: doneButtonTitle)), effectAlignment: .center, - action: { [weak self] in - guard let environment = self?.environment, let controller = environment.controller() as? MediaEditorScreen else { + action: { [weak controller] in + guard let controller else { return } switch controller.mode { @@ -870,8 +866,8 @@ final class MediaEditorScreenComponent: Component { image: state.image(.draw), size: CGSize(width: 30.0, height: 30.0) )), - action: { [weak self] in - guard let environment = self?.environment, let controller = environment.controller() as? MediaEditorScreen else { + action: { [weak controller] in + guard let controller else { return } guard !controller.node.recording.isActive else { @@ -906,8 +902,8 @@ final class MediaEditorScreenComponent: Component { image: state.image(.text), size: CGSize(width: 30.0, height: 30.0) )), - action: { [weak self] in - guard let environment = self?.environment, let controller = environment.controller() as? MediaEditorScreen else { + action: { [weak controller] in + guard let controller else { return } guard !controller.node.recording.isActive else { @@ -943,8 +939,8 @@ final class MediaEditorScreenComponent: Component { )), tag: stickerButtonTag, minSize: CGSize(width: 30.0, height: 30.0), - action: { [weak self] view, gesture in - guard let environment = self?.environment, let controller = environment.controller() as? MediaEditorScreen else { + action: { [weak controller] view, gesture in + guard let controller else { return } guard !controller.node.recording.isActive else { @@ -982,14 +978,14 @@ final class MediaEditorScreenComponent: Component { image: state.image(.tools), size: CGSize(width: 30.0, height: 30.0) )), - action: { [weak self] in - guard let environment = self?.environment, let controller = environment.controller() as? MediaEditorScreen else { + action: { [weak controller] in + guard let controller else { return } guard !controller.node.recording.isActive else { return } - openTools() + openDrawing(.tools) } )), environment: {}, @@ -1830,8 +1826,8 @@ final class MediaEditorScreenComponent: Component { mediaEditor.setAdditionalVideoOffset(offset, apply: apply) } }, - trackLongPressed: { [weak self] trackId, sourceView in - guard let self, let controller = self.environment?.controller() as? MediaEditorScreen else { + trackLongPressed: { [weak controller] trackId, sourceView in + guard let controller else { return } controller.node.presentTrackOptions(trackId: trackId, sourceView: sourceView) @@ -1912,14 +1908,14 @@ final class MediaEditorScreenComponent: Component { transition: transition, component: AnyComponent(CameraButton( content: saveContentComponent, - action: { [weak self] in - guard let environment = self?.environment, let controller = environment.controller() as? MediaEditorScreen else { + action: { [weak self, weak controller] in + guard let self, let controller else { return } guard !controller.node.recording.isActive else { return } - if let view = self?.saveButton.findTaggedView(tag: saveButtonTag) as? LottieAnimationComponent.View { + if let view = self.saveButton.findTaggedView(tag: saveButtonTag) as? LottieAnimationComponent.View { view.playOnce() } controller.requestSave() @@ -1983,16 +1979,15 @@ final class MediaEditorScreenComponent: Component { transition: transition, component: AnyComponent(CameraButton( content: dayNightContentComponent, - action: { [weak self, weak state, weak mediaEditor] in - guard let environment = self?.environment, let controller = environment.controller() as? MediaEditorScreen else { + action: { [weak controller, weak state, weak mediaEditor] in + guard let controller, let state else { return } guard !controller.node.recording.isActive else { return } - if let mediaEditor { - state?.dayNightDidChange = true + state.dayNightDidChange = true if let snapshotView = controller.node.previewContainerView.snapshotView(afterScreenUpdates: false) { controller.node.previewContainerView.addSubview(snapshotView) @@ -2079,8 +2074,8 @@ final class MediaEditorScreenComponent: Component { transition: transition, component: AnyComponent(CameraButton( content: muteContentComponent, - action: { [weak self, weak state, weak mediaEditor] in - guard let environment = self?.environment, let controller = environment.controller() as? MediaEditorScreen else { + action: { [weak state, weak controller] in + guard let controller else { return } guard !controller.node.recording.isActive else { @@ -2161,8 +2156,8 @@ final class MediaEditorScreenComponent: Component { transition: transition, component: AnyComponent(CameraButton( content: playbackContentComponent, - action: { [weak self, weak mediaEditor, weak state] in - guard let environment = self?.environment, let controller = environment.controller() as? MediaEditorScreen else { + action: { [weak controller, weak mediaEditor, weak state] in + guard let controller else { return } guard !controller.node.recording.isActive else { @@ -2211,8 +2206,8 @@ final class MediaEditorScreenComponent: Component { content: AnyComponent( FlipButtonContentComponent(tag: switchCameraButtonTag) ), - action: { [weak self] in - if let self, let environment = self.environment, let controller = environment.controller() as? MediaEditorScreen { + action: { [weak self, weak controller] in + if let self, let controller { controller.node.recording.togglePosition() if let view = self.switchCameraButton.findTaggedView(tag: switchCameraButtonTag) as? FlipButtonContentComponent.View { @@ -2246,8 +2241,8 @@ final class MediaEditorScreenComponent: Component { content: AnyComponent( Text(text: environment.strings.Common_Cancel, font: Font.regular(17.0), color: .white) ), - action: { [weak self] in - if let self, let environment = self.environment, let controller = environment.controller() as? MediaEditorScreen { + action: { [weak controller] in + if let controller { controller.node.interaction?.endTextEditing(reset: true) } } @@ -2275,8 +2270,8 @@ final class MediaEditorScreenComponent: Component { content: AnyComponent( Text(text: environment.strings.Common_Done, font: Font.regular(17.0), color: .white) ), - action: { [weak self] in - if let self, let environment = self.environment, let controller = environment.controller() as? MediaEditorScreen { + action: { [weak controller] in + if let controller { controller.node.interaction?.endTextEditing(reset: false) } } @@ -2303,8 +2298,8 @@ final class MediaEditorScreenComponent: Component { component: AnyComponent(TextSizeSliderComponent( value: sizeValue ?? 0.5, tag: nil, - updated: { [weak self] size in - if let self, let environment = self.environment, let controller = environment.controller() as? MediaEditorScreen, let component = self.component { + updated: { [weak self, weak controller] size in + if let self, let controller, let component = self.component { if let _ = component.selectedEntity { controller.node.interaction?.updateEntitySize(size) } else if [.cutoutErase, .cutoutRestore].contains(component.isDisplayingTool), let stickerMaskDrawingView = controller.node.stickerMaskDrawingView { @@ -2832,51 +2827,61 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate } else { initialValues = nil } + + var isStickerEditor = false + if case .stickerEditor = controller.mode { + isStickerEditor = true + } if let mediaEntityView = self.entitiesView.add(mediaEntity, announce: false) as? DrawingMediaEntityView { - let mediaEntitySize = mediaEntityView.bounds.size - let scaledDimensions = subject.dimensions.cgSize.aspectFittedOrSmaller(CGSize(width: 1920, height: 1920)) - let maskDrawingSize = scaledDimensions.aspectFilled(mediaEntitySize) - - let stickerMaskDrawingView = DrawingView(size: scaledDimensions, gestureView: self.previewContainerView) - stickerMaskDrawingView.stateUpdated = { [weak self] _ in - if let self { - self.requestLayout(forceUpdate: true, transition: .easeInOut(duration: 0.25)) + var updateStickerMaskDrawing: (CGPoint, CGFloat, CGFloat) -> Void = { _, _, _ in } + if isStickerEditor { + let mediaEntitySize = mediaEntityView.bounds.size + let scaledDimensions = subject.dimensions.cgSize.aspectFittedOrSmaller(CGSize(width: 1920, height: 1920)) + let maskDrawingSize = scaledDimensions.aspectFilled(mediaEntitySize) + + let stickerMaskDrawingView = DrawingView(size: scaledDimensions, gestureView: self.previewContainerView) + stickerMaskDrawingView.stateUpdated = { [weak self] _ in + if let self { + self.requestLayout(forceUpdate: true, transition: .easeInOut(duration: 0.25)) + } + } + stickerMaskDrawingView.emptyColor = .white + stickerMaskDrawingView.updateToolState(.pen(DrawingToolState.BrushState(color: DrawingColor(color: .black), size: 0.5))) + stickerMaskDrawingView.isUserInteractionEnabled = false + stickerMaskDrawingView.animationsEnabled = false + stickerMaskDrawingView.clearWithEmptyColor() + if let filter = makeLuminanceToAlphaFilter() { + self.stickerMaskWrapperView.layer.filters = [filter] + } + self.stickerMaskWrapperView.addSubview(stickerMaskDrawingView) + self.stickerMaskWrapperView.addSubview(self.stickerMaskPreviewView) + self.stickerMaskDrawingView = stickerMaskDrawingView + + var initialMaskPosition = CGPoint() + var initialMaskScale: CGFloat = 1.0 + + updateStickerMaskDrawing = { [weak stickerMaskDrawingView] position, scale, rotation in + guard let stickerMaskDrawingView else { + return + } + let maskScale = initialMaskPosition.x * 2.0 / 1080.0 + stickerMaskDrawingView.center = initialMaskPosition.offsetBy(dx: position.x * maskScale, dy: position.y * maskScale) + stickerMaskDrawingView.transform = CGAffineTransform(scaleX: initialMaskScale * scale, y: initialMaskScale * scale).rotated(by: rotation) + } + + Queue.mainQueue().after(0.1) { + let previewSize = self.previewView.bounds.size + self.stickerMaskWrapperView.frame = CGRect(origin: .zero, size: previewSize) + self.stickerMaskPreviewView.frame = CGRect(origin: .zero, size: previewSize) + + let maskScale = previewSize.width / min(maskDrawingSize.width, maskDrawingSize.height) + initialMaskScale = maskScale + initialMaskPosition = CGPoint(x: previewSize.width / 2.0, y: previewSize.height / 2.0) + stickerMaskDrawingView.bounds = CGRect(origin: .zero, size: maskDrawingSize) + + updateStickerMaskDrawing(.zero, 1.0, 0.0) } - } - stickerMaskDrawingView.emptyColor = .white - stickerMaskDrawingView.updateToolState(.pen(DrawingToolState.BrushState(color: DrawingColor(color: .black), size: 0.5))) - stickerMaskDrawingView.isUserInteractionEnabled = false - stickerMaskDrawingView.animationsEnabled = false - stickerMaskDrawingView.clearWithEmptyColor() - if let filter = makeLuminanceToAlphaFilter() { - self.stickerMaskWrapperView.layer.filters = [filter] - } - self.stickerMaskWrapperView.addSubview(stickerMaskDrawingView) - self.stickerMaskWrapperView.addSubview(self.stickerMaskPreviewView) - self.stickerMaskDrawingView = stickerMaskDrawingView - - var initialMaskPosition = CGPoint() - var initialMaskScale: CGFloat = 1.0 - - func updateStickerMaskDrawing(position: CGPoint, scale: CGFloat, rotation: CGFloat) { - let maskScale = initialMaskPosition.x * 2.0 / 1080.0 - stickerMaskDrawingView.center = initialMaskPosition.offsetBy(dx: position.x * maskScale, dy: position.y * maskScale) - stickerMaskDrawingView.transform = CGAffineTransform(scaleX: initialMaskScale * scale, y: initialMaskScale * scale).rotated(by: rotation) - } - - Queue.mainQueue().after(0.1) { - let previewSize = self.previewView.bounds.size - self.stickerMaskWrapperView.frame = CGRect(origin: .zero, size: previewSize) - self.stickerMaskPreviewView.frame = CGRect(origin: .zero, size: previewSize) - -// let filledSize = maskDrawingSize.aspectFitted(previewSize) - let maskScale = previewSize.width / min(maskDrawingSize.width, maskDrawingSize.height) - initialMaskScale = maskScale - initialMaskPosition = CGPoint(x: previewSize.width / 2.0, y: previewSize.height / 2.0) - stickerMaskDrawingView.bounds = CGRect(origin: .zero, size: maskDrawingSize) - - updateStickerMaskDrawing(position: .zero, scale: 1.0, rotation: 0.0) } self.entitiesView.sendSubviewToBack(mediaEntityView) @@ -2887,7 +2892,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate let scaleDelta = mediaEntity.scale / initialScale self.mediaEditor?.setCrop(offset: positionDelta, scale: scaleDelta, rotation: rotationDelta, mirroring: false) - updateStickerMaskDrawing(position: positionDelta, scale: scaleDelta, rotation: rotationDelta) + updateStickerMaskDrawing(positionDelta, scaleDelta, rotationDelta) } } @@ -2897,12 +2902,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate mediaEntity.scale = mediaEntity.scale * initialValues.cropScale } } - - var isStickerEditor = false - if case .stickerEditor = controller.mode { - isStickerEditor = true - } - + let mediaEditor = MediaEditor(context: self.context, mode: isStickerEditor ? .sticker : .default, subject: effectiveSubject.editorSubject, values: initialValues, hasHistogram: true) if let initialVideoPosition = controller.initialVideoPosition { mediaEditor.seek(initialVideoPosition, andPlay: true) @@ -2979,7 +2979,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate mediaEditor.setAdditionalVideo(additionalVideoPath, isDual: true, positionChanges: changes.map { VideoPositionChange(additional: $0.0, timestamp: $0.1) }) mediaEditor.setAdditionalVideoPosition(videoEntity.position, scale: videoEntity.scale, rotation: videoEntity.rotation) if let entityView = self.entitiesView.getView(for: videoEntity.uuid) as? DrawingStickerEntityView { - entityView.updated = { [weak videoEntity, weak self] in + entityView.updated = { [weak self, weak videoEntity] in if let self, let videoEntity { self.mediaEditor?.setAdditionalVideoPosition(videoEntity.position, scale: videoEntity.scale, rotation: videoEntity.rotation) } @@ -4528,13 +4528,13 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate } }, openDrawing: { [weak self] mode in - if let self { + if let self, let mediaEditor = self.mediaEditor { if self.entitiesView.hasSelection { self.entitiesView.selectEntity(nil) } switch mode { case .sticker: - self.mediaEditor?.maybePauseVideo() + mediaEditor.maybePauseVideo() var hasInteractiveStickers = true if let controller = self.controller, case .stickerEditor = controller.mode { @@ -4608,7 +4608,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate self.stickerScreen = controller self.controller?.present(controller, in: .current) case .text: - self.mediaEditor?.maybePauseVideo() + mediaEditor.maybePauseVideo() self.insertTextEntity() self.hasAnyChanges = true @@ -4749,37 +4749,32 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate self.animateInFromTool(inPlace: true) } } - controller.present(cutoutController, in: .window(.root)) + self.controller?.present(cutoutController, in: .window(.root)) self.cutoutScreen = cutoutController self.animateOutToTool(tool: mode, inPlace: true) - controller.hapticFeedback.impact(.medium) + self.controller?.hapticFeedback.impact(.medium) case .tools: - break - } - } - }, - openTools: { [weak self] in - if let self, let mediaEditor = self.mediaEditor { - if self.entitiesView.hasSelection { - self.entitiesView.selectEntity(nil) - } - var hiddenTools: [EditorToolKey] = [] - if !self.canEnhance { - hiddenTools.append(.enhance) - } - if let controller = self.controller, case .stickerEditor = controller.mode { - hiddenTools.append(.grain) - hiddenTools.append(.vignette) - } - let controller = MediaToolsScreen(context: self.context, mediaEditor: mediaEditor, hiddenTools: hiddenTools) - controller.dismissed = { [weak self] in - if let self { - self.animateInFromTool() + if self.entitiesView.hasSelection { + self.entitiesView.selectEntity(nil) } + var hiddenTools: [EditorToolKey] = [] + if !self.canEnhance { + hiddenTools.append(.enhance) + } + if let controller = self.controller, case .stickerEditor = controller.mode { + hiddenTools.append(.grain) + hiddenTools.append(.vignette) + } + let controller = MediaToolsScreen(context: self.context, mediaEditor: mediaEditor, hiddenTools: hiddenTools) + controller.dismissed = { [weak self] in + if let self { + self.animateInFromTool() + } + } + self.controller?.present(controller, in: .window(.root)) + self.animateOutToTool(tool: .tools) } - self.controller?.present(controller, in: .window(.root)) - self.animateOutToTool(tool: .tools) } }, cutoutUndo: { [weak self, weak controller] in @@ -4800,7 +4795,10 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate self.requestLayout(forceUpdate: true, transition: .easeInOut(duration: 0.25)) } } else if controller.node.isCutout { - let action = { + let action = { [weak self, weak mediaEditor] in + guard let self, let mediaEditor else { + return + } let snapshotView = self.previewView.snapshotView(afterScreenUpdates: false) if let snapshotView { self.previewView.superview?.insertSubview(snapshotView, aboveSubview: self.previewView) diff --git a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/StickerCutoutOutlineView.swift b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/StickerCutoutOutlineView.swift index 5e001b4105..86fa9782ab 100644 --- a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/StickerCutoutOutlineView.swift +++ b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/StickerCutoutOutlineView.swift @@ -60,14 +60,14 @@ final class StickerCutoutOutlineView: UIView { self.glowLayer.removeFromSuperlayer() self.outlineLayer = CAEmitterLayer() - self.outlineLayer.opacity = 0.77 + self.outlineLayer.opacity = 0.65 self.outline2Layer = CAEmitterLayer() - self.outline2Layer.opacity = 0.7 + self.outline2Layer.opacity = 0.65 self.glowLayer = CAEmitterLayer() self.layer.addSublayer(self.outlineLayer) -// self.layer.addSublayer(self.outline2Layer) + self.layer.addSublayer(self.outline2Layer) self.layer.addSublayer(self.glowLayer) let randomBeginTime = (previousBeginTime + 4) % 6 @@ -93,8 +93,8 @@ final class StickerCutoutOutlineView: UIView { lineEmitterCell.color = UIColor.white.cgColor lineEmitterCell.contents = UIImage(named: "Media Editor/ParticleDot")?.cgImage lineEmitterCell.lifetime = 2.2 - lineEmitterCell.birthRate = 800 - lineEmitterCell.scale = 0.18 + lineEmitterCell.birthRate = 1000 + lineEmitterCell.scale = 0.15 lineEmitterCell.alphaSpeed = -0.4 self.outlineLayer.emitterCells = [lineEmitterCell] @@ -112,7 +112,7 @@ final class StickerCutoutOutlineView: UIView { outline2Animation.repeatCount = .infinity outline2Animation.calculationMode = .paced outline2Animation.fillMode = .forwards - outline2Animation.beginTime = Double(randomBeginTime) + 0.02 + outline2Animation.beginTime = Double(randomBeginTime) self.outline2Layer.add(outline2Animation, forKey: "emitterPosition") let line2EmitterCell = CAEmitterCell() @@ -124,14 +124,14 @@ final class StickerCutoutOutlineView: UIView { line2EmitterCell.color = UIColor.white.cgColor line2EmitterCell.contents = UIImage(named: "Media Editor/ParticleDot")?.cgImage line2EmitterCell.lifetime = 2.2 - line2EmitterCell.birthRate = 500 - line2EmitterCell.scale = 0.14 + line2EmitterCell.birthRate = 1000 + line2EmitterCell.scale = 0.15 line2EmitterCell.alphaSpeed = -0.4 self.outline2Layer.emitterCells = [line2EmitterCell] self.outline2Layer.emitterMode = .points - self.outline2Layer.emitterSize = CGSize(width: 1.5, height: 1.5) - self.outline2Layer.emitterShape = .circle + self.outline2Layer.emitterSize = CGSize(width: 1.33, height: 1.33) + self.outline2Layer.emitterShape = .rectangle