mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 09:20:08 +00:00
[WIP] Stickers editor
This commit is contained in:
parent
9ec01a7f24
commit
47d4d4c86c
@ -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,
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user