[WIP] Stickers editor

This commit is contained in:
Ilya Laktyushin 2024-04-08 18:43:23 +04:00
parent 9ec01a7f24
commit 47d4d4c86c
3 changed files with 129 additions and 131 deletions

View File

@ -417,11 +417,11 @@ final class PremiumStickerPackAccessoryNode: SparseNode, PeekControllerAccessory
private func topItems(selectedEmoji: [String] = [], recommendedEmoji: [String], count: Int) -> [String] { private func topItems(selectedEmoji: [String] = [], recommendedEmoji: [String], count: Int) -> [String] {
var defaultItems: [String] = [ var defaultItems: [String] = [
"👍", "👎", "", "🔥", "🥰", "👏", "😁" "👍", "👎", "", "🔥", "🥰", "👏", "😁", "😎"
] ]
if !recommendedEmoji.isEmpty, let firstEmoji = recommendedEmoji.first { if !recommendedEmoji.isEmpty, let firstEmoji = recommendedEmoji.first {
defaultItems.removeLast() defaultItems.remove(at: defaultItems.count - 2)
defaultItems.append(firstEmoji) defaultItems.insert(firstEmoji, at: defaultItems.count - 1)
} }
var result = selectedEmoji.filter { !defaultItems.contains($0) } var result = selectedEmoji.filter { !defaultItems.contains($0) }
result.append(contentsOf: defaultItems) result.append(contentsOf: defaultItems)
@ -468,7 +468,7 @@ final class EmojiStickerAccessoryNode: SparseNode, PeekControllerAccessoryNode {
subject: .stickerAlt, subject: .stickerAlt,
hasTrending: false, hasTrending: false,
topReactionItems: [], topReactionItems: [],
topEmojiItems: topItems(selectedEmoji: selectedItems, recommendedEmoji: recommendedEmoji, count: 7), topEmojiItems: topItems(selectedEmoji: selectedItems, recommendedEmoji: recommendedEmoji, count: 8),
areUnicodeEmojiEnabled: true, areUnicodeEmojiEnabled: true,
areCustomEmojiEnabled: false, areCustomEmojiEnabled: false,
chatPeerId: context.account.peerId, chatPeerId: context.account.peerId,

View File

@ -88,7 +88,6 @@ final class MediaEditorScreenComponent: Component {
let selectedEntity: DrawingEntity? let selectedEntity: DrawingEntity?
let entityViewForEntity: (DrawingEntity) -> DrawingEntityView? let entityViewForEntity: (DrawingEntity) -> DrawingEntityView?
let openDrawing: (DrawingScreenType) -> Void let openDrawing: (DrawingScreenType) -> Void
let openTools: () -> Void
let cutoutUndo: () -> Void let cutoutUndo: () -> Void
init( init(
@ -105,7 +104,6 @@ final class MediaEditorScreenComponent: Component {
selectedEntity: DrawingEntity?, selectedEntity: DrawingEntity?,
entityViewForEntity: @escaping (DrawingEntity) -> DrawingEntityView?, entityViewForEntity: @escaping (DrawingEntity) -> DrawingEntityView?,
openDrawing: @escaping (DrawingScreenType) -> Void, openDrawing: @escaping (DrawingScreenType) -> Void,
openTools: @escaping () -> Void,
cutoutUndo: @escaping () -> Void cutoutUndo: @escaping () -> Void
) { ) {
self.context = context self.context = context
@ -121,7 +119,6 @@ final class MediaEditorScreenComponent: Component {
self.selectedEntity = selectedEntity self.selectedEntity = selectedEntity
self.entityViewForEntity = entityViewForEntity self.entityViewForEntity = entityViewForEntity
self.openDrawing = openDrawing self.openDrawing = openDrawing
self.openTools = openTools
self.cutoutUndo = cutoutUndo self.cutoutUndo = cutoutUndo
} }
@ -726,7 +723,6 @@ final class MediaEditorScreenComponent: Component {
let isTablet = environment.metrics.isTablet let isTablet = environment.metrics.isTablet
let openDrawing = component.openDrawing let openDrawing = component.openDrawing
let openTools = component.openTools
let cutoutUndo = component.cutoutUndo let cutoutUndo = component.cutoutUndo
let buttonSideInset: CGFloat let buttonSideInset: CGFloat
@ -766,8 +762,8 @@ final class MediaEditorScreenComponent: Component {
size: CGSize(width: 33.0, height: 33.0) size: CGSize(width: 33.0, height: 33.0)
) )
), ),
action: { [weak self] in action: { [weak controller] in
guard let environment = self?.environment, let controller = environment.controller() as? MediaEditorScreen else { guard let controller else {
return return
} }
guard !controller.node.recording.isActive else { guard !controller.node.recording.isActive else {
@ -811,8 +807,8 @@ final class MediaEditorScreenComponent: Component {
icon: doneButtonIcon, icon: doneButtonIcon,
title: doneButtonTitle)), title: doneButtonTitle)),
effectAlignment: .center, effectAlignment: .center,
action: { [weak self] in action: { [weak controller] in
guard let environment = self?.environment, let controller = environment.controller() as? MediaEditorScreen else { guard let controller else {
return return
} }
switch controller.mode { switch controller.mode {
@ -870,8 +866,8 @@ final class MediaEditorScreenComponent: Component {
image: state.image(.draw), image: state.image(.draw),
size: CGSize(width: 30.0, height: 30.0) size: CGSize(width: 30.0, height: 30.0)
)), )),
action: { [weak self] in action: { [weak controller] in
guard let environment = self?.environment, let controller = environment.controller() as? MediaEditorScreen else { guard let controller else {
return return
} }
guard !controller.node.recording.isActive else { guard !controller.node.recording.isActive else {
@ -906,8 +902,8 @@ final class MediaEditorScreenComponent: Component {
image: state.image(.text), image: state.image(.text),
size: CGSize(width: 30.0, height: 30.0) size: CGSize(width: 30.0, height: 30.0)
)), )),
action: { [weak self] in action: { [weak controller] in
guard let environment = self?.environment, let controller = environment.controller() as? MediaEditorScreen else { guard let controller else {
return return
} }
guard !controller.node.recording.isActive else { guard !controller.node.recording.isActive else {
@ -943,8 +939,8 @@ final class MediaEditorScreenComponent: Component {
)), )),
tag: stickerButtonTag, tag: stickerButtonTag,
minSize: CGSize(width: 30.0, height: 30.0), minSize: CGSize(width: 30.0, height: 30.0),
action: { [weak self] view, gesture in action: { [weak controller] view, gesture in
guard let environment = self?.environment, let controller = environment.controller() as? MediaEditorScreen else { guard let controller else {
return return
} }
guard !controller.node.recording.isActive else { guard !controller.node.recording.isActive else {
@ -982,14 +978,14 @@ final class MediaEditorScreenComponent: Component {
image: state.image(.tools), image: state.image(.tools),
size: CGSize(width: 30.0, height: 30.0) size: CGSize(width: 30.0, height: 30.0)
)), )),
action: { [weak self] in action: { [weak controller] in
guard let environment = self?.environment, let controller = environment.controller() as? MediaEditorScreen else { guard let controller else {
return return
} }
guard !controller.node.recording.isActive else { guard !controller.node.recording.isActive else {
return return
} }
openTools() openDrawing(.tools)
} }
)), )),
environment: {}, environment: {},
@ -1830,8 +1826,8 @@ final class MediaEditorScreenComponent: Component {
mediaEditor.setAdditionalVideoOffset(offset, apply: apply) mediaEditor.setAdditionalVideoOffset(offset, apply: apply)
} }
}, },
trackLongPressed: { [weak self] trackId, sourceView in trackLongPressed: { [weak controller] trackId, sourceView in
guard let self, let controller = self.environment?.controller() as? MediaEditorScreen else { guard let controller else {
return return
} }
controller.node.presentTrackOptions(trackId: trackId, sourceView: sourceView) controller.node.presentTrackOptions(trackId: trackId, sourceView: sourceView)
@ -1912,14 +1908,14 @@ final class MediaEditorScreenComponent: Component {
transition: transition, transition: transition,
component: AnyComponent(CameraButton( component: AnyComponent(CameraButton(
content: saveContentComponent, content: saveContentComponent,
action: { [weak self] in action: { [weak self, weak controller] in
guard let environment = self?.environment, let controller = environment.controller() as? MediaEditorScreen else { guard let self, let controller else {
return return
} }
guard !controller.node.recording.isActive else { guard !controller.node.recording.isActive else {
return 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() view.playOnce()
} }
controller.requestSave() controller.requestSave()
@ -1983,16 +1979,15 @@ final class MediaEditorScreenComponent: Component {
transition: transition, transition: transition,
component: AnyComponent(CameraButton( component: AnyComponent(CameraButton(
content: dayNightContentComponent, content: dayNightContentComponent,
action: { [weak self, weak state, weak mediaEditor] in action: { [weak controller, weak state, weak mediaEditor] in
guard let environment = self?.environment, let controller = environment.controller() as? MediaEditorScreen else { guard let controller, let state else {
return return
} }
guard !controller.node.recording.isActive else { guard !controller.node.recording.isActive else {
return return
} }
if let mediaEditor { if let mediaEditor {
state?.dayNightDidChange = true state.dayNightDidChange = true
if let snapshotView = controller.node.previewContainerView.snapshotView(afterScreenUpdates: false) { if let snapshotView = controller.node.previewContainerView.snapshotView(afterScreenUpdates: false) {
controller.node.previewContainerView.addSubview(snapshotView) controller.node.previewContainerView.addSubview(snapshotView)
@ -2079,8 +2074,8 @@ final class MediaEditorScreenComponent: Component {
transition: transition, transition: transition,
component: AnyComponent(CameraButton( component: AnyComponent(CameraButton(
content: muteContentComponent, content: muteContentComponent,
action: { [weak self, weak state, weak mediaEditor] in action: { [weak state, weak controller] in
guard let environment = self?.environment, let controller = environment.controller() as? MediaEditorScreen else { guard let controller else {
return return
} }
guard !controller.node.recording.isActive else { guard !controller.node.recording.isActive else {
@ -2161,8 +2156,8 @@ final class MediaEditorScreenComponent: Component {
transition: transition, transition: transition,
component: AnyComponent(CameraButton( component: AnyComponent(CameraButton(
content: playbackContentComponent, content: playbackContentComponent,
action: { [weak self, weak mediaEditor, weak state] in action: { [weak controller, weak mediaEditor, weak state] in
guard let environment = self?.environment, let controller = environment.controller() as? MediaEditorScreen else { guard let controller else {
return return
} }
guard !controller.node.recording.isActive else { guard !controller.node.recording.isActive else {
@ -2211,8 +2206,8 @@ final class MediaEditorScreenComponent: Component {
content: AnyComponent( content: AnyComponent(
FlipButtonContentComponent(tag: switchCameraButtonTag) FlipButtonContentComponent(tag: switchCameraButtonTag)
), ),
action: { [weak self] in action: { [weak self, weak controller] in
if let self, let environment = self.environment, let controller = environment.controller() as? MediaEditorScreen { if let self, let controller {
controller.node.recording.togglePosition() controller.node.recording.togglePosition()
if let view = self.switchCameraButton.findTaggedView(tag: switchCameraButtonTag) as? FlipButtonContentComponent.View { if let view = self.switchCameraButton.findTaggedView(tag: switchCameraButtonTag) as? FlipButtonContentComponent.View {
@ -2246,8 +2241,8 @@ final class MediaEditorScreenComponent: Component {
content: AnyComponent( content: AnyComponent(
Text(text: environment.strings.Common_Cancel, font: Font.regular(17.0), color: .white) Text(text: environment.strings.Common_Cancel, font: Font.regular(17.0), color: .white)
), ),
action: { [weak self] in action: { [weak controller] in
if let self, let environment = self.environment, let controller = environment.controller() as? MediaEditorScreen { if let controller {
controller.node.interaction?.endTextEditing(reset: true) controller.node.interaction?.endTextEditing(reset: true)
} }
} }
@ -2275,8 +2270,8 @@ final class MediaEditorScreenComponent: Component {
content: AnyComponent( content: AnyComponent(
Text(text: environment.strings.Common_Done, font: Font.regular(17.0), color: .white) Text(text: environment.strings.Common_Done, font: Font.regular(17.0), color: .white)
), ),
action: { [weak self] in action: { [weak controller] in
if let self, let environment = self.environment, let controller = environment.controller() as? MediaEditorScreen { if let controller {
controller.node.interaction?.endTextEditing(reset: false) controller.node.interaction?.endTextEditing(reset: false)
} }
} }
@ -2303,8 +2298,8 @@ final class MediaEditorScreenComponent: Component {
component: AnyComponent(TextSizeSliderComponent( component: AnyComponent(TextSizeSliderComponent(
value: sizeValue ?? 0.5, value: sizeValue ?? 0.5,
tag: nil, tag: nil,
updated: { [weak self] size in updated: { [weak self, weak controller] size in
if let self, let environment = self.environment, let controller = environment.controller() as? MediaEditorScreen, let component = self.component { if let self, let controller, let component = self.component {
if let _ = component.selectedEntity { if let _ = component.selectedEntity {
controller.node.interaction?.updateEntitySize(size) controller.node.interaction?.updateEntitySize(size)
} else if [.cutoutErase, .cutoutRestore].contains(component.isDisplayingTool), let stickerMaskDrawingView = controller.node.stickerMaskDrawingView { } else if [.cutoutErase, .cutoutRestore].contains(component.isDisplayingTool), let stickerMaskDrawingView = controller.node.stickerMaskDrawingView {
@ -2832,51 +2827,61 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
} else { } else {
initialValues = nil initialValues = nil
} }
var isStickerEditor = false
if case .stickerEditor = controller.mode {
isStickerEditor = true
}
if let mediaEntityView = self.entitiesView.add(mediaEntity, announce: false) as? DrawingMediaEntityView { if let mediaEntityView = self.entitiesView.add(mediaEntity, announce: false) as? DrawingMediaEntityView {
let mediaEntitySize = mediaEntityView.bounds.size var updateStickerMaskDrawing: (CGPoint, CGFloat, CGFloat) -> Void = { _, _, _ in }
let scaledDimensions = subject.dimensions.cgSize.aspectFittedOrSmaller(CGSize(width: 1920, height: 1920)) if isStickerEditor {
let maskDrawingSize = scaledDimensions.aspectFilled(mediaEntitySize) let mediaEntitySize = mediaEntityView.bounds.size
let scaledDimensions = subject.dimensions.cgSize.aspectFittedOrSmaller(CGSize(width: 1920, height: 1920))
let stickerMaskDrawingView = DrawingView(size: scaledDimensions, gestureView: self.previewContainerView) let maskDrawingSize = scaledDimensions.aspectFilled(mediaEntitySize)
stickerMaskDrawingView.stateUpdated = { [weak self] _ in
if let self { let stickerMaskDrawingView = DrawingView(size: scaledDimensions, gestureView: self.previewContainerView)
self.requestLayout(forceUpdate: true, transition: .easeInOut(duration: 0.25)) 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) self.entitiesView.sendSubviewToBack(mediaEntityView)
@ -2887,7 +2892,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
let scaleDelta = mediaEntity.scale / initialScale let scaleDelta = mediaEntity.scale / initialScale
self.mediaEditor?.setCrop(offset: positionDelta, scale: scaleDelta, rotation: rotationDelta, mirroring: false) 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 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) let mediaEditor = MediaEditor(context: self.context, mode: isStickerEditor ? .sticker : .default, subject: effectiveSubject.editorSubject, values: initialValues, hasHistogram: true)
if let initialVideoPosition = controller.initialVideoPosition { if let initialVideoPosition = controller.initialVideoPosition {
mediaEditor.seek(initialVideoPosition, andPlay: true) 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.setAdditionalVideo(additionalVideoPath, isDual: true, positionChanges: changes.map { VideoPositionChange(additional: $0.0, timestamp: $0.1) })
mediaEditor.setAdditionalVideoPosition(videoEntity.position, scale: videoEntity.scale, rotation: videoEntity.rotation) mediaEditor.setAdditionalVideoPosition(videoEntity.position, scale: videoEntity.scale, rotation: videoEntity.rotation)
if let entityView = self.entitiesView.getView(for: videoEntity.uuid) as? DrawingStickerEntityView { 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 { if let self, let videoEntity {
self.mediaEditor?.setAdditionalVideoPosition(videoEntity.position, scale: videoEntity.scale, rotation: videoEntity.rotation) 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 openDrawing: { [weak self] mode in
if let self { if let self, let mediaEditor = self.mediaEditor {
if self.entitiesView.hasSelection { if self.entitiesView.hasSelection {
self.entitiesView.selectEntity(nil) self.entitiesView.selectEntity(nil)
} }
switch mode { switch mode {
case .sticker: case .sticker:
self.mediaEditor?.maybePauseVideo() mediaEditor.maybePauseVideo()
var hasInteractiveStickers = true var hasInteractiveStickers = true
if let controller = self.controller, case .stickerEditor = controller.mode { if let controller = self.controller, case .stickerEditor = controller.mode {
@ -4608,7 +4608,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
self.stickerScreen = controller self.stickerScreen = controller
self.controller?.present(controller, in: .current) self.controller?.present(controller, in: .current)
case .text: case .text:
self.mediaEditor?.maybePauseVideo() mediaEditor.maybePauseVideo()
self.insertTextEntity() self.insertTextEntity()
self.hasAnyChanges = true self.hasAnyChanges = true
@ -4749,37 +4749,32 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
self.animateInFromTool(inPlace: true) self.animateInFromTool(inPlace: true)
} }
} }
controller.present(cutoutController, in: .window(.root)) self.controller?.present(cutoutController, in: .window(.root))
self.cutoutScreen = cutoutController self.cutoutScreen = cutoutController
self.animateOutToTool(tool: mode, inPlace: true) self.animateOutToTool(tool: mode, inPlace: true)
controller.hapticFeedback.impact(.medium) self.controller?.hapticFeedback.impact(.medium)
case .tools: case .tools:
break if self.entitiesView.hasSelection {
} self.entitiesView.selectEntity(nil)
}
},
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()
} }
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 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)) self.requestLayout(forceUpdate: true, transition: .easeInOut(duration: 0.25))
} }
} else if controller.node.isCutout { } 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) let snapshotView = self.previewView.snapshotView(afterScreenUpdates: false)
if let snapshotView { if let snapshotView {
self.previewView.superview?.insertSubview(snapshotView, aboveSubview: self.previewView) self.previewView.superview?.insertSubview(snapshotView, aboveSubview: self.previewView)

View File

@ -60,14 +60,14 @@ final class StickerCutoutOutlineView: UIView {
self.glowLayer.removeFromSuperlayer() self.glowLayer.removeFromSuperlayer()
self.outlineLayer = CAEmitterLayer() self.outlineLayer = CAEmitterLayer()
self.outlineLayer.opacity = 0.77 self.outlineLayer.opacity = 0.65
self.outline2Layer = CAEmitterLayer() self.outline2Layer = CAEmitterLayer()
self.outline2Layer.opacity = 0.7 self.outline2Layer.opacity = 0.65
self.glowLayer = CAEmitterLayer() self.glowLayer = CAEmitterLayer()
self.layer.addSublayer(self.outlineLayer) self.layer.addSublayer(self.outlineLayer)
// self.layer.addSublayer(self.outline2Layer) self.layer.addSublayer(self.outline2Layer)
self.layer.addSublayer(self.glowLayer) self.layer.addSublayer(self.glowLayer)
let randomBeginTime = (previousBeginTime + 4) % 6 let randomBeginTime = (previousBeginTime + 4) % 6
@ -93,8 +93,8 @@ final class StickerCutoutOutlineView: UIView {
lineEmitterCell.color = UIColor.white.cgColor lineEmitterCell.color = UIColor.white.cgColor
lineEmitterCell.contents = UIImage(named: "Media Editor/ParticleDot")?.cgImage lineEmitterCell.contents = UIImage(named: "Media Editor/ParticleDot")?.cgImage
lineEmitterCell.lifetime = 2.2 lineEmitterCell.lifetime = 2.2
lineEmitterCell.birthRate = 800 lineEmitterCell.birthRate = 1000
lineEmitterCell.scale = 0.18 lineEmitterCell.scale = 0.15
lineEmitterCell.alphaSpeed = -0.4 lineEmitterCell.alphaSpeed = -0.4
self.outlineLayer.emitterCells = [lineEmitterCell] self.outlineLayer.emitterCells = [lineEmitterCell]
@ -112,7 +112,7 @@ final class StickerCutoutOutlineView: UIView {
outline2Animation.repeatCount = .infinity outline2Animation.repeatCount = .infinity
outline2Animation.calculationMode = .paced outline2Animation.calculationMode = .paced
outline2Animation.fillMode = .forwards outline2Animation.fillMode = .forwards
outline2Animation.beginTime = Double(randomBeginTime) + 0.02 outline2Animation.beginTime = Double(randomBeginTime)
self.outline2Layer.add(outline2Animation, forKey: "emitterPosition") self.outline2Layer.add(outline2Animation, forKey: "emitterPosition")
let line2EmitterCell = CAEmitterCell() let line2EmitterCell = CAEmitterCell()
@ -124,14 +124,14 @@ final class StickerCutoutOutlineView: UIView {
line2EmitterCell.color = UIColor.white.cgColor line2EmitterCell.color = UIColor.white.cgColor
line2EmitterCell.contents = UIImage(named: "Media Editor/ParticleDot")?.cgImage line2EmitterCell.contents = UIImage(named: "Media Editor/ParticleDot")?.cgImage
line2EmitterCell.lifetime = 2.2 line2EmitterCell.lifetime = 2.2
line2EmitterCell.birthRate = 500 line2EmitterCell.birthRate = 1000
line2EmitterCell.scale = 0.14 line2EmitterCell.scale = 0.15
line2EmitterCell.alphaSpeed = -0.4 line2EmitterCell.alphaSpeed = -0.4
self.outline2Layer.emitterCells = [line2EmitterCell] self.outline2Layer.emitterCells = [line2EmitterCell]
self.outline2Layer.emitterMode = .points self.outline2Layer.emitterMode = .points
self.outline2Layer.emitterSize = CGSize(width: 1.5, height: 1.5) self.outline2Layer.emitterSize = CGSize(width: 1.33, height: 1.33)
self.outline2Layer.emitterShape = .circle self.outline2Layer.emitterShape = .rectangle