mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
[WIP] Stickers editor
This commit is contained in:
parent
09a0192816
commit
d9f010a806
@ -12035,11 +12035,11 @@ Sorry for the inconvenience.";
|
||||
|
||||
"MediaEditor.Undo" = "Undo";
|
||||
"MediaEditor.Erase" = "Erase";
|
||||
"MediaEditor.EraseInfo" = "Erase";
|
||||
"MediaEditor.EraseInfo" = "Erase parts of this sticker";
|
||||
"MediaEditor.Restore" = "Restore";
|
||||
"MediaEditor.RestoreInfo" = "Restore";
|
||||
"MediaEditor.RestoreInfo" = "Restore parts of this sticker";
|
||||
"MediaEditor.Cutout" = "Cut Out an Object";
|
||||
"MediaEditor.CutoutInfo" = "Cut Out an Object";
|
||||
"MediaEditor.CutoutInfo" = "Tap on an object to cut it out";
|
||||
"MediaEditor.Outline" = "Add Outline";
|
||||
"MediaEditor.SetStickerEmoji" = "Set emoji that corresponds to your sticker";
|
||||
|
||||
|
@ -1019,7 +1019,7 @@ public protocol SharedAccountContext: AnyObject {
|
||||
|
||||
func makeMediaPickerScreen(context: AccountContext, hasSearch: Bool, completion: @escaping (Any) -> Void) -> ViewController
|
||||
|
||||
func makeStickerEditorScreen(context: AccountContext, source: Any?, transitionArguments: (UIView, CGRect, UIImage?)?, completion: @escaping (TelegramMediaFile, [String], @escaping () -> Void) -> Void) -> ViewController
|
||||
func makeStickerEditorScreen(context: AccountContext, source: Any?, transitionArguments: (UIView, CGRect, UIImage?)?, completion: @escaping (TelegramMediaFile, [String], @escaping () -> Void) -> Void, cancelled: @escaping () -> Void) -> ViewController
|
||||
|
||||
func makeStickerMediaPickerScreen(context: AccountContext, getSourceRect: @escaping () -> CGRect?, completion: @escaping (Any?, UIView?, CGRect, UIImage?, Bool, @escaping (Bool?) -> (UIView, CGRect)?, @escaping () -> Void) -> Void, dismissed: @escaping () -> Void) -> ViewController
|
||||
func makeStoryMediaPickerScreen(context: AccountContext, getSourceRect: @escaping () -> CGRect, completion: @escaping (Any, UIView, CGRect, UIImage?, @escaping (Bool?) -> (UIView, CGRect)?, @escaping () -> Void) -> Void, dismissed: @escaping () -> Void, groupsPresented: @escaping () -> Void) -> ViewController
|
||||
|
@ -615,12 +615,16 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
previewView: previewView,
|
||||
parentView: self.cameraWrapperView,
|
||||
restore: { [weak self, weak previewView] in
|
||||
guard let self else{
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.modernCameraTapGestureRecognizer?.isEnabled = true
|
||||
if let previewView {
|
||||
self.cameraWrapperView.addSubview(previewView)
|
||||
if let (layout, navigationBarHeight) = self.validLayout {
|
||||
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
previewView.layer.removeAllAnimations()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
@ -1562,7 +1566,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
cameraView.center = CGPoint(x: cameraRect.size.width / 2.0, y: cameraRect.size.height / 2.0)
|
||||
cameraView.transform = CGAffineTransform(scaleX: cameraScale, y: cameraScale)
|
||||
|
||||
} else {
|
||||
} else if cameraView.superview == self.gridNode.scrollView {
|
||||
transition.updateFrame(view: cameraView, frame: cameraRect)
|
||||
}
|
||||
self.cameraActivateAreaNode.frame = cameraRect
|
||||
|
@ -41,6 +41,7 @@ swift_library(
|
||||
"//submodules/StickerPeekUI:StickerPeekUI",
|
||||
"//submodules/Pasteboard:Pasteboard",
|
||||
"//submodules/TelegramUI/Components/Stickers/StickerPackEditTitleController",
|
||||
"//submodules/TelegramUI/Components/CameraScreen",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -24,6 +24,7 @@ import MultiAnimationRenderer
|
||||
import Pasteboard
|
||||
import StickerPackEditTitleController
|
||||
import EntityKeyboard
|
||||
import CameraScreen
|
||||
|
||||
private let maxStickersCount = 120
|
||||
|
||||
@ -1281,14 +1282,21 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
packController.present(UndoOverlayController(presentationData: presentationData, content: .sticker(context: context, file: file, loop: true, title: nil, text: presentationData.strings.StickerPack_StickerAdded(info.title).string, undoText: nil, customAction: nil), elevatedLayout: false, action: { _ in return false }), in: .current)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
cancelled: cancelled
|
||||
)
|
||||
navigationController?.pushViewController(editorController)
|
||||
},
|
||||
dismissed: {}
|
||||
)
|
||||
dismissImpl = { [weak mainController] in
|
||||
mainController?.dismiss()
|
||||
if let mainController, let navigationController = mainController.navigationController {
|
||||
var viewControllers = navigationController.viewControllers
|
||||
viewControllers = viewControllers.filter { c in
|
||||
return !(c is CameraScreen) && c !== mainController
|
||||
}
|
||||
navigationController.setViewControllers(viewControllers, animated: false)
|
||||
}
|
||||
}
|
||||
navigationController?.pushViewController(mainController)
|
||||
}
|
||||
@ -1378,7 +1386,8 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
packController.present(UndoOverlayController(presentationData: presentationData, content: .sticker(context: context, file: file, loop: true, title: nil, text: presentationData.strings.StickerPack_StickerUpdated, undoText: nil, customAction: nil), elevatedLayout: false, action: { _ in return false }), in: .current)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
cancelled: {}
|
||||
)
|
||||
navigationController?.pushViewController(controller)
|
||||
}
|
||||
@ -2015,7 +2024,11 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
let layout = ItemLayout(width: fillingWidth, itemsCount: items.count)
|
||||
contentHeight = layout.height
|
||||
} else {
|
||||
let rowCount = items.count / itemsPerRow + ((items.count % itemsPerRow) == 0 ? 0 : 1)
|
||||
var itemsCount = items.count
|
||||
if info.flags.contains(.isCreator) && itemsCount < 120 {
|
||||
itemsCount += 1
|
||||
}
|
||||
let rowCount = itemsCount / itemsPerRow + ((itemsCount % itemsPerRow) == 0 ? 0 : 1)
|
||||
contentHeight = itemWidth * CGFloat(rowCount)
|
||||
}
|
||||
} else {
|
||||
|
@ -1417,6 +1417,7 @@ public class CameraScreen: ViewController {
|
||||
|
||||
private let mainPreviewContainerView: UIView
|
||||
fileprivate var mainPreviewView: CameraSimplePreviewView
|
||||
private let mainPreviewAnimationWrapperView: UIView
|
||||
|
||||
private let additionalPreviewContainerView: UIView
|
||||
fileprivate var additionalPreviewView: CameraSimplePreviewView
|
||||
@ -1550,6 +1551,10 @@ public class CameraScreen: ViewController {
|
||||
self.mainPreviewContainerView.clipsToBounds = true
|
||||
self.mainPreviewView = CameraSimplePreviewView(frame: .zero, main: true)
|
||||
|
||||
self.mainPreviewAnimationWrapperView = UIView()
|
||||
self.mainPreviewAnimationWrapperView.clipsToBounds = true
|
||||
self.mainPreviewAnimationWrapperView.isUserInteractionEnabled = false
|
||||
|
||||
self.additionalPreviewContainerView = UIView()
|
||||
self.additionalPreviewContainerView.clipsToBounds = true
|
||||
self.additionalPreviewView = CameraSimplePreviewView(frame: .zero, main: false)
|
||||
@ -1604,6 +1609,7 @@ public class CameraScreen: ViewController {
|
||||
self.view.addSubview(self.transitionCornersView)
|
||||
|
||||
self.mainPreviewContainerView.addSubview(self.mainPreviewView)
|
||||
self.mainPreviewContainerView.addSubview(self.mainPreviewAnimationWrapperView)
|
||||
self.additionalPreviewContainerView.addSubview(self.additionalPreviewView)
|
||||
|
||||
self.completion.connect { [weak self] result in
|
||||
@ -1757,7 +1763,7 @@ public class CameraScreen: ViewController {
|
||||
if let cameraHolder = controller.holder {
|
||||
camera = cameraHolder.camera
|
||||
self.mainPreviewView = cameraHolder.previewView
|
||||
self.mainPreviewContainerView.addSubview(self.mainPreviewView)
|
||||
self.mainPreviewAnimationWrapperView.addSubview(self.mainPreviewView)
|
||||
} else {
|
||||
camera = Camera(
|
||||
configuration: Camera.Configuration(
|
||||
@ -1961,7 +1967,7 @@ public class CameraScreen: ViewController {
|
||||
let transitionFraction = translation.y / self.frame.height
|
||||
if abs(transitionFraction) > 0.3 || abs(velocity.y) > 1000.0 {
|
||||
self.containerView.layer.sublayerTransform = CATransform3DIdentity
|
||||
self.mainPreviewView.center = self.previewContainerView.center.offsetBy(dx: 0.0, dy: translation.y)
|
||||
self.mainPreviewAnimationWrapperView.center = self.previewContainerView.center.offsetBy(dx: 0.0, dy: translation.y)
|
||||
|
||||
if let view = self.componentHost.view {
|
||||
view.center = view.center.offsetBy(dx: 0.0, dy: translation.y)
|
||||
@ -2123,10 +2129,14 @@ public class CameraScreen: ViewController {
|
||||
duration: 0.3
|
||||
)
|
||||
} else {
|
||||
self.mainPreviewAnimationWrapperView.bounds = self.mainPreviewView.bounds
|
||||
self.mainPreviewAnimationWrapperView.center = CGPoint(x: self.previewContainerView.frame.width / 2.0, y: self.previewContainerView.frame.height / 2.0)
|
||||
|
||||
self.mainPreviewView.layer.position = CGPoint(x: self.previewContainerView.frame.width / 2.0, y: self.previewContainerView.frame.height / 2.0)
|
||||
|
||||
let sourceInnerFrame = sourceView.convert(transitionIn.sourceRect, to: self.previewContainerView)
|
||||
let sourceCenter = sourceInnerFrame.center
|
||||
self.mainPreviewView.layer.position = CGPoint(x: self.previewContainerView.frame.width / 2.0, y: self.previewContainerView.frame.height / 2.0)
|
||||
self.mainPreviewView.layer.animatePosition(from: sourceCenter, to: self.mainPreviewView.layer.position, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, completion: { _ in
|
||||
self.mainPreviewAnimationWrapperView.layer.animatePosition(from: sourceCenter, to: self.mainPreviewAnimationWrapperView.center, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, completion: { _ in
|
||||
self.requestUpdateLayout(hasAppeared: true, transition: .immediate)
|
||||
})
|
||||
|
||||
@ -2134,12 +2144,12 @@ public class CameraScreen: ViewController {
|
||||
if let holder = controller.holder {
|
||||
sourceBounds = CGRect(origin: .zero, size: holder.parentView.frame.size.aspectFitted(sourceBounds.size))
|
||||
}
|
||||
self.mainPreviewAnimationWrapperView.layer.animateBounds(from: sourceBounds, to: self.mainPreviewView.bounds, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
|
||||
self.mainPreviewView.layer.animateBounds(from: sourceBounds, to: CGRect(origin: .zero, size: self.previewContainerView.frame.size), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
|
||||
|
||||
let sourceScale = self.mainPreviewView.layer.value(forKeyPath: "transform.scale.x") as? CGFloat ?? 1.0
|
||||
let sourceScale = sourceInnerFrame.height / self.previewContainerView.frame.height
|
||||
self.mainPreviewView.transform = CGAffineTransform.identity
|
||||
self.mainPreviewView.layer.animateScale(from: sourceScale, to: 1.0, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, completion: { _ in
|
||||
self.mainPreviewAnimationWrapperView.layer.animateScale(from: sourceScale, to: 1.0, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, completion: { _ in
|
||||
self.mainPreviewContainerView.addSubview(self.mainPreviewView)
|
||||
Queue.mainQueue().justDispatch {
|
||||
self.animatedIn = true
|
||||
}
|
||||
@ -2184,18 +2194,26 @@ public class CameraScreen: ViewController {
|
||||
removeOnCompletion: false
|
||||
)
|
||||
} else {
|
||||
self.mainPreviewAnimationWrapperView.addSubview(self.mainPreviewView)
|
||||
self.animatedIn = false
|
||||
|
||||
let destinationInnerFrame = destinationView.convert(transitionOut.destinationRect, to: self.previewContainerView)
|
||||
let initialCenter = self.mainPreviewView.layer.position
|
||||
self.mainPreviewView.layer.position = destinationInnerFrame.center
|
||||
self.mainPreviewView.layer.animatePosition(from: initialCenter, to: self.mainPreviewView.layer.position, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, completion: { _ in
|
||||
|
||||
self.mainPreviewAnimationWrapperView.center = destinationInnerFrame.center
|
||||
self.mainPreviewAnimationWrapperView.layer.animatePosition(from: initialCenter, to: self.mainPreviewAnimationWrapperView.center, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in
|
||||
completion()
|
||||
})
|
||||
|
||||
self.mainPreviewView.layer.animateBounds(from: self.mainPreviewView.bounds, to: CGRect(origin: .zero, size: self.previewContainerView.frame.size), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
|
||||
var targetBounds = self.mainPreviewView.bounds
|
||||
if let holder = controller.holder {
|
||||
targetBounds = CGRect(origin: .zero, size: holder.parentView.frame.size.aspectFitted(targetBounds.size))
|
||||
}
|
||||
self.mainPreviewView.center = self.mainPreviewView.center.offsetBy(dx: (targetBounds.width - self.mainPreviewView.bounds.width) / 2.0, dy: 0.0)
|
||||
self.mainPreviewAnimationWrapperView.layer.animateBounds(from: self.mainPreviewView.bounds, to: targetBounds, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
|
||||
|
||||
let targetScale = destinationInnerFrame.width / self.previewContainerView.frame.width
|
||||
self.mainPreviewView.transform = CGAffineTransform(scaleX: targetScale, y: targetScale)
|
||||
self.mainPreviewView.layer.animateScale(from: 1.0, to: targetScale, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
let targetScale = destinationInnerFrame.height / self.previewContainerView.frame.height
|
||||
self.mainPreviewAnimationWrapperView.layer.animateScale(from: 1.0, to: targetScale, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
|
||||
}
|
||||
|
||||
if let view = self.componentHost.view {
|
||||
@ -2684,7 +2702,11 @@ public class CameraScreen: ViewController {
|
||||
let additionalPreviewInnerFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((circleSide - additionalPreviewInnerSize.width) / 2.0), y: floorToScreenPixels((circleSide - additionalPreviewInnerSize.height) / 2.0)), size: additionalPreviewInnerSize)
|
||||
|
||||
if mainPreviewView.superview != self.mainPreviewContainerView {
|
||||
self.mainPreviewContainerView.insertSubview(mainPreviewView, at: 0)
|
||||
if case .sticker = controller.mode, !self.animatedIn {
|
||||
|
||||
} else {
|
||||
self.mainPreviewContainerView.insertSubview(mainPreviewView, at: 0)
|
||||
}
|
||||
}
|
||||
if additionalPreviewView.superview != self.additionalPreviewContainerView {
|
||||
self.additionalPreviewContainerView.insertSubview(additionalPreviewView, at: 0)
|
||||
|
@ -365,11 +365,11 @@ private final class MediaCutoutScreenComponent: Component {
|
||||
let helpText: String
|
||||
switch controller.mode {
|
||||
case .cutout:
|
||||
helpText = "Tap on an object to cut it out"
|
||||
helpText = environment.strings.MediaEditor_CutoutInfo
|
||||
case .erase:
|
||||
helpText = "Erase parts of this sticker"
|
||||
helpText = environment.strings.MediaEditor_EraseInfo
|
||||
case .restore:
|
||||
helpText = "Restore parts of this sticker"
|
||||
helpText = environment.strings.MediaEditor_RestoreInfo
|
||||
}
|
||||
|
||||
let labelSize = self.label.update(
|
||||
|
@ -62,6 +62,7 @@ import MediaEditorScreen
|
||||
import BusinessIntroSetupScreen
|
||||
import TelegramNotices
|
||||
import BotSettingsScreen
|
||||
import CameraScreen
|
||||
|
||||
private final class AccountUserInterfaceInUseContext {
|
||||
let subscribers = Bag<(Bool) -> Void>()
|
||||
@ -2366,27 +2367,42 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
return StickerPackScreen(context: context, updatedPresentationData: updatedPresentationData, mainStickerPack: mainStickerPack, stickerPacks: stickerPacks, loadedStickerPacks: loadedStickerPacks, isEditing: isEditing, expandIfNeeded: expandIfNeeded, parentNavigationController: parentNavigationController, sendSticker: sendSticker)
|
||||
}
|
||||
|
||||
public func makeStickerEditorScreen(context: AccountContext, source: Any?, transitionArguments: (UIView, CGRect, UIImage?)?, completion: @escaping (TelegramMediaFile, [String], @escaping () -> Void) -> Void) -> ViewController {
|
||||
let subject: MediaEditorScreen.Subject
|
||||
public func makeStickerEditorScreen(context: AccountContext, source: Any?, transitionArguments: (UIView, CGRect, UIImage?)?, completion: @escaping (TelegramMediaFile, [String], @escaping () -> Void) -> Void, cancelled: @escaping () -> Void) -> ViewController {
|
||||
let subject: Signal<MediaEditorScreen.Subject?, NoError>
|
||||
let mode: MediaEditorScreen.Mode.StickerEditorMode
|
||||
var fromCamera = false
|
||||
if let (file, emoji) = source as? (TelegramMediaFile, [String]) {
|
||||
subject = .sticker(file, emoji)
|
||||
subject = .single(.sticker(file, emoji))
|
||||
mode = .editing
|
||||
} else if let asset = source as? PHAsset {
|
||||
subject = .asset(asset)
|
||||
subject = .single(.asset(asset))
|
||||
mode = .addingToPack
|
||||
} else if let image = source as? UIImage {
|
||||
subject = .image(image, PixelDimensions(image.size), nil, .bottomRight)
|
||||
subject = .single(.image(image, PixelDimensions(image.size), nil, .bottomRight))
|
||||
mode = .addingToPack
|
||||
} else if let source = source as? Signal<CameraScreen.Result, NoError> {
|
||||
subject = source
|
||||
|> map { value -> MediaEditorScreen.Subject? in
|
||||
switch value {
|
||||
case .pendingImage:
|
||||
return nil
|
||||
case let .image(image):
|
||||
return .image(image.image, PixelDimensions(image.image.size), nil, .topLeft)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
fromCamera = true
|
||||
mode = .addingToPack
|
||||
} else {
|
||||
subject = .empty(PixelDimensions(width: 1080, height: 1920))
|
||||
subject = .single(.empty(PixelDimensions(width: 1080, height: 1920)))
|
||||
mode = .addingToPack
|
||||
}
|
||||
let controller = MediaEditorScreen(
|
||||
let editorController = MediaEditorScreen(
|
||||
context: context,
|
||||
mode: .stickerEditor(mode: mode),
|
||||
subject: .single(subject),
|
||||
transitionIn: transitionArguments.flatMap { .gallery(
|
||||
subject: subject,
|
||||
transitionIn: fromCamera ? .camera : transitionArguments.flatMap { .gallery(
|
||||
MediaEditorScreen.TransitionIn.GalleryTransitionIn(
|
||||
sourceView: $0.0,
|
||||
sourceRect: $0.1,
|
||||
@ -2410,7 +2426,10 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
}
|
||||
} as (MediaEditorScreen.Result, @escaping (@escaping () -> Void) -> Void) -> Void
|
||||
)
|
||||
return controller
|
||||
editorController.cancelled = { _ in
|
||||
cancelled()
|
||||
}
|
||||
return editorController
|
||||
}
|
||||
|
||||
public func makeMediaPickerScreen(context: AccountContext, hasSearch: Bool, completion: @escaping (Any) -> Void) -> ViewController {
|
||||
|
@ -226,11 +226,6 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
|
||||
self.accountSettingsController = accountSettingsController
|
||||
self.rootTabController = tabBarController
|
||||
self.pushViewController(tabBarController, animated: false)
|
||||
|
||||
// Queue.mainQueue().after(0.3) {
|
||||
// let controller = self.context.sharedContext.makeStickerEditorScreen(context: self.context, source: nil, transitionArguments: nil, completion: { _ , _ in })
|
||||
// self.chatListController?.push(controller)
|
||||
// }
|
||||
}
|
||||
|
||||
public func updateRootControllers(showCallsTab: Bool) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user