diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index d21cd772fb..9a101f2359 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -8535,3 +8535,6 @@ Sorry for the inconvenience."; "Privacy.Exceptions.DeleteAll" = "Delete All"; "Privacy.Exceptions.DeleteAllConfirmation" = "Are you sure you want to delete all exceptions?"; + +"Attachment.EnableSpoiler" = "Hide With Spoiler"; +"Attachment.DisableSpoiler" = "Disable Spoiler"; diff --git a/submodules/AnimationUI/Sources/AnimationNode.swift b/submodules/AnimationUI/Sources/AnimationNode.swift index bb6b6402b7..8d7e71b67d 100644 --- a/submodules/AnimationUI/Sources/AnimationNode.swift +++ b/submodules/AnimationUI/Sources/AnimationNode.swift @@ -169,9 +169,13 @@ public final class AnimationNode : ASDisplayNode { } } - public func loop() { + public func loop(count: Int? = nil) { if let animationView = self.animationView() { - animationView.loopMode = .loop + if let count = count { + animationView.loopMode = .repeat(Float(count)) + } else { + animationView.loopMode = .loop + } animationView.play() } } diff --git a/submodules/ComponentFlow/Source/Host/ComponentHostView.swift b/submodules/ComponentFlow/Source/Host/ComponentHostView.swift index 0315e6392f..affc53ed1c 100644 --- a/submodules/ComponentFlow/Source/Host/ComponentHostView.swift +++ b/submodules/ComponentFlow/Source/Host/ComponentHostView.swift @@ -1,7 +1,7 @@ import Foundation import UIKit -private func findTaggedViewImpl(view: UIView, tag: Any) -> UIView? { +public func findTaggedComponentViewImpl(view: UIView, tag: Any) -> UIView? { if let view = view as? ComponentTaggedView { if view.matches(tag: tag) { return view @@ -9,7 +9,7 @@ private func findTaggedViewImpl(view: UIView, tag: Any) -> UIView? { } for subview in view.subviews { - if let result = findTaggedViewImpl(view: subview, tag: tag) { + if let result = findTaggedComponentViewImpl(view: subview, tag: tag) { return result } } @@ -131,7 +131,7 @@ public final class ComponentHostView: UIView { return nil } - return findTaggedViewImpl(view: componentView, tag: tag) + return findTaggedComponentViewImpl(view: componentView, tag: tag) } } @@ -230,7 +230,7 @@ public final class ComponentView { guard let view = self.view else { return nil } - return findTaggedViewImpl(view: view, tag: tag) + return findTaggedComponentViewImpl(view: view, tag: tag) } } diff --git a/submodules/Components/PagerComponent/Sources/PagerComponent.swift b/submodules/Components/PagerComponent/Sources/PagerComponent.swift index 8078f3c65a..018c053c55 100644 --- a/submodules/Components/PagerComponent/Sources/PagerComponent.swift +++ b/submodules/Components/PagerComponent/Sources/PagerComponent.swift @@ -187,6 +187,7 @@ public final class PagerComponent Void public let isTopPanelHiddenUpdated: (Bool, Transition) -> Void public let panelHideBehavior: PagerComponentPanelHideBehavior + public let clipContentToTopPanel: Bool public init( contentInsets: UIEdgeInsets, @@ -204,7 +205,8 @@ public final class PagerComponent Void)?, isTopPanelExpandedUpdated: @escaping (Bool, Transition) -> Void, isTopPanelHiddenUpdated: @escaping (Bool, Transition) -> Void, - panelHideBehavior: PagerComponentPanelHideBehavior + panelHideBehavior: PagerComponentPanelHideBehavior, + clipContentToTopPanel: Bool ) { self.contentInsets = contentInsets self.contents = contents @@ -222,6 +224,7 @@ public final class PagerComponent Bool { @@ -258,6 +261,9 @@ public final class PagerComponent? private let topPanelVisibilityFractionUpdated = ActionSlot<(CGFloat, Transition)>() @@ -307,8 +314,13 @@ public final class PagerComponent() self.contentBackgroundView = contentBackgroundView - self.insertSubview(contentBackgroundView, at: 0) + self.contentClippingView.insertSubview(contentBackgroundView, at: 0) } let _ = contentBackgroundView.update( transition: contentBackgroundTransition, @@ -638,11 +658,9 @@ public final class PagerComponent UIImage? { if let image = UIImage(bundleImageName: "Media Editor/Spectrum") { context.draw(image.cgImage!, in: CGRect(origin: .zero, size: size)) } - - let colorSpace = CGColorSpaceCreateDeviceRGB() - var colors = [UIColor(rgb: 0xffffff).cgColor, UIColor(rgb: 0xffffff, alpha: 0.0).cgColor, UIColor(rgb: 0xffffff, alpha: 0.0).cgColor] - var locations: [CGFloat] = [0.0, 0.45, 1.0] - - var gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)! - context.drawLinearGradient(gradient, start: CGPoint(), end: CGPoint(x: size.width, y: 0.0), options: [.drawsAfterEndLocation]) - - colors = [UIColor(rgb: 0x000000, alpha: 0.0).cgColor, UIColor(rgb: 0x000000, alpha: 0.0).cgColor, UIColor(rgb: 0x000000).cgColor] - locations = [0.0, 0.5, 1.0] - - gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)! - context.drawLinearGradient(gradient, start: CGPoint(), end: CGPoint(x: size.width, y: 0.0), options: [.drawsAfterEndLocation]) + if let image = UIImage(bundleImageName: "Media Editor/Grayscale") { + context.draw(image.cgImage!, in: CGRect(origin: .zero, size: size)) + } }) } diff --git a/submodules/DrawingUI/Sources/DrawingEntitiesView.swift b/submodules/DrawingUI/Sources/DrawingEntitiesView.swift index df0e584cc6..4ff9650d66 100644 --- a/submodules/DrawingUI/Sources/DrawingEntitiesView.swift +++ b/submodules/DrawingUI/Sources/DrawingEntitiesView.swift @@ -292,14 +292,32 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView { } func removeAll() { - self.clear() + self.clear(animated: true) self.selectionChanged(nil) self.hasSelectionChanged(false) } - private func clear() { - for case let view as DrawingEntityView in self.subviews { - view.removeFromSuperview() + private func clear(animated: Bool = false) { + if animated { + for case let view as DrawingEntityView in self.subviews { + if let selectionView = view.selectionView { + selectionView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false, completion: { [weak selectionView] _ in + selectionView?.removeFromSuperview() + }) + } + view.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak view] _ in + view?.removeFromSuperview() + }) + if !(view.entity is DrawingVectorEntity) { + view.layer.animateScale(from: 0.0, to: -0.99, duration: 0.2, removeOnCompletion: false, additive: true) + } + } + + } else { + for case let view as DrawingEntityView in self.subviews { + view.selectionView?.removeFromSuperview() + view.removeFromSuperview() + } } } diff --git a/submodules/DrawingUI/Sources/DrawingGesture.swift b/submodules/DrawingUI/Sources/DrawingGesture.swift index c80ce44233..affa06b605 100644 --- a/submodules/DrawingUI/Sources/DrawingGesture.swift +++ b/submodules/DrawingUI/Sources/DrawingGesture.swift @@ -490,8 +490,6 @@ class DrawingGesturePipeline { return gf } - /// Calculates the Gram Polynomial ( s = 0 ), or its s'th - /// derivative evaluated at i, order k, over 2m + 1 points private static func gramPoly(_ index: Int, _ window: Int, _ order: Int, _ derivative: Int) -> CGFloat { var gp_val: CGFloat @@ -513,8 +511,6 @@ class DrawingGesturePipeline { return gp_val } - /// calculates the weight of the i'th data point for the t'th Least-square - /// point of the s'th derivative, over 2m + 1 points, order n private static func calcWeight(_ index: Int, _ windowLoc: Int, _ windowSize: Int, _ order: Int, _ derivative: Int) -> CGFloat { var sum: CGFloat = 0.0 @@ -1002,10 +998,10 @@ struct Polyline { } } - public internal(set) var isComplete: Bool - public let touchIdentifier: String - public var points: [Point] - public var bounds: CGRect { + var isComplete: Bool + let touchIdentifier: String + var points: [Point] + var bounds: CGRect { return self.points.reduce(.null) { partialResult, point -> CGRect in return CGRect(x: min(partialResult.origin.x, point.x), y: min(partialResult.origin.y, point.y), @@ -1144,7 +1140,7 @@ private class BezierBuilder { private class Smoother { let smoothFactor: CGFloat - init(smoothFactor: CGFloat = 0.7) { + init(smoothFactor: CGFloat = 1.0) { self.smoothFactor = smoothFactor } diff --git a/submodules/DrawingUI/Sources/DrawingMetalView.swift b/submodules/DrawingUI/Sources/DrawingMetalView.swift index 3c157783d7..4213f196d9 100644 --- a/submodules/DrawingUI/Sources/DrawingMetalView.swift +++ b/submodules/DrawingUI/Sources/DrawingMetalView.swift @@ -693,8 +693,26 @@ final class Texture { func createCGImage() -> CGImage? { let dataProvider: CGDataProvider - if #available(iOS 12.0, *) { -#if targetEnvironment(simulator) +// if #available(iOS 12.0, *) { +//#if targetEnvironment(simulator) +// guard let data = NSMutableData(capacity: self.bytesPerRow * self.height) else { +// return nil +// } +// data.length = self.bytesPerRow * self.height +// self.texture.getBytes(data.mutableBytes, bytesPerRow: self.bytesPerRow, bytesPerImage: self.bytesPerRow * self.height, from: MTLRegion(origin: MTLOrigin(), size: MTLSize(width: self.width, height: self.height, depth: 1)), mipmapLevel: 0, slice: 0) +// +// guard let provider = CGDataProvider(data: data as CFData) else { +// return nil +// } +// dataProvider = provider +//#else +// guard let buffer = self.buffer, let provider = CGDataProvider(data: Data(bytesNoCopy: buffer.contents(), count: buffer.length, deallocator: .custom { _, _ in +// }) as CFData) else { +// return nil +// } +// dataProvider = provider +//#endif +// } else { guard let data = NSMutableData(capacity: self.bytesPerRow * self.height) else { return nil } @@ -705,25 +723,7 @@ final class Texture { return nil } dataProvider = provider -#else - guard let buffer = self.buffer, let provider = CGDataProvider(data: Data(bytesNoCopy: buffer.contents(), count: buffer.length, deallocator: .custom { _, _ in - }) as CFData) else { - return nil - } - dataProvider = provider -#endif - } else { - guard let data = NSMutableData(capacity: self.bytesPerRow * self.height) else { - return nil - } - data.length = self.bytesPerRow * self.height - self.texture.getBytes(data.mutableBytes, bytesPerRow: self.bytesPerRow, bytesPerImage: self.bytesPerRow * self.height, from: MTLRegion(origin: MTLOrigin(), size: MTLSize(width: self.width, height: self.height, depth: 1)), mipmapLevel: 0, slice: 0) - - guard let provider = CGDataProvider(data: data as CFData) else { - return nil - } - dataProvider = provider - } +// } guard let image = CGImage( width: Int(self.width), diff --git a/submodules/DrawingUI/Sources/DrawingScreen.swift b/submodules/DrawingUI/Sources/DrawingScreen.swift index 6a2e212f88..5ea8066224 100644 --- a/submodules/DrawingUI/Sources/DrawingScreen.swift +++ b/submodules/DrawingUI/Sources/DrawingScreen.swift @@ -180,8 +180,8 @@ struct DrawingState: Equatable { return DrawingState( selectedTool: .pen, tools: [ - .pen(DrawingToolState.BrushState(color: DrawingColor(rgb: 0xff453a), size: 0.2)), - .arrow(DrawingToolState.BrushState(color: DrawingColor(rgb: 0xff8a00), size: 0.2)), + .pen(DrawingToolState.BrushState(color: DrawingColor(rgb: 0xff453a), size: 0.23)), + .arrow(DrawingToolState.BrushState(color: DrawingColor(rgb: 0xff8a00), size: 0.23)), .marker(DrawingToolState.BrushState(color: DrawingColor(rgb: 0xffd60a), size: 0.75)), .neon(DrawingToolState.BrushState(color: DrawingColor(rgb: 0x34c759), size: 0.4)), .eraser(DrawingToolState.EraserState(size: 0.5)), @@ -216,6 +216,7 @@ private let addButtonTag = GenericComponentViewTag() private let toolsTag = GenericComponentViewTag() private let modeTag = GenericComponentViewTag() private let flipButtonTag = GenericComponentViewTag() +private let fillButtonTag = GenericComponentViewTag() private let textSettingsTag = GenericComponentViewTag() private let sizeSliderTag = GenericComponentViewTag() private let color1Tag = GenericComponentViewTag() @@ -374,7 +375,7 @@ private final class DrawingScreenComponent: CombinedComponent { self.currentMode = .drawing self.drawingState = .initial - self.drawingViewState = DrawingView.NavigationState(canUndo: false, canRedo: false, canClear: false, canZoomOut: false) + self.drawingViewState = DrawingView.NavigationState(canUndo: false, canRedo: false, canClear: false, canZoomOut: false, isDrawing: false) self.currentColor = self.drawingState.tools.first?.color ?? DrawingColor(rgb: 0xffffff) self.updateToolState.invoke(self.drawingState.currentToolState) @@ -449,14 +450,18 @@ private final class DrawingScreenComponent: CombinedComponent { self.updated(transition: animated ? .easeInOut(duration: 0.2) : .immediate) } - func updateSelectedTool(_ tool: DrawingToolState.Key) { + func updateSelectedTool(_ tool: DrawingToolState.Key, update: Bool = true) { if self.selectedEntity != nil { - self.updateCurrentMode(.drawing) + self.skipSelectedEntityUpdate = true + self.updateCurrentMode(.drawing, update: false) + self.skipSelectedEntityUpdate = false } self.drawingState = self.drawingState.withUpdatedSelectedTool(tool) self.currentColor = self.drawingState.currentToolState.color ?? self.currentColor self.updateToolState.invoke(self.drawingState.currentToolState) - self.updated(transition: .easeInOut(duration: 0.2)) + if update { + self.updated(transition: .easeInOut(duration: 0.2)) + } } func updateBrushSize(_ size: CGFloat) { @@ -479,6 +484,7 @@ private final class DrawingScreenComponent: CombinedComponent { self.updated(transition: .easeInOut(duration: 0.2)) } + var skipSelectedEntityUpdate = false func updateSelectedEntity(_ entity: DrawingEntity?) { self.selectedEntity = entity if let entity = entity { @@ -496,7 +502,9 @@ private final class DrawingScreenComponent: CombinedComponent { self.currentMode = .drawing self.currentColor = self.drawingState.currentToolState.color ?? self.currentColor } - self.updated(transition: .easeInOut(duration: 0.2)) + if !self.skipSelectedEntityUpdate { + self.updated(transition: .easeInOut(duration: 0.2)) + } } func presentShapePicker(_ sourceView: UIView) { @@ -636,9 +644,6 @@ private final class DrawingScreenComponent: CombinedComponent { let flipButton = Child(Button.self) let fillButton = Child(Button.self) - let fillButtonTag = GenericComponentViewTag() - - let stickerFlipButton = Child(Button.self) let backButton = Child(Button.self) let doneButton = Child(Button.self) @@ -683,7 +688,10 @@ private final class DrawingScreenComponent: CombinedComponent { let presentFastColorPicker = component.presentFastColorPicker let updateFastColorPickerPan = component.updateFastColorPickerPan let dismissFastColorPicker = component.dismissFastColorPicker - + + let topInset = environment.safeInsets.top + 31.0 + let bottomInset: CGFloat = environment.inputHeight > 0.0 ? environment.inputHeight : 145.0 + if let textEntity = state.selectedEntity as? DrawingTextEntity { let textSettings = textSettings.update( component: TextSettingsComponent( @@ -692,6 +700,7 @@ private final class DrawingScreenComponent: CombinedComponent { alignment: DrawingTextAlignment(alignment: textEntity.alignment), font: DrawingTextFont(font: textEntity.font), isEmojiKeyboard: false, + tag: textSettingsTag, toggleStyle: { [weak state, weak textEntity] in guard let textEntity = textEntity else { return @@ -749,8 +758,18 @@ 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(.default(scale: false, alpha: true)) - .disappear(.default(scale: false, alpha: true)) + .appear(Transition.Appear({ _, view, transition in + if let view = findTaggedComponentViewImpl(view: view, tag: textSettingsTag) as? TextFontComponent.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 { + view.animateOut(completion: completion) + } else { + completion() + } + })) ) } @@ -762,16 +781,21 @@ private final class DrawingScreenComponent: CombinedComponent { let applySwatchColor: (DrawingColor) -> Void = { [weak state] color in if let state = state { if [.eraser, .blur].contains(state.drawingState.selectedTool) || state.selectedEntity is DrawingStickerEntity { - state.updateSelectedTool(.pen) + state.updateSelectedTool(.pen, update: false) } state.updateColor(color, animated: true) } } + var currentColor: DrawingColor? = state.currentColor + if [.eraser, .blur].contains(state.drawingState.selectedTool) || state.selectedEntity is DrawingStickerEntity { + currentColor = nil + } + var delay: Double = 0.0 let swatch1Button = swatch1Button.update( component: ColorSwatchComponent( - type: .pallete(state.currentColor == presetColors[0]), + type: .pallete(currentColor == presetColors[0]), color: presetColors[0], tag: color1Tag, action: { @@ -798,7 +822,7 @@ private final class DrawingScreenComponent: CombinedComponent { let swatch2Button = swatch2Button.update( component: ColorSwatchComponent( - type: .pallete(state.currentColor == presetColors[1]), + type: .pallete(currentColor == presetColors[1]), color: presetColors[1], tag: color2Tag, action: { @@ -825,7 +849,7 @@ private final class DrawingScreenComponent: CombinedComponent { let swatch3Button = swatch3Button.update( component: ColorSwatchComponent( - type: .pallete(state.currentColor == presetColors[2]), + type: .pallete(currentColor == presetColors[2]), color: presetColors[2], tag: color3Tag, action: { @@ -852,7 +876,7 @@ private final class DrawingScreenComponent: CombinedComponent { let swatch4Button = swatch4Button.update( component: ColorSwatchComponent( - type: .pallete(state.currentColor == presetColors[3]), + type: .pallete(currentColor == presetColors[3]), color: presetColors[3], tag: color4Tag, action: { @@ -879,7 +903,7 @@ private final class DrawingScreenComponent: CombinedComponent { let swatch5Button = swatch5Button.update( component: ColorSwatchComponent( - type: .pallete(state.currentColor == presetColors[4]), + type: .pallete(currentColor == presetColors[4]), color: presetColors[4], tag: color5Tag, action: { @@ -907,7 +931,7 @@ private final class DrawingScreenComponent: CombinedComponent { let swatch6Button = swatch6Button.update( component: ColorSwatchComponent( - type: .pallete(state.currentColor == presetColors[5]), + type: .pallete(currentColor == presetColors[5]), color: presetColors[5], tag: color6Tag, action: { @@ -934,7 +958,7 @@ private final class DrawingScreenComponent: CombinedComponent { let swatch7Button = swatch7Button.update( component: ColorSwatchComponent( - type: .pallete(state.currentColor == presetColors[6]), + type: .pallete(currentColor == presetColors[6]), color: presetColors[6], tag: color7Tag, action: { @@ -961,7 +985,7 @@ private final class DrawingScreenComponent: CombinedComponent { let swatch8Button = swatch8Button.update( component: ColorSwatchComponent( - type: .pallete(state.currentColor == presetColors[7]), + type: .pallete(currentColor == presetColors[7]), color: presetColors[7], tag: color8Tag, action: { @@ -985,7 +1009,8 @@ private final class DrawingScreenComponent: CombinedComponent { }) ) - if state.selectedEntity == nil { + if state.selectedEntity is DrawingStickerEntity || state.selectedEntity is DrawingTextEntity { + } else { let tools = tools.update( component: ToolsComponent( state: state.drawingState, @@ -1026,6 +1051,104 @@ private final class DrawingScreenComponent: CombinedComponent { ) } + var hasTopButtons = false + if let entity = state.selectedEntity { + var isFilled: Bool? + if let entity = entity as? DrawingSimpleShapeEntity { + isFilled = entity.drawType == .fill + } else if let entity = entity as? DrawingBubbleEntity { + isFilled = entity.drawType == .fill + } else if let _ = entity as? DrawingVectorEntity { + isFilled = false + } + + var hasFlip = false + if state.selectedEntity is DrawingBubbleEntity || state.selectedEntity is DrawingStickerEntity { + hasFlip = true + } + + hasTopButtons = isFilled != nil || hasFlip + + if let isFilled = isFilled { + let fillButton = fillButton.update( + component: Button( + content: AnyComponent( + Image(image: state.image(isFilled ? .fill : .stroke)) + ), + action: { [weak state] in + guard let state = state else { + return + } + if let entity = state.selectedEntity as? DrawingSimpleShapeEntity { + if case .fill = entity.drawType { + entity.drawType = .stroke + } else { + entity.drawType = .fill + } + entity.currentEntityView?.update() + } else if let entity = state.selectedEntity as? DrawingBubbleEntity { + if case .fill = entity.drawType { + entity.drawType = .stroke + } else { + entity.drawType = .fill + } + entity.currentEntityView?.update() + } else if let entity = state.selectedEntity as? DrawingVectorEntity { + if case .oneSidedArrow = entity.type { + entity.type = .twoSidedArrow + } else if case .twoSidedArrow = entity.type { + entity.type = .line + } else { + entity.type = .oneSidedArrow + } + entity.currentEntityView?.update() + } + state.updated(transition: .easeInOut(duration: 0.2)) + } + ).minSize(CGSize(width: 44.0, height: 44.0)).tagged(fillButtonTag), + availableSize: CGSize(width: 30.0, height: 30.0), + transition: .immediate + ) + context.add(fillButton + .position(CGPoint(x: context.availableSize.width / 2.0 - (hasFlip ? 46.0 : 0.0), y: environment.safeInsets.top + 31.0)) + .appear(.default(scale: true)) + .disappear(.default(scale: true)) + ) + } + + if hasFlip { + let flipButton = flipButton.update( + component: Button( + content: AnyComponent( + Image(image: state.image(.flip)) + ), + action: { [weak state] in + guard let state = state else { + return + } + if let entity = state.selectedEntity as? DrawingBubbleEntity { + var updatedTailPosition = entity.tailPosition + updatedTailPosition.x = 1.0 - updatedTailPosition.x + entity.tailPosition = updatedTailPosition + entity.currentEntityView?.update() + } else if let entity = state.selectedEntity as? DrawingStickerEntity { + entity.mirrored = !entity.mirrored + entity.currentEntityView?.update(animated: true) + } + state.updated(transition: .easeInOut(duration: 0.2)) + } + ).minSize(CGSize(width: 44.0, height: 44.0)).tagged(flipButtonTag), + availableSize: CGSize(width: 30.0, height: 30.0), + transition: .immediate + ) + context.add(flipButton + .position(CGPoint(x: context.availableSize.width / 2.0 + (isFilled != nil ? 46.0 : 0.0), y: environment.safeInsets.top + 31.0)) + .appear(.default(scale: true)) + .disappear(.default(scale: true)) + ) + } + } + var sizeSliderVisible = false var isEditingText = false var sizeValue: CGFloat? @@ -1034,11 +1157,20 @@ private final class DrawingScreenComponent: CombinedComponent { isEditingText = entityView.isEditing sizeValue = textEntity.fontSize } else { - if state.selectedEntity == nil { + if state.selectedEntity == nil || !(state.selectedEntity is DrawingStickerEntity) { sizeSliderVisible = true - sizeValue = state.drawingState.currentToolState.size + if state.selectedEntity == nil { + sizeValue = state.drawingState.currentToolState.size + } else if let entity = state.selectedEntity { + if let entity = entity as? DrawingSimpleShapeEntity { + sizeSliderVisible = entity.drawType == .stroke + } else if let entity = entity as? DrawingBubbleEntity { + sizeSliderVisible = entity.drawType == .stroke + } + sizeValue = entity.lineWidth + } } - if state.drawingViewState.canZoomOut { + if state.drawingViewState.canZoomOut && !hasTopButtons { let zoomOutButton = zoomOutButton.update( component: Button( content: AnyComponent( @@ -1064,9 +1196,10 @@ private final class DrawingScreenComponent: CombinedComponent { if let sizeValue { state.lastSize = sizeValue } + if state.drawingViewState.isDrawing { + sizeSliderVisible = false + } - let topInset = environment.safeInsets.top + 31.0 - let bottomInset: CGFloat = environment.inputHeight > 0.0 ? environment.inputHeight : 145.0 let textSize = textSize.update( component: TextSizeSliderComponent( value: sizeValue ?? state.lastSize, @@ -1103,7 +1236,7 @@ private final class DrawingScreenComponent: CombinedComponent { transition: context.transition ) context.add(undoButton - .position(CGPoint(x: environment.safeInsets.left + undoButton.size.width / 2.0 + 2.0, y: environment.safeInsets.top + 31.0)) + .position(CGPoint(x: environment.safeInsets.left + undoButton.size.width / 2.0 + 2.0, y: topInset)) .scale(isEditingText ? 0.01 : 1.0) .opacity(isEditingText ? 0.0 : 1.0) ) @@ -1122,7 +1255,7 @@ private final class DrawingScreenComponent: CombinedComponent { transition: context.transition ) context.add(redoButton - .position(CGPoint(x: environment.safeInsets.left + undoButton.size.width + 2.0 + redoButton.size.width / 2.0, y: environment.safeInsets.top + 31.0)) + .position(CGPoint(x: environment.safeInsets.left + undoButton.size.width + 2.0 + redoButton.size.width / 2.0, y: topInset)) .appear(.default(scale: true, alpha: true)) .disappear(.default(scale: true, alpha: true)) ) @@ -1142,7 +1275,7 @@ private final class DrawingScreenComponent: CombinedComponent { transition: context.transition ) context.add(clearAllButton - .position(CGPoint(x: context.availableSize.width - environment.safeInsets.right - clearAllButton.size.width / 2.0 - 13.0, y: environment.safeInsets.top + 31.0)) + .position(CGPoint(x: context.availableSize.width - environment.safeInsets.right - clearAllButton.size.width / 2.0 - 13.0, y: topInset)) .scale(isEditingText ? 0.01 : 1.0) .opacity(isEditingText ? 0.0 : 1.0) ) @@ -1162,7 +1295,7 @@ private final class DrawingScreenComponent: CombinedComponent { transition: context.transition ) context.add(textCancelButton - .position(CGPoint(x: environment.safeInsets.left + textCancelButton.size.width / 2.0 + 13.0, y: environment.safeInsets.top + 31.0)) + .position(CGPoint(x: environment.safeInsets.left + textCancelButton.size.width / 2.0 + 13.0, y: topInset)) .scale(isEditingText ? 1.0 : 0.01) .opacity(isEditingText ? 1.0 : 0.0) ) @@ -1182,245 +1315,127 @@ private final class DrawingScreenComponent: CombinedComponent { transition: context.transition ) context.add(textDoneButton - .position(CGPoint(x: context.availableSize.width - environment.safeInsets.right - textDoneButton.size.width / 2.0 - 13.0, y: environment.safeInsets.top + 31.0)) + .position(CGPoint(x: context.availableSize.width - environment.safeInsets.right - textDoneButton.size.width / 2.0 - 13.0, y: topInset)) .scale(isEditingText ? 1.0 : 0.01) .opacity(isEditingText ? 1.0 : 0.0) ) - - var isEditingShapeSize = false - if let entity = state.selectedEntity { - if entity is DrawingSimpleShapeEntity || entity is DrawingVectorEntity || entity is DrawingBubbleEntity { - isEditingShapeSize = true - } - } - + var color: DrawingColor? if let entity = state.selectedEntity, presetColors.contains(entity.color) { color = nil } else if presetColors.contains(state.currentColor) { color = nil + } else if state.selectedEntity is DrawingStickerEntity { + color = nil } else { color = state.currentColor } + + let colorButton = colorButton.update( + component: ColorSwatchComponent( + type: .main, + color: color, + tag: colorButtonTag, + action: { [weak state] in + if let state = state { + presentColorPicker(state.currentColor) + } + }, + holdAction: { + if let controller = controller() as? DrawingScreen, let buttonView = controller.node.componentHost.findTaggedView(tag: colorButtonTag) { + presentFastColorPicker(buttonView) + } + }, + pan: { point in + updateFastColorPickerPan(point) + }, + release: { + dismissFastColorPicker() + } + ), + availableSize: CGSize(width: 44.0, height: 44.0), + transition: context.transition + ) + context.add(colorButton + .position(CGPoint(x: environment.safeInsets.left + colorButton.size.width / 2.0 + 2.0, y: context.availableSize.height - environment.safeInsets.bottom - colorButton.size.height / 2.0 - 89.0)) + .appear(.default(scale: true)) + .disappear(.default(scale: true)) + ) + - if let _ = state.selectedEntity as? DrawingStickerEntity { - let stickerFlipButton = stickerFlipButton.update( - component: Button( - content: AnyComponent( - Image(image: state.image(.flip)) + let modeRightInset: CGFloat = 57.0 + let addButton = addButton.update( + component: Button( + content: AnyComponent(ZStack([ + AnyComponentWithIdentity( + id: "background", + component: AnyComponent( + BlurredRectangle( + color: UIColor(rgb: 0x888888, alpha: 0.3), + radius: 12.0 + ) + ) ), - action: { [weak state] in - guard let state = state else { - return - } - if let entity = state.selectedEntity as? DrawingStickerEntity { - entity.mirrored = !entity.mirrored - entity.currentEntityView?.update(animated: true) - } - state.updated(transition: .easeInOut(duration: 0.2)) + AnyComponentWithIdentity( + id: "icon", + component: AnyComponent( + Image(image: state.image(.add)) + ) + ), + ])), + action: { [weak state] in + guard let controller = controller() as? DrawingScreen, let state = state else { + return } - ).minSize(CGSize(width: 44.0, height: 44.0)).tagged(flipButtonTag), - availableSize: CGSize(width: 33.0, height: 33.0), - transition: .immediate - ) - context.add(stickerFlipButton - .position(CGPoint(x: environment.safeInsets.left + stickerFlipButton.size.width / 2.0 + 3.0, y: context.availableSize.height - environment.safeInsets.bottom - stickerFlipButton.size.height / 2.0 - 89.0)) - .appear(.default(scale: true)) - .disappear(.default(scale: true)) - ) - } else { - let colorButton = colorButton.update( - component: ColorSwatchComponent( - type: .main, - color: color, - tag: colorButtonTag, - action: { [weak state] in - if let state = state { - presentColorPicker(state.currentColor) + switch state.currentMode { + case .drawing: + if let buttonView = controller.node.componentHost.findTaggedView(tag: addButtonTag) as? Button.View { + state.presentShapePicker(buttonView) } - }, - holdAction: { - if let controller = controller() as? DrawingScreen, let buttonView = controller.node.componentHost.findTaggedView(tag: colorButtonTag) { - presentFastColorPicker(buttonView) - } - }, - pan: { point in - updateFastColorPickerPan(point) - }, - release: { - dismissFastColorPicker() + case .sticker: + state.presentStickerPicker() + case .text: + state.addTextEntity() } + } + ).minSize(CGSize(width: 44.0, height: 44.0)).tagged(addButtonTag), + availableSize: CGSize(width: 24.0, height: 24.0), + transition: .immediate + ) + context.add(addButton + .position(CGPoint(x: context.availableSize.width - environment.safeInsets.right - addButton.size.width / 2.0 - 2.0, y: context.availableSize.height - environment.safeInsets.bottom - addButton.size.height / 2.0 - 89.0)) + .appear(.default(scale: true)) + .disappear(.default(scale: true)) + ) + + let doneButton = doneButton.update( + component: Button( + content: AnyComponent( + Image(image: state.image(.done)) ), - availableSize: CGSize(width: 44.0, height: 44.0), - transition: context.transition - ) - context.add(colorButton - .position(CGPoint(x: environment.safeInsets.left + colorButton.size.width / 2.0 + 2.0, y: context.availableSize.height - environment.safeInsets.bottom - colorButton.size.height / 2.0 - 89.0)) - .appear(.default(scale: true)) - .disappear(.default(scale: true)) - ) - } - - var isModeControlEnabled = true - var modeRightInset: CGFloat = 57.0 - if isEditingShapeSize { - var isFilled = false - if let entity = state.selectedEntity as? DrawingSimpleShapeEntity, case .fill = entity.drawType { - isFilled = true - isModeControlEnabled = false - } else if let entity = state.selectedEntity as? DrawingBubbleEntity, case .fill = entity.drawType { - isFilled = true - isModeControlEnabled = false - } - - if let _ = state.selectedEntity as? DrawingBubbleEntity { - let flipButton = flipButton.update( - component: Button( - content: AnyComponent( - Image(image: state.image(.flip)) - ), - action: { [weak state] in - guard let state = state else { - return - } - if let entity = state.selectedEntity as? DrawingBubbleEntity { - var updatedTailPosition = entity.tailPosition - updatedTailPosition.x = 1.0 - updatedTailPosition.x - entity.tailPosition = updatedTailPosition - entity.currentEntityView?.update() - } - state.updated(transition: .easeInOut(duration: 0.2)) - } - ).minSize(CGSize(width: 44.0, height: 44.0)), - availableSize: CGSize(width: 33.0, height: 33.0), - transition: .immediate - ) - context.add(flipButton - .position(CGPoint(x: context.availableSize.width - environment.safeInsets.right - flipButton.size.width / 2.0 - 3.0 - flipButton.size.width, y: context.availableSize.height - environment.safeInsets.bottom - flipButton.size.height / 2.0 - 2.0 - UIScreenPixel)) - .appear(.default(scale: true)) - .disappear(.default(scale: true)) - ) - modeRightInset += 35.0 - } - - let fillButton = fillButton.update( - component: Button( - content: AnyComponent( - Image(image: state.image(isFilled ? .fill : .stroke)) - ), - action: { [weak state] in - guard let state = state else { - return - } - if let entity = state.selectedEntity as? DrawingSimpleShapeEntity { - if case .fill = entity.drawType { - entity.drawType = .stroke - } else { - entity.drawType = .fill - } - entity.currentEntityView?.update() - } else if let entity = state.selectedEntity as? DrawingBubbleEntity { - if case .fill = entity.drawType { - entity.drawType = .stroke - } else { - entity.drawType = .fill - } - entity.currentEntityView?.update() - } else if let entity = state.selectedEntity as? DrawingVectorEntity { - if case .oneSidedArrow = entity.type { - entity.type = .twoSidedArrow - } else if case .twoSidedArrow = entity.type { - entity.type = .line - } else { - entity.type = .oneSidedArrow - } - entity.currentEntityView?.update() - } - state.updated(transition: .easeInOut(duration: 0.2)) - } - ).minSize(CGSize(width: 44.0, height: 44.0)).tagged(fillButtonTag), - availableSize: CGSize(width: 33.0, height: 33.0), - transition: .immediate - ) - context.add(fillButton - .position(CGPoint(x: context.availableSize.width - environment.safeInsets.right - fillButton.size.width / 2.0 - 3.0, y: context.availableSize.height - environment.safeInsets.bottom - fillButton.size.height / 2.0 - 2.0 - UIScreenPixel)) - .appear(.default(scale: true)) - .disappear(.default(scale: true)) - ) - } else { - let addButton = addButton.update( - component: Button( - content: AnyComponent(ZStack([ - AnyComponentWithIdentity( - id: "background", - component: AnyComponent( - BlurredRectangle( - color: UIColor(rgb: 0x888888, alpha: 0.3), - radius: 12.0 - ) - ) - ), - AnyComponentWithIdentity( - id: "icon", - component: AnyComponent( - Image(image: state.image(.add)) - ) - ), - ])), - action: { [weak state] in - guard let controller = controller() as? DrawingScreen, let state = state else { - return - } - switch state.currentMode { - case .drawing: - if let buttonView = controller.node.componentHost.findTaggedView(tag: addButtonTag) as? Button.View { - state.presentShapePicker(buttonView) - } - case .sticker: - state.presentStickerPicker() - case .text: - state.addTextEntity() - } - } - ).minSize(CGSize(width: 44.0, height: 44.0)).tagged(addButtonTag), - availableSize: CGSize(width: 24.0, height: 24.0), - transition: .immediate - ) - context.add(addButton - .position(CGPoint(x: context.availableSize.width - environment.safeInsets.right - addButton.size.width / 2.0 - 2.0, y: context.availableSize.height - environment.safeInsets.bottom - addButton.size.height / 2.0 - 89.0)) - .appear(.default(scale: true)) - .disappear(.default(scale: true)) - ) - - let doneButton = doneButton.update( - component: Button( - content: AnyComponent( - Image(image: state.image(.done)) - ), - action: { - apply.invoke(Void()) - } - ).minSize(CGSize(width: 44.0, height: 44.0)).tagged(doneButtonTag), - availableSize: CGSize(width: 33.0, height: 33.0), - transition: .immediate - ) - context.add(doneButton - .position(CGPoint(x: context.availableSize.width - environment.safeInsets.right - doneButton.size.width / 2.0 - 3.0, y: context.availableSize.height - environment.safeInsets.bottom - doneButton.size.height / 2.0 - 2.0 - UIScreenPixel)) - .appear(Transition.Appear { _, view, transition in - transition.animateScale(view: view, from: 0.1, to: 1.0) - transition.animateAlpha(view: view, from: 0.0, to: 1.0) - - transition.animatePosition(view: view, from: CGPoint(x: 12.0, y: 0.0), to: CGPoint(), additive: true) + action: { + apply.invoke(Void()) + } + ).minSize(CGSize(width: 44.0, height: 44.0)).tagged(doneButtonTag), + availableSize: CGSize(width: 33.0, height: 33.0), + transition: .immediate + ) + context.add(doneButton + .position(CGPoint(x: context.availableSize.width - environment.safeInsets.right - doneButton.size.width / 2.0 - 3.0, y: context.availableSize.height - environment.safeInsets.bottom - doneButton.size.height / 2.0 - 2.0 - UIScreenPixel)) + .appear(Transition.Appear { _, view, transition in + transition.animateScale(view: view, from: 0.1, to: 1.0) + transition.animateAlpha(view: view, from: 0.0, to: 1.0) + + transition.animatePosition(view: view, from: CGPoint(x: 12.0, y: 0.0), to: CGPoint(), additive: true) + }) + .disappear(Transition.Disappear { view, transition, completion in + transition.setScale(view: view, scale: 0.1) + transition.setAlpha(view: view, alpha: 0.0, completion: { _ in + completion() }) - .disappear(Transition.Disappear { view, transition, completion in - transition.setScale(view: view, scale: 0.1) - transition.setAlpha(view: view, alpha: 0.0, completion: { _ in - completion() - }) - transition.animatePosition(view: view, from: CGPoint(), to: CGPoint(x: 12.0, y: 0.0), additive: true) - }) - ) - } + transition.animatePosition(view: view, from: CGPoint(), to: CGPoint(x: 12.0, y: 0.0), additive: true) + }) + ) let selectedIndex: Int switch state.currentMode { @@ -1443,8 +1458,8 @@ private final class DrawingScreenComponent: CombinedComponent { component: ModeAndSizeComponent( values: ["Draw", "Sticker", "Text"], sizeValue: selectedSize, - isEditing: isEditingShapeSize, - isEnabled: isModeControlEnabled, + isEditing: false, + isEnabled: true, rightInset: modeRightInset - 57.0, tag: modeTag, selectedIndex: selectedIndex, @@ -1478,7 +1493,6 @@ private final class DrawingScreenComponent: CombinedComponent { ) context.add(modeAndSize .position(CGPoint(x: context.availableSize.width / 2.0 - (modeRightInset - 57.0) / 2.0, y: context.availableSize.height - environment.safeInsets.bottom - modeAndSize.size.height / 2.0 - 9.0)) - .opacity(isModeControlEnabled ? 1.0 : 0.4) ) var animatingOut = false @@ -1494,7 +1508,7 @@ private final class DrawingScreenComponent: CombinedComponent { animation: LottieAnimationComponent.AnimationItem( name: "media_backToCancel", mode: .animating(loop: false), - range: isEditingShapeSize || animatingOut || component.isAvatar ? (0.5, 1.0) : (0.0, 0.5) + range: animatingOut || component.isAvatar ? (0.5, 1.0) : (0.0, 0.5) ), colors: ["__allcolors__": .white], size: CGSize(width: 33.0, height: 33.0) @@ -1730,8 +1744,17 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController { entitiesView.add(entity) entitiesView.selectEntity(entity) - if let entityView = entitiesView.getView(for: entity.uuid) as? DrawingTextEntityView { - entityView.beginEditing(accessoryView: strongSelf.textEditAccessoryView) + if let entityView = entitiesView.getView(for: entity.uuid) { + if let textEntityView = entityView as? DrawingTextEntityView { + textEntityView.beginEditing(accessoryView: strongSelf.textEditAccessoryView) + } else { + entityView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + entityView.layer.animateScale(from: 0.1, to: 1.0, duration: 0.2) + + if let selectionView = entityView.selectionView { + selectionView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, delay: 0.2) + } + } } } } @@ -1943,7 +1966,7 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController { if let view = self.componentHost.findTaggedView(tag: tag) { view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3, delay: delay) view.layer.animateScale(from: 0.01, to: 1.0, duration: 0.3, delay: delay) - delay += 0.025 + delay += 0.02 } } if let view = self.componentHost.findTaggedView(tag: sizeSliderTag) { @@ -1983,15 +2006,16 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController { buttonView.alpha = 0.0 buttonView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3) buttonView.layer.animateScale(from: 1.0, to: 0.01, duration: 0.3) - } + } + if let buttonView = self.componentHost.findTaggedView(tag: fillButtonTag) { + buttonView.alpha = 0.0 + buttonView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3) + buttonView.layer.animateScale(from: 1.0, to: 0.01, duration: 0.3) + } 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) } - if let view = self.componentHost.findTaggedView(tag: textSettingsTag) { - view.alpha = 0.0 - view.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3) - } - + let colorTags = [color1Tag, color2Tag, color3Tag, color4Tag, color5Tag, color6Tag, color7Tag, color8Tag] for tag in colorTags { if let view = self.componentHost.findTaggedView(tag: tag) { @@ -2005,7 +2029,12 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController { view.animateOut(completion: { completion() }) + } else if let view = self.componentHost.findTaggedView(tag: textSettingsTag) as? TextFontComponent.View { + view.animateOut(completion: { + completion() + }) } + if let view = self.componentHost.findTaggedView(tag: modeTag) as? ModeAndSizeComponent.View { view.animateOut() } @@ -2033,7 +2062,12 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController { let environment = ViewControllerComponentContainer.Environment( statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: 0.0, - safeInsets: UIEdgeInsets(top: layout.intrinsicInsets.top + layout.safeInsets.top, left: layout.safeInsets.left, bottom: layout.intrinsicInsets.bottom + layout.safeInsets.bottom, right: layout.safeInsets.right), + safeInsets: UIEdgeInsets( + top: layout.intrinsicInsets.top + layout.safeInsets.top, + left: layout.safeInsets.left, + bottom: layout.intrinsicInsets.bottom + layout.safeInsets.bottom, + right: layout.safeInsets.right + ), inputHeight: layout.inputHeight ?? 0.0, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, @@ -2122,6 +2156,7 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController { alignment: DrawingTextAlignment(alignment: textEntity.alignment), font: DrawingTextFont(font: textEntity.font), isEmojiKeyboard: entityView.textView.inputView != nil, + tag: nil, presentColorPicker: { [weak self] in guard let strongSelf = self, let entityView = strongSelf.entitiesView.selectedEntityView as? DrawingTextEntityView, let textEntity = entityView.entity as? DrawingTextEntity else { return diff --git a/submodules/DrawingUI/Sources/DrawingTextEntity.swift b/submodules/DrawingUI/Sources/DrawingTextEntity.swift index fab244d76c..5ef8e8b946 100644 --- a/submodules/DrawingUI/Sources/DrawingTextEntity.swift +++ b/submodules/DrawingUI/Sources/DrawingTextEntity.swift @@ -198,6 +198,9 @@ public final class DrawingTextEntity: DrawingEntity, Codable { if let renderImageData = try? container.decodeIfPresent(Data.self, forKey: .renderImage) { self.renderImage = UIImage(data: renderImageData) } + if let renderSubEntities = try? container.decodeIfPresent([CodableDrawingEntity].self, forKey: .renderSubEntities) { + self.renderSubEntities = renderSubEntities.compactMap { $0.entity as? DrawingStickerEntity } + } } public func encode(to encoder: Encoder) throws { @@ -226,6 +229,10 @@ public final class DrawingTextEntity: DrawingEntity, Codable { if let renderImage, let data = renderImage.pngData() { try container.encode(data, forKey: .renderImage) } + if let renderSubEntities = self.renderSubEntities { + let codableEntities: [CodableDrawingEntity] = renderSubEntities.map { .sticker($0) } + try container.encode(codableEntities, forKey: .renderSubEntities) + } } public func duplicate() -> DrawingEntity { @@ -247,6 +254,7 @@ public final class DrawingTextEntity: DrawingEntity, Codable { public func prepareForRender() { self.renderImage = (self.currentEntityView as? DrawingTextEntityView)?.getRenderImage() + self.renderSubEntities = (self.currentEntityView as? DrawingTextEntityView)?.getRenderSubEntities() } } @@ -283,8 +291,6 @@ final class DrawingTextEntityView: DrawingEntityView, UITextViewDelegate { self.textView.delegate = self self.addSubview(self.textView) - self.update(animated: false) - self.emojiViewProvider = { [weak self] emoji in guard let strongSelf = self else { return UIView() @@ -293,6 +299,8 @@ final class DrawingTextEntityView: DrawingEntityView, UITextViewDelegate { let pointSize: CGFloat = 128.0 return EmojiTextAttachmentView(context: context, userLocation: .other, emoji: emoji, file: emoji.file, cache: strongSelf.context.animationCache, renderer: strongSelf.context.animationRenderer, placeholderColor: UIColor.white.withAlphaComponent(0.12), pointSize: CGSize(width: pointSize, height: pointSize)) } + + self.update(animated: false) } required init?(coder: NSCoder) { @@ -312,11 +320,13 @@ final class DrawingTextEntityView: DrawingEntityView, UITextViewDelegate { self.endEditing() } + private var emojiRects: [(CGRect, ChatTextInputTextCustomEmojiAttribute)] = [] func updateEntities() { self.textView.drawingLayoutManager.ensureLayout(for: self.textView.textContainer) var customEmojiRects: [(CGRect, ChatTextInputTextCustomEmojiAttribute)] = [] + var shouldRepeat = false if let attributedText = self.textView.attributedText { let beginning = self.textView.beginningOfDocument attributedText.enumerateAttributes(in: NSMakeRange(0, attributedText.length), options: [], using: { attributes, range, _ in @@ -324,6 +334,9 @@ final class DrawingTextEntityView: DrawingEntityView, UITextViewDelegate { if let start = self.textView.position(from: beginning, offset: range.location), let end = self.textView.position(from: start, offset: range.length), let textRange = self.textView.textRange(from: start, to: end) { let rect = self.textView.firstRect(for: textRange) customEmojiRects.append((rect, value)) + if rect.origin.x.isInfinite { + shouldRepeat = true + } } } }) @@ -342,7 +355,8 @@ final class DrawingTextEntityView: DrawingEntityView, UITextViewDelegate { textColor = color.lightness > 0.99 ? UIColor.black : UIColor.white } - if !customEmojiRects.isEmpty { + self.emojiRects = customEmojiRects + if !customEmojiRects.isEmpty && !shouldRepeat { let customEmojiContainerView: CustomEmojiContainerView if let current = self.customEmojiContainerView { customEmojiContainerView = current @@ -354,15 +368,22 @@ final class DrawingTextEntityView: DrawingEntityView, UITextViewDelegate { return emojiViewProvider(emoji) }) customEmojiContainerView.isUserInteractionEnabled = false - self.textView.addSubview(customEmojiContainerView) + customEmojiContainerView.center = customEmojiContainerView.center.offsetBy(dx: 0.0, dy: 10.0) + self.addSubview(customEmojiContainerView) self.customEmojiContainerView = customEmojiContainerView } - customEmojiContainerView.update(fontSize: self.displayFontSize, textColor: textColor, emojiRects: customEmojiRects) + customEmojiContainerView.update(fontSize: self.displayFontSize * 0.8, textColor: textColor, emojiRects: customEmojiRects) } else if let customEmojiContainerView = self.customEmojiContainerView { customEmojiContainerView.removeFromSuperview() self.customEmojiContainerView = nil } + + if shouldRepeat { + Queue.mainQueue().after(0.01) { + self.updateEntities() + } + } } func beginEditing(accessoryView: UIView?) { @@ -526,9 +547,6 @@ final class DrawingTextEntityView: DrawingEntityView, UITextViewDelegate { super.layoutSubviews() var rect = self.bounds -// CGFloat correction = _textView.font.pointSize * _font.sizeCorrection; -// rect.origin.y += correction; -// rect.size.height -= correction; rect = rect.offsetBy(dx: 0.0, dy: 10.0) // CGRectOffset(rect, 0.0f, 10.0f); self.textView.frame = rect } @@ -636,7 +654,6 @@ final class DrawingTextEntityView: DrawingEntityView, UITextViewDelegate { self.updateEntities() } - super.update(animated: animated) } @@ -671,11 +688,39 @@ final class DrawingTextEntityView: DrawingEntityView, UITextViewDelegate { func getRenderImage() -> UIImage? { let rect = self.bounds UIGraphicsBeginImageContextWithOptions(rect.size, false, 1.0) - self.drawHierarchy(in: rect, afterScreenUpdates: false) + self.textView.drawHierarchy(in: rect.offsetBy(dx: 0.0, dy: 10.0), afterScreenUpdates: true) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image } + + func getRenderSubEntities() -> [DrawingStickerEntity] { + let textSize = self.textView.bounds.size + let textPosition = self.textEntity.position + let scale = self.textEntity.scale + let rotation = self.textEntity.rotation + + let itemSize: CGFloat = floor(24.0 * self.displayFontSize * 0.8 / 17.0) + + var entities: [DrawingStickerEntity] = [] + for (emojiRect, emojiAttribute) in self.emojiRects { + guard let file = emojiAttribute.file else { + continue + } + let emojiTextPosition = emojiRect.offsetBy(dx: 0.0, dy: 10.0).center.offsetBy(dx: -textSize.width / 2.0, dy: -textSize.height / 2.0) + + let entity = DrawingStickerEntity(file: file) + entity.referenceDrawingSize = CGSize(width: itemSize * 2.5, height: itemSize * 2.5) + entity.scale = scale + entity.position = textPosition.offsetBy( + dx: (emojiTextPosition.x * cos(rotation) + emojiTextPosition.y * sin(rotation)) * scale, + dy: (emojiTextPosition.y * cos(rotation) + emojiTextPosition.x * sin(rotation)) * scale + ) + entity.rotation = rotation + entities.append(entity) + } + return entities + } } final class DrawingTextEntititySelectionView: DrawingEntitySelectionView, UIGestureRecognizerDelegate { diff --git a/submodules/DrawingUI/Sources/DrawingTools.swift b/submodules/DrawingUI/Sources/DrawingTools.swift index de26b4b13a..24f2756743 100644 --- a/submodules/DrawingUI/Sources/DrawingTools.swift +++ b/submodules/DrawingUI/Sources/DrawingTools.swift @@ -267,27 +267,6 @@ final class NeonTool: DrawingElement { self.path = bezierPath -// if self.arrow && polyline.isComplete, polyline.points.count > 2 { -// let lastPoint = lastPosition -// var secondPoint = polyline.points[polyline.points.count - 2] -// if secondPoint.location.distance(to: lastPoint) < self.renderArrowLineWidth { -// secondPoint = polyline.points[polyline.points.count - 3] -// } -// let angle = lastPoint.angle(to: secondPoint.location) -// let point1 = lastPoint.pointAt(distance: self.renderArrowLength, angle: angle - CGFloat.pi * 0.15) -// let point2 = lastPoint.pointAt(distance: self.renderArrowLength, angle: angle + CGFloat.pi * 0.15) -// -// let arrowPath = UIBezierPath() -// arrowPath.move(to: point2) -// arrowPath.addLine(to: lastPoint) -// arrowPath.addLine(to: point1) -// let arrowThickPath = arrowPath.cgPath.copy(strokingWithWidth: self.renderArrowLineWidth, lineCap: .round, lineJoin: .round, miterLimit: 0.0) -// -// combinedPath.usesEvenOddFillRule = false -// combinedPath.append(UIBezierPath(cgPath: arrowThickPath)) -// } - - let cgPath = bezierPath.path.cgPath.copy(strokingWithWidth: self.renderLineWidth, lineCap: .round, lineJoin: .round, miterLimit: 0.0) self.renderPath = cgPath diff --git a/submodules/DrawingUI/Sources/DrawingView.swift b/submodules/DrawingUI/Sources/DrawingView.swift index 24fdbb8f90..bf2290da8a 100644 --- a/submodules/DrawingUI/Sources/DrawingView.swift +++ b/submodules/DrawingUI/Sources/DrawingView.swift @@ -49,6 +49,7 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw let canRedo: Bool let canClear: Bool let canZoomOut: Bool + let isDrawing: Bool } enum Action { @@ -107,6 +108,8 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw private var previousStrokePoint: CGPoint? private var strokeRecognitionTimer: SwiftSignalKit.Timer? + private var isDrawing = false + private func loadTemplates() { func load(_ name: String) { if let url = getAppBundle().url(forResource: name, withExtension: "json"), @@ -249,6 +252,7 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw } else { switch state { case .began: + strongSelf.isDrawing = true strongSelf.previousStrokePoint = nil if strongSelf.uncommitedElement != nil { @@ -264,11 +268,16 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw } if let renderLayer = newElement.setupRenderLayer() { + if let currentDrawingLayer = strongSelf.currentDrawingLayer { + strongSelf.currentDrawingLayer = nil + currentDrawingLayer.removeFromSuperlayer() + } strongSelf.currentDrawingView.layer.addSublayer(renderLayer) strongSelf.currentDrawingLayer = renderLayer } newElement.updatePath(path, state: state) strongSelf.uncommitedElement = newElement + strongSelf.updateInternalState() case .changed: strongSelf.uncommitedElement?.updatePath(path, state: state) @@ -339,16 +348,20 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw } case .ended: + strongSelf.isDrawing = false strongSelf.strokeRecognitionTimer?.invalidate() strongSelf.strokeRecognitionTimer = nil strongSelf.uncommitedElement?.updatePath(path, state: state) Queue.mainQueue().after(0.05) { strongSelf.finishDrawing() } + strongSelf.updateInternalState() case .cancelled: + strongSelf.isDrawing = false strongSelf.strokeRecognitionTimer?.invalidate() strongSelf.strokeRecognitionTimer = nil strongSelf.cancelDrawing() + strongSelf.updateInternalState() } } } @@ -572,9 +585,20 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw self.uncommitedElement = nil self.elements.removeAll() self.redoElements.removeAll() + + let snapshotView = UIImageView(image: self.drawingImage) + snapshotView.frame = self.bounds + self.addSubview(snapshotView) + self.drawingImage = nil self.commit(reset: true) + Queue.mainQueue().justDispatch { + snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak snapshotView] _ in + snapshotView?.removeFromSuperview() + }) + } + self.updateInternalState() self.lassoView.reset() @@ -587,8 +611,18 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw self.uncommitedElement = nil self.redoElements.append(lastElement) self.elements.removeLast() + + let snapshotView = UIImageView(image: self.drawingImage) + snapshotView.frame = self.bounds + self.addSubview(snapshotView) self.commit(reset: true) + Queue.mainQueue().justDispatch { + snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak snapshotView] _ in + snapshotView?.removeFromSuperview() + }) + } + self.updateInternalState() } @@ -600,6 +634,7 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw self.elements.append(lastElement) self.redoElements.removeLast() self.uncommitedElement = lastElement + self.commit(reset: false) self.uncommitedElement = nil @@ -611,13 +646,13 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw func updateToolState(_ state: DrawingToolState) { switch state { case let .pen(brushState): - self.drawingGesturePipeline?.mode = .location + self.drawingGesturePipeline?.mode = .polyline self.tool = .pen self.toolColor = brushState.color self.toolBrushSize = brushState.size self.toolHasArrow = false case let .arrow(brushState): - self.drawingGesturePipeline?.mode = .location + self.drawingGesturePipeline?.mode = .polyline self.tool = .pen self.toolColor = brushState.color self.toolBrushSize = brushState.size @@ -691,7 +726,8 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw canUndo: !self.elements.isEmpty, canRedo: !self.redoElements.isEmpty, canClear: !self.elements.isEmpty, - canZoomOut: self.zoomScale > 1.0 + .ulpOfOne + canZoomOut: self.zoomScale > 1.0 + .ulpOfOne, + isDrawing: self.isDrawing )) } diff --git a/submodules/DrawingUI/Sources/PenTool.swift b/submodules/DrawingUI/Sources/PenTool.swift index 9c4ec8ac47..216106d2a1 100644 --- a/submodules/DrawingUI/Sources/PenTool.swift +++ b/submodules/DrawingUI/Sources/PenTool.swift @@ -2,73 +2,6 @@ import Foundation import UIKit import Display -struct PointWeighted { - let point: CGPoint - let weight: CGFloat - - static let zero = PointWeighted(point: CGPoint.zero, weight: 0) -} - -struct LineSegment { - let start: CGPoint - let end: CGPoint - - var length: CGFloat { - return start.distance(to: end) - } - - func average(with line: LineSegment) -> LineSegment { - return LineSegment(start: start.average(with: line.start), end: end.average(with: line.end)) - } - - func normalLine(from weightedPoint: PointWeighted) -> LineSegment { - return normalLine(withMiddle: weightedPoint.point, weight: weightedPoint.weight) - } - - func normalLine(withMiddle middle: CGPoint, weight: CGFloat) -> LineSegment { - let relativeEnd = start.diff(to: end) - - guard weight != 0 && relativeEnd != CGPoint.zero else { - return LineSegment(start: middle, end: middle) - } - - let moddle = weight / 2 - let lengthK = moddle / length - - let k = CGPoint(x: relativeEnd.x * lengthK, y: relativeEnd.y * lengthK) - - var normalLineStart = CGPoint(x: k.y, y: -k.x) - var normalLineEnd = CGPoint(x: -k.y, y: k.x) - - normalLineStart.x += middle.x; - normalLineStart.y += middle.y; - - normalLineEnd.x += middle.x; - normalLineEnd.y += middle.y; - - return LineSegment(start: normalLineStart, end: normalLineEnd) - } -} - - -extension CGPoint { - func average(with point: CGPoint) -> CGPoint { - return CGPoint(x: (x + point.x) * 0.5, y: (y + point.y) * 0.5) - } - - func diff(to point: CGPoint) -> CGPoint { - return CGPoint(x: point.x - x, y: point.y - y) - } - - func forward(to point: CGPoint, by: CGFloat) -> CGPoint { - let diff = diff(to: point) - let distance = sqrt(pow(diff.x, 2) + pow(diff.y, 2)) - let k = by / distance - - return CGPoint(x: point.x + diff.x * k, y: point.y + diff.y * k) - } -} - final class PenTool: DrawingElement { class RenderLayer: SimpleLayer, DrawingRenderLayer { func setup(size: CGSize) { @@ -79,15 +12,12 @@ final class PenTool: DrawingElement { self.frame = bounds } - private var paths: [UIBezierPath] = [] - private var tempPath: UIBezierPath? private var color: UIColor? - fileprivate func draw(paths: [UIBezierPath], tempPath: UIBezierPath?, color: UIColor, rect: CGRect) { - self.paths = paths - self.tempPath = tempPath + private var line: StrokeLine? + fileprivate func draw(line: StrokeLine, color: UIColor, rect: CGRect) { + self.line = line self.color = color - self.setNeedsDisplay(rect.insetBy(dx: -50.0, dy: -50.0)) } @@ -118,21 +48,7 @@ final class PenTool: DrawingElement { } override func draw(in ctx: CGContext) { - guard let color = self.color else { - return - } - - ctx.setFillColor(color.cgColor) - - for path in self.paths { - ctx.addPath(path.cgPath) - ctx.fillPath() - } - - if let tempPath = self.tempPath { - ctx.addPath(tempPath.cgPath) - ctx.fillPath() - } + self.line?.drawInContext(ctx) } } @@ -146,14 +62,12 @@ final class PenTool: DrawingElement { var path: Polyline? var boundingBox: CGRect? - var didSetupArrow = false + private var renderLine: StrokeLine let renderLineWidth: CGFloat let renderArrowLength: CGFloat let renderArrowLineWidth: CGFloat - var bezierPaths: [UIBezierPath] = [] - var tempBezierPath: UIBezierPath? - + var didSetupArrow = false var arrowLeftPath: UIBezierPath? var arrowLeftPoint: CGPoint? var arrowRightPath: UIBezierPath? @@ -167,37 +81,20 @@ final class PenTool: DrawingElement { return self.path?.bounds.offsetBy(dx: self.translation.x, dy: self.translation.y) ?? .zero } - var _points: [Polyline.Point] = [] - var points: [Polyline.Point] { + guard let linePath = self.path else { + return [] + } var points: [Polyline.Point] = [] - var lastPoint: Polyline.Point? - for point in self._points { + for point in linePath.points { points.append(point.offsetBy(self.translation)) - lastPoint = point - } - if let arrowLeftPoint, let lastPoint { - points.append(lastPoint.withLocation(arrowLeftPoint.offsetBy(self.translation))) - } - if let arrowRightPoint, let lastPoint { - points.append(lastPoint.withLocation(arrowRightPoint.offsetBy(self.translation))) } return points } - private let pointsPerLine: Int = 4 - private var nextPointIndex: Int = 0 - private var drawPoints = [PointWeighted](repeating: PointWeighted.zero, count: 4) - - private var arrowParams: (CGPoint, CGFloat)? - func containsPoint(_ point: CGPoint) -> Bool { - for path in self.bezierPaths { - if path.contains(point.offsetBy(CGPoint(x: -self.translation.x, y: -self.translation.y))) { - return true - } - } return false + // return self.renderPath?.contains(point.offsetBy(CGPoint(x: -self.translation.x, y: -self.translation.y))) ?? false } func hasPointsInsidePath(_ path: UIBezierPath) -> Bool { @@ -220,15 +117,15 @@ final class PenTool: DrawingElement { self.lineWidth = lineWidth self.arrow = arrow - let minLineWidth = max(1.0, max(drawingSize.width, drawingSize.height) * 0.0015) - let maxLineWidth = max(10.0, max(drawingSize.width, drawingSize.height) * 0.05) + let minLineWidth = max(1.0, max(drawingSize.width, drawingSize.height) * 0.002) + let maxLineWidth = max(10.0, max(drawingSize.width, drawingSize.height) * 0.07) let lineWidth = minLineWidth + (maxLineWidth - minLineWidth) * lineWidth self.renderLineWidth = lineWidth - self.renderArrowLength = lineWidth * 7.0 - self.renderArrowLineWidth = lineWidth * 2.0 + self.renderArrowLength = lineWidth * 3.0 + self.renderArrowLineWidth = lineWidth * 0.8 - self.path = Polyline(points: []) + self.renderLine = StrokeLine(color: color.toUIColor(), minLineWidth: minLineWidth + (lineWidth - minLineWidth) * 0.3, lineWidth: lineWidth) } func finishArrow(_ completion: @escaping () -> Void) { @@ -248,57 +145,47 @@ final class PenTool: DrawingElement { return layer } - var lastPoint: CGPoint? - func updateWithLocation(_ point: CGPoint, ended: Bool = false) { - if ended { - self.lastPoint = self.drawPoints[self.nextPointIndex - 1].point - - if let path = tempBezierPath { - bezierPaths.last?.append(path) - } - tempBezierPath = nil - nextPointIndex = 0 - } else { - addPoint(point) - } - } - + var previousPoint: CGPoint? func updatePath(_ path: DrawingGesturePipeline.DrawingResult, state: DrawingGesturePipeline.DrawingGestureState) { - guard case let .location(point) = path else { + guard case let .polyline(line) = path, let point = line.points.last else { return } - - self._points.append(point) - self.path?.points.append(point) + self.path = line - switch state { - case .began: - addPoint(point.location) - case .changed: - if self._points.count > 1 { - self.updateTouchPoints(point: self._points[self._points.count - 1].location, previousPoint: self._points[self._points.count - 2].location) - self.updateWithLocation(point.location) - } - case .ended: - self.updateTouchPoints(point: self._points[self._points.count - 1].location, previousPoint: self._points[self._points.count - 2].location) - self.updateWithLocation(point.location, ended: true) - + let filterDistance: CGFloat + if point.velocity > 1200 { + filterDistance = 75.0 + } else { + filterDistance = 35.0 + } + + if let previousPoint, point.location.distance(to: previousPoint) < filterDistance, state == .changed, self.renderLine.ready { + return + } + self.previousPoint = point.location + + let rect = self.renderLine.draw(at: point) + if let currentRenderLayer = self.currentRenderLayer as? RenderLayer { + currentRenderLayer.draw(line: self.renderLine, color: self.color.toUIColor(), rect: rect) + } + + if state == .ended { if self.arrow { let points = self.path?.points ?? [] - var direction: CGFloat? - let p2 = points[points.count - 1].location - for i in 1 ..< min(points.count - 2, 12) { - let p1 = points[points.count - 1 - i].location - if p1.distance(to: p2) > renderArrowLength * 0.5 { - direction = p2.angle(to: p1) - break + var direction: CGFloat? + if points.count > 4 { + let p2 = points[points.count - 1].location + for i in 1 ..< min(points.count - 2, 12) { + let p1 = points[points.count - 1 - i].location + if p1.distance(to: p2) > renderArrowLength * 0.5 { + direction = p2.angle(to: p1) + break + } } } - if let point = self.lastPoint, let direction { - self.arrowParams = (point, direction) - + if let point = points.last?.location, let direction { let arrowLeftPath = UIBezierPath() arrowLeftPath.move(to: point) let leftPoint = point.pointAt(distance: self.renderArrowLength, angle: direction - 0.45) @@ -316,127 +203,7 @@ final class PenTool: DrawingElement { self.arrowRightPoint = rightPoint } } - case .cancelled: - break } - - if let currentRenderLayer = self.currentRenderLayer as? RenderLayer { - currentRenderLayer.draw(paths: self.bezierPaths, tempPath: self.tempBezierPath, color: self.color.toUIColor(), rect: CGRect(origin: .zero, size: self.drawingSize)) - } - } - - private let minDistance: CGFloat = 2 - - private func addPoint(_ point: CGPoint) { - if isFirstPoint { - startNewLine(from: PointWeighted(point: point, weight: 2.0)) - } else { - let previousPoint = self.drawPoints[nextPointIndex - 1].point - guard previousPoint.distance(to: point) >= minDistance else { - return - } - if isStartOfNextLine { - finalizeBezier(nextLineStartPoint: point) - startNewLine(from: self.drawPoints[3]) - } - - let weightedPoint = PointWeighted(point: point, weight: weightForLine(between: previousPoint, and: point)) - addPoint(point: weightedPoint) - } - - let newBezier = generateBezierPath(withPointIndex: nextPointIndex - 1) - self.tempBezierPath = newBezier - } - - private var isFirstPoint: Bool { - return nextPointIndex == 0 - } - - private var isStartOfNextLine: Bool { - return nextPointIndex >= pointsPerLine - } - - private func startNewLine(from weightedPoint: PointWeighted) { - drawPoints[0] = weightedPoint - nextPointIndex = 1 - } - - private func addPoint(point: PointWeighted) { - drawPoints[nextPointIndex] = point - nextPointIndex += 1 - } - - private func finalizeBezier(nextLineStartPoint: CGPoint) { - let touchPoint2 = drawPoints[2].point - let newTouchPoint3 = touchPoint2.average(with: nextLineStartPoint) - drawPoints[3] = PointWeighted(point: newTouchPoint3, weight: weightForLine(between: touchPoint2, and: newTouchPoint3)) - - guard let bezier = generateBezierPath(withPointIndex: 3) else { - return - } - self.bezierPaths.append(bezier) - - } - - private func generateBezierPath(withPointIndex index: Int) -> UIBezierPath? { - switch index { - case 0: - return UIBezierPath.dot(with: drawPoints[0]) - case 1: - return UIBezierPath.curve(withPointA: drawPoints[0], pointB: drawPoints[1]) - case 2: - return UIBezierPath.curve(withPointA: drawPoints[0], pointB: drawPoints[1], pointC: drawPoints[2]) - case 3: - return UIBezierPath.curve(withPointA: drawPoints[0], pointB: drawPoints[1], pointC: drawPoints[2], pointD: drawPoints[3]) - default: - return nil - } - } - - private func weightForLine(between pointA: CGPoint, and pointB: CGPoint) -> CGFloat { - let length = pointA.distance(to: pointB) - - let limitRange: CGFloat = 50 - - var lowerer: CGFloat = 0.2 - var constant: CGFloat = 2 - - let toolWidth = self.renderLineWidth - - constant = toolWidth - 3.0 - lowerer = 0.25 * toolWidth / 10.0 - - - let r = min(limitRange, length) - - return (r * lowerer) + constant - } - - public var firstPoint: CGPoint = .zero - public var currentPoint: CGPoint = .zero - private var previousPoint: CGPoint = .zero - private var previousPreviousPoint: CGPoint = .zero - - private func setTouchPoints(point: CGPoint, previousPoint: CGPoint) { - self.previousPoint = previousPoint - self.previousPreviousPoint = previousPoint - self.currentPoint = point - } - - private func updateTouchPoints(point: CGPoint, previousPoint: CGPoint) { - self.previousPreviousPoint = self.previousPoint - self.previousPoint = previousPoint - self.currentPoint = point - } - - private func calculateMidPoint(_ p1 : CGPoint, p2 : CGPoint) -> CGPoint { - return CGPoint(x: (p1.x + p2.x) * 0.5, y: (p1.y + p2.y) * 0.5); - } - - private func getMidPoints() -> (CGPoint, CGPoint) { - let mid1 : CGPoint = calculateMidPoint(previousPoint, p2: previousPreviousPoint) - let mid2 : CGPoint = calculateMidPoint(currentPoint, p2: previousPoint) - return (mid1, mid2) } func draw(in context: CGContext, size: CGSize) { @@ -445,12 +212,8 @@ final class PenTool: DrawingElement { context.translateBy(x: self.translation.x, y: self.translation.y) context.setShouldAntialias(true) - - context.setFillColor(self.color.toCGColor()) - for path in self.bezierPaths { - context.addPath(path.cgPath) - context.fillPath() - } + + self.renderLine.drawInContext(context) if let arrowLeftPath, let arrowRightPath { context.setStrokeColor(self.color.toCGColor()) @@ -468,101 +231,210 @@ final class PenTool: DrawingElement { } } -extension UIBezierPath { - - class func dot(with weightedPoint: PointWeighted) -> UIBezierPath { - let path = UIBezierPath() - path.addArc(withCenter: weightedPoint.point, radius: weightedPoint.weight / 2.0, startAngle: 0, endAngle: CGFloat.pi * 2, clockwise: true) - - return path - } - - class func curve(withPointA pointA: PointWeighted, pointB: PointWeighted) -> UIBezierPath { - let lines = normalToLine(from: pointA, to: pointB) - - let path = UIBezierPath() - path.move(to: lines.0.start) - path.addLine(to: lines.1.start) - let arcA = lines.1.start - let arcB = lines.1.end - path.addQuadCurve(to: arcB, controlPoint: pointA.point.forward(to: pointB.point, by: arcA.distance(to: arcB) / 1.1)) - path.addLine(to: lines.0.end) - path.close() - - return path +private class StrokeLine { + struct Segment { + let a: CGPoint + let b: CGPoint + let c: CGPoint + let d: CGPoint + let abWidth: CGFloat + let cdWidth: CGFloat } - class func curve(withPointA pointA: PointWeighted, pointB: PointWeighted, pointC: PointWeighted) -> UIBezierPath { - let linesAB = normalToLine(from: pointA, to: pointB) - let linesBC = normalToLine(from: pointB, to: pointC) + struct Point { + let position: CGPoint + let width: CGFloat - let lineA = linesAB.0 - let lineB = linesAB.1.average(with: linesBC.0) - let lineC = linesBC.1 - - let path = UIBezierPath() - path.move(to: lineA.start) - path.addQuadCurve(to: lineC.start, controlPoint: lineB.start) - let arcA = lineC.start - let arcB = lineC.end - - path.addQuadCurve(to: arcB, controlPoint: pointB.point.forward(to: pointC.point, by: arcA.distance(to: arcB) / 1.1)) - path.addQuadCurve(to: lineA.end, controlPoint: lineB.end) - path.close() - - return path - } - - class func line(withPointA pointA: PointWeighted, pointB: PointWeighted, pointC: PointWeighted, prevLineSegment: LineSegment, roundedEnd: Bool = true) -> (UIBezierPath, LineSegment) { - let linesAB = normalToLine(from: pointA, to: pointB) - let linesBC = normalToLine(from: pointB, to: pointC) - -// let lineA = linesAB.0 - let lineB = linesAB.1.average(with: linesBC.0) - let lineC = linesBC.1 - - let path = UIBezierPath() - path.move(to: prevLineSegment.start) - path.addQuadCurve(to: lineC.start, controlPoint: lineB.start) - if roundedEnd { - let arcA = lineC.start - let arcB = lineC.end - - path.addQuadCurve(to: arcB, controlPoint: pointB.point.forward(to: pointC.point, by: arcA.distance(to: arcB) / 1.1)) - } else { - path.addLine(to: lineC.end) + init(position: CGPoint, width: CGFloat) { + self.position = position + self.width = width } - path.addQuadCurve(to: prevLineSegment.end, controlPoint: lineB.end) - path.close() + } + + private(set) var points: [Point] = [] + private var smoothPoints: [Point] = [] + private var segments: [Segment] = [] - return (path, lineC) + private let minLineWidth: CGFloat + let lineWidth: CGFloat + private var lastWidth: CGFloat? + + var ready = false + + let color: UIColor + + init(color: UIColor, minLineWidth: CGFloat, lineWidth: CGFloat) { + self.color = color + self.minLineWidth = minLineWidth + self.lineWidth = lineWidth } - class func curve(withPointA pointA: PointWeighted, pointB: PointWeighted, pointC: PointWeighted, pointD: PointWeighted) -> UIBezierPath { - let linesAB = normalToLine(from: pointA, to: pointB) - let linesBC = normalToLine(from: pointB, to: pointC) - let linesCD = normalToLine(from: pointC, to: pointD) + func draw(at point: Polyline.Point) -> CGRect { + var velocity = point.velocity + if velocity.isZero { + velocity = 600.0 + } + let width = extractLineWidth(from: velocity) + self.lastWidth = width - let lineA = linesAB.0 - let lineB = linesAB.1.average(with: linesBC.0) - let lineC = linesBC.1.average(with: linesCD.0) - let lineD = linesCD.1 - - let path = UIBezierPath() - path.move(to: lineA.start) - path.addCurve(to: lineD.start, controlPoint1: lineB.start, controlPoint2: lineC.start) - let arcA = lineD.start - let arcB = lineD.end - path.addQuadCurve(to: arcB, controlPoint: pointC.point.forward(to: pointD.point, by: arcA.distance(to: arcB) / 1.1)) - path.addCurve(to: lineA.end, controlPoint1: lineC.end, controlPoint2: lineB.end) - path.close() - - return path + let point = Point(position: point.location, width: width) + return appendPoint(point) } - class func normalToLine(from pointA: PointWeighted, to pointB: PointWeighted) -> (LineSegment, LineSegment) { - let line = LineSegment(start: pointA.point, end: pointB.point) + func drawInContext(_ context: CGContext) { + self.drawSegments(self.segments, inContext: context) + } + + func extractLineWidth(from velocity: CGFloat) -> CGFloat { + let minValue = self.minLineWidth + let maxValue = self.lineWidth - return (line.normalLine(from: pointA), line.normalLine(from: pointB)) + var width = max(minValue, min(maxValue + 1.0 - (velocity / 180.0), maxValue)) + if let lastWidth = self.lastWidth { + width = width * 0.2 + lastWidth * 0.8 + } + return width + } + + func appendPoint(_ point: Point) -> CGRect { + self.points.append(point) + + guard self.points.count > 2 else { return .null } + + let index = self.points.count - 1 + let point0 = self.points[index - 2] + let point1 = self.points[index - 1] + let point2 = self.points[index] + + let newSmoothPoints = smoothPoints( + fromPoint0: point0, + point1: point1, + point2: point2 + ) + + let lastOldSmoothPoint = smoothPoints.last + smoothPoints.append(contentsOf: newSmoothPoints) + + guard smoothPoints.count > 1 else { return .null } + + let newSegments: ([Segment], CGRect) = { + guard let lastOldSmoothPoint = lastOldSmoothPoint else { + return segments(fromSmoothPoints: newSmoothPoints) + } + return segments(fromSmoothPoints: [lastOldSmoothPoint] + newSmoothPoints) + }() + segments.append(contentsOf: newSegments.0) + + self.ready = true + + return newSegments.1 + } + + func smoothPoints(fromPoint0 point0: Point, point1: Point, point2: Point) -> [Point] { + var smoothPoints = [Point]() + + let midPoint1 = (point0.position + point1.position) * 0.5 + let midPoint2 = (point1.position + point2.position) * 0.5 + + let segmentDistance = 3.0 + let distance = midPoint1.distance(to: midPoint2) + let numberOfSegments = min(128, max(floor(distance / segmentDistance), 32)) + + let step = 1.0 / numberOfSegments + for t in stride(from: 0, to: 1, by: step) { + let position = midPoint1 * pow(1 - t, 2) + point1.position * 2 * (1 - t) * t + midPoint2 * t * t + let size = pow(1 - t, 2) * ((point0.width + point1.width) * 0.5) + 2 * (1 - t) * t * point1.width + t * t * ((point1.width + point2.width) * 0.5) + let point = Point(position: position, width: size) + smoothPoints.append(point) + } + + let finalPoint = Point(position: midPoint2, width: (point1.width + point2.width) * 0.5) + smoothPoints.append(finalPoint) + + return smoothPoints + } + + func segments(fromSmoothPoints smoothPoints: [Point]) -> ([Segment], CGRect) { + var segments: [Segment] = [] + var updateRect = CGRect.null + for i in 1 ..< smoothPoints.count { + let previousPoint = smoothPoints[i - 1].position + let previousWidth = smoothPoints[i - 1].width + let currentPoint = smoothPoints[i].position + let currentWidth = smoothPoints[i].width + let direction = currentPoint - previousPoint + + guard !currentPoint.isEqual(to: previousPoint, epsilon: 0.0001) else { + continue + } + + var perpendicular = CGPoint(x: -direction.y, y: direction.x) + let length = perpendicular.length + if length > 0.0 { + perpendicular = perpendicular / length + } + + let a = previousPoint + perpendicular * previousWidth / 2 + let b = previousPoint - perpendicular * previousWidth / 2 + let c = currentPoint + perpendicular * currentWidth / 2 + let d = currentPoint - perpendicular * currentWidth / 2 + + let ab: CGPoint = { + let center = (b + a) / 2 + let radius = center - b + return .init(x: center.x - radius.y, y: center.y + radius.x) + }() + let cd: CGPoint = { + let center = (c + d) / 2 + let radius = center - c + return .init(x: center.x + radius.y, y: center.y - radius.x) + }() + + let minX = min(a.x, b.x, c.x, d.x, ab.x, cd.x) + let minY = min(a.y, b.y, c.y, d.y, ab.y, cd.y) + let maxX = max(a.x, b.x, c.x, d.x, ab.x, cd.x) + let maxY = max(a.y, b.y, c.y, d.y, ab.y, cd.y) + + updateRect = updateRect.union(CGRect(x: minX, y: minY, width: maxX - minX, height: maxY - minY)) + + segments.append(Segment(a: a, b: b, c: c, d: d, abWidth: previousWidth, cdWidth: currentWidth)) + } + return (segments, updateRect) + } + + func drawSegments(_ segments: [Segment], inContext context: CGContext) { + for segment in segments { + context.beginPath() + + //let color = [UIColor.red, UIColor.green, UIColor.blue, UIColor.yellow].randomElement()! + + context.setStrokeColor(color.cgColor) + context.setFillColor(color.cgColor) + + context.move(to: segment.b) + + let abStartAngle = atan2(segment.b.y - segment.a.y, segment.b.x - segment.a.x) + context.addArc( + center: (segment.a + segment.b)/2, + radius: segment.abWidth/2, + startAngle: abStartAngle, + endAngle: abStartAngle + .pi, + clockwise: true + ) + context.addLine(to: segment.c) + + let cdStartAngle = atan2(segment.c.y - segment.d.y, segment.c.x - segment.d.x) + context.addArc( + center: (segment.c + segment.d) / 2, + radius: segment.cdWidth/2, + startAngle: cdStartAngle, + endAngle: cdStartAngle + .pi, + clockwise: true + ) + context.closePath() + + context.fillPath() + context.strokePath() + } } } diff --git a/submodules/DrawingUI/Sources/StickerPickerScreen.swift b/submodules/DrawingUI/Sources/StickerPickerScreen.swift index 3bc684a0b4..11d1e54f5d 100644 --- a/submodules/DrawingUI/Sources/StickerPickerScreen.swift +++ b/submodules/DrawingUI/Sources/StickerPickerScreen.swift @@ -156,7 +156,8 @@ private final class StickerSelectionComponent: Component { hiddenInputHeight: 0.0, inputHeight: 0.0, displayBottomPanel: true, - isExpanded: true + isExpanded: true, + clipContentToTopPanel: false )), environment: {}, containerSize: availableSize diff --git a/submodules/DrawingUI/Sources/TextSettingsComponent.swift b/submodules/DrawingUI/Sources/TextSettingsComponent.swift index fb750e347f..915f755365 100644 --- a/submodules/DrawingUI/Sources/TextSettingsComponent.swift +++ b/submodules/DrawingUI/Sources/TextSettingsComponent.swift @@ -181,13 +181,15 @@ final class TextFontComponent: Component { let values: [DrawingTextFont] let selectedValue: DrawingTextFont + let tag: AnyObject? let updated: (DrawingTextFont) -> Void - init(styleButton: AnyComponent, alignmentButton: AnyComponent, values: [DrawingTextFont], selectedValue: DrawingTextFont, updated: @escaping (DrawingTextFont) -> Void) { + init(styleButton: AnyComponent, alignmentButton: AnyComponent, values: [DrawingTextFont], selectedValue: DrawingTextFont, tag: AnyObject?, updated: @escaping (DrawingTextFont) -> Void) { self.styleButton = styleButton self.alignmentButton = alignmentButton self.values = values self.selectedValue = selectedValue + self.tag = tag self.updated = updated } @@ -195,7 +197,7 @@ final class TextFontComponent: Component { return lhs.styleButton == rhs.styleButton && lhs.alignmentButton == rhs.alignmentButton && lhs.values == rhs.values && lhs.selectedValue == rhs.selectedValue } - public final class View: UIView { + final class View: UIView, ComponentTaggedView { private let styleButtonHost: ComponentView private let alignmentButtonHost: ComponentView @@ -206,8 +208,19 @@ final class TextFontComponent: Component { private let maskCenter = SimpleLayer() private let maskRight = SimpleGradientLayer() + 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 { + let tag = tag as AnyObject + if componentTag === tag { + return true + } + } + return false + } + override init(frame: CGRect) { if #available(iOS 11.0, *) { self.scrollView.contentInsetAdjustmentBehavior = .never @@ -257,8 +270,57 @@ final class TextFontComponent: Component { } } + 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 + } + } + } + } + + 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, transition: Transition) -> CGSize { + self.component = component self.updated = component.updated var contentWidth: CGFloat = 10.0 @@ -362,6 +424,7 @@ final class TextSettingsComponent: CombinedComponent { let alignment: DrawingTextAlignment let font: DrawingTextFont let isEmojiKeyboard: Bool + let tag: AnyObject? let presentColorPicker: () -> Void let presentFastColorPicker: (GenericComponentViewTag) -> Void @@ -378,6 +441,7 @@ final class TextSettingsComponent: CombinedComponent { alignment: DrawingTextAlignment, font: DrawingTextFont, isEmojiKeyboard: Bool, + tag: AnyObject?, presentColorPicker: @escaping () -> Void = {}, presentFastColorPicker: @escaping (GenericComponentViewTag) -> Void = { _ in }, updateFastColorPickerPan: @escaping (CGPoint) -> Void = { _ in }, @@ -392,6 +456,7 @@ final class TextSettingsComponent: CombinedComponent { self.alignment = alignment self.font = font self.isEmojiKeyboard = isEmojiKeyboard + self.tag = tag self.presentColorPicker = presentColorPicker self.presentFastColorPicker = presentFastColorPicker self.updateFastColorPickerPan = updateFastColorPickerPan @@ -459,7 +524,7 @@ final class TextSettingsComponent: CombinedComponent { func makeState() -> State { State() } - + static var body: Body { let colorButton = Child(ColorSwatchComponent.self) let colorButtonTag = GenericComponentViewTag() @@ -554,6 +619,7 @@ final class TextSettingsComponent: CombinedComponent { ), values: DrawingTextFont.allCases, selectedValue: component.font, + tag: component.tag, updated: { font in updateFont(font) } @@ -723,6 +789,7 @@ final class TextSizeSliderComponent: Component { if let size = self.validSize, let component = self.component { let _ = self.updateLayout(size: size, component: component, transition: .easeInOut(duration: 0.2)) } + self.released() default: break } diff --git a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift index 35948a3a70..cae2ef44a7 100644 --- a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift +++ b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift @@ -1567,7 +1567,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable { if !items.isEmpty { items.append(.separator) } - items.append(.action(ContextMenuActionItem(text: hasSpoilers ? "Disable Spoiler Effect" : "Spoiler Effect", icon: { _ in return nil }, animationName: "anim_spoiler", action: { [weak self] _, f in + items.append(.action(ContextMenuActionItem(text: hasSpoilers ? strings.Attachment_DisableSpoiler : strings.Attachment_EnableSpoiler, icon: { _ in return nil }, animationName: "anim_spoiler", action: { [weak self] _, f in f(.default) guard let strongSelf = self else { return diff --git a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift index 617ac521da..0aa21649e4 100644 --- a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift +++ b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift @@ -32,15 +32,20 @@ public func peerInfoProfilePhotos(context: AccountContext, peerId: EnginePeer.Id |> distinctUntilChanged |> mapToSignal { entries -> Signal<(Bool, [AvatarGalleryEntry])?, NoError> in if let entries = entries { - if let firstEntry = entries.first { + if var firstEntry = entries.first { return context.account.postbox.peerView(id: peerId) |> mapToSignal { peerView -> Signal<(Bool, [AvatarGalleryEntry])?, NoError>in if let peer = peerViewMainPeer(peerView) { var secondEntry: TelegramMediaImage? var lastEntry: TelegramMediaImage? if let cachedData = peerView.cachedData as? CachedUserData { - if firstEntry.representations.first?.representation.isPersonal == true, case let .known(photo) = cachedData.photo { - secondEntry = photo + if let firstRepresentation = firstEntry.representations.first, firstRepresentation.representation.isPersonal { + if firstRepresentation.representation.hasVideo, case let .known(photo) = cachedData.personalPhoto, let peerReference = PeerReference(peer) { + firstEntry = .topImage(firstEntry.representations, photo?.videoRepresentations.map { VideoRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatar(peer: peerReference, resource: $0.resource)) } ?? [], firstEntry.peer, firstEntry.indexData, firstEntry.immediateThumbnailData, nil) + } + if case let .known(photo) = cachedData.photo { + secondEntry = photo + } } if case let .known(photo) = cachedData.fallbackPhoto { lastEntry = photo @@ -329,7 +334,7 @@ public func fetchedAvatarGalleryEntries(engine: TelegramEngine, account: Account } else { var photos = photos if let secondEntry { - photos.insert(TelegramPeerPhoto(image: secondEntry, reference: secondEntry.reference, date: 0, index: 1, totalCount: 0, messageId: nil), at: 1) + photos.insert(TelegramPeerPhoto(image: secondEntry, reference: secondEntry.reference, date: photos.first?.date ?? 0, index: 1, totalCount: 0, messageId: nil), at: 1) } if let lastEntry { photos.append(TelegramPeerPhoto(image: lastEntry, reference: lastEntry.reference, date: 0, index: photos.count, totalCount: 0, messageId: nil)) @@ -337,7 +342,11 @@ public func fetchedAvatarGalleryEntries(engine: TelegramEngine, account: Account for photo in photos { let indexData = GalleryItemIndexData(position: index, totalCount: Int32(photos.count)) if result.isEmpty, let first = initialEntries.first { - result.append(.image(photo.image.imageId, photo.image.reference, first.representations, photo.image.videoRepresentations.map({ VideoRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData, nil, false)) + var videoRepresentations: [VideoRepresentationWithReference] = photo.image.videoRepresentations.map({ VideoRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }) + if videoRepresentations.isEmpty { + videoRepresentations = first.videoRepresentations + } + result.append(.image(photo.image.imageId, photo.image.reference, first.representations, videoRepresentations, peer, secondEntry != nil ? 0 : photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData, nil, false)) } else { result.append(.image(photo.image.imageId, photo.image.reference, photo.image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), photo.image.videoRepresentations.map({ VideoRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData, nil, photo.image.id == lastEntry?.id)) } diff --git a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryItemFooterContentNode.swift b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryItemFooterContentNode.swift index e770298e0e..de52914c8c 100644 --- a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryItemFooterContentNode.swift +++ b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryItemFooterContentNode.swift @@ -108,8 +108,10 @@ final class AvatarGalleryItemFooterContentNode: GalleryFooterContentNode { var canShare = true switch entry { case let .image(_, _, _, videoRepresentations, peer, date, _, _, _, _, _): - nameText = peer.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "" - if let date = date { + if date != 0 { + nameText = peer.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "" + } + if let date = date, date != 0 { dateText = humanReadableStringForTimestamp(strings: self.strings, dateTimeFormat: self.dateTimeFormat, timestamp: date).string } diff --git a/submodules/PeerInfoUI/Sources/DeviceContactInfoController.swift b/submodules/PeerInfoUI/Sources/DeviceContactInfoController.swift index 78af966f4f..2e3299e879 100644 --- a/submodules/PeerInfoUI/Sources/DeviceContactInfoController.swift +++ b/submodules/PeerInfoUI/Sources/DeviceContactInfoController.swift @@ -1,6 +1,7 @@ import Foundation import UIKit import Display +import AsyncDisplayKit import SwiftSignalKit import Postbox import TelegramCore @@ -21,6 +22,8 @@ import ItemListAddressItem import LocalizedPeerData import PhoneNumberFormat import UndoUI +import GalleryUI +import PeerAvatarGalleryUI private enum DeviceContactInfoAction { case sendMessage @@ -45,8 +48,9 @@ private final class DeviceContactInfoControllerArguments { let openAddress: (DeviceContactAddressData) -> Void let displayCopyContextMenu: (DeviceContactInfoEntryTag, String) -> Void let updateShareViaException: (Bool) -> Void + let openAvatar: (Peer) -> Void - init(context: AccountContext, isPlain: Bool, updateEditingName: @escaping (ItemListAvatarAndNameInfoItemName) -> Void, updatePhone: @escaping (Int64, String) -> Void, updatePhoneLabel: @escaping (Int64, String) -> Void, deletePhone: @escaping (Int64) -> Void, setPhoneIdWithRevealedOptions: @escaping (Int64?, Int64?) -> Void, addPhoneNumber: @escaping () -> Void, performAction: @escaping (DeviceContactInfoAction) -> Void, toggleSelection: @escaping (DeviceContactInfoDataId) -> Void, callPhone: @escaping (String) -> Void, openUrl: @escaping (String) -> Void, openAddress: @escaping (DeviceContactAddressData) -> Void, displayCopyContextMenu: @escaping (DeviceContactInfoEntryTag, String) -> Void, updateShareViaException: @escaping (Bool) -> Void) { + init(context: AccountContext, isPlain: Bool, updateEditingName: @escaping (ItemListAvatarAndNameInfoItemName) -> Void, updatePhone: @escaping (Int64, String) -> Void, updatePhoneLabel: @escaping (Int64, String) -> Void, deletePhone: @escaping (Int64) -> Void, setPhoneIdWithRevealedOptions: @escaping (Int64?, Int64?) -> Void, addPhoneNumber: @escaping () -> Void, performAction: @escaping (DeviceContactInfoAction) -> Void, toggleSelection: @escaping (DeviceContactInfoDataId) -> Void, callPhone: @escaping (String) -> Void, openUrl: @escaping (String) -> Void, openAddress: @escaping (DeviceContactAddressData) -> Void, displayCopyContextMenu: @escaping (DeviceContactInfoEntryTag, String) -> Void, updateShareViaException: @escaping (Bool) -> Void, openAvatar: @escaping (Peer) -> Void) { self.context = context self.isPlain = isPlain self.updateEditingName = updateEditingName @@ -62,6 +66,7 @@ private final class DeviceContactInfoControllerArguments { self.openAddress = openAddress self.displayCopyContextMenu = displayCopyContextMenu self.updateShareViaException = updateShareViaException + self.openAvatar = openAvatar } } @@ -122,7 +127,7 @@ private enum DeviceContactInfoEntryId: Hashable { } private enum DeviceContactInfoEntry: ItemListNodeEntry { - case info(Int, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, peer: Peer, state: ItemListAvatarAndNameInfoItemState, job: String?, isPlain: Bool) + case info(Int, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, peer: Peer, state: ItemListAvatarAndNameInfoItemState, job: String?, isPlain: Bool, hiddenAvatar: TelegramMediaImageRepresentation?) case invite(Int, PresentationTheme, String) case sendMessage(Int, PresentationTheme, String) @@ -204,8 +209,8 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry { static func ==(lhs: DeviceContactInfoEntry, rhs: DeviceContactInfoEntry) -> Bool { switch lhs { - case let .info(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsPeer, lhsState, lhsJobSummary, lhsIsPlain): - if case let .info(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer, rhsState, rhsJobSummary, rhsIsPlain) = rhs { + case let .info(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsPeer, lhsState, lhsJobSummary, lhsIsPlain, lhsHiddenAvatar): + if case let .info(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer, rhsState, rhsJobSummary, rhsIsPlain, rhsHiddenAvatar) = rhs { if lhsIndex != rhsIndex { return false } @@ -230,6 +235,9 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry { if lhsIsPlain != rhsIsPlain { return false } + if lhsHiddenAvatar != rhsHiddenAvatar { + return false + } return true } else { return false @@ -347,7 +355,7 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry { private var sortIndex: Int { switch self { - case let .info(index, _, _, _, _, _, _, _): + case let .info(index, _, _, _, _, _, _, _, _): return index case let .sendMessage(index, _, _): return index @@ -395,11 +403,14 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry { func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem { let arguments = arguments as! DeviceContactInfoControllerArguments switch self { - case let .info(_, _, _, dateTimeFormat, peer, state, jobSummary, _): + case let .info(_, _, _, dateTimeFormat, peer, state, jobSummary, _, hiddenAvatar): return ItemListAvatarAndNameInfoItem(accountContext: arguments.context, presentationData: presentationData, dateTimeFormat: dateTimeFormat, mode: .contact, peer: EnginePeer(peer), presence: nil, label: jobSummary, memberCount: nil, state: state, sectionId: self.section, style: arguments.isPlain ? .plain : .blocks(withTopInset: false, withExtendedBottomInset: true), editingNameUpdated: { editingName in arguments.updateEditingName(editingName) }, avatarTapped: { - }, context: nil, call: nil) + if peer.smallProfileImage != nil { + arguments.openAvatar(peer) + } + }, context: ItemListAvatarAndNameInfoItemContext(hiddenAvatarRepresentation: hiddenAvatar), call: nil) case let .sendMessage(_, _, title): return ItemListActionItem(presentationData: presentationData, title: title, kind: .generic, alignment: .natural, sectionId: self.section, style: arguments.isPlain ? .plain : .blocks, action: { arguments.performAction(.sendMessage) @@ -614,7 +625,7 @@ private func filteredContactData(contactData: DeviceContactExtendedData, exclude return DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: contactData.basicData.firstName, lastName: contactData.basicData.lastName, phoneNumbers: phoneNumbers), middleName: contactData.middleName, prefix: contactData.prefix, suffix: contactData.suffix, organization: includeJob ? contactData.organization : "", jobTitle: includeJob ? contactData.jobTitle : "", department: includeJob ? contactData.department : "", emailAddresses: emailAddresses, urls: urls, addresses: addresses, birthdayDate: includeBirthday ? contactData.birthdayDate : nil, socialProfiles: socialProfiles, instantMessagingProfiles: instantMessagingProfiles, note: includeNote ? contactData.note : "") } -private func deviceContactInfoEntries(account: Account, engine: TelegramEngine, presentationData: PresentationData, peer: Peer?, isShare: Bool, shareViaException: Bool, contactData: DeviceContactExtendedData, isContact: Bool, state: DeviceContactInfoState, selecting: Bool, editingPhoneNumbers: Bool) -> [DeviceContactInfoEntry] { +private func deviceContactInfoEntries(account: Account, engine: TelegramEngine, presentationData: PresentationData, peer: Peer?, isShare: Bool, shareViaException: Bool, contactData: DeviceContactExtendedData, isContact: Bool, state: DeviceContactInfoState, selecting: Bool, editingPhoneNumbers: Bool, hiddenAvatar: TelegramMediaImageRepresentation?) -> [DeviceContactInfoEntry] { var entries: [DeviceContactInfoEntry] = [] var editingName: ItemListAvatarAndNameInfoItemName? @@ -652,7 +663,7 @@ private func deviceContactInfoEntries(account: Account, engine: TelegramEngine, firstName = presentationData.strings.Message_Contact } - entries.append(.info(entries.count, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer: peer ?? TelegramUser(id: PeerId(namespace: .max, id: PeerId.Id._internalFromInt64Value(0)), accessHash: nil, firstName: firstName, lastName: isOrganization ? nil : personName.1, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: []), state: ItemListAvatarAndNameInfoItemState(editingName: editingName, updatingName: nil), job: isOrganization ? nil : jobSummary, isPlain: !isShare)) + entries.append(.info(entries.count, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer: peer ?? TelegramUser(id: PeerId(namespace: .max, id: PeerId.Id._internalFromInt64Value(0)), accessHash: nil, firstName: firstName, lastName: isOrganization ? nil : personName.1, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: []), state: ItemListAvatarAndNameInfoItemState(editingName: editingName, updatingName: nil), job: isOrganization ? nil : jobSummary, isPlain: !isShare, hiddenAvatar: hiddenAvatar)) if !selecting { if let _ = peer { @@ -856,6 +867,7 @@ public func deviceContactInfoController(context: AccountContext, updatedPresenta var openAddressImpl: ((DeviceContactAddressData) -> Void)? var inviteImpl: (([String]) -> Void)? var dismissImpl: ((Bool) -> Void)? + var openAvatarImpl: ((Peer) -> Void)? let actionsDisposable = DisposableSet() @@ -1042,12 +1054,15 @@ public func deviceContactInfoController(context: AccountContext, updatedPresenta state.addToPrivacyExceptions = value return state } + }, openAvatar: { peer in + openAvatarImpl?(peer) }) + let hiddenAvatarPromise = Promise(nil) let presentationData = updatedPresentationData?.signal ?? context.sharedContext.presentationData let previousEditingPhoneIds = Atomic?>(value: nil) - let signal = combineLatest(presentationData, statePromise.get(), contactData) - |> map { presentationData, state, peerAndContactData -> (ItemListControllerState, (ItemListNodeState, Any)) in + let signal = combineLatest(presentationData, statePromise.get(), contactData, hiddenAvatarPromise.get()) + |> map { presentationData, state, peerAndContactData, hiddenAvatar -> (ItemListControllerState, (ItemListNodeState, Any)) in var leftNavigationButton: ItemListNavigationButton? switch subject { case .vcard: @@ -1230,7 +1245,7 @@ public func deviceContactInfoController(context: AccountContext, updatedPresenta focusItemTag = DeviceContactInfoEntryTag.editingPhone(insertedPhoneId) } - let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: deviceContactInfoEntries(account: context.account, engine: context.engine, presentationData: presentationData, peer: peerAndContactData.0, isShare: isShare, shareViaException: shareViaException, contactData: peerAndContactData.2, isContact: peerAndContactData.1 != nil, state: state, selecting: selecting, editingPhoneNumbers: editingPhones), style: isShare ? .blocks : .plain, focusItemTag: focusItemTag) + let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: deviceContactInfoEntries(account: context.account, engine: context.engine, presentationData: presentationData, peer: peerAndContactData.0, isShare: isShare, shareViaException: shareViaException, contactData: peerAndContactData.2, isContact: peerAndContactData.1 != nil, state: state, selecting: selecting, editingPhoneNumbers: editingPhones, hiddenAvatar: hiddenAvatar), style: isShare ? .blocks : .plain, focusItemTag: focusItemTag) return (controllerState, (listState, arguments)) } @@ -1329,6 +1344,32 @@ public func deviceContactInfoController(context: AccountContext, updatedPresenta } } } + openAvatarImpl = { [weak controller] peer in + let avatarController = AvatarGalleryController(context: context, peer: peer, replaceRootController: { _, _ in + }) + hiddenAvatarPromise.set( + avatarController.hiddenMedia + |> map { entry -> TelegramMediaImageRepresentation? in + return entry?.representations.first?.representation + } + ) + presentControllerImpl?(avatarController, AvatarGalleryControllerPresentationArguments(transitionArguments: { [weak controller] entry in + var transitionNode: ((ASDisplayNode, CGRect, () -> (UIView?, UIView?)), CGRect)? + controller?.forEachItemNode({ itemNode in + if let itemNode = itemNode as? ItemListAvatarAndNameInfoItemNode { + transitionNode = itemNode.avatarTransitionNode() + } + }) + + if let transitionNode = transitionNode { + return GalleryTransitionArguments(transitionNode: transitionNode.0, addToTransitionSurface: { [weak controller] view in + controller?.view.addSubview(view) + }) + } else { + return nil + } + })) + } return controller } diff --git a/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift b/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift index 0427e8996f..365d4b0aef 100644 --- a/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift +++ b/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift @@ -256,6 +256,8 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode { } } + fileprivate var clipContentToTopPanel: Bool = false + var externalTopPanelContainerImpl: PagerExternalTopPanelContainer? public override var externalTopPanelContainer: UIView? { return self.externalTopPanelContainerImpl @@ -1417,7 +1419,8 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode { hiddenInputHeight: hiddenInputHeight, inputHeight: inputHeight, displayBottomPanel: true, - isExpanded: isExpanded && !self.isEmojiSearchActive + isExpanded: isExpanded && !self.isEmojiSearchActive, + clipContentToTopPanel: self.clipContentToTopPanel )), environment: {}, containerSize: CGSize(width: width, height: expandedHeight) @@ -1895,6 +1898,7 @@ public final class EntityInputView: UIInputView, AttachmentTextInputPanelInputVi chatPeerId: nil ) self.inputNode = inputNode + inputNode.clipContentToTopPanel = hideBackground inputNode.emojiInputInteraction = inputInteraction inputNode.externalTopPanelContainerImpl = nil inputNode.switchToTextInput = { [weak self] in diff --git a/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusSelectionComponent.swift b/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusSelectionComponent.swift index abb10a58ef..89c8e373ac 100644 --- a/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusSelectionComponent.swift +++ b/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusSelectionComponent.swift @@ -189,7 +189,8 @@ public final class EmojiStatusSelectionComponent: Component { hiddenInputHeight: 0.0, inputHeight: 0.0, displayBottomPanel: false, - isExpanded: false + isExpanded: false, + clipContentToTopPanel: false )), environment: {}, containerSize: availableSize diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EntityKeyboard.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EntityKeyboard.swift index d1a261d2fd..b27e146844 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EntityKeyboard.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EntityKeyboard.swift @@ -113,6 +113,7 @@ public final class EntityKeyboardComponent: Component { public let inputHeight: CGFloat public let displayBottomPanel: Bool public let isExpanded: Bool + public let clipContentToTopPanel: Bool public init( theme: PresentationTheme, @@ -141,7 +142,8 @@ public final class EntityKeyboardComponent: Component { hiddenInputHeight: CGFloat, inputHeight: CGFloat, displayBottomPanel: Bool, - isExpanded: Bool + isExpanded: Bool, + clipContentToTopPanel: Bool ) { self.theme = theme self.strings = strings @@ -170,6 +172,7 @@ public final class EntityKeyboardComponent: Component { self.inputHeight = inputHeight self.displayBottomPanel = displayBottomPanel self.isExpanded = isExpanded + self.clipContentToTopPanel = clipContentToTopPanel } public static func ==(lhs: EntityKeyboardComponent, rhs: EntityKeyboardComponent) -> Bool { @@ -230,6 +233,9 @@ public final class EntityKeyboardComponent: Component { if lhs.isExpanded != rhs.isExpanded { return false } + if lhs.clipContentToTopPanel != rhs.clipContentToTopPanel { + return false + } return true } @@ -738,7 +744,8 @@ public final class EntityKeyboardComponent: Component { } strongSelf.isTopPanelHiddenUpdated(isTopPanelHidden: isTopPanelHidden, transition: transition) }, - panelHideBehavior: panelHideBehavior + panelHideBehavior: panelHideBehavior, + clipContentToTopPanel: component.clipContentToTopPanel )), environment: { EntityKeyboardChildEnvironment( diff --git a/submodules/TelegramUI/Components/ForumCreateTopicScreen/Sources/ForumCreateTopicScreen.swift b/submodules/TelegramUI/Components/ForumCreateTopicScreen/Sources/ForumCreateTopicScreen.swift index 16b3b0ddd2..9532cff772 100644 --- a/submodules/TelegramUI/Components/ForumCreateTopicScreen/Sources/ForumCreateTopicScreen.swift +++ b/submodules/TelegramUI/Components/ForumCreateTopicScreen/Sources/ForumCreateTopicScreen.swift @@ -420,7 +420,8 @@ private final class TopicIconSelectionComponent: Component { hiddenInputHeight: 0.0, inputHeight: 0.0, displayBottomPanel: false, - isExpanded: true + isExpanded: true, + clipContentToTopPanel: false )), environment: {}, containerSize: availableSize diff --git a/submodules/TelegramUI/Images.xcassets/Media Editor/Grayscale.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Media Editor/Grayscale.imageset/Contents.json new file mode 100644 index 0000000000..d46f889235 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Media Editor/Grayscale.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "grayscale.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Media Editor/Grayscale.imageset/grayscale.png b/submodules/TelegramUI/Images.xcassets/Media Editor/Grayscale.imageset/grayscale.png new file mode 100644 index 0000000000..43b56b692d Binary files /dev/null and b/submodules/TelegramUI/Images.xcassets/Media Editor/Grayscale.imageset/grayscale.png differ diff --git a/submodules/TelegramUI/Resources/Animations/anim_spoiler.json b/submodules/TelegramUI/Resources/Animations/anim_spoiler.json index 40fea5542f..14eacbda1c 100644 --- a/submodules/TelegramUI/Resources/Animations/anim_spoiler.json +++ b/submodules/TelegramUI/Resources/Animations/anim_spoiler.json @@ -1 +1 @@ -{"v":"5.9.6","fr":60,"ip":0,"op":180,"w":512,"h":512,"nm":"spoiler","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"blurIcon Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256,256,0],"ix":2,"l":2},"a":{"a":0,"k":[12,12,0],"ix":1,"l":2},"s":{"a":0,"k":[2133.333,2133.333,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.276],[0.276,0],[0,0.276],[-0.276,0]],"o":[[0,0.276],[-0.276,0],[0,-0.276],[0.276,0]],"v":[[0.5,0],[0,0.5],[-0.5,0],[0,-0.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[20.5,15.83],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":18,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":24,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":36,"s":[120,120]},{"t":48,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.367],[0.367,0],[0,0.367],[-0.367,0]],"o":[[0,0.367],[-0.367,0],[0,-0.367],[0.367,0]],"v":[[0.665,0],[0,0.665],[-0.665,0],[0,-0.665]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[18.167,15.995],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":16,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":22,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":34,"s":[120,120]},{"t":46,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.552],[0.552,0],[0,0.552],[-0.552,0]],"o":[[0,0.552],[-0.552,0],[0,-0.552],[0.552,0]],"v":[[1,0],[0,1],[-1,0],[0,-1]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[15.333,16.165],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":14,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":20,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":32,"s":[120,120]},{"t":44,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.643],[0.643,0],[0,0.643],[-0.643,0]],"o":[[0,0.643],[-0.643,0],[0,-0.643],[0.643,0]],"v":[[1.165,0],[0,1.165],[-1.165,0],[0,-1.165]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[12,16.165],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":12,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":18,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":30,"s":[120,120]},{"t":42,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.552],[0.552,0],[0,0.552],[-0.552,0]],"o":[[0,0.552],[-0.552,0],[0,-0.552],[0.552,0]],"v":[[1,0],[0,1],[-1,0],[0,-1]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[8.667,16.165],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":16,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":28,"s":[120,120]},{"t":40,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":1,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.367],[0.367,0],[0,0.367],[-0.367,0]],"o":[[0,0.367],[-0.367,0],[0,-0.367],[0.367,0]],"v":[[0.665,0],[0,0.665],[-0.665,0],[0,-0.665]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[5.833,15.995],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":8,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":14,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":26,"s":[120,120]},{"t":38,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":1,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.276],[0.276,0],[0,0.276],[-0.276,0]],"o":[[0,0.276],[-0.276,0],[0,-0.276],[0.276,0]],"v":[[0.5,0],[0,0.5],[-0.5,0],[0,-0.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[3.5,15.83],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":6,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":12,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":24,"s":[120,120]},{"t":36,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":1,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.276],[0.276,0],[0,0.276],[-0.276,0]],"o":[[0,0.276],[-0.276,0],[0,-0.276],[0.276,0]],"v":[[0.5,0],[0,0.5],[-0.5,0],[0,-0.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[20.5,8.17],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":14,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":20,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":32,"s":[120,120]},{"t":44,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":1,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.367],[0.367,0],[0,0.367],[-0.367,0]],"o":[[0,0.367],[-0.367,0],[0,-0.367],[0.367,0]],"v":[[0.665,0],[0,0.665],[-0.665,0],[0,-0.665]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[18.167,7.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":12,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":18,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":30,"s":[120,120]},{"t":42,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":1,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.552],[0.552,0],[0,0.552],[-0.552,0]],"o":[[0,0.552],[-0.552,0],[0,-0.552],[0.552,0]],"v":[[1,0],[0,1],[-1,0],[0,-1]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[15.333,7.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":16,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":28,"s":[120,120]},{"t":40,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":1,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.643],[0.643,0],[0,0.643],[-0.643,0]],"o":[[0,0.643],[-0.643,0],[0,-0.643],[0.643,0]],"v":[[1.165,0],[0,1.165],[-1.165,0],[0,-1.165]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[12,7.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":8,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":14,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":26,"s":[120,120]},{"t":38,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 11","np":1,"cix":2,"bm":0,"ix":11,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.552],[0.552,0],[0,0.552],[-0.552,0]],"o":[[0,0.552],[-0.552,0],[0,-0.552],[0.552,0]],"v":[[1,0],[0,1],[-1,0],[0,-1]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[8.667,7.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":6,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":12,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":24,"s":[120,120]},{"t":36,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 12","np":1,"cix":2,"bm":0,"ix":12,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.367],[0.367,0],[0,0.367],[-0.367,0]],"o":[[0,0.367],[-0.367,0],[0,-0.367],[0.367,0]],"v":[[0.665,0],[0,0.665],[-0.665,0],[0,-0.665]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[5.833,7.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":4,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":10,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":22,"s":[120,120]},{"t":34,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 13","np":1,"cix":2,"bm":0,"ix":13,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.276],[0.276,0],[0,0.276],[-0.276,0]],"o":[[0,0.276],[-0.276,0],[0,-0.276],[0.276,0]],"v":[[0.5,0],[0,0.5],[-0.5,0],[0,-0.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[3.5,8.17],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":2,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":8,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":20,"s":[120,120]},{"t":32,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 14","np":1,"cix":2,"bm":0,"ix":14,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.367],[0.367,0],[0,0.367],[-0.367,0]],"o":[[0,0.367],[-0.367,0],[0,-0.367],[0.367,0]],"v":[[0.665,0],[0,0.665],[-0.665,0],[0,-0.665]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[20.335,12.005],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":16,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":22,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":34,"s":[120,120]},{"t":46,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 15","np":1,"cix":2,"bm":0,"ix":15,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.461],[0.461,0],[0,0.461],[-0.461,0]],"o":[[0,0.461],[-0.461,0],[0,-0.461],[0.461,0]],"v":[[0.835,0],[0,0.835],[-0.835,0],[0,-0.835]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[18.057,12.005],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":14,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":20,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":32,"s":[120,120]},{"t":44,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 16","np":1,"cix":2,"bm":0,"ix":16,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.643],[0.643,0],[0,0.643],[-0.643,0]],"o":[[0,0.643],[-0.643,0],[0,-0.643],[0.643,0]],"v":[[1.165,0],[0,1.165],[-1.165,0],[0,-1.165]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[15.278,12.005],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":12,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":18,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":30,"s":[120,120]},{"t":42,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 17","np":1,"cix":2,"bm":0,"ix":17,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.737],[0.737,0],[0,0.737],[-0.737,0]],"o":[[0,0.737],[-0.737,0],[0,-0.737],[0.737,0]],"v":[[1.335,0],[0,1.335],[-1.335,0],[0,-1.335]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[12,12.005],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":16,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":28,"s":[120,120]},{"t":40,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 18","np":1,"cix":2,"bm":0,"ix":18,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.643],[0.643,0],[0,0.643],[-0.643,0]],"o":[[0,0.643],[-0.643,0],[0,-0.643],[0.643,0]],"v":[[1.165,0],[0,1.165],[-1.165,0],[0,-1.165]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[8.722,12.005],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":8,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":14,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":26,"s":[120,120]},{"t":38,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 19","np":1,"cix":2,"bm":0,"ix":19,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.461],[0.461,0],[0,0.461],[-0.461,0]],"o":[[0,0.461],[-0.461,0],[0,-0.461],[0.461,0]],"v":[[0.835,0],[0,0.835],[-0.835,0],[0,-0.835]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[5.943,12.005],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":6,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":12,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":24,"s":[120,120]},{"t":36,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 20","np":1,"cix":2,"bm":0,"ix":20,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.367],[0.367,0],[0,0.367],[-0.367,0]],"o":[[0,0.367],[-0.367,0],[0,-0.367],[0.367,0]],"v":[[0.665,0],[0,0.665],[-0.665,0],[0,-0.665]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[3.665,12.005],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":4,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":10,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":22,"s":[120,120]},{"t":34,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 21","np":1,"cix":2,"bm":0,"ix":21,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.185],[0.185,0],[0,0.185],[-0.185,0]],"o":[[0,0.185],[-0.185,0],[0,-0.185],[0.185,0]],"v":[[0.335,0],[0,0.335],[-0.335,0],[0,-0.335]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[20.665,4.665],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":12,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":18,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":30,"s":[120,120]},{"t":42,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 22","np":1,"cix":2,"bm":0,"ix":22,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.276],[0.276,0],[0,0.276],[-0.276,0]],"o":[[0,0.276],[-0.276,0],[0,-0.276],[0.276,0]],"v":[[0.5,0],[0,0.5],[-0.5,0],[0,-0.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[18.108,4.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":16,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":28,"s":[120,120]},{"t":40,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 23","np":1,"cix":2,"bm":0,"ix":23,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.367],[0.367,0],[0,0.367],[-0.367,0]],"o":[[0,0.367],[-0.367,0],[0,-0.367],[0.367,0]],"v":[[0.665,0],[0,0.665],[-0.665,0],[0,-0.665]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[15.222,4.335],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":8,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":14,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":26,"s":[120,120]},{"t":38,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 24","np":1,"cix":2,"bm":0,"ix":24,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.461],[0.461,0],[0,0.461],[-0.461,0]],"o":[[0,0.461],[-0.461,0],[0,-0.461],[0.461,0]],"v":[[0.835,0],[0,0.835],[-0.835,0],[0,-0.835]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[12,4.165],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":6,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":12,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":24,"s":[120,120]},{"t":36,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 25","np":1,"cix":2,"bm":0,"ix":25,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.367],[0.367,0],[0,0.367],[-0.367,0]],"o":[[0,0.367],[-0.367,0],[0,-0.367],[0.367,0]],"v":[[0.665,0],[0,0.665],[-0.665,0],[0,-0.665]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[8.778,4.335],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":4,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":10,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":22,"s":[120,120]},{"t":34,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 26","np":1,"cix":2,"bm":0,"ix":26,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.276],[0.276,0],[0,0.276],[-0.276,0]],"o":[[0,0.276],[-0.276,0],[0,-0.276],[0.276,0]],"v":[[0.5,0],[0,0.5],[-0.5,0],[0,-0.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[5.892,4.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":2,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":8,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":20,"s":[120,120]},{"t":32,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 27","np":1,"cix":2,"bm":0,"ix":27,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.185],[0.185,0],[0,0.185],[-0.185,0]],"o":[[0,0.185],[-0.185,0],[0,-0.185],[0.185,0]],"v":[[0.335,0],[0,0.335],[-0.335,0],[0,-0.335]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[3.335,4.665],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":0,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":6,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":18,"s":[120,120]},{"t":30,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 28","np":1,"cix":2,"bm":0,"ix":28,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.185],[0.185,0],[0,0.185],[-0.185,0]],"o":[[0,0.185],[-0.185,0],[0,-0.185],[0.185,0]],"v":[[0.335,0],[0,0.335],[-0.335,0],[0,-0.335]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[20.665,19.335],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":20,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":26,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":38,"s":[120,120]},{"t":50,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 29","np":1,"cix":2,"bm":0,"ix":29,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.276],[0.276,0],[0,0.276],[-0.276,0]],"o":[[0,0.276],[-0.276,0],[0,-0.276],[0.276,0]],"v":[[0.5,0],[0,0.5],[-0.5,0],[0,-0.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[18.108,19.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":18,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":24,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":36,"s":[120,120]},{"t":48,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 30","np":1,"cix":2,"bm":0,"ix":30,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.367],[0.367,0],[0,0.367],[-0.367,0]],"o":[[0,0.367],[-0.367,0],[0,-0.367],[0.367,0]],"v":[[0.665,0],[0,0.665],[-0.665,0],[0,-0.665]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[15.222,19.665],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":16,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":22,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":34,"s":[120,120]},{"t":46,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 31","np":1,"cix":2,"bm":0,"ix":31,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.461],[0.461,0],[0,0.461],[-0.461,0]],"o":[[0,0.461],[-0.461,0],[0,-0.461],[0.461,0]],"v":[[0.835,0],[0,0.835],[-0.835,0],[0,-0.835]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[12,19.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":14,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":20,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":32,"s":[120,120]},{"t":44,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 32","np":1,"cix":2,"bm":0,"ix":32,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.367],[0.367,0],[0,0.367],[-0.367,0]],"o":[[0,0.367],[-0.367,0],[0,-0.367],[0.367,0]],"v":[[0.665,0],[0,0.665],[-0.665,0],[0,-0.665]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[8.778,19.665],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":12,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":18,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":30,"s":[120,120]},{"t":42,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 33","np":1,"cix":2,"bm":0,"ix":33,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.276],[0.276,0],[0,0.276],[-0.276,0]],"o":[[0,0.276],[-0.276,0],[0,-0.276],[0.276,0]],"v":[[0.5,0],[0,0.5],[-0.5,0],[0,-0.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[5.892,19.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":16,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":28,"s":[120,120]},{"t":40,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 34","np":1,"cix":2,"bm":0,"ix":34,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.185],[0.185,0],[0,0.185],[-0.185,0]],"o":[[0,0.185],[-0.185,0],[0,-0.185],[0.185,0]],"v":[[0.335,0],[0,0.335],[-0.335,0],[0,-0.335]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[3.335,19.335],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":8,"s":[100,100]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":14,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":26,"s":[120,120]},{"t":38,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 35","np":1,"cix":2,"bm":0,"ix":35,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":184,"st":0,"ct":1,"bm":0}],"markers":[]} \ No newline at end of file +{"v":"5.9.6","fr":60,"ip":0,"op":180,"w":512,"h":512,"nm":"spoiler","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Photo 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256,256,0],"ix":2,"l":2},"a":{"a":0,"k":[120,120,0],"ix":1,"l":2},"s":{"a":0,"k":[213.333,213.333,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-4.139,-3.657],[-0.213,-0.227],[0,0]],"o":[[0,0],[3.657,-4.138],[0.233,0.206],[0,0],[0,0]],"v":[[-29.394,0.151],[-16.646,-14.275],[-2.53,-15.147],[-1.861,-14.497],[29.394,18.804]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":66,"s":[0]},{"t":72,"s":[100]}],"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":13.3,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[164.394,152.553],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-4.125,-3.672],[-0.197,-0.209],[0,0]],"o":[[0,0],[3.672,-4.125],[0.214,0.191],[0,0],[0,0]],"v":[[-62.525,-1.85],[-29.754,-38.659],[-15.636,-39.478],[-15.018,-38.879],[62.525,43.15]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.578],"y":[-0.098]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[0]},{"i":{"x":[0.613],"y":[0.621]},"o":{"x":[0.286],"y":[0.32]},"t":64,"s":[29.189]},{"i":{"x":[0.593],"y":[1]},"o":{"x":[0.268],"y":[0.361]},"t":66,"s":[63.058]},{"t":69,"s":[100]}],"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":13.3,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[107.525,146.85],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-8.284,0],[0,8.284],[8.284,0],[0,-8.284]],"o":[[8.284,0],[0,-8.284],[-8.284,0],[0,8.284]],"v":[[35,-20],[50,-35],[35,-50],[20,-35]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[154.791,84.883],"ix":2},"a":{"a":0,"k":[34.791,-35.117],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.6,0.6],"y":[0,0]},"t":62,"s":[100,100]},{"t":70,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-13.373,0],[0,0],[-4.889,-2.615],[-2.615,-4.889],[0,-13.373],[0,0],[2.615,-4.889],[4.889,-2.615],[13.373,0],[0,0],[4.889,2.615],[2.615,4.889],[0,13.373],[0,0],[-2.615,4.889],[-4.889,2.615]],"o":[[0,0],[13.373,0],[4.889,2.615],[2.615,4.889],[0,0],[0,13.373],[-2.615,4.889],[-4.889,2.615],[0,0],[-13.373,0],[-4.889,-2.615],[-2.615,-4.889],[0,0],[0,-13.373],[2.615,-4.889],[4.889,-2.615]],"v":[[-36.542,-75],[36.542,-75],[59.653,-70.993],[70.993,-59.653],[75,-36.542],[75,36.542],[70.993,59.653],[59.653,70.993],[36.542,75],[-36.542,75],[-59.653,70.993],[-70.993,59.653],[-75,36.542],[-75,-36.542],[-70.993,-59.653],[-59.653,-70.993]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[0]},{"t":80,"s":[50]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[100]},{"t":80,"s":[50]}],"ix":2},"o":{"a":0,"k":294,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":13.3,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[120,120],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":3,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":60,"op":80,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Photo 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256,256,0],"ix":2,"l":2},"a":{"a":0,"k":[120,120,0],"ix":1,"l":2},"s":{"a":0,"k":[213.333,213.333,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-4.139,-3.657],[-0.213,-0.227],[0,0]],"o":[[0,0],[3.657,-4.138],[0.233,0.206],[0,0],[0,0]],"v":[[-29.394,0.151],[-16.646,-14.275],[-2.53,-15.147],[-1.861,-14.497],[29.394,18.804]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":0,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":13.3,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[164.394,152.553],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-4.139,-3.657],[-0.213,-0.227],[0,0]],"o":[[0,0],[3.657,-4.138],[0.233,0.206],[0,0],[0,0]],"v":[[-29.394,0.151],[-16.646,-14.275],[-2.53,-15.147],[-1.861,-14.497],[29.394,18.804]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":0,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":13.3,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[164.394,152.553],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-4.125,-3.672],[-0.197,-0.209],[0,0]],"o":[[0,0],[3.672,-4.125],[0.214,0.191],[0,0],[0,0]],"v":[[-62.525,-1.85],[-29.754,-38.659],[-15.636,-39.478],[-15.018,-38.879],[62.525,43.15]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":82,"s":[0]},{"t":100,"s":[59]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":13.3,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[107.525,146.85],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-8.284,0],[0,8.284],[8.284,0],[0,-8.284]],"o":[[8.284,0],[0,-8.284],[-8.284,0],[0,8.284]],"v":[[35,-20],[50,-35],[35,-50],[20,-35]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[154.791,84.883],"ix":2},"a":{"a":0,"k":[34.791,-35.117],"ix":1},"s":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":3,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-13.373,0],[0,0],[-4.889,-2.615],[-2.615,-4.889],[0,-13.373],[0,0],[2.615,-4.889],[4.889,-2.615],[13.373,0],[0,0],[4.889,2.615],[2.615,4.889],[0,13.373],[0,0],[-2.615,4.889],[-4.889,2.615]],"o":[[0,0],[13.373,0],[4.889,2.615],[2.615,4.889],[0,0],[0,13.373],[-2.615,4.889],[-4.889,2.615],[0,0],[-13.373,0],[-4.889,-2.615],[-2.615,-4.889],[0,0],[0,-13.373],[2.615,-4.889],[4.889,-2.615]],"v":[[-36.542,-75],[36.542,-75],[59.653,-70.993],[70.993,-59.653],[75,-36.542],[75,36.542],[70.993,59.653],[59.653,70.993],[36.542,75],[-36.542,75],[-59.653,70.993],[-70.993,59.653],[-75,36.542],[-75,-36.542],[-70.993,-59.653],[-59.653,-70.993]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":80,"s":[50]},{"t":100,"s":[25]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":80,"s":[50]},{"t":100,"s":[75]}],"ix":2},"o":{"a":0,"k":114,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":13.3,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[120,120],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":3,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":182,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Photo","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256,256,0],"ix":2,"l":2},"a":{"a":0,"k":[120,120,0],"ix":1,"l":2},"s":{"a":0,"k":[213.333,213.333,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-4.139,-3.657],[-0.213,-0.227],[0,0]],"o":[[0,0],[3.657,-4.138],[0.233,0.206],[0,0],[0,0]],"v":[[-29.394,0.151],[-16.646,-14.275],[-2.53,-15.147],[-1.861,-14.497],[29.394,18.804]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":11,"s":[0]},{"t":19,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":13.3,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[164.394,152.553],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-4.139,-3.657],[-0.213,-0.227],[0,0]],"o":[[0,0],[3.657,-4.138],[0.233,0.206],[0,0],[0,0]],"v":[[-29.394,0.151],[-16.646,-14.275],[-2.53,-15.147],[-1.861,-14.497],[29.394,18.804]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":11,"s":[0]},{"t":19,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":13.3,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[164.394,152.553],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-4.125,-3.672],[-0.197,-0.209],[0,0]],"o":[[0,0],[3.672,-4.125],[0.214,0.191],[0,0],[0,0]],"v":[[-62.525,-1.85],[-29.754,-38.659],[-15.636,-39.478],[-15.018,-38.879],[62.525,43.15]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[59]},{"t":17,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":13.3,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[107.525,146.85],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-8.284,0],[0,8.284],[8.284,0],[0,-8.284]],"o":[[8.284,0],[0,-8.284],[-8.284,0],[0,8.284]],"v":[[35,-20],[50,-35],[35,-50],[20,-35]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[154.791,84.883],"ix":2},"a":{"a":0,"k":[34.791,-35.117],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[0,0]},{"t":20,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":3,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-13.373,0],[0,0],[-4.889,-2.615],[-2.615,-4.889],[0,-13.373],[0,0],[2.615,-4.889],[4.889,-2.615],[13.373,0],[0,0],[4.889,2.615],[2.615,4.889],[0,13.373],[0,0],[-2.615,4.889],[-4.889,2.615]],"o":[[0,0],[13.373,0],[4.889,2.615],[2.615,4.889],[0,0],[0,13.373],[-2.615,4.889],[-4.889,2.615],[0,0],[-13.373,0],[-4.889,-2.615],[-2.615,-4.889],[0,0],[0,-13.373],[2.615,-4.889],[4.889,-2.615]],"v":[[-36.542,-75],[36.542,-75],[59.653,-70.993],[70.993,-59.653],[75,-36.542],[75,36.542],[70.993,59.653],[59.653,70.993],[36.542,75],[-36.542,75],[-59.653,70.993],[-70.993,59.653],[-75,36.542],[-75,-36.542],[-70.993,-59.653],[-59.653,-70.993]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[25]},{"t":30,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[75]},{"t":30,"s":[100]}],"ix":2},"o":{"a":0,"k":114,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":13.3,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[120,120],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":3,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"blurIcon Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256,256,0],"ix":2,"l":2},"a":{"a":0,"k":[12,12,0],"ix":1,"l":2},"s":{"a":0,"k":[2133.333,2133.333,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.276],[0.276,0],[0,0.276],[-0.276,0]],"o":[[0,0.276],[-0.276,0],[0,-0.276],[0.276,0]],"v":[[0.5,0],[0,0.5],[-0.5,0],[0,-0.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[20.5,15.83],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":15,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":18,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":73,"s":[0,0]},{"t":81,"s":[100,100],"h":1}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.367],[0.367,0],[0,0.367],[-0.367,0]],"o":[[0,0.367],[-0.367,0],[0,-0.367],[0.367,0]],"v":[[0.665,0],[0,0.665],[-0.665,0],[0,-0.665]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[18.167,15.995],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":13,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":15,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":70,"s":[0,0]},{"t":76,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.552],[0.552,0],[0,0.552],[-0.552,0]],"o":[[0,0.552],[-0.552,0],[0,-0.552],[0.552,0]],"v":[[1,0],[0,1],[-1,0],[0,-1]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[15.333,16.165],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":13,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":68,"s":[0,0]},{"t":73,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.643],[0.643,0],[0,0.643],[-0.643,0]],"o":[[0,0.643],[-0.643,0],[0,-0.643],[0.643,0]],"v":[[1.165,0],[0,1.165],[-1.165,0],[0,-1.165]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[12,16.165],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":66,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":67,"s":[50,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":68,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":89,"s":[100,100]},{"t":94,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.552],[0.552,0],[0,0.552],[-0.552,0]],"o":[[0,0.552],[-0.552,0],[0,-0.552],[0.552,0]],"v":[[1,0],[0,1],[-1,0],[0,-1]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[8.667,16.165],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":65,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":66,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":67,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":85,"s":[100,100]},{"t":89,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":1,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.367],[0.367,0],[0,0.367],[-0.367,0]],"o":[[0,0.367],[-0.367,0],[0,-0.367],[0.367,0]],"v":[[0.665,0],[0,0.665],[-0.665,0],[0,-0.665]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[5.833,15.995],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":63,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":65,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":67,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":80,"s":[100,100]},{"t":85,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":1,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.276],[0.276,0],[0,0.276],[-0.276,0]],"o":[[0,0.276],[-0.276,0],[0,-0.276],[0.276,0]],"v":[[0.5,0],[0,0.5],[-0.5,0],[0,-0.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[3.5,15.83],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":64,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":80,"s":[100,100]},{"t":82,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":1,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.276],[0.276,0],[0,0.276],[-0.276,0]],"o":[[0,0.276],[-0.276,0],[0,-0.276],[0.276,0]],"v":[[0.5,0],[0,0.5],[-0.5,0],[0,-0.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[20.5,8.17],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":15,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":18,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":73,"s":[0,0]},{"t":81,"s":[100,100],"h":1}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":1,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.367],[0.367,0],[0,0.367],[-0.367,0]],"o":[[0,0.367],[-0.367,0],[0,-0.367],[0.367,0]],"v":[[0.665,0],[0,0.665],[-0.665,0],[0,-0.665]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[18.167,7.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":13,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":15,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":70,"s":[0,0]},{"t":76,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":1,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.552],[0.552,0],[0,0.552],[-0.552,0]],"o":[[0,0.552],[-0.552,0],[0,-0.552],[0.552,0]],"v":[[1,0],[0,1],[-1,0],[0,-1]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[15.333,7.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":13,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":68,"s":[0,0]},{"t":73,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":1,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.643],[0.643,0],[0,0.643],[-0.643,0]],"o":[[0,0.643],[-0.643,0],[0,-0.643],[0.643,0]],"v":[[1.165,0],[0,1.165],[-1.165,0],[0,-1.165]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[12,7.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":66,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":67,"s":[50,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":68,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":89,"s":[100,100]},{"t":94,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 11","np":1,"cix":2,"bm":0,"ix":11,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.552],[0.552,0],[0,0.552],[-0.552,0]],"o":[[0,0.552],[-0.552,0],[0,-0.552],[0.552,0]],"v":[[1,0],[0,1],[-1,0],[0,-1]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[8.667,7.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":65,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":66,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":67,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":85,"s":[100,100]},{"t":89,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 12","np":1,"cix":2,"bm":0,"ix":12,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.367],[0.367,0],[0,0.367],[-0.367,0]],"o":[[0,0.367],[-0.367,0],[0,-0.367],[0.367,0]],"v":[[0.665,0],[0,0.665],[-0.665,0],[0,-0.665]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[5.833,7.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":63,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":65,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":67,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":80,"s":[100,100]},{"t":85,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 13","np":1,"cix":2,"bm":0,"ix":13,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.276],[0.276,0],[0,0.276],[-0.276,0]],"o":[[0,0.276],[-0.276,0],[0,-0.276],[0.276,0]],"v":[[0.5,0],[0,0.5],[-0.5,0],[0,-0.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[3.5,8.17],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":64,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":80,"s":[100,100]},{"t":82,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 14","np":1,"cix":2,"bm":0,"ix":14,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.367],[0.367,0],[0,0.367],[-0.367,0]],"o":[[0,0.367],[-0.367,0],[0,-0.367],[0.367,0]],"v":[[0.665,0],[0,0.665],[-0.665,0],[0,-0.665]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[20.335,12.005],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":15,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":18,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":73,"s":[0,0]},{"t":81,"s":[100,100],"h":1}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 15","np":1,"cix":2,"bm":0,"ix":15,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.461],[0.461,0],[0,0.461],[-0.461,0]],"o":[[0,0.461],[-0.461,0],[0,-0.461],[0.461,0]],"v":[[0.835,0],[0,0.835],[-0.835,0],[0,-0.835]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[18.057,12.005],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":13,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":15,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":70,"s":[0,0]},{"t":76,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 16","np":1,"cix":2,"bm":0,"ix":16,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.643],[0.643,0],[0,0.643],[-0.643,0]],"o":[[0,0.643],[-0.643,0],[0,-0.643],[0.643,0]],"v":[[1.165,0],[0,1.165],[-1.165,0],[0,-1.165]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[15.278,12.005],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":13,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":68,"s":[0,0]},{"t":73,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 17","np":1,"cix":2,"bm":0,"ix":17,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.737],[0.737,0],[0,0.737],[-0.737,0]],"o":[[0,0.737],[-0.737,0],[0,-0.737],[0.737,0]],"v":[[1.335,0],[0,1.335],[-1.335,0],[0,-1.335]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[12,12.005],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":66,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":67,"s":[50,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":68,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":89,"s":[100,100]},{"t":94,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 18","np":1,"cix":2,"bm":0,"ix":18,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.643],[0.643,0],[0,0.643],[-0.643,0]],"o":[[0,0.643],[-0.643,0],[0,-0.643],[0.643,0]],"v":[[1.165,0],[0,1.165],[-1.165,0],[0,-1.165]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[8.722,12.005],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":65,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":66,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":67,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":85,"s":[100,100]},{"t":89,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 19","np":1,"cix":2,"bm":0,"ix":19,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.461],[0.461,0],[0,0.461],[-0.461,0]],"o":[[0,0.461],[-0.461,0],[0,-0.461],[0.461,0]],"v":[[0.835,0],[0,0.835],[-0.835,0],[0,-0.835]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[5.943,12.005],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":63,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":65,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":67,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":80,"s":[100,100]},{"t":85,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 20","np":1,"cix":2,"bm":0,"ix":20,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.367],[0.367,0],[0,0.367],[-0.367,0]],"o":[[0,0.367],[-0.367,0],[0,-0.367],[0.367,0]],"v":[[0.665,0],[0,0.665],[-0.665,0],[0,-0.665]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[3.665,12.005],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":64,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":80,"s":[100,100]},{"t":82,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 21","np":1,"cix":2,"bm":0,"ix":21,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.185],[0.185,0],[0,0.185],[-0.185,0]],"o":[[0,0.185],[-0.185,0],[0,-0.185],[0.185,0]],"v":[[0.335,0],[0,0.335],[-0.335,0],[0,-0.335]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[20.665,4.665],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":15,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":18,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":73,"s":[0,0]},{"t":81,"s":[100,100],"h":1}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 22","np":1,"cix":2,"bm":0,"ix":22,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.276],[0.276,0],[0,0.276],[-0.276,0]],"o":[[0,0.276],[-0.276,0],[0,-0.276],[0.276,0]],"v":[[0.5,0],[0,0.5],[-0.5,0],[0,-0.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[18.108,4.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":13,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":15,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":70,"s":[0,0]},{"t":76,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 23","np":1,"cix":2,"bm":0,"ix":23,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.367],[0.367,0],[0,0.367],[-0.367,0]],"o":[[0,0.367],[-0.367,0],[0,-0.367],[0.367,0]],"v":[[0.665,0],[0,0.665],[-0.665,0],[0,-0.665]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[15.222,4.335],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":13,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":68,"s":[0,0]},{"t":73,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 24","np":1,"cix":2,"bm":0,"ix":24,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.461],[0.461,0],[0,0.461],[-0.461,0]],"o":[[0,0.461],[-0.461,0],[0,-0.461],[0.461,0]],"v":[[0.835,0],[0,0.835],[-0.835,0],[0,-0.835]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[12,4.165],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":66,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":67,"s":[50,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":68,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":89,"s":[100,100]},{"t":94,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 25","np":1,"cix":2,"bm":0,"ix":25,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.367],[0.367,0],[0,0.367],[-0.367,0]],"o":[[0,0.367],[-0.367,0],[0,-0.367],[0.367,0]],"v":[[0.665,0],[0,0.665],[-0.665,0],[0,-0.665]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[8.778,4.335],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":65,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":66,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":67,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":85,"s":[100,100]},{"t":89,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 26","np":1,"cix":2,"bm":0,"ix":26,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.276],[0.276,0],[0,0.276],[-0.276,0]],"o":[[0,0.276],[-0.276,0],[0,-0.276],[0.276,0]],"v":[[0.5,0],[0,0.5],[-0.5,0],[0,-0.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[5.892,4.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":63,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":65,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":67,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":80,"s":[100,100]},{"t":85,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 27","np":1,"cix":2,"bm":0,"ix":27,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.185],[0.185,0],[0,0.185],[-0.185,0]],"o":[[0,0.185],[-0.185,0],[0,-0.185],[0.185,0]],"v":[[0.335,0],[0,0.335],[-0.335,0],[0,-0.335]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[3.335,4.665],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":64,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":80,"s":[100,100]},{"t":82,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 28","np":1,"cix":2,"bm":0,"ix":28,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.185],[0.185,0],[0,0.185],[-0.185,0]],"o":[[0,0.185],[-0.185,0],[0,-0.185],[0.185,0]],"v":[[0.335,0],[0,0.335],[-0.335,0],[0,-0.335]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[20.665,19.335],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":15,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":18,"s":[0,0]},{"i":{"x":[0.4,0.4],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":73,"s":[0,0]},{"t":81,"s":[100,100],"h":1}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 29","np":1,"cix":2,"bm":0,"ix":29,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.276],[0.276,0],[0,0.276],[-0.276,0]],"o":[[0,0.276],[-0.276,0],[0,-0.276],[0.276,0]],"v":[[0.5,0],[0,0.5],[-0.5,0],[0,-0.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[18.108,19.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":13,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":15,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":70,"s":[0,0]},{"t":76,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 30","np":1,"cix":2,"bm":0,"ix":30,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.367],[0.367,0],[0,0.367],[-0.367,0]],"o":[[0,0.367],[-0.367,0],[0,-0.367],[0.367,0]],"v":[[0.665,0],[0,0.665],[-0.665,0],[0,-0.665]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[15.222,19.665],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":13,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":68,"s":[0,0]},{"t":73,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 31","np":1,"cix":2,"bm":0,"ix":31,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.461],[0.461,0],[0,0.461],[-0.461,0]],"o":[[0,0.461],[-0.461,0],[0,-0.461],[0.461,0]],"v":[[0.835,0],[0,0.835],[-0.835,0],[0,-0.835]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[12,19.835],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":66,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":67,"s":[50,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":68,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":89,"s":[100,100]},{"t":94,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 32","np":1,"cix":2,"bm":0,"ix":32,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.367],[0.367,0],[0,0.367],[-0.367,0]],"o":[[0,0.367],[-0.367,0],[0,-0.367],[0.367,0]],"v":[[0.665,0],[0,0.665],[-0.665,0],[0,-0.665]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[8.778,19.665],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":65,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":66,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":67,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":85,"s":[100,100]},{"t":89,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 33","np":1,"cix":2,"bm":0,"ix":33,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.276],[0.276,0],[0,0.276],[-0.276,0]],"o":[[0,0.276],[-0.276,0],[0,-0.276],[0.276,0]],"v":[[0.5,0],[0,0.5],[-0.5,0],[0,-0.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[5.892,19.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":63,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":65,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":67,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":80,"s":[100,100]},{"t":85,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 34","np":1,"cix":2,"bm":0,"ix":34,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.185],[0.185,0],[0,0.185],[-0.185,0]],"o":[[0,0.185],[-0.185,0],[0,-0.185],[0.185,0]],"v":[[0.335,0],[0,0.335],[-0.335,0],[0,-0.335]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[3.335,19.335],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[0,0]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":64,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":80,"s":[100,100]},{"t":82,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 35","np":1,"cix":2,"bm":0,"ix":35,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":184,"st":0,"ct":1,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 92daf2f5d9..7e7c4a7981 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -1372,27 +1372,28 @@ private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatL let ItemInfo = 3 let ItemDelete = 4 - let compactName = EnginePeer(user).compactDisplayTitle - - items[.peerDataSettings]!.append(PeerInfoScreenActionItem(id: ItemSuggest, text: presentationData.strings.UserInfo_SuggestPhoto(compactName).string, color: .accent, icon: UIImage(bundleImageName: "Peer Info/SuggestAvatar"), action: { - interaction.suggestPhoto() - })) - - items[.peerDataSettings]!.append(PeerInfoScreenActionItem(id: ItemCustom, text: presentationData.strings.UserInfo_SetCustomPhoto(compactName).string, color: .accent, icon: UIImage(bundleImageName: "Settings/SetAvatar"), action: { - interaction.setCustomPhoto() - })) - - if user.photo.first?.isPersonal == true || state.updatingAvatar != nil { - var representation: TelegramMediaImageRepresentation? - if let cachedData = data.cachedData as? CachedUserData, case let .known(photo) = cachedData.photo { - representation = photo?.representationForDisplayAtSize(PixelDimensions(width: 28, height: 28)) - } - - items[.peerDataSettings]!.append(PeerInfoScreenActionItem(id: ItemReset, text: presentationData.strings.UserInfo_ResetCustomPhoto, color: .accent, icon: nil, iconSignal: peerAvatarCompleteImage(account: context.account, peer: EnginePeer(user), forceProvidedRepresentation: true, representation: representation, size: CGSize(width: 28.0, height: 28.0)), action: { - interaction.resetCustomPhoto() + if !user.flags.contains(.isSupport) { + let compactName = EnginePeer(user).compactDisplayTitle + items[.peerDataSettings]!.append(PeerInfoScreenActionItem(id: ItemSuggest, text: presentationData.strings.UserInfo_SuggestPhoto(compactName).string, color: .accent, icon: UIImage(bundleImageName: "Peer Info/SuggestAvatar"), action: { + interaction.suggestPhoto() })) + + items[.peerDataSettings]!.append(PeerInfoScreenActionItem(id: ItemCustom, text: presentationData.strings.UserInfo_SetCustomPhoto(compactName).string, color: .accent, icon: UIImage(bundleImageName: "Settings/SetAvatar"), action: { + interaction.setCustomPhoto() + })) + + if user.photo.first?.isPersonal == true || state.updatingAvatar != nil { + var representation: TelegramMediaImageRepresentation? + if let cachedData = data.cachedData as? CachedUserData, case let .known(photo) = cachedData.photo { + representation = photo?.representationForDisplayAtSize(PixelDimensions(width: 28, height: 28)) + } + + items[.peerDataSettings]!.append(PeerInfoScreenActionItem(id: ItemReset, text: presentationData.strings.UserInfo_ResetCustomPhoto, color: .accent, icon: nil, iconSignal: peerAvatarCompleteImage(account: context.account, peer: EnginePeer(user), forceProvidedRepresentation: true, representation: representation, size: CGSize(width: 28.0, height: 28.0)), action: { + interaction.resetCustomPhoto() + })) + } + items[.peerDataSettings]!.append(PeerInfoScreenCommentItem(id: ItemInfo, text: presentationData.strings.UserInfo_CustomPhotoInfo(compactName).string)) } - items[.peerDataSettings]!.append(PeerInfoScreenCommentItem(id: ItemInfo, text: presentationData.strings.UserInfo_CustomPhotoInfo(compactName).string)) if data.isContact { items[.peerSettings]!.append(PeerInfoScreenActionItem(id: ItemDelete, text: presentationData.strings.UserInfo_DeleteContact, color: .destructive, action: {