mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various fixes
This commit is contained in:
parent
729b4d952c
commit
9937826307
@ -197,7 +197,7 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView {
|
||||
}
|
||||
|
||||
private var initialEntitiesData: Data?
|
||||
public func setup(withEntitiesData entitiesData: Data!) {
|
||||
public func setup(withEntitiesData entitiesData: Data?) {
|
||||
self.clear()
|
||||
|
||||
self.initialEntitiesData = entitiesData
|
||||
@ -329,12 +329,13 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView {
|
||||
let view = entity.makeView(context: self.context)
|
||||
view.containerView = self
|
||||
|
||||
view.onSnapToXAxis = { [weak self] snappedToX in
|
||||
guard let strongSelf = self else {
|
||||
view.onSnapToXAxis = { [weak self, weak view] snappedToX in
|
||||
guard let strongSelf = self, let strongView = view else {
|
||||
return
|
||||
}
|
||||
let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut)
|
||||
if snappedToX {
|
||||
strongSelf.insertSubview(strongSelf.xAxisView, belowSubview: strongView)
|
||||
if strongSelf.xAxisView.alpha < 1.0 {
|
||||
strongSelf.hapticFeedback.impact(.light)
|
||||
}
|
||||
@ -343,12 +344,13 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView {
|
||||
transition.updateAlpha(layer: strongSelf.xAxisView.layer, alpha: 0.0)
|
||||
}
|
||||
}
|
||||
view.onSnapToYAxis = { [weak self] snappedToY in
|
||||
guard let strongSelf = self else {
|
||||
view.onSnapToYAxis = { [weak self, weak view] snappedToY in
|
||||
guard let strongSelf = self, let strongView = view else {
|
||||
return
|
||||
}
|
||||
let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut)
|
||||
if snappedToY {
|
||||
strongSelf.insertSubview(strongSelf.yAxisView, belowSubview: strongView)
|
||||
if strongSelf.yAxisView.alpha < 1.0 {
|
||||
strongSelf.hapticFeedback.impact(.light)
|
||||
}
|
||||
@ -573,13 +575,13 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView {
|
||||
return self.selectedEntityView != nil
|
||||
}
|
||||
|
||||
public func handlePinch(_ gestureRecognizer: UIPinchGestureRecognizer!) {
|
||||
public func handlePinch(_ gestureRecognizer: UIPinchGestureRecognizer) {
|
||||
if let selectedEntityView = self.selectedEntityView, let selectionView = selectedEntityView.selectionView {
|
||||
selectionView.handlePinch(gestureRecognizer)
|
||||
}
|
||||
}
|
||||
|
||||
public func handleRotate(_ gestureRecognizer: UIRotationGestureRecognizer!) {
|
||||
public func handleRotate(_ gestureRecognizer: UIRotationGestureRecognizer) {
|
||||
if let selectedEntityView = self.selectedEntityView, let selectionView = selectedEntityView.selectionView {
|
||||
selectionView.handleRotate(gestureRecognizer)
|
||||
}
|
||||
|
@ -338,21 +338,105 @@ final class DrawingSettings: Codable, Equatable {
|
||||
|
||||
private final class ReferenceContentSource: ContextReferenceContentSource {
|
||||
private let sourceView: UIView
|
||||
|
||||
init(sourceView: UIView) {
|
||||
private let customPosition: CGPoint
|
||||
|
||||
init(sourceView: UIView, customPosition: CGPoint) {
|
||||
self.sourceView = sourceView
|
||||
self.customPosition = customPosition
|
||||
}
|
||||
|
||||
func transitionInfo() -> ContextControllerReferenceViewInfo? {
|
||||
return ContextControllerReferenceViewInfo(referenceView: self.sourceView, contentAreaInScreenSpace: UIScreen.main.bounds, customPosition: CGPoint(x: 7.0, y: 3.0))
|
||||
return ContextControllerReferenceViewInfo(referenceView: self.sourceView, contentAreaInScreenSpace: UIScreen.main.bounds, customPosition: customPosition)
|
||||
}
|
||||
}
|
||||
|
||||
private final class BlurredGradientComponent: Component {
|
||||
enum Position {
|
||||
case top
|
||||
case bottom
|
||||
}
|
||||
|
||||
let position: Position
|
||||
let tag: AnyObject?
|
||||
|
||||
public init(
|
||||
position: Position,
|
||||
tag: AnyObject?
|
||||
) {
|
||||
self.position = position
|
||||
self.tag = tag
|
||||
}
|
||||
|
||||
public static func ==(lhs: BlurredGradientComponent, rhs: BlurredGradientComponent) -> Bool {
|
||||
if lhs.position != rhs.position {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
public final class View: BlurredBackgroundView, ComponentTaggedView {
|
||||
private var component: BlurredGradientComponent?
|
||||
|
||||
public func matches(tag: Any) -> Bool {
|
||||
if let component = self.component, let componentTag = component.tag {
|
||||
let tag = tag as AnyObject
|
||||
if componentTag === tag {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private var gradientMask = UIImageView()
|
||||
private var gradientForeground = SimpleGradientLayer()
|
||||
|
||||
public func update(component: BlurredGradientComponent, availableSize: CGSize, transition: Transition) -> CGSize {
|
||||
self.component = component
|
||||
|
||||
self.updateColor(color: UIColor(rgb: 0x000000, alpha: 0.25), transition: transition.containedViewLayoutTransition)
|
||||
|
||||
if self.mask == nil {
|
||||
self.mask = self.gradientMask
|
||||
self.gradientMask.image = generateGradientImage(
|
||||
size: CGSize(width: 1.0, height: availableSize.height),
|
||||
colors: [UIColor(rgb: 0xffffff, alpha: 1.0), UIColor(rgb: 0xffffff, alpha: 1.0), UIColor(rgb: 0xffffff, alpha: 0.0)],
|
||||
locations: component.position == .top ? [0.0, 0.5, 1.0] : [1.0, 0.5, 0.0],
|
||||
direction: .vertical
|
||||
)
|
||||
|
||||
self.gradientForeground.colors = [UIColor(rgb: 0x000000, alpha: 0.35).cgColor, UIColor(rgb: 0x000000, alpha: 0.0).cgColor]
|
||||
self.gradientForeground.startPoint = CGPoint(x: 0.5, y: component.position == .top ? 0.0 : 1.0)
|
||||
self.gradientForeground.endPoint = CGPoint(x: 0.5, y: component.position == .top ? 1.0 : 0.0)
|
||||
|
||||
self.layer.addSublayer(self.gradientForeground)
|
||||
}
|
||||
|
||||
transition.setFrame(view: self.gradientMask, frame: CGRect(origin: .zero, size: availableSize))
|
||||
transition.setFrame(layer: self.gradientForeground, frame: CGRect(origin: .zero, size: availableSize))
|
||||
|
||||
self.update(size: availableSize, transition: transition.containedViewLayoutTransition)
|
||||
|
||||
return availableSize
|
||||
}
|
||||
}
|
||||
|
||||
public func makeView() -> View {
|
||||
return View(color: nil, enableBlur: true)
|
||||
}
|
||||
|
||||
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||
return view.update(component: self, availableSize: availableSize, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum DrawingScreenTransition {
|
||||
case animateIn
|
||||
case animateOut
|
||||
}
|
||||
|
||||
private let topGradientTag = GenericComponentViewTag()
|
||||
private let bottomGradientTag = GenericComponentViewTag()
|
||||
private let undoButtonTag = GenericComponentViewTag()
|
||||
private let redoButtonTag = GenericComponentViewTag()
|
||||
private let clearAllButtonTag = GenericComponentViewTag()
|
||||
@ -365,6 +449,7 @@ private let fillButtonTag = GenericComponentViewTag()
|
||||
private let zoomOutButtonTag = GenericComponentViewTag()
|
||||
private let textSettingsTag = GenericComponentViewTag()
|
||||
private let sizeSliderTag = GenericComponentViewTag()
|
||||
private let fontTag = GenericComponentViewTag()
|
||||
private let color1Tag = GenericComponentViewTag()
|
||||
private let color2Tag = GenericComponentViewTag()
|
||||
private let color3Tag = GenericComponentViewTag()
|
||||
@ -373,6 +458,7 @@ private let color5Tag = GenericComponentViewTag()
|
||||
private let color6Tag = GenericComponentViewTag()
|
||||
private let color7Tag = GenericComponentViewTag()
|
||||
private let color8Tag = GenericComponentViewTag()
|
||||
private let colorTags = [color1Tag, color2Tag, color3Tag, color4Tag, color5Tag, color6Tag, color7Tag, color8Tag]
|
||||
private let doneButtonTag = GenericComponentViewTag()
|
||||
|
||||
private final class DrawingScreenComponent: CombinedComponent {
|
||||
@ -399,6 +485,7 @@ private final class DrawingScreenComponent: CombinedComponent {
|
||||
let presentFastColorPicker: (UIView) -> Void
|
||||
let updateFastColorPickerPan: (CGPoint) -> Void
|
||||
let dismissFastColorPicker: () -> Void
|
||||
let presentFontPicker: (UIView) -> Void
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
@ -420,7 +507,8 @@ private final class DrawingScreenComponent: CombinedComponent {
|
||||
presentColorPicker: @escaping (DrawingColor) -> Void,
|
||||
presentFastColorPicker: @escaping (UIView) -> Void,
|
||||
updateFastColorPickerPan: @escaping (CGPoint) -> Void,
|
||||
dismissFastColorPicker: @escaping () -> Void
|
||||
dismissFastColorPicker: @escaping () -> Void,
|
||||
presentFontPicker: @escaping (UIView) -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.isVideo = isVideo
|
||||
@ -442,6 +530,7 @@ private final class DrawingScreenComponent: CombinedComponent {
|
||||
self.presentFastColorPicker = presentFastColorPicker
|
||||
self.updateFastColorPickerPan = updateFastColorPickerPan
|
||||
self.dismissFastColorPicker = dismissFastColorPicker
|
||||
self.presentFontPicker = presentFontPicker
|
||||
}
|
||||
|
||||
static func ==(lhs: DrawingScreenComponent, rhs: DrawingScreenComponent) -> Bool {
|
||||
@ -758,7 +847,7 @@ private final class DrawingScreenComponent: CombinedComponent {
|
||||
)
|
||||
]
|
||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }.withUpdated(theme: defaultDarkPresentationTheme)
|
||||
let contextController = ContextController(account: self.context.account, presentationData: presentationData, source: .reference(ReferenceContentSource(sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))))
|
||||
let contextController = ContextController(account: self.context.account, presentationData: presentationData, source: .reference(ReferenceContentSource(sourceView: sourceView, customPosition: CGPoint(x: 7.0, y: 3.0))), items: .single(ContextController.Items(content: .list(items))))
|
||||
self.present(contextController)
|
||||
}
|
||||
|
||||
@ -804,6 +893,9 @@ private final class DrawingScreenComponent: CombinedComponent {
|
||||
}
|
||||
|
||||
static var body: Body {
|
||||
let topGradient = Child(BlurredGradientComponent.self)
|
||||
let bottomGradient = Child(BlurredGradientComponent.self)
|
||||
|
||||
let undoButton = Child(Button.self)
|
||||
|
||||
let redoButton = Child(Button.self)
|
||||
@ -887,10 +979,36 @@ private final class DrawingScreenComponent: CombinedComponent {
|
||||
let presentFastColorPicker = component.presentFastColorPicker
|
||||
let updateFastColorPickerPan = component.updateFastColorPickerPan
|
||||
let dismissFastColorPicker = component.dismissFastColorPicker
|
||||
let presentFontPicker = component.presentFontPicker
|
||||
|
||||
let topInset = environment.safeInsets.top + 31.0
|
||||
let bottomInset: CGFloat = environment.inputHeight > 0.0 ? environment.inputHeight : 145.0
|
||||
|
||||
let topGradient = topGradient.update(
|
||||
component: BlurredGradientComponent(
|
||||
position: .top,
|
||||
tag: topGradientTag
|
||||
),
|
||||
availableSize: CGSize(width: context.availableSize.width, height: 111.0),
|
||||
transition: .immediate
|
||||
)
|
||||
context.add(topGradient
|
||||
.position(CGPoint(x: context.availableSize.width / 2.0, y: topGradient.size.height / 2.0))
|
||||
)
|
||||
|
||||
let bottomGradient = bottomGradient.update(
|
||||
component: BlurredGradientComponent(
|
||||
position: .bottom,
|
||||
tag: bottomGradientTag
|
||||
|
||||
),
|
||||
availableSize: CGSize(width: context.availableSize.width, height: 155.0),
|
||||
transition: .immediate
|
||||
)
|
||||
context.add(bottomGradient
|
||||
.position(CGPoint(x: context.availableSize.width / 2.0, y: context.availableSize.height - bottomGradient.size.height / 2.0))
|
||||
)
|
||||
|
||||
if let textEntity = state.selectedEntity as? DrawingTextEntity {
|
||||
let textSettings = textSettings.update(
|
||||
component: TextSettingsComponent(
|
||||
@ -900,6 +1018,7 @@ private final class DrawingScreenComponent: CombinedComponent {
|
||||
font: DrawingTextFont(font: textEntity.font),
|
||||
isEmojiKeyboard: false,
|
||||
tag: textSettingsTag,
|
||||
fontTag: fontTag,
|
||||
toggleStyle: { [weak state, weak textEntity] in
|
||||
guard let textEntity = textEntity else {
|
||||
return
|
||||
@ -940,15 +1059,10 @@ private final class DrawingScreenComponent: CombinedComponent {
|
||||
}
|
||||
state?.updated(transition: .easeInOut(duration: 0.2))
|
||||
},
|
||||
updateFont: { [weak state, weak textEntity] font in
|
||||
guard let textEntity = textEntity else {
|
||||
return
|
||||
presentFontPicker: {
|
||||
if let controller = controller() as? DrawingScreen, let buttonView = controller.node.componentHost.findTaggedView(tag: fontTag) {
|
||||
presentFontPicker(buttonView)
|
||||
}
|
||||
textEntity.font = font.font
|
||||
if let entityView = textEntity.currentEntityView {
|
||||
entityView.update()
|
||||
}
|
||||
state?.updated(transition: .easeInOut(duration: 0.2))
|
||||
},
|
||||
toggleKeyboard: nil
|
||||
),
|
||||
@ -958,12 +1072,12 @@ private final class DrawingScreenComponent: CombinedComponent {
|
||||
context.add(textSettings
|
||||
.position(CGPoint(x: context.availableSize.width / 2.0, y: context.availableSize.height - environment.safeInsets.bottom - textSettings.size.height / 2.0 - 89.0))
|
||||
.appear(Transition.Appear({ _, view, transition in
|
||||
if let view = findTaggedComponentViewImpl(view: view, tag: textSettingsTag) as? TextFontComponent.View, !transition.animation.isImmediate {
|
||||
if let view = view as? TextSettingsComponent.View, !transition.animation.isImmediate {
|
||||
view.animateIn()
|
||||
}
|
||||
}))
|
||||
.disappear(Transition.Disappear({ view, transition, completion in
|
||||
if let view = findTaggedComponentViewImpl(view: view, tag: textSettingsTag) as? TextFontComponent.View, !transition.animation.isImmediate {
|
||||
if let view = view as? TextSettingsComponent.View, !transition.animation.isImmediate {
|
||||
view.animateOut(completion: completion)
|
||||
} else {
|
||||
completion()
|
||||
@ -1769,11 +1883,11 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController {
|
||||
|
||||
private let textEditAccessoryView: UIInputView
|
||||
private let textEditAccessoryHost: ComponentView<Empty>
|
||||
|
||||
|
||||
private var presentationData: PresentationData
|
||||
private let hapticFeedback = HapticFeedback()
|
||||
private var validLayout: (ContainerViewLayout, UIInterfaceOrientation?)?
|
||||
|
||||
|
||||
private var _drawingView: DrawingView?
|
||||
var drawingView: DrawingView {
|
||||
if self._drawingView == nil, let controller = self.controller {
|
||||
@ -1802,7 +1916,7 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController {
|
||||
ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Paint_ClearConfirm, color: .destructive, action: { [weak actionSheet, weak self] in
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
|
||||
self?._drawingView?.performAction(action)
|
||||
})
|
||||
]),
|
||||
@ -1841,7 +1955,11 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController {
|
||||
private var _entitiesView: DrawingEntitiesView?
|
||||
var entitiesView: DrawingEntitiesView {
|
||||
if self._entitiesView == nil, let controller = self.controller {
|
||||
self._entitiesView = DrawingEntitiesView(context: self.context, size: controller.size)
|
||||
if let externalEntitiesView = controller.externalEntitiesView {
|
||||
self._entitiesView = externalEntitiesView
|
||||
} else {
|
||||
self._entitiesView = DrawingEntitiesView(context: self.context, size: controller.size)
|
||||
}
|
||||
self._drawingView?.entitiesView = self._entitiesView
|
||||
self._entitiesView?.drawingView = self._drawingView
|
||||
self._entitiesView?.entityAdded = { [weak self] entity in
|
||||
@ -1870,21 +1988,6 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController {
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
// let image = generateImage(controller.size, contextGenerator: { size, context in
|
||||
// let bounds = CGRect(origin: .zero, size: size)
|
||||
// if let cgImage = currentImage.cgImage {
|
||||
// context.draw(cgImage, in: bounds)
|
||||
// }
|
||||
// if let cgImage = strongSelf.drawingView.drawingImage?.cgImage {
|
||||
// context.draw(cgImage, in: bounds)
|
||||
// }
|
||||
// telegramFastBlurMore(Int32(imageContext.size.width * imageContext.scale), Int32(imageContext.size.height * imageContext.scale), Int32(imageContext.bytesPerRow), imageContext.bytes)
|
||||
//
|
||||
//
|
||||
//
|
||||
// }, opaque: true, scale: 1.0)
|
||||
// return image
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
@ -2039,7 +2142,7 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController {
|
||||
ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.PhotoEditor_DiscardChanges, color: .accent, action: { [weak actionSheet, weak self] in
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
|
||||
self?.controller?.requestDismiss()
|
||||
})
|
||||
]),
|
||||
@ -2063,7 +2166,7 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController {
|
||||
self.view.disablesInteractiveKeyboardGestureRecognizer = true
|
||||
self.view.disablesInteractiveTransitionGestureRecognizer = true
|
||||
}
|
||||
|
||||
|
||||
private var currentEyedropperView: EyedropperView?
|
||||
func presentEyedropper(retryLaterForVideo: Bool = true, dismissed: @escaping () -> Void) {
|
||||
guard let controller = self.controller else {
|
||||
@ -2080,17 +2183,11 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController {
|
||||
}
|
||||
|
||||
guard let currentImage = controller.getCurrentImage() else {
|
||||
// if controller.isVideo && retryIfFailed {
|
||||
// Queue.mainQueue().after(0.01) {
|
||||
// self.presentEyedropper(retryIfFailed: false, dismissed: dismissed)
|
||||
// }
|
||||
// } else {
|
||||
self.entitiesView.play()
|
||||
controller.updateVideoPlayback(true)
|
||||
// }
|
||||
self.entitiesView.play()
|
||||
controller.updateVideoPlayback(true)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let sourceImage = generateImage(controller.drawingView.imageSize, contextGenerator: { size, context in
|
||||
let bounds = CGRect(origin: .zero, size: size)
|
||||
if let cgImage = currentImage.cgImage {
|
||||
@ -2135,6 +2232,7 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController {
|
||||
|
||||
func presentColorPicker(initialColor: DrawingColor, dismissed: @escaping () -> Void = {}) {
|
||||
self.dismissCurrentEyedropper()
|
||||
self.dismissFontPicker()
|
||||
|
||||
guard let controller = self.controller else {
|
||||
return
|
||||
@ -2153,6 +2251,7 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController {
|
||||
private var fastColorPickerView: ColorSpectrumPickerView?
|
||||
func presentFastColorPicker(sourceView: UIView) {
|
||||
self.dismissCurrentEyedropper()
|
||||
self.dismissFontPicker()
|
||||
|
||||
guard self.fastColorPickerView == nil, let superview = sourceView.superview else {
|
||||
return
|
||||
@ -2191,7 +2290,61 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController {
|
||||
})
|
||||
}
|
||||
|
||||
private weak var currentFontPicker: ContextController?
|
||||
func presentFontPicker(sourceView: UIView) {
|
||||
guard !self.dismissFontPicker() else {
|
||||
return
|
||||
}
|
||||
let fonts: [DrawingTextFont] = [
|
||||
.sanFrancisco,
|
||||
.newYork,
|
||||
.other("MarkerFelt-Wide", "Marker Felt"),
|
||||
.other("Chalkduster", "Chalkduster"),
|
||||
.other("Menlo-Bold", "Menlo"),
|
||||
.other("Copperplate-Bold", "Copperplate"),
|
||||
.other("GillSans-SemiBold", "Gill Sans"),
|
||||
.other("Papyrus", "Papyrus")
|
||||
]
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
for font in fonts {
|
||||
items.append(.action(ContextMenuActionItem(text: font.title, textFont: .custom(font.uiFont(size: 17.0)), icon: { _ in return nil }, animationName: nil, action: { [weak self] f in
|
||||
f.dismissWithResult(.default)
|
||||
guard let strongSelf = self, let entityView = strongSelf.entitiesView.selectedEntityView as? DrawingTextEntityView, let textEntity = entityView.entity as? DrawingTextEntity else {
|
||||
return
|
||||
}
|
||||
textEntity.font = font.font
|
||||
entityView.update()
|
||||
|
||||
if let (layout, orientation) = strongSelf.validLayout {
|
||||
strongSelf.containerLayoutUpdated(layout: layout, orientation: orientation, forceUpdate: true, transition: .immediate)
|
||||
}
|
||||
})))
|
||||
}
|
||||
|
||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }.withUpdated(theme: defaultDarkPresentationTheme)
|
||||
let contextController = ContextController(account: self.context.account, presentationData: presentationData, source: .reference(ReferenceContentSource(sourceView: sourceView, customPosition: CGPoint(x: 7.0, y: 0.0))), items: .single(ContextController.Items(content: .list(items))))
|
||||
self.controller?.present(contextController, in: .window(.root))
|
||||
self.currentFontPicker = contextController
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func dismissFontPicker() -> Bool {
|
||||
if let currentFontPicker = self.currentFontPicker {
|
||||
self.currentFontPicker = nil
|
||||
currentFontPicker.dismiss()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func animateIn() {
|
||||
if let view = self.componentHost.findTaggedView(tag: topGradientTag) {
|
||||
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
}
|
||||
if let view = self.componentHost.findTaggedView(tag: bottomGradientTag) {
|
||||
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
}
|
||||
if let buttonView = self.componentHost.findTaggedView(tag: undoButtonTag) {
|
||||
buttonView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
buttonView.layer.animateScale(from: 0.01, to: 1.0, duration: 0.3)
|
||||
@ -2205,7 +2358,6 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController {
|
||||
buttonView.layer.animateScale(from: 0.01, to: 1.0, duration: 0.3)
|
||||
}
|
||||
var delay: Double = 0.0
|
||||
let colorTags = [color1Tag, color2Tag, color3Tag, color4Tag, color5Tag, color6Tag, color7Tag, color8Tag]
|
||||
for tag in colorTags {
|
||||
if let view = self.componentHost.findTaggedView(tag: tag) {
|
||||
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3, delay: delay)
|
||||
@ -2223,6 +2375,12 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController {
|
||||
self.containerLayoutUpdated(layout: layout, orientation: orientation, animateOut: true, transition: .easeInOut(duration: 0.2))
|
||||
}
|
||||
|
||||
if let view = self.componentHost.findTaggedView(tag: topGradientTag) {
|
||||
view.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)
|
||||
}
|
||||
if let view = self.componentHost.findTaggedView(tag: bottomGradientTag) {
|
||||
view.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)
|
||||
}
|
||||
if let buttonView = self.componentHost.findTaggedView(tag: undoButtonTag) {
|
||||
buttonView.alpha = 0.0
|
||||
buttonView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3)
|
||||
@ -2264,8 +2422,7 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController {
|
||||
if let view = self.componentHost.findTaggedView(tag: sizeSliderTag) {
|
||||
view.layer.animatePosition(from: CGPoint(), to: CGPoint(x: -33.0, y: 0.0), duration: 0.3, removeOnCompletion: false, additive: true)
|
||||
}
|
||||
|
||||
let colorTags = [color1Tag, color2Tag, color3Tag, color4Tag, color5Tag, color6Tag, color7Tag, color8Tag]
|
||||
|
||||
for tag in colorTags {
|
||||
if let view = self.componentHost.findTaggedView(tag: tag) {
|
||||
view.alpha = 0.0
|
||||
@ -2278,7 +2435,7 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController {
|
||||
view.animateOut(completion: {
|
||||
completion()
|
||||
})
|
||||
} else if let view = self.componentHost.findTaggedView(tag: textSettingsTag) as? TextFontComponent.View {
|
||||
} else if let view = self.componentHost.findTaggedView(tag: textSettingsTag) as? TextSettingsComponent.View {
|
||||
view.animateOut(completion: {
|
||||
completion()
|
||||
})
|
||||
@ -2301,7 +2458,7 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController {
|
||||
return result
|
||||
}
|
||||
|
||||
func containerLayoutUpdated(layout: ContainerViewLayout, orientation: UIInterfaceOrientation?, animateOut: Bool = false, transition: Transition) {
|
||||
func containerLayoutUpdated(layout: ContainerViewLayout, orientation: UIInterfaceOrientation?, forceUpdate: Bool = false, animateOut: Bool = false, transition: Transition) {
|
||||
guard let controller = self.controller else {
|
||||
return
|
||||
}
|
||||
@ -2370,13 +2527,16 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController {
|
||||
},
|
||||
dismissFastColorPicker: { [weak self] in
|
||||
self?.dismissFastColorPicker()
|
||||
},
|
||||
presentFontPicker: { [weak self] sourceView in
|
||||
self?.presentFontPicker(sourceView: sourceView)
|
||||
}
|
||||
)
|
||||
),
|
||||
environment: {
|
||||
environment
|
||||
},
|
||||
forceUpdate: animateOut,
|
||||
forceUpdate: forceUpdate || animateOut,
|
||||
containerSize: layout.size
|
||||
)
|
||||
if let componentView = self.componentHost.view {
|
||||
@ -2409,6 +2569,7 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController {
|
||||
font: DrawingTextFont(font: textEntity.font),
|
||||
isEmojiKeyboard: entityView.textView.inputView != nil,
|
||||
tag: nil,
|
||||
fontTag: fontTag,
|
||||
presentColorPicker: { [weak self] in
|
||||
guard let strongSelf = self, let entityView = strongSelf.entitiesView.selectedEntityView as? DrawingTextEntityView, let textEntity = entityView.entity as? DrawingTextEntity else {
|
||||
return
|
||||
@ -2430,6 +2591,7 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController {
|
||||
self?.dismissFastColorPicker()
|
||||
},
|
||||
toggleStyle: { [weak self] in
|
||||
self?.dismissFontPicker()
|
||||
guard let strongSelf = self, let entityView = strongSelf.entitiesView.selectedEntityView as? DrawingTextEntityView, let textEntity = entityView.entity as? DrawingTextEntity else {
|
||||
return
|
||||
}
|
||||
@ -2452,6 +2614,7 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController {
|
||||
}
|
||||
},
|
||||
toggleAlignment: { [weak self] in
|
||||
self?.dismissFontPicker()
|
||||
guard let strongSelf = self, let entityView = strongSelf.entitiesView.selectedEntityView as? DrawingTextEntityView, let textEntity = entityView.entity as? DrawingTextEntity else {
|
||||
return
|
||||
}
|
||||
@ -2471,21 +2634,16 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController {
|
||||
strongSelf.containerLayoutUpdated(layout: layout, orientation: orientation, transition: .immediate)
|
||||
}
|
||||
},
|
||||
updateFont: { [weak self] font in
|
||||
guard let strongSelf = self, let entityView = strongSelf.entitiesView.selectedEntityView as? DrawingTextEntityView, let textEntity = entityView.entity as? DrawingTextEntity else {
|
||||
return
|
||||
}
|
||||
textEntity.font = font.font
|
||||
entityView.update()
|
||||
|
||||
if let (layout, orientation) = strongSelf.validLayout {
|
||||
strongSelf.containerLayoutUpdated(layout: layout, orientation: orientation, transition: .immediate)
|
||||
presentFontPicker: { [weak self] in
|
||||
if let buttonView = self?.textEditAccessoryHost.findTaggedView(tag: fontTag) {
|
||||
self?.presentFontPicker(sourceView: buttonView)
|
||||
}
|
||||
},
|
||||
toggleKeyboard: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.dismissFontPicker()
|
||||
strongSelf.toggleInputMode()
|
||||
}
|
||||
)
|
||||
@ -2567,19 +2725,26 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController {
|
||||
private let originalSize: CGSize
|
||||
private let isVideo: Bool
|
||||
private let isAvatar: Bool
|
||||
private let externalEntitiesView: DrawingEntitiesView?
|
||||
|
||||
public var requestDismiss: (() -> Void)!
|
||||
public var requestApply: (() -> Void)!
|
||||
public var getCurrentImage: (() -> UIImage?)!
|
||||
public var updateVideoPlayback: ((Bool) -> Void)!
|
||||
public var requestDismiss: () -> Void = {}
|
||||
public var requestApply: () -> Void = {}
|
||||
public var getCurrentImage: () -> UIImage? = { return nil }
|
||||
public var updateVideoPlayback: (Bool) -> Void = { _ in }
|
||||
|
||||
public init(context: AccountContext, size: CGSize, originalSize: CGSize, isVideo: Bool, isAvatar: Bool ) {
|
||||
public init(context: AccountContext, size: CGSize, originalSize: CGSize, isVideo: Bool, isAvatar: Bool, entitiesView: (UIView & TGPhotoDrawingEntitiesView)?) {
|
||||
self.context = context
|
||||
self.size = size
|
||||
self.originalSize = originalSize
|
||||
self.isVideo = isVideo
|
||||
self.isAvatar = isAvatar
|
||||
|
||||
if let entitiesView = entitiesView as? DrawingEntitiesView {
|
||||
self.externalEntitiesView = entitiesView
|
||||
} else {
|
||||
self.externalEntitiesView = nil
|
||||
}
|
||||
|
||||
super.init(navigationBarPresentationData: nil)
|
||||
|
||||
self.statusBar.statusBarStyle = .Hide
|
||||
@ -2612,7 +2777,7 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController {
|
||||
super.displayNodeDidLoad()
|
||||
}
|
||||
|
||||
public func generateResultData() -> TGPaintingData! {
|
||||
public func generateResultData() -> TGPaintingData? {
|
||||
if self.drawingView.isEmpty && self.entitiesView.entities.isEmpty {
|
||||
return nil
|
||||
}
|
||||
@ -2692,7 +2857,7 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController {
|
||||
return image
|
||||
}
|
||||
|
||||
public func animateOut(_ completion: (() -> Void)!) {
|
||||
public func animateOut(_ completion: @escaping (() -> Void)) {
|
||||
self.selectionContainerView.alpha = 0.0
|
||||
|
||||
self.node.animateOut(completion: completion)
|
||||
|
@ -576,14 +576,14 @@ class DrawingEntitySnapTool {
|
||||
var updatedPosition = updatedPosition
|
||||
|
||||
let snapXDelta: CGFloat = (entityView.superview?.frame.width ?? 0.0) * 0.02
|
||||
let snapXVelocity: CGFloat = snapXDelta * 16.0
|
||||
let snapXVelocity: CGFloat = snapXDelta * 12.0
|
||||
let snapXSkipTranslation: CGFloat = snapXDelta * 2.0
|
||||
|
||||
if abs(velocity.x) < snapXVelocity || self.xState?.waitForLeave == true {
|
||||
if let snapLocation = (entityView.superview as? DrawingEntitiesView)?.getEntityCenterPosition() {
|
||||
if let (skipped, waitForLeave) = self.xState {
|
||||
if waitForLeave {
|
||||
if updatedPosition.x > snapLocation.x - snapXDelta * 1.5 && updatedPosition.x < snapLocation.x + snapXDelta * 1.5 {
|
||||
if updatedPosition.x > snapLocation.x - snapXDelta * 2.0 && updatedPosition.x < snapLocation.x + snapXDelta * 2.0 {
|
||||
|
||||
} else {
|
||||
self.xState = nil
|
||||
@ -604,22 +604,19 @@ class DrawingEntitySnapTool {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if self.xState != nil {
|
||||
print()
|
||||
}
|
||||
self.xState = nil
|
||||
self.onSnapXUpdated(false)
|
||||
}
|
||||
|
||||
let snapYDelta: CGFloat = (entityView.superview?.frame.width ?? 0.0) * 0.02
|
||||
let snapYVelocity: CGFloat = snapYDelta * 16.0
|
||||
let snapYVelocity: CGFloat = snapYDelta * 12.0
|
||||
let snapYSkipTranslation: CGFloat = snapYDelta * 2.0
|
||||
|
||||
if abs(velocity.y) < snapYVelocity || self.yState?.waitForLeave == true {
|
||||
if let snapLocation = (entityView.superview as? DrawingEntitiesView)?.getEntityCenterPosition() {
|
||||
if let (skipped, waitForLeave) = self.yState {
|
||||
if waitForLeave {
|
||||
if updatedPosition.y > snapLocation.y - snapYDelta * 1.5 && updatedPosition.y < snapLocation.y + snapYDelta * 1.5 {
|
||||
if updatedPosition.y > snapLocation.y - snapYDelta * 2.0 && updatedPosition.y < snapLocation.y + snapYDelta * 2.0 {
|
||||
|
||||
} else {
|
||||
self.yState = nil
|
||||
|
@ -79,9 +79,7 @@ public final class DrawingTextEntity: DrawingEntity, Codable {
|
||||
enum Font: Codable {
|
||||
case sanFrancisco
|
||||
case newYork
|
||||
case monospaced
|
||||
case round
|
||||
case custom(String, String)
|
||||
case other(String, String)
|
||||
}
|
||||
|
||||
enum Alignment: Codable {
|
||||
@ -543,7 +541,7 @@ final class DrawingTextEntityView: DrawingEntityView, UITextViewDelegate {
|
||||
self.textView.drawingLayoutManager.textContainers.first?.lineFragmentPadding = floor(fontSize * 0.24)
|
||||
|
||||
if let (font, name) = availableFonts[text.string.lowercased()] {
|
||||
self.textEntity.font = .custom(font, name)
|
||||
self.textEntity.font = .other(font, name)
|
||||
}
|
||||
|
||||
var font: UIFont
|
||||
@ -552,11 +550,7 @@ final class DrawingTextEntityView: DrawingEntityView, UITextViewDelegate {
|
||||
font = Font.with(size: fontSize, design: .regular, weight: .semibold)
|
||||
case .newYork:
|
||||
font = Font.with(size: fontSize, design: .serif, weight: .semibold)
|
||||
case .monospaced:
|
||||
font = Font.with(size: fontSize, design: .monospace, weight: .semibold)
|
||||
case .round:
|
||||
font = Font.with(size: fontSize, design: .round, weight: .semibold)
|
||||
case let .custom(fontName, _):
|
||||
case let .other(fontName, _):
|
||||
font = UIFont(name: fontName, size: fontSize) ?? Font.with(size: fontSize, design: .regular, weight: .semibold)
|
||||
}
|
||||
|
||||
@ -854,7 +848,7 @@ final class DrawingTextEntititySelectionView: DrawingEntitySelectionView, UIGest
|
||||
switch gestureRecognizer.state {
|
||||
case .began, .changed:
|
||||
let scale = gestureRecognizer.scale
|
||||
entity.fontSize = max(0.1, entity.scale * scale)
|
||||
entity.scale = max(0.1, entity.scale * scale)
|
||||
entityView.update()
|
||||
|
||||
gestureRecognizer.scale = 1.0
|
||||
|
@ -699,63 +699,6 @@ class BezierPath {
|
||||
}
|
||||
}
|
||||
|
||||
func concaveHullPath(points: [CGPoint]) -> CGPath {
|
||||
let hull = getHull(points, concavity: 1000.0)
|
||||
let hullPath = CGMutablePath()
|
||||
var moved = true
|
||||
for point in hull {
|
||||
if moved {
|
||||
hullPath.move(to: point)
|
||||
moved = false
|
||||
} else {
|
||||
hullPath.addLine(to: point)
|
||||
}
|
||||
}
|
||||
hullPath.closeSubpath()
|
||||
|
||||
return hullPath
|
||||
}
|
||||
|
||||
func expandPath(_ path: CGPath, width: CGFloat) -> CGPath {
|
||||
let expandedPath = path.copy(strokingWithWidth: width * 2.0, lineCap: .round, lineJoin: .round, miterLimit: 0.0)
|
||||
|
||||
class UserInfo {
|
||||
let outputPath = CGMutablePath()
|
||||
var passedFirst = false
|
||||
}
|
||||
var userInfo = UserInfo()
|
||||
|
||||
withUnsafeMutablePointer(to: &userInfo) { userInfoPointer in
|
||||
expandedPath.apply(info: userInfoPointer) { (userInfo, nextElementPointer) in
|
||||
let element = nextElementPointer.pointee
|
||||
let userInfoPointer = userInfo!.assumingMemoryBound(to: UserInfo.self)
|
||||
let userInfo = userInfoPointer.pointee
|
||||
|
||||
if !userInfo.passedFirst {
|
||||
if case .closeSubpath = element.type {
|
||||
userInfo.passedFirst = true
|
||||
}
|
||||
} else {
|
||||
switch element.type {
|
||||
case .moveToPoint:
|
||||
userInfo.outputPath.move(to: element.points[0])
|
||||
case .addLineToPoint:
|
||||
userInfo.outputPath.addLine(to: element.points[0])
|
||||
case .addQuadCurveToPoint:
|
||||
userInfo.outputPath.addQuadCurve(to: element.points[1], control: element.points[0])
|
||||
case .addCurveToPoint:
|
||||
userInfo.outputPath.addCurve(to: element.points[2], control1: element.points[0], control2: element.points[1])
|
||||
case .closeSubpath:
|
||||
userInfo.outputPath.closeSubpath()
|
||||
@unknown default:
|
||||
userInfo.outputPath.closeSubpath()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return userInfo.outputPath
|
||||
}
|
||||
|
||||
class Matrix {
|
||||
private(set) var m: [Float]
|
||||
|
||||
|
@ -365,14 +365,12 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw
|
||||
self.strokeRecognitionTimer?.invalidate()
|
||||
}
|
||||
|
||||
public func setup(withDrawing drawingData: Data!) {
|
||||
public func setup(withDrawing drawingData: Data?) {
|
||||
if let drawingData = drawingData, let image = UIImage(data: drawingData) {
|
||||
self.hasOpaqueData = true
|
||||
self.drawingImage = image
|
||||
self.layer.contents = image.cgImage
|
||||
//let codableElements = try? JSONDecoder().decode([CodableDrawingElement].self, from: drawingData) {
|
||||
//self.elements = codableElements.map { $0.element }
|
||||
//self.commit(reset: true)
|
||||
|
||||
self.updateInternalState()
|
||||
}
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ class ModeAndSizeComponent: Component {
|
||||
|
||||
init() {
|
||||
self.backgroundNode = NavigationBackgroundNode(color: UIColor(rgb: 0x888888, alpha: 0.3))
|
||||
self.node = SegmentedControlNode(theme: SegmentedControlTheme(backgroundColor: .clear, foregroundColor: UIColor(rgb: 0x6f7075, alpha: 0.6), shadowColor: .black, textColor: UIColor(rgb: 0xffffff), dividerColor: UIColor(rgb: 0x505155, alpha: 0.6)), items: [], selectedIndex: 0, cornerRadius: 16.0)
|
||||
self.node = SegmentedControlNode(theme: SegmentedControlTheme(backgroundColor: .clear, foregroundColor: UIColor(rgb: 0xffffff, alpha: 0.2), shadowColor: .black, textColor: UIColor(rgb: 0xffffff), dividerColor: UIColor(rgb: 0x505155, alpha: 0.6)), items: [], selectedIndex: 0, cornerRadius: 16.0)
|
||||
|
||||
self.knob = UIImageView(image: generateKnobImage())
|
||||
|
||||
|
@ -2,7 +2,7 @@ import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
|
||||
final class PenTool: DrawingElement, Codable {
|
||||
final class PenTool: DrawingElement {
|
||||
class RenderView: UIView, DrawingRenderView {
|
||||
private weak var element: PenTool?
|
||||
private var isEraser = false
|
||||
@ -12,11 +12,10 @@ final class PenTool: DrawingElement, Codable {
|
||||
|
||||
private var start = 0
|
||||
private var segmentsCount = 0
|
||||
private var velocity: CGFloat?
|
||||
|
||||
private var displayScale: CGFloat = 1.0
|
||||
|
||||
func setup(size: CGSize, screenSize: CGSize, isEraser: Bool, useDisplayLink: Bool) {
|
||||
func setup(size: CGSize, screenSize: CGSize, isEraser: Bool) {
|
||||
self.isEraser = isEraser
|
||||
|
||||
self.backgroundColor = .clear
|
||||
@ -75,7 +74,7 @@ final class PenTool: DrawingElement, Codable {
|
||||
})
|
||||
}
|
||||
|
||||
fileprivate func draw(element: PenTool, velocity: CGFloat, rect: CGRect) {
|
||||
fileprivate func draw(element: PenTool, rect: CGRect) {
|
||||
self.element = element
|
||||
|
||||
self.alpha = element.color.alpha
|
||||
@ -105,7 +104,7 @@ final class PenTool: DrawingElement, Codable {
|
||||
context.scaleBy(x: 1.0 / self.displayScale, y: 1.0 / self.displayScale)
|
||||
|
||||
context.setBlendMode(.copy)
|
||||
element.drawSegments(in: context, from: self.start, upTo: newStart)
|
||||
element.drawSegments(in: context, from: self.start, to: newStart)
|
||||
}, opaque: false)
|
||||
self.accumulationImage = image
|
||||
self.layer.contents = image?.cgImage
|
||||
@ -115,11 +114,6 @@ final class PenTool: DrawingElement, Codable {
|
||||
|
||||
self.segmentsCount = element.segments.count
|
||||
|
||||
// if let previous = self.velocity {
|
||||
// self.velocity = velocity * 0.4 + previous * 0.6
|
||||
// } else {
|
||||
// self.velocity = velocity
|
||||
// }
|
||||
if let rect = rect {
|
||||
self.activeView?.setNeedsDisplay(rect.insetBy(dx: -10.0, dy: -10.0).applying(CGAffineTransform(scaleX: 1.0 / self.displayScale, y: 1.0 / self.displayScale)))
|
||||
} else {
|
||||
@ -134,7 +128,7 @@ final class PenTool: DrawingElement, Codable {
|
||||
return
|
||||
}
|
||||
context.scaleBy(x: 1.0 / parent.displayScale, y: 1.0 / parent.displayScale)
|
||||
element.drawSegments(in: context, from: parent.start, upTo: parent.segmentsCount)
|
||||
element.drawSegments(in: context, from: parent.start, to: parent.segmentsCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -195,67 +189,7 @@ final class PenTool: DrawingElement, Codable {
|
||||
|
||||
self.renderColor = color.withUpdatedAlpha(1.0).toUIColor()
|
||||
}
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case uuid
|
||||
case drawingSize
|
||||
case color
|
||||
case isEraser
|
||||
case hasArrow
|
||||
case isBlur
|
||||
|
||||
case renderLineWidth
|
||||
case renderMinLineWidth
|
||||
case renderArrowLength
|
||||
case renderArrowLineWidth
|
||||
|
||||
case arrowStart
|
||||
case arrowDirection
|
||||
|
||||
case renderSegments
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
self.uuid = try container.decode(UUID.self, forKey: .uuid)
|
||||
self.drawingSize = try container.decode(CGSize.self, forKey: .drawingSize)
|
||||
self.color = try container.decode(DrawingColor.self, forKey: .color)
|
||||
self.isEraser = try container.decode(Bool.self, forKey: .isEraser)
|
||||
self.hasArrow = try container.decode(Bool.self, forKey: .hasArrow)
|
||||
self.isBlur = try container.decode(Bool.self, forKey: .isBlur)
|
||||
self.renderLineWidth = try container.decode(CGFloat.self, forKey: .renderLineWidth)
|
||||
self.renderMinLineWidth = try container.decode(CGFloat.self, forKey: .renderMinLineWidth)
|
||||
self.renderArrowLength = try container.decode(CGFloat.self, forKey: .renderArrowLength)
|
||||
self.renderArrowLineWidth = try container.decode(CGFloat.self, forKey: .renderArrowLineWidth)
|
||||
|
||||
self.arrowStart = try container.decodeIfPresent(CGPoint.self, forKey: .arrowStart)
|
||||
self.arrowDirection = try container.decodeIfPresent(CGFloat.self, forKey: .arrowDirection)
|
||||
|
||||
self.segments = try container.decode([Segment].self, forKey: .renderSegments)
|
||||
|
||||
self.renderColor = self.color.withUpdatedAlpha(1.0).toUIColor()
|
||||
self.maybeSetupArrow()
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(self.uuid, forKey: .uuid)
|
||||
try container.encode(self.drawingSize, forKey: .drawingSize)
|
||||
try container.encode(self.color, forKey: .color)
|
||||
try container.encode(self.isEraser, forKey: .isEraser)
|
||||
try container.encode(self.hasArrow, forKey: .hasArrow)
|
||||
try container.encode(self.isBlur, forKey: .isBlur)
|
||||
try container.encode(self.renderLineWidth, forKey: .renderLineWidth)
|
||||
try container.encode(self.renderMinLineWidth, forKey: .renderMinLineWidth)
|
||||
try container.encode(self.renderArrowLength, forKey: .renderArrowLength)
|
||||
try container.encode(self.renderArrowLineWidth, forKey: .renderArrowLineWidth)
|
||||
|
||||
try container.encodeIfPresent(self.arrowStart, forKey: .arrowStart)
|
||||
try container.encodeIfPresent(self.arrowDirection, forKey: .arrowDirection)
|
||||
|
||||
try container.encode(self.segments, forKey: .renderSegments)
|
||||
}
|
||||
|
||||
var isFinishingArrow = false
|
||||
func finishArrow(_ completion: @escaping () -> Void) {
|
||||
if let arrowStart, let arrowDirection {
|
||||
@ -271,7 +205,7 @@ final class PenTool: DrawingElement, Codable {
|
||||
|
||||
func setupRenderView(screenSize: CGSize) -> DrawingRenderView? {
|
||||
let view = RenderView()
|
||||
view.setup(size: self.drawingSize, screenSize: screenSize, isEraser: self.isEraser, useDisplayLink: self.color.toUIColor().rgb == 0xbf5af2)
|
||||
view.setup(size: self.drawingSize, screenSize: screenSize, isEraser: self.isEraser)
|
||||
self.currentRenderView = view
|
||||
return view
|
||||
}
|
||||
@ -290,9 +224,9 @@ final class PenTool: DrawingElement, Codable {
|
||||
if point.velocity > 1200.0 {
|
||||
filterDistance = 70.0
|
||||
} else {
|
||||
filterDistance = 15.0
|
||||
filterDistance = 5.0
|
||||
}
|
||||
|
||||
|
||||
if let previousPoint, point.location.distance(to: previousPoint) < filterDistance, state == .changed, self.segments.count > 1 {
|
||||
return
|
||||
}
|
||||
@ -312,7 +246,7 @@ final class PenTool: DrawingElement, Codable {
|
||||
let rect = append(point: Point(position: point.location, width: effectiveRenderLineWidth))
|
||||
|
||||
if let currentRenderView = self.currentRenderView as? RenderView, let rect = rect {
|
||||
currentRenderView.draw(element: self, velocity: point.velocity, rect: rect)
|
||||
currentRenderView.draw(element: self, rect: rect)
|
||||
}
|
||||
|
||||
if state == .ended {
|
||||
@ -385,7 +319,7 @@ final class PenTool: DrawingElement, Codable {
|
||||
if self.isBlur, let blurredImage = self.blurredImage {
|
||||
let maskContext = DrawingContext(size: size, scale: 0.5, clear: true)
|
||||
maskContext?.withFlippedContext { maskContext in
|
||||
self.drawSegments(in: maskContext, from: 0, upTo: self.segments.count)
|
||||
self.drawSegments(in: maskContext, from: 0, to: self.segments.count)
|
||||
}
|
||||
if let maskImage = maskContext?.generateImage()?.cgImage, let blurredImage = blurredImage.cgImage {
|
||||
context.clip(to: CGRect(origin: .zero, size: size), mask: maskImage)
|
||||
@ -396,7 +330,7 @@ final class PenTool: DrawingElement, Codable {
|
||||
}
|
||||
|
||||
} else {
|
||||
self.drawSegments(in: context, from: 0, upTo: self.segments.count)
|
||||
self.drawSegments(in: context, from: 0, to: self.segments.count)
|
||||
}
|
||||
|
||||
if let arrowLeftPath, let arrowRightPath {
|
||||
@ -434,38 +368,6 @@ final class PenTool: DrawingElement, Codable {
|
||||
self.radius2 = radius2
|
||||
self.rect = rect
|
||||
}
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case a
|
||||
case b
|
||||
case c
|
||||
case d
|
||||
case radius1
|
||||
case radius2
|
||||
case rect
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
self.a = try container.decode(CGPoint.self, forKey: .a)
|
||||
self.b = try container.decode(CGPoint.self, forKey: .b)
|
||||
self.c = try container.decode(CGPoint.self, forKey: .c)
|
||||
self.d = try container.decode(CGPoint.self, forKey: .d)
|
||||
self.radius1 = try container.decode(CGFloat.self, forKey: .radius1)
|
||||
self.radius2 = try container.decode(CGFloat.self, forKey: .radius2)
|
||||
self.rect = try container.decode(CGRect.self, forKey: .rect)
|
||||
}
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(self.a, forKey: .a)
|
||||
try container.encode(self.b, forKey: .b)
|
||||
try container.encode(self.c, forKey: .c)
|
||||
try container.encode(self.d, forKey: .d)
|
||||
try container.encode(self.radius1, forKey: .radius1)
|
||||
try container.encode(self.radius2, forKey: .radius2)
|
||||
try container.encode(self.rect, forKey: .rect)
|
||||
}
|
||||
}
|
||||
|
||||
private struct Point {
|
||||
@ -708,11 +610,10 @@ final class PenTool: DrawingElement, Codable {
|
||||
return path
|
||||
}
|
||||
|
||||
private func drawSegments(in context: CGContext, from: Int, upTo: Int) {
|
||||
// context.setStrokeColor(self.renderColor.cgColor)
|
||||
private func drawSegments(in context: CGContext, from: Int, to: Int) {
|
||||
context.setFillColor(self.renderColor.cgColor)
|
||||
|
||||
for i in from ..< upTo {
|
||||
for i in from ..< to {
|
||||
let segment = self.segments[i]
|
||||
|
||||
var segmentPath: CGPath
|
||||
@ -726,7 +627,6 @@ final class PenTool: DrawingElement, Codable {
|
||||
|
||||
context.addPath(segmentPath)
|
||||
context.fillPath()
|
||||
// context.strokePath()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -47,9 +47,7 @@ enum DrawingTextAlignment: Equatable {
|
||||
enum DrawingTextFont: Equatable, Hashable {
|
||||
case sanFrancisco
|
||||
case newYork
|
||||
case monospaced
|
||||
case round
|
||||
case custom(String, String)
|
||||
case other(String, String)
|
||||
|
||||
init(font: DrawingTextEntity.Font) {
|
||||
switch font {
|
||||
@ -57,12 +55,8 @@ enum DrawingTextFont: Equatable, Hashable {
|
||||
self = .sanFrancisco
|
||||
case .newYork:
|
||||
self = .newYork
|
||||
case .monospaced:
|
||||
self = .monospaced
|
||||
case .round:
|
||||
self = .round
|
||||
case let .custom(font, name):
|
||||
self = .custom(font, name)
|
||||
case let .other(font, name):
|
||||
self = .other(font, name)
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,12 +66,8 @@ enum DrawingTextFont: Equatable, Hashable {
|
||||
return .sanFrancisco
|
||||
case .newYork:
|
||||
return .newYork
|
||||
case .monospaced:
|
||||
return .monospaced
|
||||
case .round:
|
||||
return .round
|
||||
case let .custom(font, name):
|
||||
return .custom(font, name)
|
||||
case let .other(font, name):
|
||||
return .other(font, name)
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,27 +77,19 @@ enum DrawingTextFont: Equatable, Hashable {
|
||||
return "San Francisco"
|
||||
case .newYork:
|
||||
return "New York"
|
||||
case .monospaced:
|
||||
return "Monospaced"
|
||||
case .round:
|
||||
return "Rounded"
|
||||
case let .custom(_, name):
|
||||
case let .other(_, name):
|
||||
return name
|
||||
}
|
||||
}
|
||||
|
||||
var uiFont: UIFont {
|
||||
func uiFont(size: CGFloat) -> UIFont {
|
||||
switch self {
|
||||
case .sanFrancisco:
|
||||
return Font.semibold(13.0)
|
||||
return Font.semibold(size)
|
||||
case .newYork:
|
||||
return Font.with(size: 13.0, design: .serif, weight: .semibold)
|
||||
case .monospaced:
|
||||
return Font.with(size: 13.0, design: .monospace, weight: .semibold)
|
||||
case .round:
|
||||
return Font.with(size: 13.0, design: .round, weight: .semibold)
|
||||
case let .custom(font, _):
|
||||
return UIFont(name: font, size: 13.0) ?? Font.semibold(13.0)
|
||||
return Font.with(size: size, design: .serif, weight: .semibold)
|
||||
case let .other(font, _):
|
||||
return UIFont(name: font, size: size) ?? Font.semibold(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -185,40 +167,24 @@ final class TextAlignmentComponent: Component {
|
||||
}
|
||||
|
||||
final class TextFontComponent: Component {
|
||||
let styleButton: AnyComponent<Empty>
|
||||
let alignmentButton: AnyComponent<Empty>
|
||||
|
||||
let values: [DrawingTextFont]
|
||||
let selectedValue: DrawingTextFont
|
||||
let tag: AnyObject?
|
||||
let updated: (DrawingTextFont) -> Void
|
||||
let tapped: () -> Void
|
||||
|
||||
init(styleButton: AnyComponent<Empty>, alignmentButton: AnyComponent<Empty>, values: [DrawingTextFont], selectedValue: DrawingTextFont, tag: AnyObject?, updated: @escaping (DrawingTextFont) -> Void) {
|
||||
self.styleButton = styleButton
|
||||
self.alignmentButton = alignmentButton
|
||||
self.values = values
|
||||
init(selectedValue: DrawingTextFont, tag: AnyObject?, tapped: @escaping () -> Void) {
|
||||
self.selectedValue = selectedValue
|
||||
self.tag = tag
|
||||
self.updated = updated
|
||||
self.tapped = tapped
|
||||
}
|
||||
|
||||
static func == (lhs: TextFontComponent, rhs: TextFontComponent) -> Bool {
|
||||
return lhs.styleButton == rhs.styleButton && lhs.alignmentButton == rhs.alignmentButton && lhs.values == rhs.values && lhs.selectedValue == rhs.selectedValue
|
||||
return lhs.selectedValue == rhs.selectedValue
|
||||
}
|
||||
|
||||
final class View: UIView, ComponentTaggedView {
|
||||
private let styleButtonHost: ComponentView<Empty>
|
||||
private let alignmentButtonHost: ComponentView<Empty>
|
||||
|
||||
private var buttons: [DrawingTextFont: HighlightableButton] = [:]
|
||||
private let scrollView = UIScrollView()
|
||||
private let scrollMask = UIView()
|
||||
private let maskLeft = SimpleGradientLayer()
|
||||
private let maskCenter = SimpleLayer()
|
||||
private let maskRight = SimpleGradientLayer()
|
||||
|
||||
private var button = HighlightableButton()
|
||||
|
||||
private var component: TextFontComponent?
|
||||
private var updated: (DrawingTextFont) -> Void = { _ in }
|
||||
|
||||
public func matches(tag: Any) -> Bool {
|
||||
if let component = self.component, let componentTag = component.tag {
|
||||
@ -231,39 +197,9 @@ final class TextFontComponent: Component {
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
if #available(iOS 11.0, *) {
|
||||
self.scrollView.contentInsetAdjustmentBehavior = .never
|
||||
}
|
||||
self.scrollView.showsHorizontalScrollIndicator = false
|
||||
self.scrollView.showsVerticalScrollIndicator = false
|
||||
self.scrollView.decelerationRate = .fast
|
||||
|
||||
self.styleButtonHost = ComponentView()
|
||||
self.alignmentButtonHost = ComponentView()
|
||||
|
||||
super.init(frame: frame)
|
||||
|
||||
self.mask = self.scrollMask
|
||||
|
||||
self.maskLeft.type = .axial
|
||||
self.maskLeft.startPoint = CGPoint(x: 0.0, y: 0.5)
|
||||
self.maskLeft.endPoint = CGPoint(x: 1.0, y: 0.5)
|
||||
self.maskLeft.colors = [UIColor.white.withAlphaComponent(0.0).cgColor, UIColor.white.cgColor]
|
||||
self.maskLeft.locations = [0.0, 1.0]
|
||||
|
||||
self.maskCenter.backgroundColor = UIColor.white.cgColor
|
||||
|
||||
self.maskRight.type = .axial
|
||||
self.maskRight.startPoint = CGPoint(x: 0.0, y: 0.5)
|
||||
self.maskRight.endPoint = CGPoint(x: 1.0, y: 0.5)
|
||||
self.maskRight.colors = [UIColor.white.cgColor, UIColor.white.withAlphaComponent(0.0).cgColor]
|
||||
self.maskRight.locations = [0.0, 1.0]
|
||||
|
||||
self.scrollMask.layer.addSublayer(self.maskLeft)
|
||||
self.scrollMask.layer.addSublayer(self.maskCenter)
|
||||
self.scrollMask.layer.addSublayer(self.maskRight)
|
||||
|
||||
self.addSubview(self.scrollView)
|
||||
self.addSubview(self.button)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
@ -271,160 +207,26 @@ final class TextFontComponent: Component {
|
||||
}
|
||||
|
||||
@objc private func pressed(_ sender: HighlightableButton) {
|
||||
for (font, button) in self.buttons {
|
||||
if button === sender {
|
||||
self.updated(font)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func animateIn() {
|
||||
var delay: Double = 0.0
|
||||
|
||||
if let view = self.styleButtonHost.view {
|
||||
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
view.layer.animateScale(from: 0.01, to: 1.0, duration: 0.2)
|
||||
delay += 0.02
|
||||
}
|
||||
|
||||
if let view = self.alignmentButtonHost.view {
|
||||
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, delay: delay)
|
||||
view.layer.animateScale(from: 0.01, to: 1.0, duration: 0.2, delay: delay)
|
||||
delay += 0.02
|
||||
}
|
||||
|
||||
if let component = self.component {
|
||||
for value in component.values {
|
||||
if let view = self.buttons[value] {
|
||||
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, delay: delay)
|
||||
view.layer.animateScale(from: 0.01, to: 1.0, duration: 0.2, delay: delay)
|
||||
delay += 0.02
|
||||
}
|
||||
}
|
||||
component.tapped()
|
||||
}
|
||||
}
|
||||
|
||||
func animateOut(completion: @escaping () -> Void) {
|
||||
if let view = self.styleButtonHost.view {
|
||||
view.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false)
|
||||
}
|
||||
|
||||
if let view = self.alignmentButtonHost.view {
|
||||
view.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false)
|
||||
}
|
||||
|
||||
if let component = self.component {
|
||||
for value in component.values {
|
||||
if let view = self.buttons[value] {
|
||||
view.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { _ in
|
||||
completion()
|
||||
})
|
||||
}
|
||||
|
||||
private var previousValue: DrawingTextFont?
|
||||
|
||||
func update(component: TextFontComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||
self.component = component
|
||||
self.updated = component.updated
|
||||
|
||||
var contentWidth: CGFloat = 10.0
|
||||
let value = component.selectedValue
|
||||
|
||||
let styleSize = self.styleButtonHost.update(
|
||||
transition: transition,
|
||||
component: component.styleButton,
|
||||
environment: {},
|
||||
containerSize: CGSize(width: 30.0, height: 30.0)
|
||||
)
|
||||
if let view = self.styleButtonHost.view {
|
||||
if view.superview == nil {
|
||||
self.scrollView.addSubview(view)
|
||||
}
|
||||
view.frame = CGRect(origin: CGPoint(x: contentWidth - 7.0, y: -7.0), size: styleSize)
|
||||
}
|
||||
self.button.setTitle(value.title, for: .normal)
|
||||
self.button.titleLabel?.font = value.uiFont(size: 13.0)
|
||||
self.button.sizeToFit()
|
||||
self.button.frame = CGRect(origin: .zero, size: CGSize(width: self.button.frame.width + 16.0, height: 30.0))
|
||||
self.button.layer.cornerRadius = 11.0
|
||||
self.button.layer.borderWidth = 1.0 - UIScreenPixel
|
||||
self.button.layer.borderColor = UIColor.white.cgColor
|
||||
self.button.addTarget(self, action: #selector(self.pressed(_:)), for: .touchUpInside)
|
||||
|
||||
contentWidth += 44.0
|
||||
|
||||
let alignmentSize = self.alignmentButtonHost.update(
|
||||
transition: transition,
|
||||
component: component.alignmentButton,
|
||||
environment: {},
|
||||
containerSize: CGSize(width: 30.0, height: 30.0)
|
||||
)
|
||||
if let view = self.alignmentButtonHost.view {
|
||||
if view.superview == nil {
|
||||
self.scrollView.addSubview(view)
|
||||
}
|
||||
view.frame = CGRect(origin: CGPoint(x: contentWidth - 7.0, y: -6.0 - UIScreenPixel), size: alignmentSize)
|
||||
}
|
||||
|
||||
contentWidth += 36.0
|
||||
|
||||
var validIds = Set<DrawingTextFont>()
|
||||
for value in component.values {
|
||||
validIds.insert(value)
|
||||
|
||||
contentWidth += 12.0
|
||||
let button: HighlightableButton
|
||||
if let current = self.buttons[value] {
|
||||
button = current
|
||||
} else {
|
||||
button = HighlightableButton()
|
||||
button.setTitle(value.title, for: .normal)
|
||||
button.titleLabel?.font = value.uiFont
|
||||
button.sizeToFit()
|
||||
button.frame = CGRect(origin: .zero, size: CGSize(width: button.frame.width + 16.0, height: 30.0))
|
||||
button.layer.cornerRadius = 11.0
|
||||
button.addTarget(self, action: #selector(self.pressed(_:)), for: .touchUpInside)
|
||||
|
||||
self.buttons[value] = button
|
||||
|
||||
self.scrollView.addSubview(button)
|
||||
}
|
||||
|
||||
if value == component.selectedValue {
|
||||
button.layer.borderWidth = 1.0 - UIScreenPixel
|
||||
button.layer.borderColor = UIColor.white.cgColor
|
||||
} else {
|
||||
button.layer.borderWidth = UIScreenPixel
|
||||
button.layer.borderColor = UIColor.white.withAlphaComponent(0.5).cgColor
|
||||
}
|
||||
|
||||
button.frame = CGRect(origin: CGPoint(x: contentWidth, y: 0.0), size: button.frame.size)
|
||||
contentWidth += button.frame.width
|
||||
}
|
||||
contentWidth += 12.0
|
||||
|
||||
for (font, button) in self.buttons {
|
||||
if !validIds.contains(font) {
|
||||
button.removeFromSuperview()
|
||||
self.buttons[font] = nil
|
||||
}
|
||||
}
|
||||
|
||||
if self.scrollView.contentSize.width != contentWidth {
|
||||
self.scrollView.contentSize = CGSize(width: contentWidth, height: 30.0)
|
||||
}
|
||||
self.scrollView.frame = CGRect(origin: .zero, size: availableSize)
|
||||
|
||||
self.scrollMask.frame = CGRect(origin: .zero, size: availableSize)
|
||||
self.maskLeft.frame = CGRect(origin: .zero, size: CGSize(width: 12.0, height: 30.0))
|
||||
self.maskCenter.frame = CGRect(origin: CGPoint(x: 12.0, y: 0.0), size: CGSize(width: availableSize.width - 24.0, height: 30.0))
|
||||
self.maskRight.frame = CGRect(origin: CGPoint(x: availableSize.width - 12.0, y: 0.0), size: CGSize(width: 12.0, height: 30.0))
|
||||
|
||||
if component.selectedValue != self.previousValue {
|
||||
self.previousValue = component.selectedValue
|
||||
|
||||
if let button = self.buttons[component.selectedValue] {
|
||||
self.scrollView.scrollRectToVisible(button.frame.insetBy(dx: -48.0, dy: 0.0), animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
return availableSize
|
||||
return CGSize(width: self.button.frame.width, height: availableSize.height)
|
||||
}
|
||||
}
|
||||
|
||||
@ -444,6 +246,7 @@ final class TextSettingsComponent: CombinedComponent {
|
||||
let font: DrawingTextFont
|
||||
let isEmojiKeyboard: Bool
|
||||
let tag: AnyObject?
|
||||
let fontTag: AnyObject?
|
||||
|
||||
let presentColorPicker: () -> Void
|
||||
let presentFastColorPicker: (GenericComponentViewTag) -> Void
|
||||
@ -451,7 +254,7 @@ final class TextSettingsComponent: CombinedComponent {
|
||||
let dismissFastColorPicker: () -> Void
|
||||
let toggleStyle: () -> Void
|
||||
let toggleAlignment: () -> Void
|
||||
let updateFont: (DrawingTextFont) -> Void
|
||||
let presentFontPicker: () -> Void
|
||||
let toggleKeyboard: (() -> Void)?
|
||||
|
||||
init(
|
||||
@ -461,13 +264,14 @@ final class TextSettingsComponent: CombinedComponent {
|
||||
font: DrawingTextFont,
|
||||
isEmojiKeyboard: Bool,
|
||||
tag: AnyObject?,
|
||||
fontTag: AnyObject?,
|
||||
presentColorPicker: @escaping () -> Void = {},
|
||||
presentFastColorPicker: @escaping (GenericComponentViewTag) -> Void = { _ in },
|
||||
updateFastColorPickerPan: @escaping (CGPoint) -> Void = { _ in },
|
||||
dismissFastColorPicker: @escaping () -> Void = {},
|
||||
toggleStyle: @escaping () -> Void,
|
||||
toggleAlignment: @escaping () -> Void,
|
||||
updateFont: @escaping (DrawingTextFont) -> Void,
|
||||
presentFontPicker: @escaping () -> Void,
|
||||
toggleKeyboard: (() -> Void)?
|
||||
) {
|
||||
self.color = color
|
||||
@ -476,13 +280,14 @@ final class TextSettingsComponent: CombinedComponent {
|
||||
self.font = font
|
||||
self.isEmojiKeyboard = isEmojiKeyboard
|
||||
self.tag = tag
|
||||
self.fontTag = fontTag
|
||||
self.presentColorPicker = presentColorPicker
|
||||
self.presentFastColorPicker = presentFastColorPicker
|
||||
self.updateFastColorPickerPan = updateFastColorPickerPan
|
||||
self.dismissFastColorPicker = dismissFastColorPicker
|
||||
self.toggleStyle = toggleStyle
|
||||
self.toggleAlignment = toggleAlignment
|
||||
self.updateFont = updateFont
|
||||
self.presentFontPicker = presentFontPicker
|
||||
self.toggleKeyboard = toggleKeyboard
|
||||
}
|
||||
|
||||
@ -540,6 +345,46 @@ final class TextSettingsComponent: CombinedComponent {
|
||||
}
|
||||
}
|
||||
|
||||
class View: UIView, ComponentTaggedView {
|
||||
var componentTag: AnyObject?
|
||||
|
||||
public func matches(tag: Any) -> Bool {
|
||||
if let componentTag = self.componentTag {
|
||||
let tag = tag as AnyObject
|
||||
if componentTag === tag {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func animateIn() {
|
||||
var delay: Double = 0.0
|
||||
for view in self.subviews {
|
||||
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, delay: delay)
|
||||
view.layer.animateScale(from: 0.01, to: 1.0, duration: 0.2, delay: delay)
|
||||
delay += 0.02
|
||||
}
|
||||
}
|
||||
|
||||
func animateOut(completion: @escaping () -> Void) {
|
||||
var isFirst = true
|
||||
for view in self.subviews {
|
||||
view.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: isFirst ? { _ in
|
||||
completion()
|
||||
} : nil)
|
||||
view.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false)
|
||||
isFirst = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func makeView() -> View {
|
||||
let view = View()
|
||||
view.componentTag = self.tag
|
||||
return view
|
||||
}
|
||||
|
||||
func makeState() -> State {
|
||||
State()
|
||||
}
|
||||
@ -548,6 +393,8 @@ final class TextSettingsComponent: CombinedComponent {
|
||||
let colorButton = Child(ColorSwatchComponent.self)
|
||||
let colorButtonTag = GenericComponentViewTag()
|
||||
|
||||
let alignmentButton = Child(Button.self)
|
||||
let styleButton = Child(Button.self)
|
||||
let keyboardButton = Child(Button.self)
|
||||
let font = Child(TextFontComponent.self)
|
||||
|
||||
@ -557,7 +404,6 @@ final class TextSettingsComponent: CombinedComponent {
|
||||
|
||||
let toggleStyle = component.toggleStyle
|
||||
let toggleAlignment = component.toggleAlignment
|
||||
let updateFont = component.updateFont
|
||||
|
||||
var offset: CGFloat = 6.0
|
||||
if let color = component.color {
|
||||
@ -588,9 +434,9 @@ final class TextSettingsComponent: CombinedComponent {
|
||||
transition: context.transition
|
||||
)
|
||||
context.add(colorButton
|
||||
.position(CGPoint(x: colorButton.size.width / 2.0, y: context.availableSize.height / 2.0))
|
||||
.position(CGPoint(x: colorButton.size.width / 2.0 + 2.0, y: context.availableSize.height / 2.0))
|
||||
)
|
||||
offset += 32.0
|
||||
offset += 42.0
|
||||
}
|
||||
|
||||
let styleImage: UIImage
|
||||
@ -610,55 +456,53 @@ final class TextSettingsComponent: CombinedComponent {
|
||||
fontAvailableWidth -= 72.0
|
||||
}
|
||||
|
||||
var fonts: [DrawingTextFont] = [
|
||||
.sanFrancisco,
|
||||
.newYork,
|
||||
.monospaced,
|
||||
.round
|
||||
]
|
||||
if case .custom = component.font {
|
||||
fonts.insert(component.font, at: 0)
|
||||
}
|
||||
|
||||
let font = font.update(
|
||||
component: TextFontComponent(
|
||||
styleButton: AnyComponent(
|
||||
Button(
|
||||
content: AnyComponent(
|
||||
Image(
|
||||
image: styleImage
|
||||
)
|
||||
),
|
||||
action: {
|
||||
toggleStyle()
|
||||
}
|
||||
).minSize(CGSize(width: 44.0, height: 44.0))
|
||||
let styleButton = styleButton.update(
|
||||
component: Button(
|
||||
content: AnyComponent(
|
||||
Image(
|
||||
image: styleImage
|
||||
)
|
||||
),
|
||||
alignmentButton: AnyComponent(
|
||||
Button(
|
||||
content: AnyComponent(
|
||||
TextAlignmentComponent(
|
||||
alignment: component.alignment
|
||||
)
|
||||
),
|
||||
action: {
|
||||
toggleAlignment()
|
||||
}
|
||||
).minSize(CGSize(width: 44.0, height: 44.0))
|
||||
),
|
||||
values: fonts,
|
||||
selectedValue: component.font,
|
||||
tag: component.tag,
|
||||
updated: { font in
|
||||
updateFont(font)
|
||||
action: {
|
||||
toggleStyle()
|
||||
}
|
||||
),
|
||||
availableSize: CGSize(width: fontAvailableWidth, height: 30.0),
|
||||
).minSize(CGSize(width: 44.0, height: 44.0)),
|
||||
availableSize: CGSize(width: 30.0, height: 30.0),
|
||||
transition: .easeInOut(duration: 0.2)
|
||||
)
|
||||
context.add(font
|
||||
.position(CGPoint(x: offset + font.size.width / 2.0, y: context.availableSize.height / 2.0))
|
||||
context.add(styleButton
|
||||
.position(CGPoint(x: offset + styleButton.size.width / 2.0, y: context.availableSize.height / 2.0))
|
||||
.update(Transition.Update { _, view, transition in
|
||||
if let snapshot = view.snapshotView(afterScreenUpdates: false) {
|
||||
transition.setAlpha(view: snapshot, alpha: 0.0, completion: { [weak snapshot] _ in
|
||||
snapshot?.removeFromSuperview()
|
||||
})
|
||||
snapshot.frame = view.frame
|
||||
transition.animateAlpha(view: view, from: 0.0, to: 1.0)
|
||||
view.superview?.addSubview(snapshot)
|
||||
}
|
||||
})
|
||||
)
|
||||
offset += 44.0
|
||||
|
||||
let alignmentButton = alignmentButton.update(
|
||||
component: Button(
|
||||
content: AnyComponent(
|
||||
TextAlignmentComponent(
|
||||
alignment: component.alignment
|
||||
)
|
||||
),
|
||||
action: {
|
||||
toggleAlignment()
|
||||
}
|
||||
).minSize(CGSize(width: 44.0, height: 44.0)),
|
||||
availableSize: context.availableSize,
|
||||
transition: .easeInOut(duration: 0.2)
|
||||
)
|
||||
context.add(alignmentButton
|
||||
.position(CGPoint(x: offset + alignmentButton.size.width / 2.0, y: context.availableSize.height / 2.0 + 1.0 - UIScreenPixel))
|
||||
)
|
||||
offset += 45.0
|
||||
|
||||
if let toggleKeyboard = component.toggleKeyboard {
|
||||
let keyboardButton = keyboardButton.update(
|
||||
@ -675,13 +519,28 @@ final class TextSettingsComponent: CombinedComponent {
|
||||
}
|
||||
).minSize(CGSize(width: 44.0, height: 44.0)),
|
||||
availableSize: CGSize(width: 32.0, height: 32.0),
|
||||
transition: .easeInOut(duration: 0.2)
|
||||
transition: .easeInOut(duration: 0.15)
|
||||
)
|
||||
context.add(keyboardButton
|
||||
.position(CGPoint(x: context.availableSize.width - keyboardButton.size.width / 2.0, y: context.availableSize.height / 2.0))
|
||||
.position(CGPoint(x: offset + keyboardButton.size.width / 2.0 + (component.isEmojiKeyboard ? 3.0 : 0.0), y: context.availableSize.height / 2.0))
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
let font = font.update(
|
||||
component: TextFontComponent(
|
||||
selectedValue: component.font,
|
||||
tag: component.fontTag,
|
||||
tapped: {
|
||||
component.presentFontPicker()
|
||||
}
|
||||
),
|
||||
availableSize: CGSize(width: fontAvailableWidth, height: 30.0),
|
||||
transition: .easeInOut(duration: 0.2)
|
||||
)
|
||||
context.add(font
|
||||
.position(CGPoint(x: context.availableSize.width - font.size.width / 2.0 - 16.0, y: context.availableSize.height / 2.0))
|
||||
)
|
||||
|
||||
return context.availableSize
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
@protocol TGPhotoPaintEntityRenderer <NSObject>
|
||||
|
||||
- (void)entitiesForTime:(CMTime)time fps:(NSInteger)fps size:(CGSize)size completion:(void(^)(NSArray<CIImage *> *))completion;
|
||||
- (void)entitiesForTime:(CMTime)time fps:(NSInteger)fps size:(CGSize)size completion:(void(^_Nonnull)(NSArray<CIImage *> * _Nonnull))completion;
|
||||
|
||||
@end
|
||||
|
||||
@ -17,45 +17,18 @@
|
||||
|
||||
@end
|
||||
|
||||
@protocol TGPhotoPaintStickerRenderView <NSObject>
|
||||
|
||||
@property (nonatomic, copy) void(^started)(double);
|
||||
|
||||
- (void)setIsVisible:(bool)isVisible;
|
||||
- (void)seekTo:(double)timestamp;
|
||||
- (void)play;
|
||||
- (void)pause;
|
||||
- (void)resetToStart;
|
||||
|
||||
- (void)playFromFrame:(NSInteger)frameIndex;
|
||||
- (void)copyStickerView:(NSObject<TGPhotoPaintStickerRenderView> *)view;
|
||||
|
||||
- (int64_t)documentId;
|
||||
- (UIImage *)image;
|
||||
|
||||
@end
|
||||
|
||||
@protocol TGPhotoPaintStickersScreen <NSObject>
|
||||
|
||||
@property (nonatomic, copy) void(^screenDidAppear)(void);
|
||||
@property (nonatomic, copy) void(^screenWillDisappear)(void);
|
||||
|
||||
- (void)restore;
|
||||
- (void)invalidate;
|
||||
|
||||
@end
|
||||
|
||||
@protocol TGCaptionPanelView <NSObject>
|
||||
|
||||
@property (nonatomic, readonly) UIView *view;
|
||||
@property (nonatomic, readonly) UIView * _Nonnull view;
|
||||
|
||||
- (NSAttributedString *)caption;
|
||||
- (void)setCaption:(NSAttributedString *)caption;
|
||||
- (NSAttributedString * _Nonnull)caption;
|
||||
- (void)setCaption:(NSAttributedString * _Nullable)caption;
|
||||
- (void)dismissInput;
|
||||
|
||||
@property (nonatomic, copy) void(^sendPressed)(NSAttributedString *string);
|
||||
@property (nonatomic, copy) void(^focusUpdated)(BOOL focused);
|
||||
@property (nonatomic, copy) void(^heightUpdated)(BOOL animated);
|
||||
@property (nonatomic, copy) void(^ _Nullable sendPressed)(NSAttributedString * _Nullable string);
|
||||
@property (nonatomic, copy) void(^ _Nullable focusUpdated)(BOOL focused);
|
||||
@property (nonatomic, copy) void(^ _Nullable heightUpdated)(BOOL animated);
|
||||
|
||||
- (CGFloat)updateLayoutSize:(CGSize)size sideInset:(CGFloat)sideInset;
|
||||
- (CGFloat)baseHeight;
|
||||
@ -67,20 +40,20 @@
|
||||
|
||||
@property (nonatomic, readonly) BOOL isTracking;
|
||||
|
||||
@property (nonatomic, copy) void(^zoomOut)(void);
|
||||
@property (nonatomic, copy) void(^ _Nonnull zoomOut)(void);
|
||||
|
||||
- (void)updateZoomScale:(CGFloat)scale;
|
||||
|
||||
- (void)setupWithDrawingData:(NSData *)drawingData;
|
||||
- (void)setupWithDrawingData:(NSData * _Nullable)drawingData;
|
||||
|
||||
@end
|
||||
|
||||
@protocol TGPhotoDrawingEntitiesView <NSObject>
|
||||
|
||||
@property (nonatomic, copy) CGPoint (^getEntityCenterPosition)(void);
|
||||
@property (nonatomic, copy) CGFloat (^getEntityInitialRotation)(void);
|
||||
@property (nonatomic, copy) CGPoint (^ _Nonnull getEntityCenterPosition)(void);
|
||||
@property (nonatomic, copy) CGFloat (^ _Nonnull getEntityInitialRotation)(void);
|
||||
|
||||
@property (nonatomic, copy) void(^hasSelectionChanged)(bool);
|
||||
@property (nonatomic, copy) void(^ _Nonnull hasSelectionChanged)(bool);
|
||||
@property (nonatomic, readonly) BOOL hasSelection;
|
||||
|
||||
- (void)play;
|
||||
@ -91,22 +64,22 @@
|
||||
- (void)clearSelection;
|
||||
- (void)onZoom;
|
||||
|
||||
- (void)handlePinch:(UIPinchGestureRecognizer *)gestureRecognizer;
|
||||
- (void)handleRotate:(UIRotationGestureRecognizer *)gestureRecognizer;
|
||||
- (void)handlePinch:(UIPinchGestureRecognizer * _Nonnull)gestureRecognizer;
|
||||
- (void)handleRotate:(UIRotationGestureRecognizer * _Nonnull)gestureRecognizer;
|
||||
|
||||
- (void)setupWithEntitiesData:(NSData *)entitiesData;
|
||||
- (void)setupWithEntitiesData:(NSData * _Nullable)entitiesData;
|
||||
|
||||
@end
|
||||
|
||||
@protocol TGPhotoDrawingInterfaceController <NSObject>
|
||||
|
||||
@property (nonatomic, copy) void(^requestDismiss)(void);
|
||||
@property (nonatomic, copy) void(^requestApply)(void);
|
||||
@property (nonatomic, copy) UIImage *(^getCurrentImage)(void);
|
||||
@property (nonatomic, copy) void(^updateVideoPlayback)(bool);
|
||||
@property (nonatomic, copy) void(^ _Nonnull requestDismiss)(void);
|
||||
@property (nonatomic, copy) void(^ _Nonnull requestApply)(void);
|
||||
@property (nonatomic, copy) UIImage * _Nullable(^ _Nonnull getCurrentImage)(void);
|
||||
@property (nonatomic, copy) void(^ _Nonnull updateVideoPlayback)(bool);
|
||||
|
||||
- (TGPaintingData *)generateResultData;
|
||||
- (void)animateOut:(void(^)(void))completion;
|
||||
- (TGPaintingData * _Nullable)generateResultData;
|
||||
- (void)animateOut:(void(^_Nonnull)(void))completion;
|
||||
|
||||
- (void)adapterContainerLayoutUpdatedSize:(CGSize)size
|
||||
intrinsicInsets:(UIEdgeInsets)intrinsicInsets
|
||||
@ -121,30 +94,23 @@
|
||||
|
||||
@protocol TGPhotoDrawingAdapter <NSObject>
|
||||
|
||||
@property (nonatomic, readonly) id<TGPhotoDrawingView> drawingView;
|
||||
@property (nonatomic, readonly) id<TGPhotoDrawingEntitiesView> drawingEntitiesView;
|
||||
@property (nonatomic, readonly) UIView * selectionContainerView;
|
||||
@property (nonatomic, readonly) UIView * contentWrapperView;
|
||||
@property (nonatomic, readonly) id<TGPhotoDrawingInterfaceController> interfaceController;
|
||||
@property (nonatomic, readonly) id<TGPhotoDrawingView> _Nonnull drawingView;
|
||||
@property (nonatomic, readonly) id<TGPhotoDrawingEntitiesView> _Nonnull drawingEntitiesView;
|
||||
@property (nonatomic, readonly) UIView * _Nonnull selectionContainerView;
|
||||
@property (nonatomic, readonly) UIView * _Nonnull contentWrapperView;
|
||||
@property (nonatomic, readonly) id<TGPhotoDrawingInterfaceController> _Nonnull interfaceController;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@protocol TGPhotoPaintStickersContext <NSObject>
|
||||
|
||||
- (int64_t)documentIdForDocument:(id)document;
|
||||
- (TGStickerMaskDescription *)maskDescriptionForDocument:(id)document;
|
||||
|
||||
- (UIView<TGPhotoPaintStickerRenderView> *)stickerViewForDocument:(id)document;
|
||||
|
||||
@property (nonatomic, copy) id<TGPhotoPaintStickersScreen>(^presentStickersController)(void(^)(id, bool, UIView *, CGRect));
|
||||
|
||||
@property (nonatomic, copy) id<TGCaptionPanelView>(^captionPanelView)(void);
|
||||
@property (nonatomic, copy) id<TGCaptionPanelView> _Nullable(^ _Nullable captionPanelView)(void);
|
||||
|
||||
|
||||
- (UIView<TGPhotoSolidRoundedButtonView> *)solidRoundedButton:(NSString *)title action:(void(^)(void))action;
|
||||
- (id<TGPhotoDrawingAdapter>)drawingAdapter:(CGSize)size originalSize:(CGSize)originalSize isVideo:(bool)isVideo isAvatar:(bool)isAvatar;
|
||||
- (UIView<TGPhotoSolidRoundedButtonView> *_Nonnull)solidRoundedButton:(NSString *_Nonnull)title action:(void(^_Nonnull)(void))action;
|
||||
- (id<TGPhotoDrawingAdapter> _Nonnull)drawingAdapter:(CGSize)size originalSize:(CGSize)originalSize isVideo:(bool)isVideo isAvatar:(bool)isAvatar entitiesView:(UIView<TGPhotoDrawingEntitiesView> * _Nullable)entitiesView;
|
||||
|
||||
- (UIView<TGPhotoDrawingEntitiesView> *)drawingEntitiesViewWithSize:(CGSize)size;
|
||||
- (UIView<TGPhotoDrawingEntitiesView> * _Nonnull)drawingEntitiesViewWithSize:(CGSize)size;
|
||||
|
||||
@end
|
||||
|
@ -85,7 +85,7 @@ const CGSize TGPhotoPaintingMaxSize = { 1920.0f, 1920.0f };
|
||||
_stickersContext = stickersContext;
|
||||
|
||||
CGSize size = TGScaleToSize(photoEditor.originalSize, [TGPhotoDrawingController maximumPaintingSize]);
|
||||
_drawingAdapter = [_stickersContext drawingAdapter:size originalSize:photoEditor.originalSize isVideo:photoEditor.forVideo isAvatar:isAvatar];
|
||||
_drawingAdapter = [_stickersContext drawingAdapter:size originalSize:photoEditor.originalSize isVideo:photoEditor.forVideo isAvatar:isAvatar entitiesView:entitiesView];
|
||||
_interfaceController = (UIViewController<TGPhotoDrawingInterfaceController> *)_drawingAdapter.interfaceController;
|
||||
|
||||
__weak TGPhotoDrawingController *weakSelf = self;
|
||||
|
@ -336,7 +336,7 @@
|
||||
_fullPaintingView = [[UIImageView alloc] init];
|
||||
_fullPaintingView.frame = _fullPreviewView.frame;
|
||||
|
||||
_fullEntitiesView = [_stickersContext drawingEntitiesViewWithSize:CGSizeMake(0, 0)];
|
||||
_fullEntitiesView = [_stickersContext drawingEntitiesViewWithSize:_photoEditor.originalSize];
|
||||
_fullEntitiesView.userInteractionEnabled = false;
|
||||
CGRect rect = [TGPhotoDrawingController fittedCropRect:_photoEditor.cropRect originalSize:_photoEditor.originalSize keepOriginalSize:true];
|
||||
_fullEntitiesView.frame = CGRectMake(0, 0, rect.size.width, rect.size.height);
|
||||
|
@ -1162,35 +1162,6 @@
|
||||
//
|
||||
//#pragma mark Stickers
|
||||
//
|
||||
//- (void)presentStickersView
|
||||
//{
|
||||
// if (_stickersScreen != nil) {
|
||||
// [_stickersScreen restore];
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// __weak TGPhotoPaintController *weakSelf = self;
|
||||
// _stickersScreen = _stickersContext.presentStickersController(^(id document, bool animated, UIView *view, CGRect rect) {
|
||||
// __strong TGPhotoPaintController *strongSelf = weakSelf;
|
||||
// if (strongSelf != nil) {
|
||||
// [strongSelf createNewStickerWithDocument:document animated:animated transitionPoint:CGPointZero snapshotView:nil];
|
||||
// }
|
||||
// });
|
||||
// _stickersScreen.screenDidAppear = ^{
|
||||
// __strong TGPhotoPaintController *strongSelf = weakSelf;
|
||||
// if (strongSelf != nil) {
|
||||
// strongSelf.controlVideoPlayback(false);
|
||||
// [strongSelf->_entitiesContainerView updateVisibility:false];
|
||||
// }
|
||||
// };
|
||||
// _stickersScreen.screenWillDisappear = ^{
|
||||
// __strong TGPhotoPaintController *strongSelf = weakSelf;
|
||||
// if (strongSelf != nil) {
|
||||
// strongSelf.controlVideoPlayback(true);
|
||||
// [strongSelf->_entitiesContainerView updateVisibility:true];
|
||||
// }
|
||||
// };
|
||||
//}
|
||||
//
|
||||
//- (void)createNewStickerWithDocument:(id)document animated:(bool)animated transitionPoint:(CGPoint)transitionPoint snapshotView:(UIView *)snapshotView
|
||||
//{
|
||||
|
@ -32,8 +32,6 @@ const CGFloat TGPhotoStickerSelectionViewHandleSide = 30.0f;
|
||||
|
||||
@interface TGPhotoStickerEntityView ()
|
||||
{
|
||||
UIView<TGPhotoPaintStickerRenderView> *_stickerView;
|
||||
|
||||
id _document;
|
||||
bool _animated;
|
||||
bool _mirrored;
|
||||
@ -53,17 +51,7 @@ const CGFloat TGPhotoStickerSelectionViewHandleSide = 30.0f;
|
||||
_entityUUID = entity.uuid;
|
||||
_baseSize = entity.baseSize;
|
||||
_mirrored = entity.isMirrored;
|
||||
|
||||
_stickerView = [context stickerViewForDocument:entity.document];
|
||||
|
||||
__weak TGPhotoStickerEntityView *weakSelf = self;
|
||||
_stickerView.started = ^(double duration) {
|
||||
__strong TGPhotoStickerEntityView *strongSelf = weakSelf;
|
||||
if (strongSelf != nil && strongSelf.started != nil)
|
||||
strongSelf.started(duration);
|
||||
};
|
||||
[self addSubview:_stickerView];
|
||||
|
||||
|
||||
_document = entity.document;
|
||||
_animated = entity.animated;
|
||||
|
||||
@ -71,14 +59,9 @@ const CGFloat TGPhotoStickerSelectionViewHandleSide = 30.0f;
|
||||
|
||||
CGSize displaySize = [self fittedSizeForSize:imageSize maxSize:CGSizeMake(512.0f, 512.0f)];
|
||||
|
||||
_stickerView.frame = CGRectMake(CGFloor((self.frame.size.width - displaySize.width) / 2.0f), CGFloor((self.frame.size.height - displaySize.height) / 2.0f), displaySize.width, displaySize.height);
|
||||
|
||||
CGFloat scale = displaySize.width > displaySize.height ? self.frame.size.width / displaySize.width : self.frame.size.height / displaySize.height;
|
||||
_defaultTransform = CATransform3DMakeScale(scale, scale, 1.0f);
|
||||
_stickerView.layer.transform = _defaultTransform;
|
||||
|
||||
if (_mirrored)
|
||||
_stickerView.layer.transform = CATransform3DRotate(_defaultTransform, M_PI, 0, 1, 0);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@ -127,45 +110,17 @@ const CGFloat TGPhotoStickerSelectionViewHandleSide = 30.0f;
|
||||
|
||||
- (bool)precisePointInside:(CGPoint)point
|
||||
{
|
||||
CGPoint imagePoint = [_stickerView convertPoint:point fromView:self];
|
||||
if (![_stickerView pointInside:[_stickerView convertPoint:point fromView:self] withEvent:nil])
|
||||
return false;
|
||||
|
||||
return [_stickerView isOpaqueAtPoint:imagePoint];
|
||||
return false;
|
||||
}
|
||||
|
||||
- (void)mirror
|
||||
{
|
||||
_mirrored = !_mirrored;
|
||||
|
||||
if (iosMajorVersion() >= 7)
|
||||
{
|
||||
CATransform3D startTransform = _defaultTransform;
|
||||
if (!_mirrored)
|
||||
{
|
||||
startTransform = _stickerView.layer.transform;
|
||||
}
|
||||
CATransform3D targetTransform = CATransform3DRotate(_defaultTransform, 0, 0, 1, 0);
|
||||
if (_mirrored)
|
||||
{
|
||||
targetTransform = CATransform3DRotate(_defaultTransform, M_PI, 0, 1, 0);
|
||||
targetTransform.m34 = -1.0f / _stickerView.frame.size.width;
|
||||
}
|
||||
|
||||
[UIView animateWithDuration:0.25 animations:^
|
||||
{
|
||||
_stickerView.layer.transform = targetTransform;
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
_stickerView.layer.transform = CATransform3DRotate(_defaultTransform, _mirrored ? M_PI : 0, 0, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
- (UIImage *)image
|
||||
{
|
||||
return [_stickerView image];
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (TGPhotoPaintEntitySelectionView *)createSelectionView
|
||||
@ -182,35 +137,35 @@ const CGFloat TGPhotoStickerSelectionViewHandleSide = 30.0f;
|
||||
}
|
||||
|
||||
- (void)updateVisibility:(bool)visible {
|
||||
[_stickerView setIsVisible:visible];
|
||||
|
||||
}
|
||||
|
||||
- (void)seekTo:(double)timestamp {
|
||||
[_stickerView seekTo:timestamp];
|
||||
|
||||
}
|
||||
|
||||
- (void)play {
|
||||
[_stickerView play];
|
||||
|
||||
}
|
||||
|
||||
- (void)pause {
|
||||
[_stickerView pause];
|
||||
|
||||
}
|
||||
|
||||
- (void)resetToStart {
|
||||
[_stickerView resetToStart];
|
||||
|
||||
}
|
||||
|
||||
- (void)playFromFrame:(NSInteger)frameIndex {
|
||||
[_stickerView playFromFrame:frameIndex];
|
||||
|
||||
}
|
||||
|
||||
- (void)copyStickerView:(TGPhotoStickerEntityView *)view {
|
||||
[_stickerView copyStickerView:view->_stickerView];
|
||||
|
||||
}
|
||||
|
||||
- (int64_t)documentId {
|
||||
return [_stickerView documentId];
|
||||
return 0;
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -58,7 +58,7 @@ public enum LegacyAttachmentMenuMediaEditing {
|
||||
case file
|
||||
}
|
||||
|
||||
public func legacyMediaEditor(context: AccountContext, peer: Peer, threadTitle: String?, media: AnyMediaReference, initialCaption: NSAttributedString, snapshots: [UIView], transitionCompletion: (() -> Void)?, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, present: @escaping (ViewController, Any?) -> Void) {
|
||||
public func legacyMediaEditor(context: AccountContext, peer: Peer, threadTitle: String?, media: AnyMediaReference, initialCaption: NSAttributedString, snapshots: [UIView], transitionCompletion: (() -> Void)?, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, present: @escaping (ViewController, Any?) -> Void) {
|
||||
let _ = (fetchMediaData(context: context, postbox: context.account.postbox, userLocation: .other, mediaReference: media)
|
||||
|> deliverOnMainQueue).start(next: { (value, isImage) in
|
||||
guard case let .data(data) = value, data.complete else {
|
||||
@ -76,13 +76,6 @@ public func legacyMediaEditor(context: AccountContext, peer: Peer, threadTitle:
|
||||
paintStickersContext.captionPanelView = {
|
||||
return getCaptionPanelView()
|
||||
}
|
||||
paintStickersContext.presentStickersController = { completion in
|
||||
return presentStickers({ file, animated, view, rect in
|
||||
let coder = PostboxEncoder()
|
||||
coder.encodeRootObject(file)
|
||||
completion?(coder.makeData(), animated, view, rect)
|
||||
})
|
||||
}
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let recipientName: String
|
||||
@ -132,7 +125,7 @@ public func legacyMediaEditor(context: AccountContext, peer: Peer, threadTitle:
|
||||
})
|
||||
}
|
||||
|
||||
public func legacyAttachmentMenu(context: AccountContext, peer: Peer, threadTitle: String?, chatLocation: ChatLocation, editMediaOptions: LegacyAttachmentMenuMediaEditing?, saveEditedPhotos: Bool, allowGrouping: Bool, hasSchedule: Bool, canSendPolls: Bool, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>), parentController: LegacyController, recentlyUsedInlineBots: [Peer], initialCaption: NSAttributedString, openGallery: @escaping () -> Void, openCamera: @escaping (TGAttachmentCameraView?, TGMenuSheetController?) -> Void, openFileGallery: @escaping () -> Void, openWebSearch: @escaping () -> Void, openMap: @escaping () -> Void, openContacts: @escaping () -> Void, openPoll: @escaping () -> Void, presentSelectionLimitExceeded: @escaping () -> Void, presentCantSendMultipleFiles: @escaping () -> Void, presentJpegConversionAlert: @escaping (@escaping (Bool) -> Void) -> Void, presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32, ((String) -> UIView?)?, @escaping () -> Void) -> Void, selectRecentlyUsedInlineBot: @escaping (Peer) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, present: @escaping (ViewController, Any?) -> Void) -> TGMenuSheetController {
|
||||
public func legacyAttachmentMenu(context: AccountContext, peer: Peer, threadTitle: String?, chatLocation: ChatLocation, editMediaOptions: LegacyAttachmentMenuMediaEditing?, saveEditedPhotos: Bool, allowGrouping: Bool, hasSchedule: Bool, canSendPolls: Bool, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>), parentController: LegacyController, recentlyUsedInlineBots: [Peer], initialCaption: NSAttributedString, openGallery: @escaping () -> Void, openCamera: @escaping (TGAttachmentCameraView?, TGMenuSheetController?) -> Void, openFileGallery: @escaping () -> Void, openWebSearch: @escaping () -> Void, openMap: @escaping () -> Void, openContacts: @escaping () -> Void, openPoll: @escaping () -> Void, presentSelectionLimitExceeded: @escaping () -> Void, presentCantSendMultipleFiles: @escaping () -> Void, presentJpegConversionAlert: @escaping (@escaping (Bool) -> Void) -> Void, presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32, ((String) -> UIView?)?, @escaping () -> Void) -> Void, selectRecentlyUsedInlineBot: @escaping (Peer) -> Void, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, present: @escaping (ViewController, Any?) -> Void) -> TGMenuSheetController {
|
||||
let defaultVideoPreset = defaultVideoPresetForContext(context)
|
||||
UserDefaults.standard.set(defaultVideoPreset.rawValue as NSNumber, forKey: "TG_preferredVideoPreset_v0")
|
||||
|
||||
@ -195,13 +188,6 @@ public func legacyAttachmentMenu(context: AccountContext, peer: Peer, threadTitl
|
||||
paintStickersContext.captionPanelView = {
|
||||
return getCaptionPanelView()
|
||||
}
|
||||
paintStickersContext.presentStickersController = { completion in
|
||||
return presentStickers({ file, animated, view, rect in
|
||||
let coder = PostboxEncoder()
|
||||
coder.encodeRootObject(file)
|
||||
completion?(coder.makeData(), animated, view, rect)
|
||||
})
|
||||
}
|
||||
|
||||
if canSendImageOrVideo {
|
||||
let carouselItem = TGAttachmentCarouselItemView(context: parentController.context, camera: PGCamera.cameraAvailable(), selfPortrait: false, forProfilePhoto: false, assetType: TGMediaAssetAnyType, saveEditedPhotos: !isSecretChat && saveEditedPhotos, allowGrouping: editMediaOptions == nil && allowGrouping, allowSelection: editMediaOptions == nil, allowEditing: true, document: false, selectionLimit: selectionLimit)!
|
||||
|
@ -20,18 +20,11 @@ public func guessMimeTypeByFileExtension(_ ext: String) -> String {
|
||||
return TGMimeTypeMap.mimeType(forExtension: ext) ?? "application/binary"
|
||||
}
|
||||
|
||||
public func configureLegacyAssetPicker(_ controller: TGMediaAssetsController, context: AccountContext, peer: Peer, chatLocation: ChatLocation, captionsEnabled: Bool = true, storeCreatedAssets: Bool = true, showFileTooltip: Bool = false, initialCaption: NSAttributedString, hasSchedule: Bool, presentWebSearch: (() -> Void)?, presentSelectionLimitExceeded: @escaping () -> Void, presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?, getCaptionPanelView: @escaping () -> TGCaptionPanelView?) {
|
||||
public func configureLegacyAssetPicker(_ controller: TGMediaAssetsController, context: AccountContext, peer: Peer, chatLocation: ChatLocation, captionsEnabled: Bool = true, storeCreatedAssets: Bool = true, showFileTooltip: Bool = false, initialCaption: NSAttributedString, hasSchedule: Bool, presentWebSearch: (() -> Void)?, presentSelectionLimitExceeded: @escaping () -> Void, presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, getCaptionPanelView: @escaping () -> TGCaptionPanelView?) {
|
||||
let paintStickersContext = LegacyPaintStickersContext(context: context)
|
||||
paintStickersContext.captionPanelView = {
|
||||
return getCaptionPanelView()
|
||||
}
|
||||
paintStickersContext.presentStickersController = { completion in
|
||||
return presentStickers({ file, animated, view, rect in
|
||||
let coder = PostboxEncoder()
|
||||
coder.encodeRootObject(file)
|
||||
completion?(coder.makeData(), animated, view, rect)
|
||||
})
|
||||
}
|
||||
|
||||
controller.captionsEnabled = captionsEnabled
|
||||
controller.inhibitDocumentCaptions = false
|
||||
|
@ -1,187 +0,0 @@
|
||||
import UIKit
|
||||
import Display
|
||||
import TelegramCore
|
||||
import AccountContext
|
||||
import SwiftSignalKit
|
||||
import AnimatedStickerNode
|
||||
import TelegramAnimatedStickerNode
|
||||
import StickerResources
|
||||
import LegacyComponents
|
||||
|
||||
class LegacyPaintStickerView: UIView, TGPhotoPaintStickerRenderView {
|
||||
var started: ((Double) -> Void)?
|
||||
|
||||
private let context: AccountContext
|
||||
private let file: TelegramMediaFile
|
||||
private var currentSize: CGSize?
|
||||
private var dimensions: CGSize?
|
||||
|
||||
private let imageNode: TransformImageNode
|
||||
private var animationNode: AnimatedStickerNode?
|
||||
|
||||
private var didSetUpAnimationNode = false
|
||||
private let stickerFetchedDisposable = MetaDisposable()
|
||||
|
||||
private let cachedDisposable = MetaDisposable()
|
||||
|
||||
init(context: AccountContext, file: TelegramMediaFile) {
|
||||
self.context = context
|
||||
self.file = file
|
||||
|
||||
self.imageNode = TransformImageNode()
|
||||
|
||||
super.init(frame: CGRect())
|
||||
|
||||
self.addSubnode(self.imageNode)
|
||||
|
||||
self.setup()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.stickerFetchedDisposable.dispose()
|
||||
self.cachedDisposable.dispose()
|
||||
}
|
||||
|
||||
func image() -> UIImage! {
|
||||
if self.imageNode.contents != nil {
|
||||
return UIImage(cgImage: self.imageNode.contents as! CGImage)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func documentId() -> Int64 {
|
||||
return self.file.fileId.id
|
||||
}
|
||||
|
||||
private func setup() {
|
||||
if let dimensions = self.file.dimensions {
|
||||
if self.file.isAnimatedSticker || self.file.isVideoSticker {
|
||||
if self.animationNode == nil {
|
||||
let animationNode = DefaultAnimatedStickerNodeImpl()
|
||||
animationNode.autoplay = false
|
||||
self.animationNode = animationNode
|
||||
animationNode.started = { [weak self, weak animationNode] in
|
||||
self?.imageNode.isHidden = true
|
||||
|
||||
if let animationNode = animationNode {
|
||||
let _ = (animationNode.status
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] status in
|
||||
self?.started?(status.duration)
|
||||
})
|
||||
}
|
||||
}
|
||||
self.addSubnode(animationNode)
|
||||
}
|
||||
let dimensions = self.file.dimensions ?? PixelDimensions(width: 512, height: 512)
|
||||
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: self.context.account.postbox, userLocation: .other, file: self.file, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 256.0, height: 256.0))))
|
||||
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: self.context.account, userLocation: .other, fileReference: stickerPackFileReference(self.file), resource: self.file.resource).start())
|
||||
} else {
|
||||
if let animationNode = self.animationNode {
|
||||
animationNode.visibility = false
|
||||
self.animationNode = nil
|
||||
animationNode.removeFromSupernode()
|
||||
self.imageNode.isHidden = false
|
||||
self.didSetUpAnimationNode = false
|
||||
}
|
||||
self.imageNode.setSignal(chatMessageSticker(account: self.context.account, userLocation: .other, file: self.file, small: false, synchronousLoad: false))
|
||||
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: self.context.account, userLocation: .other, fileReference: stickerPackFileReference(self.file), resource: chatMessageStickerResource(file: self.file, small: false)).start())
|
||||
}
|
||||
|
||||
self.dimensions = dimensions.cgSize
|
||||
self.setNeedsLayout()
|
||||
}
|
||||
}
|
||||
|
||||
var isVisible: Bool = true
|
||||
func setIsVisible(_ visible: Bool) {
|
||||
self.isVisible = visible
|
||||
self.updateVisibility()
|
||||
}
|
||||
|
||||
var isPlaying = false
|
||||
func updateVisibility() {
|
||||
let isPlaying = self.isVisible
|
||||
if self.isPlaying != isPlaying {
|
||||
self.isPlaying = isPlaying
|
||||
|
||||
if isPlaying && !self.didSetUpAnimationNode {
|
||||
self.didSetUpAnimationNode = true
|
||||
let dimensions = self.file.dimensions ?? PixelDimensions(width: 512, height: 512)
|
||||
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 384.0, height: 384.0))
|
||||
let source = AnimatedStickerResourceSource(account: self.context.account, resource: self.file.resource, isVideo: self.file.isVideoSticker)
|
||||
self.animationNode?.setup(source: source, width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .direct(cachePathPrefix: nil))
|
||||
|
||||
self.cachedDisposable.set((source.cachedDataPath(width: 384, height: 384)
|
||||
|> deliverOn(Queue.concurrentDefaultQueue())).start())
|
||||
}
|
||||
self.animationNode?.visibility = isPlaying
|
||||
}
|
||||
}
|
||||
|
||||
func seek(to timestamp: Double) {
|
||||
self.isVisible = false
|
||||
self.isPlaying = false
|
||||
self.animationNode?.seekTo(.timestamp(timestamp))
|
||||
}
|
||||
|
||||
func play() {
|
||||
self.isVisible = true
|
||||
self.updateVisibility()
|
||||
}
|
||||
|
||||
func pause() {
|
||||
self.isVisible = false
|
||||
self.isPlaying = false
|
||||
self.animationNode?.pause()
|
||||
}
|
||||
|
||||
func resetToStart() {
|
||||
self.isVisible = false
|
||||
self.isPlaying = false
|
||||
self.animationNode?.seekTo(.timestamp(0.0))
|
||||
}
|
||||
|
||||
func play(fromFrame frameIndex: Int) {
|
||||
self.isVisible = true
|
||||
self.updateVisibility()
|
||||
self.animationNode?.play(firstFrame: false, fromIndex: frameIndex)
|
||||
}
|
||||
|
||||
func copyStickerView(_ view: TGPhotoPaintStickerRenderView!) {
|
||||
guard let view = view as? LegacyPaintStickerView, let animationNode = view.animationNode else {
|
||||
return
|
||||
}
|
||||
self.animationNode?.cloneCurrentFrame(from: animationNode)
|
||||
self.animationNode?.play(firstFrame: false, fromIndex: animationNode.currentFrameIndex)
|
||||
self.updateVisibility()
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
let size = self.bounds.size
|
||||
|
||||
if size.width > 0 && self.currentSize != size {
|
||||
self.currentSize = size
|
||||
|
||||
let sideSize: CGFloat = size.width
|
||||
let boundingSize = CGSize(width: sideSize, height: sideSize)
|
||||
|
||||
if let dimensions = self.dimensions {
|
||||
let imageSize = dimensions.aspectFitted(boundingSize)
|
||||
self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets()))()
|
||||
self.imageNode.frame = CGRect(origin: CGPoint(x: floor((size.width - imageSize.width) / 2.0), y: (size.height - imageSize.height) / 2.0), size: imageSize)
|
||||
if let animationNode = self.animationNode {
|
||||
animationNode.frame = CGRect(origin: CGPoint(x: floor((size.width - imageSize.width) / 2.0), y: (size.height - imageSize.height) / 2.0), size: imageSize)
|
||||
animationNode.updateLayout(size: imageSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -482,14 +482,14 @@ public final class LegacyPaintEntityRenderer: NSObject, TGPhotoPaintEntityRender
|
||||
}
|
||||
}
|
||||
|
||||
public func entities(for time: CMTime, fps: Int, size: CGSize, completion: (([CIImage]?) -> Void)!) {
|
||||
public func entities(for time: CMTime, fps: Int, size: CGSize, completion: @escaping ([CIImage]) -> Void) {
|
||||
let entities = self.entities
|
||||
let maxSide = max(size.width, size.height)
|
||||
let paintingScale = maxSide / 1920.0
|
||||
|
||||
self.queue.async {
|
||||
if entities.isEmpty {
|
||||
completion(nil)
|
||||
completion([])
|
||||
} else {
|
||||
let count = Atomic<Int>(value: 1)
|
||||
let images = Atomic<[(CIImage, Int)]>(value: [])
|
||||
@ -543,8 +543,7 @@ public final class LegacyPaintEntityRenderer: NSObject, TGPhotoPaintEntityRender
|
||||
}
|
||||
|
||||
public final class LegacyPaintStickersContext: NSObject, TGPhotoPaintStickersContext {
|
||||
public var captionPanelView: (() -> TGCaptionPanelView?)!
|
||||
public var presentStickersController: ((((Any?, Bool, UIView?, CGRect) -> Void)?) -> TGPhotoPaintStickersScreen?)!
|
||||
public var captionPanelView: (() -> TGCaptionPanelView?)?
|
||||
|
||||
private let context: AccountContext
|
||||
|
||||
@ -552,63 +551,15 @@ public final class LegacyPaintStickersContext: NSObject, TGPhotoPaintStickersCon
|
||||
self.context = context
|
||||
}
|
||||
|
||||
public func documentId(forDocument document: Any!) -> Int64 {
|
||||
if let data = document as? Data{
|
||||
let decoder = PostboxDecoder(buffer: MemoryBuffer(data: data))
|
||||
if let file = decoder.decodeRootObject() as? TelegramMediaFile {
|
||||
return file.fileId.id
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
public func maskDescription(forDocument document: Any!) -> TGStickerMaskDescription? {
|
||||
if let data = document as? Data{
|
||||
let decoder = PostboxDecoder(buffer: MemoryBuffer(data: data))
|
||||
if let file = decoder.decodeRootObject() as? TelegramMediaFile {
|
||||
for attribute in file.attributes {
|
||||
if case let .Sticker(_, _, maskData) = attribute {
|
||||
if let maskData = maskData {
|
||||
return TGStickerMaskDescription(n: maskData.n, point: CGPoint(x: maskData.x, y: maskData.y), zoom: CGFloat(maskData.zoom))
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public func stickerView(forDocument document: Any!) -> (UIView & TGPhotoPaintStickerRenderView)! {
|
||||
if let data = document as? Data{
|
||||
let decoder = PostboxDecoder(buffer: MemoryBuffer(data: data))
|
||||
if let file = decoder.decodeRootObject() as? TelegramMediaFile {
|
||||
return LegacyPaintStickerView(context: self.context, file: file)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
class LegacyDrawingAdapter: NSObject, TGPhotoDrawingAdapter {
|
||||
let drawingView: TGPhotoDrawingView!
|
||||
let drawingEntitiesView: TGPhotoDrawingEntitiesView!
|
||||
let drawingView: TGPhotoDrawingView
|
||||
let drawingEntitiesView: TGPhotoDrawingEntitiesView
|
||||
let selectionContainerView: UIView
|
||||
let contentWrapperView: UIView!
|
||||
let interfaceController: TGPhotoDrawingInterfaceController!
|
||||
let contentWrapperView: UIView
|
||||
let interfaceController: TGPhotoDrawingInterfaceController
|
||||
|
||||
init(context: AccountContext, size: CGSize, originalSize: CGSize, isVideo: Bool, isAvatar: Bool) {
|
||||
let interfaceController = DrawingScreen(context: context, size: size, originalSize: originalSize, isVideo: isVideo, isAvatar: isAvatar)
|
||||
init(context: AccountContext, size: CGSize, originalSize: CGSize, isVideo: Bool, isAvatar: Bool, entitiesView: (UIView & TGPhotoDrawingEntitiesView)?) {
|
||||
let interfaceController = DrawingScreen(context: context, size: size, originalSize: originalSize, isVideo: isVideo, isAvatar: isAvatar, entitiesView: entitiesView)
|
||||
self.interfaceController = interfaceController
|
||||
self.drawingView = interfaceController.drawingView
|
||||
self.drawingEntitiesView = interfaceController.entitiesView
|
||||
@ -619,18 +570,18 @@ public final class LegacyPaintStickersContext: NSObject, TGPhotoPaintStickersCon
|
||||
}
|
||||
}
|
||||
|
||||
public func drawingAdapter(_ size: CGSize, originalSize: CGSize, isVideo: Bool, isAvatar: Bool) -> TGPhotoDrawingAdapter! {
|
||||
return LegacyDrawingAdapter(context: self.context, size: size, originalSize: originalSize, isVideo: isVideo, isAvatar: isAvatar)
|
||||
public func drawingAdapter(_ size: CGSize, originalSize: CGSize, isVideo: Bool, isAvatar: Bool, entitiesView: (UIView & TGPhotoDrawingEntitiesView)?) -> TGPhotoDrawingAdapter {
|
||||
return LegacyDrawingAdapter(context: self.context, size: size, originalSize: originalSize, isVideo: isVideo, isAvatar: isAvatar, entitiesView: entitiesView)
|
||||
}
|
||||
|
||||
public func solidRoundedButton(_ title: String!, action: (() -> Void)!) -> (UIView & TGPhotoSolidRoundedButtonView)! {
|
||||
public func solidRoundedButton(_ title: String, action: @escaping () -> Void) -> UIView & TGPhotoSolidRoundedButtonView {
|
||||
let theme = SolidRoundedButtonTheme(theme: self.context.sharedContext.currentPresentationData.with { $0 }.theme)
|
||||
let button = SolidRoundedButtonView(title: title, theme: theme, height: 50.0, cornerRadius: 10.0)
|
||||
button.pressed = action
|
||||
return button
|
||||
}
|
||||
|
||||
public func drawingEntitiesView(with size: CGSize) -> (UIView & TGPhotoDrawingEntitiesView)! {
|
||||
public func drawingEntitiesView(with size: CGSize) -> UIView & TGPhotoDrawingEntitiesView {
|
||||
let view = DrawingEntitiesView(context: self.context, size: size)
|
||||
return view
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ enum LegacyMediaPickerGallerySource {
|
||||
case selection(item: TGMediaSelectableItem)
|
||||
}
|
||||
|
||||
func presentLegacyMediaPickerGallery(context: AccountContext, peer: EnginePeer?, threadTitle: String?, chatLocation: ChatLocation?, presentationData: PresentationData, source: LegacyMediaPickerGallerySource, immediateThumbnail: UIImage?, selectionContext: TGMediaSelectionContext?, editingContext: TGMediaEditingContext, hasSilentPosting: Bool, hasSchedule: Bool, hasTimer: Bool, updateHiddenMedia: @escaping (String?) -> Void, initialLayout: ContainerViewLayout?, transitionHostView: @escaping () -> UIView?, transitionView: @escaping (String) -> UIView?, completed: @escaping (TGMediaSelectableItem & TGMediaEditableItem, Bool, Int32?, @escaping () -> Void) -> Void, presentStickers: ((@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?)?, presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, present: @escaping (ViewController, Any?) -> Void, finishedTransitionIn: @escaping () -> Void, willTransitionOut: @escaping () -> Void, dismissAll: @escaping () -> Void) -> TGModernGalleryController {
|
||||
func presentLegacyMediaPickerGallery(context: AccountContext, peer: EnginePeer?, threadTitle: String?, chatLocation: ChatLocation?, presentationData: PresentationData, source: LegacyMediaPickerGallerySource, immediateThumbnail: UIImage?, selectionContext: TGMediaSelectionContext?, editingContext: TGMediaEditingContext, hasSilentPosting: Bool, hasSchedule: Bool, hasTimer: Bool, updateHiddenMedia: @escaping (String?) -> Void, initialLayout: ContainerViewLayout?, transitionHostView: @escaping () -> UIView?, transitionView: @escaping (String) -> UIView?, completed: @escaping (TGMediaSelectableItem & TGMediaEditableItem, Bool, Int32?, @escaping () -> Void) -> Void, presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, present: @escaping (ViewController, Any?) -> Void, finishedTransitionIn: @escaping () -> Void, willTransitionOut: @escaping () -> Void, dismissAll: @escaping () -> Void) -> TGModernGalleryController {
|
||||
let reminder = peer?.id == context.account.peerId
|
||||
let hasSilentPosting = hasSilentPosting && peer?.id != context.account.peerId
|
||||
|
||||
@ -111,17 +111,6 @@ func presentLegacyMediaPickerGallery(context: AccountContext, peer: EnginePeer?,
|
||||
paintStickersContext.captionPanelView = {
|
||||
return getCaptionPanelView()
|
||||
}
|
||||
paintStickersContext.presentStickersController = { completion in
|
||||
if let presentStickers = presentStickers {
|
||||
return presentStickers({ file, animated, view, rect in
|
||||
let coder = PostboxEncoder()
|
||||
coder.encodeRootObject(file)
|
||||
completion?(coder.makeData(), animated, view, rect)
|
||||
})
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
let controller = TGModernGalleryController(context: legacyController.context)!
|
||||
controller.asyncTransitionIn = true
|
||||
|
@ -151,7 +151,6 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
public weak var webSearchController: WebSearchController?
|
||||
|
||||
public var openCamera: ((TGAttachmentCameraView?) -> Void)?
|
||||
public var presentStickers: ((@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?)?
|
||||
public var presentSchedulePicker: (Bool, @escaping (Int32) -> Void) -> Void = { _, _ in }
|
||||
public var presentTimerPicker: (@escaping (Int32) -> Void) -> Void = { _ in }
|
||||
public var presentWebSearch: (MediaGroupsScreen) -> Void = { _ in }
|
||||
@ -681,7 +680,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
if let strongSelf = self {
|
||||
strongSelf.controller?.interaction?.sendSelected(result, silently, scheduleTime, false, completion)
|
||||
}
|
||||
}, presentStickers: controller.presentStickers, presentSchedulePicker: controller.presentSchedulePicker, presentTimerPicker: controller.presentTimerPicker, getCaptionPanelView: controller.getCaptionPanelView, present: { [weak self] c, a in
|
||||
}, presentSchedulePicker: controller.presentSchedulePicker, presentTimerPicker: controller.presentTimerPicker, getCaptionPanelView: controller.getCaptionPanelView, present: { [weak self] c, a in
|
||||
self?.controller?.present(c, in: .window(.root), with: a)
|
||||
}, finishedTransitionIn: { [weak self] in
|
||||
self?.openingMedia = false
|
||||
@ -717,7 +716,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
if let strongSelf = self {
|
||||
strongSelf.controller?.interaction?.sendSelected(result, silently, scheduleTime, false, completion)
|
||||
}
|
||||
}, presentStickers: controller.presentStickers, presentSchedulePicker: controller.presentSchedulePicker, presentTimerPicker: controller.presentTimerPicker, getCaptionPanelView: controller.getCaptionPanelView, present: { [weak self] c, a in
|
||||
}, presentSchedulePicker: controller.presentSchedulePicker, presentTimerPicker: controller.presentTimerPicker, getCaptionPanelView: controller.getCaptionPanelView, present: { [weak self] c, a in
|
||||
self?.controller?.present(c, in: .window(.root), with: a, blockInteraction: true)
|
||||
}, finishedTransitionIn: { [weak self] in
|
||||
self?.openingMedia = false
|
||||
@ -1498,7 +1497,6 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
if let strongSelf = self {
|
||||
let mediaPicker = MediaPickerScreen(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: strongSelf.peer, threadTitle: strongSelf.threadTitle, chatLocation: strongSelf.chatLocation, bannedSendMedia: strongSelf.bannedSendMedia, subject: .assets(collection), editingContext: strongSelf.interaction?.editingState, selectionContext: strongSelf.interaction?.selectionState)
|
||||
|
||||
mediaPicker.presentStickers = strongSelf.presentStickers
|
||||
mediaPicker.presentSchedulePicker = strongSelf.presentSchedulePicker
|
||||
mediaPicker.presentTimerPicker = strongSelf.presentTimerPicker
|
||||
mediaPicker.getCaptionPanelView = strongSelf.getCaptionPanelView
|
||||
|
@ -6154,16 +6154,6 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
||||
}
|
||||
|
||||
let paintStickersContext = LegacyPaintStickersContext(context: strongSelf.context)
|
||||
// paintStickersContext.presentStickersController = { completion in
|
||||
// let controller = DrawingStickersScreen(context: strongSelf.context, selectSticker: { fileReference, node, rect in
|
||||
// let coder = PostboxEncoder()
|
||||
// coder.encodeRootObject(fileReference.media)
|
||||
// completion?(coder.makeData(), fileReference.media.isAnimatedSticker, node.view, rect)
|
||||
// return true
|
||||
// })
|
||||
// strongSelf.controller?.present(controller, in: .window(.root))
|
||||
// return controller
|
||||
// }
|
||||
|
||||
let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: hasPhotos && !fromGallery, hasViewButton: false, personalPhoto: peerId.namespace == Namespaces.Peer.CloudUser, isVideo: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: false, forum: false, title: nil, isSuggesting: false)!
|
||||
mixin.forceDark = true
|
||||
@ -6308,9 +6298,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
||||
}
|
||||
let uploadInterface = LegacyLiveUploadInterface(context: context)
|
||||
let signal: SSignal
|
||||
if let asset = asset as? AVAsset {
|
||||
signal = TGMediaVideoConverter.convert(asset, adjustments: adjustments, watcher: uploadInterface, entityRenderer: entityRenderer)!
|
||||
} else if let url = asset as? URL, let data = try? Data(contentsOf: url, options: [.mappedRead]), let image = UIImage(data: data), let entityRenderer = entityRenderer {
|
||||
if let url = asset as? URL, url.absoluteString.hasSuffix(".jpg"), let data = try? Data(contentsOf: url, options: [.mappedRead]), let image = UIImage(data: data), let entityRenderer = entityRenderer {
|
||||
let durationSignal: SSignal = SSignal(generator: { subscriber in
|
||||
let disposable = (entityRenderer.duration()).start(next: { duration in
|
||||
subscriber.putNext(duration)
|
||||
@ -6329,6 +6317,8 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
||||
}
|
||||
})
|
||||
|
||||
} else if let asset = asset as? AVAsset {
|
||||
signal = TGMediaVideoConverter.convert(asset, adjustments: adjustments, watcher: uploadInterface, entityRenderer: entityRenderer)!
|
||||
} else {
|
||||
signal = SSignal.complete()
|
||||
}
|
||||
|
@ -1012,19 +1012,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if let mediaReference = mediaReference, let peer = message.peers[message.id.peerId] {
|
||||
legacyMediaEditor(context: strongSelf.context, peer: peer, threadTitle: strongSelf.threadInfo?.title, media: mediaReference, initialCaption: NSAttributedString(), snapshots: snapshots, transitionCompletion: {
|
||||
transitionCompletion()
|
||||
}, presentStickers: { [weak self] completion in
|
||||
if let strongSelf = self {
|
||||
let controller = DrawingStickersScreen(context: strongSelf.context, selectSticker: { result in
|
||||
if let (fileReference, view, rect) = result {
|
||||
completion(fileReference.media, fileReference.media.isAnimatedSticker || fileReference.media.isVideoSticker, view, rect)
|
||||
}
|
||||
return true
|
||||
})
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
return controller
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}, getCaptionPanelView: { [weak self] in
|
||||
return self?.getCaptionPanelView()
|
||||
}, sendMessagesWithSignals: { [weak self] signals, _, _ in
|
||||
@ -3807,20 +3794,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
|
||||
if let mediaReference = mediaReference, let peer = message.peers[message.id.peerId] {
|
||||
legacyMediaEditor(context: strongSelf.context, peer: peer, threadTitle: strongSelf.threadInfo?.title, media: mediaReference, initialCaption: NSAttributedString(string: message.text), snapshots: [], transitionCompletion: nil, presentStickers: { [weak self] completion in
|
||||
if let strongSelf = self {
|
||||
let controller = DrawingStickersScreen(context: strongSelf.context, selectSticker: { result in
|
||||
if let (fileReference, view, rect) = result {
|
||||
completion(fileReference.media, fileReference.media.isAnimatedSticker || fileReference.media.isVideoSticker, view, rect)
|
||||
}
|
||||
return true
|
||||
})
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
return controller
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}, getCaptionPanelView: { [weak self] in
|
||||
legacyMediaEditor(context: strongSelf.context, peer: peer, threadTitle: strongSelf.threadInfo?.title, media: mediaReference, initialCaption: NSAttributedString(string: message.text), snapshots: [], transitionCompletion: nil, getCaptionPanelView: { [weak self] in
|
||||
return self?.getCaptionPanelView()
|
||||
}, sendMessagesWithSignals: { [weak self] signals, _, _ in
|
||||
if let strongSelf = self {
|
||||
@ -11923,19 +11897,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
done(time)
|
||||
})
|
||||
}
|
||||
}, presentStickers: { [weak self] completion in
|
||||
if let strongSelf = self {
|
||||
let controller = DrawingStickersScreen(context: strongSelf.context, selectSticker: { result in
|
||||
if let (fileReference, view, rect) = result {
|
||||
completion(fileReference.media, fileReference.media.isAnimatedSticker || fileReference.media.isVideoSticker, view, rect)
|
||||
}
|
||||
return true
|
||||
})
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
return controller
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}, getCaptionPanelView: { [weak self] in
|
||||
return self?.getCaptionPanelView()
|
||||
}, dismissedWithResult: { [weak self] in
|
||||
@ -12567,19 +12528,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
done(time)
|
||||
})
|
||||
}
|
||||
}, presentStickers: { [weak self] completion in
|
||||
if let strongSelf = self {
|
||||
let controller = DrawingStickersScreen(context: strongSelf.context, selectSticker: { result in
|
||||
if let (fileReference, view, rect) = result {
|
||||
completion(fileReference.media, fileReference.media.isAnimatedSticker || fileReference.media.isVideoSticker, view, rect)
|
||||
}
|
||||
return true
|
||||
})
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
return controller
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}, getCaptionPanelView: { [weak self] in
|
||||
return self?.getCaptionPanelView()
|
||||
})
|
||||
@ -12667,19 +12615,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
})
|
||||
})
|
||||
}
|
||||
}, presentStickers: { [weak self] completion in
|
||||
if let strongSelf = self {
|
||||
let controller = DrawingStickersScreen(context: strongSelf.context, selectSticker: { result in
|
||||
if let (fileReference, view, rect) = result {
|
||||
completion(fileReference.media, fileReference.media.isAnimatedSticker || fileReference.media.isVideoSticker, view, rect)
|
||||
}
|
||||
return true
|
||||
})
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
return controller
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}, getCaptionPanelView: { [weak self] in
|
||||
return self?.getCaptionPanelView()
|
||||
}, present: { [weak self] c, a in
|
||||
@ -12881,20 +12816,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
})
|
||||
}
|
||||
controller.presentStickers = { [weak self] completion in
|
||||
if let strongSelf = self {
|
||||
let controller = DrawingStickersScreen(context: strongSelf.context, selectSticker: { result in
|
||||
if let (fileReference, view, rect) = result {
|
||||
completion(fileReference.media, fileReference.media.isAnimatedSticker || fileReference.media.isVideoSticker, view, rect)
|
||||
}
|
||||
return true
|
||||
})
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
return controller
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
controller.presentSchedulePicker = { [weak self] media, done in
|
||||
if let strongSelf = self {
|
||||
strongSelf.presentScheduleTimePicker(style: media ? .media : .default, completion: { [weak self] time in
|
||||
@ -12980,20 +12901,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
})
|
||||
}))
|
||||
controller.presentStickers = { [weak self] completion in
|
||||
if let strongSelf = self {
|
||||
let controller = DrawingStickersScreen(context: strongSelf.context, selectSticker: { result in
|
||||
if let (fileReference, view, rect) = result {
|
||||
completion(fileReference.media, fileReference.media.isAnimatedSticker || fileReference.media.isVideoSticker, view, rect)
|
||||
}
|
||||
return true
|
||||
})
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
return controller
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
controller.getCaptionPanelView = { [weak self] in
|
||||
return self?.getCaptionPanelView()
|
||||
}
|
||||
@ -13029,19 +12936,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
done(time)
|
||||
})
|
||||
}
|
||||
}, presentStickers: { [weak self] completion in
|
||||
if let strongSelf = self {
|
||||
let controller = DrawingStickersScreen(context: strongSelf.context, selectSticker: { result in
|
||||
if let (fileReference, view, rect) = result {
|
||||
completion(fileReference.media, fileReference.media.isAnimatedSticker || fileReference.media.isVideoSticker, view, rect)
|
||||
}
|
||||
return true
|
||||
})
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
return controller
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}, getCaptionPanelView: { [weak self] in
|
||||
return self?.getCaptionPanelView()
|
||||
})
|
||||
@ -13088,20 +12982,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
})
|
||||
}))
|
||||
controller.presentStickers = { [weak self] completion in
|
||||
if let strongSelf = self {
|
||||
let controller = DrawingStickersScreen(context: strongSelf.context, selectSticker: { result in
|
||||
if let (fileReference, view, rect) = result {
|
||||
completion(fileReference.media, fileReference.media.isAnimatedSticker || fileReference.media.isVideoSticker, view, rect)
|
||||
}
|
||||
return true
|
||||
})
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
return controller
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
controller.getCaptionPanelView = { [weak self] in
|
||||
return self?.getCaptionPanelView()
|
||||
}
|
||||
|
@ -366,9 +366,7 @@ public func createChannelController(context: AccountContext) -> ViewController {
|
||||
}
|
||||
let uploadInterface = LegacyLiveUploadInterface(context: context)
|
||||
let signal: SSignal
|
||||
if let asset = asset as? AVAsset {
|
||||
signal = TGMediaVideoConverter.convert(asset, adjustments: adjustments, watcher: uploadInterface, entityRenderer: entityRenderer)!
|
||||
} else if let url = asset as? URL, let data = try? Data(contentsOf: url, options: [.mappedRead]), let image = UIImage(data: data), let entityRenderer = entityRenderer {
|
||||
if let url = asset as? URL, url.absoluteString.hasSuffix(".jpg"), let data = try? Data(contentsOf: url, options: [.mappedRead]), let image = UIImage(data: data), let entityRenderer = entityRenderer {
|
||||
let durationSignal: SSignal = SSignal(generator: { subscriber in
|
||||
let disposable = (entityRenderer.duration()).start(next: { duration in
|
||||
subscriber.putNext(duration)
|
||||
@ -387,6 +385,8 @@ public func createChannelController(context: AccountContext) -> ViewController {
|
||||
}
|
||||
})
|
||||
|
||||
} else if let asset = asset as? AVAsset {
|
||||
signal = TGMediaVideoConverter.convert(asset, adjustments: adjustments, watcher: uploadInterface, entityRenderer: entityRenderer)!
|
||||
} else {
|
||||
signal = SSignal.complete()
|
||||
}
|
||||
|
@ -639,9 +639,7 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
|
||||
}
|
||||
let uploadInterface = LegacyLiveUploadInterface(context: context)
|
||||
let signal: SSignal
|
||||
if let asset = asset as? AVAsset {
|
||||
signal = TGMediaVideoConverter.convert(asset, adjustments: adjustments, watcher: uploadInterface, entityRenderer: entityRenderer)!
|
||||
} else if let url = asset as? URL, let data = try? Data(contentsOf: url, options: [.mappedRead]), let image = UIImage(data: data), let entityRenderer = entityRenderer {
|
||||
if let url = asset as? URL, url.absoluteString.hasSuffix(".jpg"), let data = try? Data(contentsOf: url, options: [.mappedRead]), let image = UIImage(data: data), let entityRenderer = entityRenderer {
|
||||
let durationSignal: SSignal = SSignal(generator: { subscriber in
|
||||
let disposable = (entityRenderer.duration()).start(next: { duration in
|
||||
subscriber.putNext(duration)
|
||||
@ -660,6 +658,8 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
|
||||
}
|
||||
})
|
||||
|
||||
} else if let asset = asset as? AVAsset {
|
||||
signal = TGMediaVideoConverter.convert(asset, adjustments: adjustments, watcher: uploadInterface, entityRenderer: entityRenderer)!
|
||||
} else {
|
||||
signal = SSignal.complete()
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -10,7 +10,7 @@ import ShareController
|
||||
import LegacyUI
|
||||
import LegacyMediaPickerUI
|
||||
|
||||
func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: ChatLocation, cameraView: TGAttachmentCameraView?, menuController: TGMenuSheetController?, parentController: ViewController, attachmentController: ViewController? = nil, editingMedia: Bool, saveCapturedPhotos: Bool, mediaGrouping: Bool, initialCaption: NSAttributedString, hasSchedule: Bool, photoOnly: Bool, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, recognizedQRCode: @escaping (String) -> Void = { _ in }, presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, dismissedWithResult: @escaping () -> Void = {}, finishedTransitionIn: @escaping () -> Void = {}) {
|
||||
func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: ChatLocation, cameraView: TGAttachmentCameraView?, menuController: TGMenuSheetController?, parentController: ViewController, attachmentController: ViewController? = nil, editingMedia: Bool, saveCapturedPhotos: Bool, mediaGrouping: Bool, initialCaption: NSAttributedString, hasSchedule: Bool, photoOnly: Bool, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, recognizedQRCode: @escaping (String) -> Void = { _ in }, presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, dismissedWithResult: @escaping () -> Void = {}, finishedTransitionIn: @escaping () -> Void = {}) {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme)
|
||||
legacyController.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .portrait, compactSize: .portrait)
|
||||
@ -70,13 +70,6 @@ func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: Ch
|
||||
paintStickersContext.captionPanelView = {
|
||||
return getCaptionPanelView()
|
||||
}
|
||||
paintStickersContext.presentStickersController = { completion in
|
||||
return presentStickers({ file, animated, view, rect in
|
||||
let coder = PostboxEncoder()
|
||||
coder.encodeRootObject(file)
|
||||
completion?(coder.makeData(), animated, view, rect)
|
||||
})
|
||||
}
|
||||
|
||||
controller.stickersContext = paintStickersContext
|
||||
controller.isImportant = true
|
||||
|
@ -3912,19 +3912,6 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
if let mediaReference = mediaReference, let peer = message.peers[message.id.peerId] {
|
||||
legacyMediaEditor(context: strongSelf.context, peer: peer, threadTitle: message.associatedThreadInfo?.title, media: mediaReference, initialCaption: NSAttributedString(), snapshots: snapshots, transitionCompletion: {
|
||||
transitionCompletion()
|
||||
}, presentStickers: { [weak self] completion in
|
||||
if let strongSelf = self {
|
||||
let controller = DrawingStickersScreen(context: strongSelf.context, selectSticker: { result in
|
||||
if let (fileReference, view, rect) = result {
|
||||
completion(fileReference.media, fileReference.media.isAnimatedSticker || fileReference.media.isVideoSticker, view, rect)
|
||||
}
|
||||
return true
|
||||
})
|
||||
strongSelf.controller?.present(controller, in: .window(.root))
|
||||
return controller
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}, getCaptionPanelView: {
|
||||
return nil
|
||||
}, sendMessagesWithSignals: { [weak self] signals, _, _ in
|
||||
@ -6948,9 +6935,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}
|
||||
let uploadInterface = LegacyLiveUploadInterface(context: context)
|
||||
let signal: SSignal
|
||||
if let asset = asset as? AVAsset {
|
||||
signal = TGMediaVideoConverter.convert(asset, adjustments: adjustments, watcher: uploadInterface, entityRenderer: entityRenderer)!
|
||||
} else if let url = asset as? URL, let data = try? Data(contentsOf: url, options: [.mappedRead]), let image = UIImage(data: data), let entityRenderer = entityRenderer {
|
||||
if let url = asset as? URL, url.absoluteString.hasSuffix(".jpg"), let data = try? Data(contentsOf: url, options: [.mappedRead]), let image = UIImage(data: data), let entityRenderer = entityRenderer {
|
||||
let durationSignal: SSignal = SSignal(generator: { subscriber in
|
||||
let disposable = (entityRenderer.duration()).start(next: { duration in
|
||||
subscriber.putNext(duration)
|
||||
@ -6969,6 +6954,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}
|
||||
})
|
||||
|
||||
} else if let asset = asset as? AVAsset {
|
||||
signal = TGMediaVideoConverter.convert(asset, adjustments: adjustments, watcher: uploadInterface, entityRenderer: entityRenderer)!
|
||||
} else {
|
||||
signal = SSignal.complete()
|
||||
}
|
||||
@ -7153,19 +7140,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}
|
||||
|
||||
let paintStickersContext = LegacyPaintStickersContext(context: strongSelf.context)
|
||||
paintStickersContext.presentStickersController = { completion in
|
||||
let controller = DrawingStickersScreen(context: strongSelf.context, selectSticker: { result in
|
||||
if let (fileReference, view, rect) = result {
|
||||
let coder = PostboxEncoder()
|
||||
coder.encodeRootObject(fileReference.media)
|
||||
completion?(coder.makeData(), fileReference.media.isAnimatedSticker || fileReference.media.isVideoSticker, view, rect)
|
||||
}
|
||||
return true
|
||||
})
|
||||
(strongSelf.controller?.navigationController?.topViewController as? ViewController)?.present(controller, in: .window(.root))
|
||||
return controller
|
||||
}
|
||||
|
||||
|
||||
var isForum = false
|
||||
if let peer = strongSelf.data?.peer as? TelegramChannel, peer.flags.contains(.isForum) {
|
||||
isForum = true
|
||||
|
@ -312,7 +312,7 @@ private func galleryItems(account: Account, results: [ChatContextResult], curren
|
||||
return (galleryItems, focusItem)
|
||||
}
|
||||
|
||||
func presentLegacyWebSearchGallery(context: AccountContext, peer: EnginePeer?, threadTitle: String?, chatLocation: ChatLocation?, presentationData: PresentationData, results: [ChatContextResult], current: ChatContextResult, selectionContext: TGMediaSelectionContext?, editingContext: TGMediaEditingContext, updateHiddenMedia: @escaping (String?) -> Void, initialLayout: ContainerViewLayout?, transitionHostView: @escaping () -> UIView?, transitionView: @escaping (ChatContextResult) -> UIView?, completed: @escaping (ChatContextResult) -> Void, presentStickers: ((@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?)?, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, present: (ViewController, Any?) -> Void) {
|
||||
func presentLegacyWebSearchGallery(context: AccountContext, peer: EnginePeer?, threadTitle: String?, chatLocation: ChatLocation?, presentationData: PresentationData, results: [ChatContextResult], current: ChatContextResult, selectionContext: TGMediaSelectionContext?, editingContext: TGMediaEditingContext, updateHiddenMedia: @escaping (String?) -> Void, initialLayout: ContainerViewLayout?, transitionHostView: @escaping () -> UIView?, transitionView: @escaping (ChatContextResult) -> UIView?, completed: @escaping (ChatContextResult) -> Void, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, present: (ViewController, Any?) -> Void) {
|
||||
let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme, initialLayout: nil)
|
||||
legacyController.statusBar.statusBarStyle = presentationData.theme.rootController.statusBarStyle.style
|
||||
|
||||
@ -331,17 +331,6 @@ func presentLegacyWebSearchGallery(context: AccountContext, peer: EnginePeer?, t
|
||||
paintStickersContext.captionPanelView = {
|
||||
return getCaptionPanelView()
|
||||
}
|
||||
paintStickersContext.presentStickersController = { completion in
|
||||
if let presentStickers = presentStickers {
|
||||
return presentStickers({ file, animated, view, rect in
|
||||
let coder = PostboxEncoder()
|
||||
coder.encodeRootObject(file)
|
||||
completion?(coder.makeData(), animated, view, rect)
|
||||
})
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
let controller = TGModernGalleryController(context: legacyController.context)!
|
||||
controller.asyncTransitionIn = true
|
||||
|
@ -107,12 +107,6 @@ public final class WebSearchController: ViewController {
|
||||
|
||||
private var navigationContentNode: WebSearchNavigationContentNode?
|
||||
|
||||
public var presentStickers: ((@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?)? {
|
||||
didSet {
|
||||
self.controllerNode.presentStickers = self.presentStickers
|
||||
}
|
||||
}
|
||||
|
||||
public var getCaptionPanelView: () -> TGCaptionPanelView? = { return nil } {
|
||||
didSet {
|
||||
self.controllerNode.getCaptionPanelView = self.getCaptionPanelView
|
||||
|
@ -184,7 +184,6 @@ class WebSearchControllerNode: ASDisplayNode {
|
||||
var cancel: (() -> Void)?
|
||||
var dismissInput: (() -> Void)?
|
||||
|
||||
var presentStickers: ((@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?)?
|
||||
var getCaptionPanelView: () -> TGCaptionPanelView? = { return nil }
|
||||
|
||||
init(controller: WebSearchController, context: AccountContext, presentationData: PresentationData, controllerInteraction: WebSearchControllerInteraction, peer: EnginePeer?, chatLocation: ChatLocation?, mode: WebSearchMode, attachment: Bool) {
|
||||
@ -744,7 +743,7 @@ class WebSearchControllerNode: ASDisplayNode {
|
||||
strongSelf.controllerInteraction.sendSelected(result, false, nil)
|
||||
strongSelf.cancel?()
|
||||
}
|
||||
}, presentStickers: self.presentStickers, getCaptionPanelView: self.getCaptionPanelView, present: present)
|
||||
}, getCaptionPanelView: self.getCaptionPanelView, present: present)
|
||||
}
|
||||
} else {
|
||||
if let results = self.currentProcessedResults?.results {
|
||||
|
Loading…
x
Reference in New Issue
Block a user