mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 14:20:20 +00:00
Story covers
This commit is contained in:
@@ -0,0 +1,589 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import ComponentFlow
|
||||
import SwiftSignalKit
|
||||
import ViewControllerComponent
|
||||
import ComponentDisplayAdapters
|
||||
import TelegramPresentationData
|
||||
import AccountContext
|
||||
import TelegramCore
|
||||
import MultilineTextComponent
|
||||
import MediaEditor
|
||||
import MediaScrubberComponent
|
||||
import ButtonComponent
|
||||
|
||||
private final class MediaCoverScreenComponent: Component {
|
||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||
|
||||
let context: AccountContext
|
||||
let mediaEditor: MediaEditor
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
mediaEditor: MediaEditor
|
||||
) {
|
||||
self.context = context
|
||||
self.mediaEditor = mediaEditor
|
||||
}
|
||||
|
||||
static func ==(lhs: MediaCoverScreenComponent, rhs: MediaCoverScreenComponent) -> Bool {
|
||||
if lhs.context !== rhs.context {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
final class State: ComponentState {
|
||||
enum ImageKey: Hashable {
|
||||
case done
|
||||
}
|
||||
private var cachedImages: [ImageKey: UIImage] = [:]
|
||||
func image(_ key: ImageKey) -> UIImage {
|
||||
if let image = self.cachedImages[key] {
|
||||
return image
|
||||
} else {
|
||||
var image: UIImage
|
||||
switch key {
|
||||
case .done:
|
||||
image = generateTintedImage(image: UIImage(bundleImageName: "Media Editor/Done"), color: .white)!
|
||||
}
|
||||
cachedImages[key] = image
|
||||
return image
|
||||
}
|
||||
}
|
||||
|
||||
var playerStateDisposable: Disposable?
|
||||
var playerState: MediaEditorPlayerState?
|
||||
|
||||
init(mediaEditor: MediaEditor) {
|
||||
super.init()
|
||||
|
||||
self.playerStateDisposable = (mediaEditor.playerState(framesCount: 16)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] playerState in
|
||||
if let self {
|
||||
if self.playerState != playerState {
|
||||
self.playerState = playerState
|
||||
self.updated()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.playerStateDisposable?.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
func makeState() -> State {
|
||||
return State(mediaEditor: self.mediaEditor)
|
||||
}
|
||||
|
||||
public final class View: UIView {
|
||||
private let buttonsContainerView = UIView()
|
||||
private let buttonsBackgroundView = UIImageView()
|
||||
private let previewContainerView = UIView()
|
||||
private let cancelButton = ComponentView<Empty>()
|
||||
private let label = ComponentView<Empty>()
|
||||
private let doneButton = ComponentView<Empty>()
|
||||
private let scrubber = ComponentView<Empty>()
|
||||
|
||||
private let fadeView = UIView()
|
||||
|
||||
private var component: MediaCoverScreenComponent?
|
||||
private weak var state: State?
|
||||
private var environment: ViewControllerComponentContainer.Environment?
|
||||
|
||||
override init(frame: CGRect) {
|
||||
self.buttonsContainerView.clipsToBounds = true
|
||||
|
||||
self.fadeView.alpha = 0.0
|
||||
self.fadeView.backgroundColor = UIColor(rgb: 0x000000, alpha: 0.7)
|
||||
|
||||
self.buttonsBackgroundView.image = generateImage(CGSize(width: 22.0, height: 22.0), rotatedContext: { size, context in
|
||||
context.setFillColor(UIColor.black.cgColor)
|
||||
context.fill(CGRect(origin: .zero, size: size))
|
||||
|
||||
context.setBlendMode(.clear)
|
||||
context.setFillColor(UIColor.clear.cgColor)
|
||||
context.addPath(CGPath(roundedRect: CGRect(x: 0.0, y: -11.0, width: size.width, height: 22.0), cornerWidth: 11.0, cornerHeight: 11.0, transform: nil))
|
||||
context.fillPath()
|
||||
})?.stretchableImage(withLeftCapWidth: 11, topCapHeight: 11)
|
||||
|
||||
super.init(frame: frame)
|
||||
|
||||
self.backgroundColor = .clear
|
||||
|
||||
self.addSubview(self.buttonsContainerView)
|
||||
self.buttonsContainerView.addSubview(self.buttonsBackgroundView)
|
||||
|
||||
self.addSubview(self.fadeView)
|
||||
self.addSubview(self.previewContainerView)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func animateInFromEditor() {
|
||||
self.buttonsBackgroundView.layer.animatePosition(from: CGPoint(x: 0.0, y: 44.0), to: .zero, duration: 0.2, additive: true)
|
||||
|
||||
self.label.view?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
|
||||
if let view = self.doneButton.view {
|
||||
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
view.layer.animateScale(from: 0.1, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
|
||||
private var animatingOut = false
|
||||
func animateOutToEditor(completion: @escaping () -> Void) {
|
||||
self.animatingOut = true
|
||||
|
||||
self.fadeView.layer.animateAlpha(from: self.fadeView.alpha, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
self.buttonsBackgroundView.layer.animatePosition(from: .zero, to: CGPoint(x: 0.0, y: 44.0), duration: 0.2, removeOnCompletion: false, additive: true)
|
||||
|
||||
self.label.view?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
|
||||
if let view = self.scrubber.view {
|
||||
view.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { _ in
|
||||
completion()
|
||||
})
|
||||
view.layer.animateScale(from: 1.0, to: 0.1, duration: 0.2)
|
||||
}
|
||||
|
||||
if let view = self.cancelButton.view {
|
||||
view.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
view.layer.animateScale(from: 1.0, to: 0.1, duration: 0.2)
|
||||
}
|
||||
|
||||
if let view = self.doneButton.view {
|
||||
view.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
view.layer.animateScale(from: 1.0, to: 0.1, duration: 0.2)
|
||||
}
|
||||
|
||||
self.state?.updated()
|
||||
}
|
||||
|
||||
// override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
// let result = super.hitTest(point, with: event)
|
||||
// if let controller = self.environment?.controller() as? MediaCoverScreen, [.erase, .restore].contains(controller.mode), result == self.previewContainerView {
|
||||
// return nil
|
||||
// }
|
||||
// return result
|
||||
// }
|
||||
|
||||
func update(component: MediaCoverScreenComponent, availableSize: CGSize, state: State, environment: Environment<ViewControllerComponentContainer.Environment>, transition: ComponentTransition) -> CGSize {
|
||||
let environment = environment[ViewControllerComponentContainer.Environment.self].value
|
||||
self.environment = environment
|
||||
|
||||
guard let controller = environment.controller() as? MediaCoverScreen else {
|
||||
return .zero
|
||||
}
|
||||
|
||||
// let isFirstTime = self.component == nil
|
||||
self.component = component
|
||||
self.state = state
|
||||
|
||||
let isTablet: Bool
|
||||
if case .regular = environment.metrics.widthClass {
|
||||
isTablet = true
|
||||
} else {
|
||||
isTablet = false
|
||||
}
|
||||
|
||||
let buttonSideInset: CGFloat = 16.0
|
||||
var controlsBottomInset: CGFloat = 0.0
|
||||
let previewSize: CGSize
|
||||
var topInset: CGFloat = environment.statusBarHeight + 5.0
|
||||
if isTablet {
|
||||
let previewHeight = availableSize.height - topInset - 75.0
|
||||
previewSize = CGSize(width: floorToScreenPixels(previewHeight / 1.77778), height: previewHeight)
|
||||
} else {
|
||||
previewSize = CGSize(width: availableSize.width, height: floorToScreenPixels(availableSize.width * 1.77778))
|
||||
if availableSize.height < previewSize.height + 30.0 {
|
||||
topInset = 0.0
|
||||
controlsBottomInset = -75.0
|
||||
}
|
||||
}
|
||||
|
||||
let previewContainerFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - previewSize.width) / 2.0), y: environment.safeInsets.top), size: CGSize(width: previewSize.width, height: availableSize.height - environment.safeInsets.top - environment.safeInsets.bottom + controlsBottomInset))
|
||||
let buttonsContainerFrame = CGRect(origin: CGPoint(x: 0.0, y: availableSize.height - environment.safeInsets.bottom + controlsBottomInset - 31.0), size: CGSize(width: availableSize.width, height: environment.safeInsets.bottom - controlsBottomInset))
|
||||
|
||||
let cancelButtonSize = self.cancelButton.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(Button(
|
||||
content: AnyComponent(
|
||||
MultilineTextComponent(text: .plain(NSAttributedString(string: "Cancel", font: Font.regular(17.0), textColor: .white)))
|
||||
),
|
||||
action: { [weak controller] in
|
||||
controller?.requestDismiss(animated: true)
|
||||
}
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: 120.0, height: 44.0)
|
||||
)
|
||||
let cancelButtonFrame = CGRect(
|
||||
origin: CGPoint(x: 16.0, y: 80.0),
|
||||
size: cancelButtonSize
|
||||
)
|
||||
if let cancelButtonView = self.cancelButton.view {
|
||||
if cancelButtonView.superview == nil {
|
||||
self.addSubview(cancelButtonView)
|
||||
setupButtonShadow(cancelButtonView)
|
||||
}
|
||||
transition.setFrame(view: cancelButtonView, frame: cancelButtonFrame)
|
||||
}
|
||||
|
||||
let doneButtonSize = self.doneButton.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(
|
||||
ButtonComponent(
|
||||
background: ButtonComponent.Background(
|
||||
color: environment.theme.list.itemCheckColors.fillColor,
|
||||
foreground: environment.theme.list.itemCheckColors.foregroundColor,
|
||||
pressedColor: environment.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.9)
|
||||
),
|
||||
content: AnyComponentWithIdentity(
|
||||
id: AnyHashable(0),
|
||||
component: AnyComponent(ButtonTextContentComponent(
|
||||
text: "Save Cover",
|
||||
badge: 0,
|
||||
textColor: environment.theme.list.itemCheckColors.foregroundColor,
|
||||
badgeBackground: .clear,
|
||||
badgeForeground: .clear
|
||||
))
|
||||
),
|
||||
isEnabled: true,
|
||||
displaysProgress: false,
|
||||
action: { [weak controller, weak self] in
|
||||
if let playerState = self?.state?.playerState, let mediaEditor = self?.component?.mediaEditor, let image = mediaEditor.resultImage {
|
||||
mediaEditor.setCoverImageTimestamp(playerState.position)
|
||||
controller?.completed(playerState.position, image)
|
||||
}
|
||||
controller?.requestDismiss(animated: true)
|
||||
}
|
||||
)
|
||||
),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - buttonSideInset * 2.0, height: 50.0)
|
||||
)
|
||||
let doneButtonFrame = CGRect(
|
||||
origin: CGPoint(x: floor((availableSize.width - doneButtonSize.width) / 2.0), y: availableSize.height - 99.0),
|
||||
size: doneButtonSize
|
||||
)
|
||||
if let doneButtonView = self.doneButton.view {
|
||||
if doneButtonView.superview == nil {
|
||||
self.addSubview(doneButtonView)
|
||||
}
|
||||
transition.setFrame(view: doneButtonView, frame: doneButtonFrame)
|
||||
}
|
||||
|
||||
let labelSize = self.label.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(Text(text: "Story Cover", font: Font.semibold(17.0), color: UIColor(rgb: 0xffffff))),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - 88.0, height: 44.0)
|
||||
)
|
||||
let labelFrame = CGRect(
|
||||
origin: CGPoint(x: floorToScreenPixels((availableSize.width - labelSize.width) / 2.0), y: 80.0),
|
||||
size: labelSize
|
||||
)
|
||||
if let labelView = self.label.view {
|
||||
if labelView.superview == nil {
|
||||
self.addSubview(labelView)
|
||||
setupButtonShadow(labelView)
|
||||
}
|
||||
if labelView.bounds.width > 0.0 && labelFrame.width != labelView.bounds.width {
|
||||
if let snapshotView = labelView.snapshotView(afterScreenUpdates: false) {
|
||||
snapshotView.center = labelView.center
|
||||
self.buttonsContainerView.addSubview(snapshotView)
|
||||
|
||||
labelView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { _ in
|
||||
snapshotView.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
}
|
||||
labelView.bounds = CGRect(origin: .zero, size: labelFrame.size)
|
||||
transition.setPosition(view: labelView, position: labelFrame.center)
|
||||
}
|
||||
|
||||
transition.setFrame(view: self.buttonsContainerView, frame: buttonsContainerFrame)
|
||||
transition.setFrame(view: self.buttonsBackgroundView, frame: CGRect(origin: .zero, size: buttonsContainerFrame.size))
|
||||
|
||||
transition.setFrame(view: self.previewContainerView, frame: previewContainerFrame)
|
||||
|
||||
if let playerState = state.playerState {
|
||||
let visibleTracks = playerState.tracks.filter { $0.id == 0 }.map { MediaScrubberComponent.Track($0) }
|
||||
|
||||
let mediaEditor = component.mediaEditor
|
||||
let scrubberInset: CGFloat = buttonSideInset
|
||||
let scrubberSize = self.scrubber.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(MediaScrubberComponent(
|
||||
context: component.context,
|
||||
style: .cover,
|
||||
theme: environment.theme,
|
||||
generationTimestamp: playerState.generationTimestamp,
|
||||
position: playerState.position,
|
||||
minDuration: 1.0,
|
||||
maxDuration: storyMaxVideoDuration,
|
||||
isPlaying: playerState.isPlaying,
|
||||
tracks: visibleTracks,
|
||||
portalView: controller.portalView,
|
||||
positionUpdated: { [weak mediaEditor] position, apply in
|
||||
if let mediaEditor {
|
||||
mediaEditor.seek(position, andPlay: false)
|
||||
}
|
||||
},
|
||||
trackTrimUpdated: { _, _, _, _, _ in
|
||||
},
|
||||
trackOffsetUpdated: { _, _, _ in
|
||||
},
|
||||
trackLongPressed: { _, _ in
|
||||
}
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: previewSize.width - scrubberInset * 2.0, height: availableSize.height)
|
||||
)
|
||||
|
||||
let scrubberFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - scrubberSize.width) / 2.0), y: availableSize.height - environment.safeInsets.bottom - scrubberSize.height + controlsBottomInset + 3.0 - 40.0), size: scrubberSize)
|
||||
if let scrubberView = self.scrubber.view {
|
||||
var animateIn = false
|
||||
if scrubberView.superview == nil {
|
||||
animateIn = true
|
||||
self.addSubview(scrubberView)
|
||||
}
|
||||
if animateIn {
|
||||
scrubberView.frame = scrubberFrame
|
||||
} else {
|
||||
transition.setFrame(view: scrubberView, frame: scrubberFrame)
|
||||
}
|
||||
if animateIn {
|
||||
scrubberView.layer.animatePosition(from: CGPoint(x: 0.0, y: 44.0), to: .zero, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
||||
scrubberView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
scrubberView.layer.animateScale(from: 0.6, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return availableSize
|
||||
}
|
||||
}
|
||||
|
||||
func makeView() -> View {
|
||||
return View()
|
||||
}
|
||||
|
||||
public func update(view: View, availableSize: CGSize, state: State, environment: Environment<ViewControllerComponentContainer.Environment>, transition: ComponentTransition) -> CGSize {
|
||||
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
final class MediaCoverScreen: ViewController {
|
||||
fileprivate final class Node: ViewControllerTracingNode, ASGestureRecognizerDelegate {
|
||||
private weak var controller: MediaCoverScreen?
|
||||
private let context: AccountContext
|
||||
|
||||
fileprivate let componentHost: ComponentView<ViewControllerComponentContainer.Environment>
|
||||
|
||||
private var presentationData: PresentationData
|
||||
private var validLayout: ContainerViewLayout?
|
||||
|
||||
init(controller: MediaCoverScreen) {
|
||||
self.controller = controller
|
||||
self.context = controller.context
|
||||
|
||||
self.presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
self.componentHost = ComponentView<ViewControllerComponentContainer.Environment>()
|
||||
|
||||
super.init()
|
||||
|
||||
self.backgroundColor = .clear
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
self.view.disablesInteractiveModalDismiss = true
|
||||
self.view.disablesInteractiveKeyboardGestureRecognizer = true
|
||||
}
|
||||
|
||||
@objc func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func animateInFromEditor() {
|
||||
if let view = self.componentHost.view as? MediaCoverScreenComponent.View {
|
||||
view.animateInFromEditor()
|
||||
}
|
||||
}
|
||||
|
||||
func animateOutToEditor(completion: @escaping () -> Void) {
|
||||
if let mediaEditor = self.controller?.mediaEditor {
|
||||
mediaEditor.play()
|
||||
}
|
||||
if let view = self.componentHost.view as? MediaCoverScreenComponent.View {
|
||||
view.animateOutToEditor(completion: completion)
|
||||
}
|
||||
}
|
||||
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
let result = super.hitTest(point, with: event)
|
||||
if result === self.view {
|
||||
return nil
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func requestLayout(transition: ComponentTransition) {
|
||||
if let layout = self.validLayout {
|
||||
self.containerLayoutUpdated(layout: layout, forceUpdate: true, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
func containerLayoutUpdated(layout: ContainerViewLayout, forceUpdate: Bool = false, animateOut: Bool = false, transition: ComponentTransition) {
|
||||
guard let controller = self.controller else {
|
||||
return
|
||||
}
|
||||
let isFirstTime = self.validLayout == nil
|
||||
self.validLayout = layout
|
||||
|
||||
let isTablet = layout.metrics.isTablet
|
||||
|
||||
let previewSize: CGSize
|
||||
let topInset: CGFloat = (layout.statusBarHeight ?? 0.0) + 5.0
|
||||
if isTablet {
|
||||
let previewHeight = layout.size.height - topInset - 75.0
|
||||
previewSize = CGSize(width: floorToScreenPixels(previewHeight / 1.77778), height: previewHeight)
|
||||
} else {
|
||||
previewSize = CGSize(width: layout.size.width, height: floorToScreenPixels(layout.size.width * 1.77778))
|
||||
}
|
||||
let bottomInset = layout.size.height - previewSize.height - topInset
|
||||
|
||||
let environment = ViewControllerComponentContainer.Environment(
|
||||
statusBarHeight: layout.statusBarHeight ?? 0.0,
|
||||
navigationHeight: 0.0,
|
||||
safeInsets: UIEdgeInsets(
|
||||
top: topInset,
|
||||
left: layout.safeInsets.left,
|
||||
bottom: bottomInset,
|
||||
right: layout.safeInsets.right
|
||||
),
|
||||
additionalInsets: layout.additionalInsets,
|
||||
inputHeight: layout.inputHeight ?? 0.0,
|
||||
metrics: layout.metrics,
|
||||
deviceMetrics: layout.deviceMetrics,
|
||||
orientation: nil,
|
||||
isVisible: true,
|
||||
theme: self.presentationData.theme,
|
||||
strings: self.presentationData.strings,
|
||||
dateTimeFormat: self.presentationData.dateTimeFormat,
|
||||
controller: { [weak self] in
|
||||
return self?.controller
|
||||
}
|
||||
)
|
||||
|
||||
let componentSize = self.componentHost.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(
|
||||
MediaCoverScreenComponent(
|
||||
context: self.context,
|
||||
mediaEditor: controller.mediaEditor
|
||||
)
|
||||
),
|
||||
environment: {
|
||||
environment
|
||||
},
|
||||
forceUpdate: forceUpdate || animateOut,
|
||||
containerSize: layout.size
|
||||
)
|
||||
if let componentView = self.componentHost.view {
|
||||
if componentView.superview == nil {
|
||||
self.view.insertSubview(componentView, at: 3)
|
||||
componentView.clipsToBounds = true
|
||||
}
|
||||
let componentFrame = CGRect(origin: .zero, size: componentSize)
|
||||
transition.setFrame(view: componentView, frame: CGRect(origin: componentFrame.origin, size: CGSize(width: componentFrame.width, height: componentFrame.height)))
|
||||
}
|
||||
|
||||
if isFirstTime {
|
||||
self.animateInFromEditor()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate var node: Node {
|
||||
return self.displayNode as! Node
|
||||
}
|
||||
|
||||
fileprivate let context: AccountContext
|
||||
fileprivate let mediaEditor: MediaEditor
|
||||
fileprivate let previewView: MediaEditorPreviewView
|
||||
fileprivate let portalView: PortalView
|
||||
|
||||
var completed: (Double, UIImage) -> Void = { _, _ in }
|
||||
var dismissed: () -> Void = {}
|
||||
|
||||
private var initialValues: MediaEditorValues
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
mediaEditor: MediaEditor,
|
||||
previewView: MediaEditorPreviewView,
|
||||
portalView: PortalView
|
||||
) {
|
||||
self.context = context
|
||||
self.mediaEditor = mediaEditor
|
||||
self.previewView = previewView
|
||||
self.portalView = portalView
|
||||
self.initialValues = mediaEditor.values.makeCopy()
|
||||
|
||||
super.init(navigationBarPresentationData: nil)
|
||||
self.navigationPresentation = .flatModal
|
||||
|
||||
self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
|
||||
|
||||
self.statusBar.statusBarStyle = .White
|
||||
|
||||
if let coverImageTimestamp = mediaEditor.values.coverImageTimestamp {
|
||||
mediaEditor.seek(coverImageTimestamp, andPlay: false)
|
||||
} else {
|
||||
mediaEditor.seek(0.0, andPlay: false)
|
||||
}
|
||||
}
|
||||
|
||||
required init(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func loadDisplayNode() {
|
||||
self.displayNode = Node(controller: self)
|
||||
|
||||
super.displayNodeDidLoad()
|
||||
}
|
||||
|
||||
func requestDismiss(animated: Bool) {
|
||||
self.dismissed()
|
||||
|
||||
self.node.animateOutToEditor(completion: {
|
||||
self.dismiss()
|
||||
})
|
||||
}
|
||||
|
||||
override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
super.containerLayoutUpdated(layout, transition: transition)
|
||||
|
||||
(self.displayNode as! Node).containerLayoutUpdated(layout: layout, transition: ComponentTransition(transition))
|
||||
}
|
||||
}
|
||||
|
||||
private func setupButtonShadow(_ view: UIView, radius: CGFloat = 2.0) {
|
||||
view.layer.shadowOffset = CGSize(width: 0.0, height: 0.0)
|
||||
view.layer.shadowRadius = radius
|
||||
view.layer.shadowColor = UIColor.black.cgColor
|
||||
view.layer.shadowOpacity = 0.35
|
||||
}
|
||||
Reference in New Issue
Block a user