mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various fixes
This commit is contained in:
parent
80079dba5a
commit
fdff55d7ea
@ -870,7 +870,7 @@ public protocol SharedAccountContext: AnyObject {
|
|||||||
func makeStorageManagementController(context: AccountContext) -> ViewController
|
func makeStorageManagementController(context: AccountContext) -> ViewController
|
||||||
func makeAttachmentFileController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, bannedSendMedia: (Int32, Bool)?, presentGallery: @escaping () -> Void, presentFiles: @escaping () -> Void, send: @escaping (AnyMediaReference) -> Void) -> AttachmentFileController
|
func makeAttachmentFileController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, bannedSendMedia: (Int32, Bool)?, presentGallery: @escaping () -> Void, presentFiles: @escaping () -> Void, send: @escaping (AnyMediaReference) -> Void) -> AttachmentFileController
|
||||||
func makeGalleryCaptionPanelView(context: AccountContext, chatLocation: ChatLocation, customEmojiAvailable: Bool, present: @escaping (ViewController) -> Void, presentInGlobalOverlay: @escaping (ViewController) -> Void) -> NSObject?
|
func makeGalleryCaptionPanelView(context: AccountContext, chatLocation: ChatLocation, customEmojiAvailable: Bool, present: @escaping (ViewController) -> Void, presentInGlobalOverlay: @escaping (ViewController) -> Void) -> NSObject?
|
||||||
func makeHashtagSearchController(context: AccountContext, peer: EnginePeer?, query: String) -> ViewController
|
func makeHashtagSearchController(context: AccountContext, peer: EnginePeer?, query: String, all: Bool) -> ViewController
|
||||||
func makeMyStoriesController(context: AccountContext, isArchive: Bool) -> ViewController
|
func makeMyStoriesController(context: AccountContext, isArchive: Bool) -> ViewController
|
||||||
func navigateToChatController(_ params: NavigateToChatControllerParams)
|
func navigateToChatController(_ params: NavigateToChatControllerParams)
|
||||||
func navigateToForumChannel(context: AccountContext, peerId: EnginePeer.Id, navigationController: NavigationController)
|
func navigateToForumChannel(context: AccountContext, peerId: EnginePeer.Id, navigationController: NavigationController)
|
||||||
|
@ -3368,13 +3368,13 @@ private final class ShimmerEffectNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class ChatListSearchShimmerNode: ASDisplayNode {
|
public final class ChatListSearchShimmerNode: ASDisplayNode {
|
||||||
private let backgroundColorNode: ASDisplayNode
|
private let backgroundColorNode: ASDisplayNode
|
||||||
private let effectNode: ShimmerEffectNode
|
private let effectNode: ShimmerEffectNode
|
||||||
private let maskNode: ASImageNode
|
private let maskNode: ASImageNode
|
||||||
private var currentParams: (size: CGSize, presentationData: PresentationData, key: ChatListSearchPaneKey)?
|
private var currentParams: (size: CGSize, presentationData: PresentationData, key: ChatListSearchPaneKey)?
|
||||||
|
|
||||||
init(key: ChatListSearchPaneKey) {
|
public init(key: ChatListSearchPaneKey) {
|
||||||
self.backgroundColorNode = ASDisplayNode()
|
self.backgroundColorNode = ASDisplayNode()
|
||||||
self.effectNode = ShimmerEffectNode()
|
self.effectNode = ShimmerEffectNode()
|
||||||
self.maskNode = ASImageNode()
|
self.maskNode = ASImageNode()
|
||||||
@ -3388,7 +3388,7 @@ private final class ChatListSearchShimmerNode: ASDisplayNode {
|
|||||||
self.addSubnode(self.maskNode)
|
self.addSubnode(self.maskNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(context: AccountContext, size: CGSize, presentationData: PresentationData, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, key: ChatListSearchPaneKey, hasSelection: Bool, transition: ContainedViewLayoutTransition) {
|
public func update(context: AccountContext, size: CGSize, presentationData: PresentationData, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, key: ChatListSearchPaneKey, hasSelection: Bool, transition: ContainedViewLayoutTransition) {
|
||||||
if self.currentParams?.size != size || self.currentParams?.presentationData !== presentationData || self.currentParams?.key != key {
|
if self.currentParams?.size != size || self.currentParams?.presentationData !== presentationData || self.currentParams?.key != key {
|
||||||
self.currentParams = (size, presentationData, key)
|
self.currentParams = (size, presentationData, key)
|
||||||
|
|
||||||
|
@ -52,6 +52,7 @@ private func prepareForRendering(entityView: DrawingEntityView) {
|
|||||||
public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView {
|
public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView {
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private let size: CGSize
|
private let size: CGSize
|
||||||
|
private let hasBin: Bool
|
||||||
|
|
||||||
weak var drawingView: DrawingView?
|
weak var drawingView: DrawingView?
|
||||||
public weak var selectionContainerView: DrawingSelectionContainerView?
|
public weak var selectionContainerView: DrawingSelectionContainerView?
|
||||||
@ -85,9 +86,10 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView {
|
|||||||
|
|
||||||
private let hapticFeedback = HapticFeedback()
|
private let hapticFeedback = HapticFeedback()
|
||||||
|
|
||||||
public init(context: AccountContext, size: CGSize) {
|
public init(context: AccountContext, size: CGSize, hasBin: Bool = false) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.size = size
|
self.size = size
|
||||||
|
self.hasBin = hasBin
|
||||||
|
|
||||||
super.init(frame: CGRect(origin: .zero, size: size))
|
super.init(frame: CGRect(origin: .zero, size: size))
|
||||||
|
|
||||||
@ -690,67 +692,71 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView {
|
|||||||
public func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) {
|
public func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) {
|
||||||
let location = gestureRecognizer.location(in: self)
|
let location = gestureRecognizer.location(in: self)
|
||||||
if let selectedEntityView = self.selectedEntityView, let selectionView = selectedEntityView.selectionView {
|
if let selectedEntityView = self.selectedEntityView, let selectionView = selectedEntityView.selectionView {
|
||||||
var isTrappedInBin = false
|
if !self.hasBin {
|
||||||
let scale = 100.0 / selectedEntityView.bounds.size.width
|
|
||||||
switch gestureRecognizer.state {
|
|
||||||
case .changed:
|
|
||||||
if self.updateBin(location: location) {
|
|
||||||
isTrappedInBin = true
|
|
||||||
}
|
|
||||||
case .ended, .cancelled:
|
|
||||||
let _ = self.updateBin(location: nil)
|
|
||||||
if selectedEntityView.isTrappedInBin {
|
|
||||||
selectedEntityView.layer.animateScale(from: scale, to: 0.01, duration: 0.2, removeOnCompletion: false)
|
|
||||||
selectedEntityView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { _ in
|
|
||||||
self.remove(uuid: selectedEntityView.entity.uuid)
|
|
||||||
})
|
|
||||||
self.selectEntity(nil)
|
|
||||||
|
|
||||||
Queue.mainQueue().after(0.3, {
|
|
||||||
self.onInteractionUpdated(false)
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
let transition = Transition.easeInOut(duration: 0.2)
|
|
||||||
if isTrappedInBin, let binView = self.bin.view {
|
|
||||||
if !selectedEntityView.isTrappedInBin {
|
|
||||||
let refs = [
|
|
||||||
self.xAxisView,
|
|
||||||
self.yAxisView,
|
|
||||||
self.topEdgeView,
|
|
||||||
self.leftEdgeView,
|
|
||||||
self.rightEdgeView,
|
|
||||||
self.bottomEdgeView
|
|
||||||
]
|
|
||||||
for ref in refs {
|
|
||||||
transition.setAlpha(view: ref, alpha: 0.0)
|
|
||||||
}
|
|
||||||
self.edgePreviewUpdated(false)
|
|
||||||
|
|
||||||
selectedEntityView.isTrappedInBin = true
|
|
||||||
transition.setAlpha(view: selectionView, alpha: 0.0)
|
|
||||||
transition.animatePosition(view: selectionView, from: selectionView.center, to: self.convert(binView.center, to: selectionView.superview))
|
|
||||||
transition.animateScale(view: selectionView, from: 0.0, to: -0.5, additive: true)
|
|
||||||
|
|
||||||
transition.setPosition(view: selectedEntityView, position: binView.center)
|
|
||||||
|
|
||||||
let rotation = selectedEntityView.layer.transform.decompose().rotation
|
|
||||||
var transform = CATransform3DMakeScale(scale, scale, 1.0)
|
|
||||||
transform = CATransform3DRotate(transform, CGFloat(rotation.z), 0.0, 0.0, 1.0)
|
|
||||||
|
|
||||||
transition.setTransform(view: selectedEntityView, transform: transform)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if selectedEntityView.isTrappedInBin {
|
|
||||||
selectedEntityView.isTrappedInBin = false
|
|
||||||
transition.setAlpha(view: selectionView, alpha: 1.0)
|
|
||||||
selectedEntityView.layer.animateScale(from: scale, to: selectedEntityView.entity.scale, duration: 0.13)
|
|
||||||
}
|
|
||||||
selectionView.handlePan(gestureRecognizer)
|
selectionView.handlePan(gestureRecognizer)
|
||||||
|
} else {
|
||||||
|
var isTrappedInBin = false
|
||||||
|
let scale = 100.0 / selectedEntityView.bounds.size.width
|
||||||
|
switch gestureRecognizer.state {
|
||||||
|
case .changed:
|
||||||
|
if self.updateBin(location: location) {
|
||||||
|
isTrappedInBin = true
|
||||||
|
}
|
||||||
|
case .ended, .cancelled:
|
||||||
|
let _ = self.updateBin(location: nil)
|
||||||
|
if selectedEntityView.isTrappedInBin {
|
||||||
|
selectedEntityView.layer.animateScale(from: scale, to: 0.01, duration: 0.2, removeOnCompletion: false)
|
||||||
|
selectedEntityView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { _ in
|
||||||
|
self.remove(uuid: selectedEntityView.entity.uuid)
|
||||||
|
})
|
||||||
|
self.selectEntity(nil)
|
||||||
|
|
||||||
|
Queue.mainQueue().after(0.3, {
|
||||||
|
self.onInteractionUpdated(false)
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
let transition = Transition.easeInOut(duration: 0.2)
|
||||||
|
if isTrappedInBin, let binView = self.bin.view {
|
||||||
|
if !selectedEntityView.isTrappedInBin {
|
||||||
|
let refs = [
|
||||||
|
self.xAxisView,
|
||||||
|
self.yAxisView,
|
||||||
|
self.topEdgeView,
|
||||||
|
self.leftEdgeView,
|
||||||
|
self.rightEdgeView,
|
||||||
|
self.bottomEdgeView
|
||||||
|
]
|
||||||
|
for ref in refs {
|
||||||
|
transition.setAlpha(view: ref, alpha: 0.0)
|
||||||
|
}
|
||||||
|
self.edgePreviewUpdated(false)
|
||||||
|
|
||||||
|
selectedEntityView.isTrappedInBin = true
|
||||||
|
transition.setAlpha(view: selectionView, alpha: 0.0)
|
||||||
|
transition.animatePosition(view: selectionView, from: selectionView.center, to: self.convert(binView.center, to: selectionView.superview))
|
||||||
|
transition.animateScale(view: selectionView, from: 0.0, to: -0.5, additive: true)
|
||||||
|
|
||||||
|
transition.setPosition(view: selectedEntityView, position: binView.center)
|
||||||
|
|
||||||
|
let rotation = selectedEntityView.layer.transform.decompose().rotation
|
||||||
|
var transform = CATransform3DMakeScale(scale, scale, 1.0)
|
||||||
|
transform = CATransform3DRotate(transform, CGFloat(rotation.z), 0.0, 0.0, 1.0)
|
||||||
|
|
||||||
|
transition.setTransform(view: selectedEntityView, transform: transform)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if selectedEntityView.isTrappedInBin {
|
||||||
|
selectedEntityView.isTrappedInBin = false
|
||||||
|
transition.setAlpha(view: selectionView, alpha: 1.0)
|
||||||
|
selectedEntityView.layer.animateScale(from: scale, to: selectedEntityView.entity.scale, duration: 0.13)
|
||||||
|
}
|
||||||
|
selectionView.handlePan(gestureRecognizer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if gestureRecognizer.numberOfTouches == 1, let viewToSelect = self.entity(at: location) {
|
} else if gestureRecognizer.numberOfTouches == 1, let viewToSelect = self.entity(at: location) {
|
||||||
self.selectEntity(viewToSelect.entity)
|
self.selectEntity(viewToSelect.entity)
|
||||||
|
@ -2965,7 +2965,7 @@ public final class DrawingToolsInteraction {
|
|||||||
private let onInteractionUpdated: (Bool) -> Void
|
private let onInteractionUpdated: (Bool) -> Void
|
||||||
private let onTextEditingEnded: (Bool) -> Void
|
private let onTextEditingEnded: (Bool) -> Void
|
||||||
|
|
||||||
private let getCurrentImage: () -> UIImage?
|
public let getCurrentImage: () -> UIImage?
|
||||||
private let getControllerNode: () -> ASDisplayNode?
|
private let getControllerNode: () -> ASDisplayNode?
|
||||||
private let present: (ViewController, PresentationContextType, Any?) -> Void
|
private let present: (ViewController, PresentationContextType, Any?) -> Void
|
||||||
private let addSubview: (UIView) -> Void
|
private let addSubview: (UIView) -> Void
|
||||||
|
@ -329,7 +329,7 @@ public final class DrawingStickerEntityView: DrawingEntityView {
|
|||||||
if size.width > 0 && self.currentSize != size {
|
if size.width > 0 && self.currentSize != size {
|
||||||
self.currentSize = size
|
self.currentSize = size
|
||||||
|
|
||||||
let sideSize: CGFloat = size.width
|
let sideSize: CGFloat = max(size.width, size.height)
|
||||||
let boundingSize = CGSize(width: sideSize, height: sideSize)
|
let boundingSize = CGSize(width: sideSize, height: sideSize)
|
||||||
|
|
||||||
let imageSize = self.dimensions.aspectFitted(boundingSize)
|
let imageSize = self.dimensions.aspectFitted(boundingSize)
|
||||||
@ -656,7 +656,47 @@ final class DrawingStickerEntititySelectionView: DrawingEntitySelectionView {
|
|||||||
let handleSize = CGSize(width: 9.0 / self.scale, height: 9.0 / self.scale)
|
let handleSize = CGSize(width: 9.0 / self.scale, height: 9.0 / self.scale)
|
||||||
let handlePath = CGPath(ellipseIn: CGRect(origin: CGPoint(x: (bounds.width - handleSize.width) / 2.0, y: (bounds.height - handleSize.height) / 2.0), size: handleSize), transform: nil)
|
let handlePath = CGPath(ellipseIn: CGRect(origin: CGPoint(x: (bounds.width - handleSize.width) / 2.0, y: (bounds.height - handleSize.height) / 2.0), size: handleSize), transform: nil)
|
||||||
let lineWidth = (1.0 + UIScreenPixel) / self.scale
|
let lineWidth = (1.0 + UIScreenPixel) / self.scale
|
||||||
|
|
||||||
|
let radius = (self.bounds.width - inset * 2.0) / 2.0
|
||||||
|
let circumference: CGFloat = 2.0 * .pi * radius
|
||||||
|
let relativeDashLength: CGFloat = 0.25
|
||||||
|
|
||||||
|
self.border.lineWidth = 2.0 / self.scale
|
||||||
|
|
||||||
|
let actualInset: CGFloat
|
||||||
|
if entity.isRectangle {
|
||||||
|
let aspectRatio = entity.baseSize.width / entity.baseSize.height
|
||||||
|
|
||||||
|
let width: CGFloat
|
||||||
|
let height: CGFloat
|
||||||
|
|
||||||
|
if entity.baseSize.width > entity.baseSize.height {
|
||||||
|
width = self.bounds.width - inset * 2.0
|
||||||
|
height = self.bounds.height / aspectRatio - inset * 2.0
|
||||||
|
} else {
|
||||||
|
width = self.bounds.width * aspectRatio - inset * 2.0
|
||||||
|
height = self.bounds.height - inset * 2.0
|
||||||
|
}
|
||||||
|
|
||||||
|
actualInset = floorToScreenPixels((self.bounds.width - width) / 2.0)
|
||||||
|
|
||||||
|
let cornerRadius: CGFloat = 12.0 - self.scale
|
||||||
|
let perimeter: CGFloat = 2.0 * (width + height - cornerRadius * (4.0 - .pi))
|
||||||
|
let count = 12
|
||||||
|
let dashLength = perimeter / CGFloat(count)
|
||||||
|
self.border.lineDashPattern = [dashLength * relativeDashLength, dashLength * relativeDashLength] as [NSNumber]
|
||||||
|
|
||||||
|
self.border.path = UIBezierPath(roundedRect: CGRect(origin: CGPoint(x: floorToScreenPixels((self.bounds.width - width) / 2.0), y: floorToScreenPixels((self.bounds.height - height) / 2.0)), size: CGSize(width: width, height: height)), cornerRadius: cornerRadius).cgPath
|
||||||
|
} else {
|
||||||
|
actualInset = inset
|
||||||
|
|
||||||
|
let count = 10
|
||||||
|
let dashLength = circumference / CGFloat(count)
|
||||||
|
self.border.lineDashPattern = [dashLength * relativeDashLength, dashLength * relativeDashLength] as [NSNumber]
|
||||||
|
|
||||||
|
self.border.path = UIBezierPath(ovalIn: CGRect(origin: CGPoint(x: inset, y: inset), size: CGSize(width: self.bounds.width - inset * 2.0, height: self.bounds.height - inset * 2.0))).cgPath
|
||||||
|
}
|
||||||
|
|
||||||
let handles = [
|
let handles = [
|
||||||
self.leftHandle,
|
self.leftHandle,
|
||||||
self.rightHandle
|
self.rightHandle
|
||||||
@ -668,29 +708,8 @@ final class DrawingStickerEntititySelectionView: DrawingEntitySelectionView {
|
|||||||
handle.lineWidth = lineWidth
|
handle.lineWidth = lineWidth
|
||||||
}
|
}
|
||||||
|
|
||||||
self.leftHandle.position = CGPoint(x: inset, y: self.bounds.midY)
|
|
||||||
self.rightHandle.position = CGPoint(x: self.bounds.maxX - inset, y: self.bounds.midY)
|
|
||||||
|
|
||||||
|
self.leftHandle.position = CGPoint(x: actualInset, y: self.bounds.midY)
|
||||||
let radius = (self.bounds.width - inset * 2.0) / 2.0
|
self.rightHandle.position = CGPoint(x: self.bounds.maxX - actualInset, y: self.bounds.midY)
|
||||||
let circumference: CGFloat = 2.0 * .pi * radius
|
|
||||||
let count = 10
|
|
||||||
let relativeDashLength: CGFloat = 0.25
|
|
||||||
let dashLength = circumference / CGFloat(count)
|
|
||||||
self.border.lineDashPattern = [dashLength * relativeDashLength, dashLength * relativeDashLength] as [NSNumber]
|
|
||||||
|
|
||||||
self.border.lineWidth = 2.0 / self.scale
|
|
||||||
|
|
||||||
if entity.isRectangle {
|
|
||||||
let aspectRatio = entity.baseSize.width / entity.baseSize.height
|
|
||||||
|
|
||||||
let width: CGFloat = self.bounds.width - inset * 2.0
|
|
||||||
let height: CGFloat = self.bounds.height / aspectRatio - inset * 2.0
|
|
||||||
|
|
||||||
let cornerRadius: CGFloat = 12.0 - self.scale
|
|
||||||
self.border.path = UIBezierPath(roundedRect: CGRect(origin: CGPoint(x: floorToScreenPixels((self.bounds.width - width) / 2.0), y: floorToScreenPixels((self.bounds.height - height) / 2.0)), size: CGSize(width: width, height: height)), cornerRadius: cornerRadius).cgPath
|
|
||||||
} else {
|
|
||||||
self.border.path = UIBezierPath(ovalIn: CGRect(origin: CGPoint(x: inset, y: inset), size: CGSize(width: self.bounds.width - inset * 2.0, height: self.bounds.height - inset * 2.0))).cgPath
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ public final class HashtagSearchController: TelegramBaseController {
|
|||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private let peer: EnginePeer?
|
private let peer: EnginePeer?
|
||||||
private let query: String
|
private let query: String
|
||||||
|
let all: Bool
|
||||||
private var transitionDisposable: Disposable?
|
private var transitionDisposable: Disposable?
|
||||||
private let openMessageFromSearchDisposable = MetaDisposable()
|
private let openMessageFromSearchDisposable = MetaDisposable()
|
||||||
|
|
||||||
@ -30,10 +31,11 @@ public final class HashtagSearchController: TelegramBaseController {
|
|||||||
return self.displayNode as! HashtagSearchControllerNode
|
return self.displayNode as! HashtagSearchControllerNode
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(context: AccountContext, peer: EnginePeer?, query: String) {
|
public init(context: AccountContext, peer: EnginePeer?, query: String, all: Bool = false) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.peer = peer
|
self.peer = peer
|
||||||
self.query = query
|
self.query = query
|
||||||
|
self.all = all
|
||||||
|
|
||||||
self.animationCache = context.animationCache
|
self.animationCache = context.animationCache
|
||||||
self.animationRenderer = context.animationRenderer
|
self.animationRenderer = context.animationRenderer
|
||||||
|
@ -11,17 +11,16 @@ import ChatListSearchItemHeader
|
|||||||
final class HashtagSearchControllerNode: ASDisplayNode {
|
final class HashtagSearchControllerNode: ASDisplayNode {
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private weak var controller: HashtagSearchController?
|
private weak var controller: HashtagSearchController?
|
||||||
|
private let query: String
|
||||||
|
|
||||||
private let navigationBar: NavigationBar?
|
private let navigationBar: NavigationBar?
|
||||||
|
|
||||||
private let segmentedControlNode: SegmentedControlNode
|
private let segmentedControlNode: SegmentedControlNode
|
||||||
let listNode: ListView
|
let listNode: ListView
|
||||||
|
let shimmerNode: ChatListSearchShimmerNode
|
||||||
|
|
||||||
let chatController: ChatController?
|
let chatController: ChatController?
|
||||||
|
|
||||||
|
|
||||||
private let query: String
|
|
||||||
|
|
||||||
private var containerLayout: (ContainerViewLayout, CGFloat)?
|
private var containerLayout: (ContainerViewLayout, CGFloat)?
|
||||||
private var enqueuedTransitions: [(ChatListSearchContainerTransition, Bool)] = []
|
private var enqueuedTransitions: [(ChatListSearchContainerTransition, Bool)] = []
|
||||||
private var hasValidLayout = false
|
private var hasValidLayout = false
|
||||||
@ -34,6 +33,10 @@ final class HashtagSearchControllerNode: ASDisplayNode {
|
|||||||
|
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
|
self.shimmerNode = ChatListSearchShimmerNode(key: .chats)
|
||||||
|
self.shimmerNode.isUserInteractionEnabled = false
|
||||||
|
self.shimmerNode.allowsGroupOpacity = true
|
||||||
|
|
||||||
self.listNode = ListView()
|
self.listNode = ListView()
|
||||||
self.listNode.accessibilityPageScrolledString = { row, count in
|
self.listNode.accessibilityPageScrolledString = { row, count in
|
||||||
return presentationData.strings.VoiceOver_ScrollStatus(row, count).string
|
return presentationData.strings.VoiceOver_ScrollStatus(row, count).string
|
||||||
@ -48,7 +51,7 @@ final class HashtagSearchControllerNode: ASDisplayNode {
|
|||||||
items.append(peer?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) ?? "")
|
items.append(peer?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) ?? "")
|
||||||
}
|
}
|
||||||
items.append(presentationData.strings.HashtagSearch_AllChats)
|
items.append(presentationData.strings.HashtagSearch_AllChats)
|
||||||
self.segmentedControlNode = SegmentedControlNode(theme: SegmentedControlTheme(theme: presentationData.theme), items: items.map { SegmentedControlItem(title: $0) }, selectedIndex: 0)
|
self.segmentedControlNode = SegmentedControlNode(theme: SegmentedControlTheme(theme: presentationData.theme), items: items.map { SegmentedControlItem(title: $0) }, selectedIndex: controller.all ? 1 : 0)
|
||||||
|
|
||||||
if let peer = peer {
|
if let peer = peer {
|
||||||
self.chatController = context.sharedContext.makeChatController(context: context, chatLocation: .peer(id: peer.id), subject: nil, botStart: nil, mode: .inline(navigationController))
|
self.chatController = context.sharedContext.makeChatController(context: context, chatLocation: .peer(id: peer.id), subject: nil, botStart: nil, mode: .inline(navigationController))
|
||||||
@ -65,7 +68,15 @@ final class HashtagSearchControllerNode: ASDisplayNode {
|
|||||||
self.backgroundColor = presentationData.theme.chatList.backgroundColor
|
self.backgroundColor = presentationData.theme.chatList.backgroundColor
|
||||||
|
|
||||||
self.addSubnode(self.listNode)
|
self.addSubnode(self.listNode)
|
||||||
self.listNode.isHidden = true
|
// self.addSubnode(self.shimmerNode)
|
||||||
|
|
||||||
|
if controller.all {
|
||||||
|
self.chatController?.displayNode.isHidden = true
|
||||||
|
self.listNode.isHidden = false
|
||||||
|
} else {
|
||||||
|
self.chatController?.displayNode.isHidden = false
|
||||||
|
self.listNode.isHidden = true
|
||||||
|
}
|
||||||
|
|
||||||
self.segmentedControlNode.selectedIndexChanged = { [weak self] index in
|
self.segmentedControlNode.selectedIndexChanged = { [weak self] index in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
@ -164,6 +175,11 @@ final class HashtagSearchControllerNode: ASDisplayNode {
|
|||||||
self.listNode.bounds = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: layout.size.height)
|
self.listNode.bounds = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: layout.size.height)
|
||||||
self.listNode.position = CGPoint(x: layout.size.width / 2.0, y: layout.size.height / 2.0)
|
self.listNode.position = CGPoint(x: layout.size.width / 2.0, y: layout.size.height / 2.0)
|
||||||
|
|
||||||
|
let overflowInset: CGFloat = 0.0
|
||||||
|
let topInset = navigationBarHeight
|
||||||
|
self.shimmerNode.frame = CGRect(origin: CGPoint(x: overflowInset, y: topInset), size: CGSize(width: layout.size.width - overflowInset * 2.0, height: layout.size.height))
|
||||||
|
self.shimmerNode.update(context: self.context, size: CGSize(width: layout.size.width - overflowInset * 2.0, height: layout.size.height), presentationData: self.context.sharedContext.currentPresentationData.with { $0 }, animationCache: self.context.animationCache, animationRenderer: self.context.animationRenderer, key: .chats, hasSelection: false, transition: transition)
|
||||||
|
|
||||||
insets.top += 4.0
|
insets.top += 4.0
|
||||||
|
|
||||||
let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition)
|
let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition)
|
||||||
|
@ -188,6 +188,10 @@ final class MediaPickerGridItemNode: GridItemNode {
|
|||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
} else if let (draft, _) = self.currentDraftState {
|
||||||
|
let tag = Month(localTimestamp: draft.timestamp).packedValue
|
||||||
|
self._cachedTag = tag
|
||||||
|
return tag
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -433,7 +433,7 @@ private final class CameraScreenComponent: CombinedComponent {
|
|||||||
case .began:
|
case .began:
|
||||||
return .single(.pendingImage)
|
return .single(.pendingImage)
|
||||||
case let .finished(image, additionalImage, _):
|
case let .finished(image, additionalImage, _):
|
||||||
return .single(.image(CameraScreen.Result.Image(image: image, additionalImage: additionalImage, additionalImagePosition: .bottomRight)))
|
return .single(.image(CameraScreen.Result.Image(image: image, additionalImage: additionalImage, additionalImagePosition: .topRight)))
|
||||||
case .failed:
|
case .failed:
|
||||||
return .complete()
|
return .complete()
|
||||||
}
|
}
|
||||||
@ -470,7 +470,7 @@ private final class CameraScreenComponent: CombinedComponent {
|
|||||||
self.resultDisposable.set((self.camera.stopRecording()
|
self.resultDisposable.set((self.camera.stopRecording()
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] result in
|
|> deliverOnMainQueue).start(next: { [weak self] result in
|
||||||
if let self, case let .finished(mainResult, additionalResult, duration, positionChangeTimestamps, _) = result {
|
if let self, case let .finished(mainResult, additionalResult, duration, positionChangeTimestamps, _) = result {
|
||||||
self.completion.invoke(.single(.video(CameraScreen.Result.Video(videoPath: mainResult.0, coverImage: mainResult.1, mirror: mainResult.2, additionalVideoPath: additionalResult?.0, additionalCoverImage: additionalResult?.1, dimensions: PixelDimensions(width: 1080, height: 1920), duration: duration, positionChangeTimestamps: positionChangeTimestamps, additionalVideoPosition: .bottomRight))))
|
self.completion.invoke(.single(.video(CameraScreen.Result.Video(videoPath: mainResult.0, coverImage: mainResult.1, mirror: mainResult.2, additionalVideoPath: additionalResult?.0, additionalCoverImage: additionalResult?.1, dimensions: PixelDimensions(width: 1080, height: 1920), duration: duration, positionChangeTimestamps: positionChangeTimestamps, additionalVideoPosition: .topRight))))
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
self.isTransitioning = true
|
self.isTransitioning = true
|
||||||
@ -1075,7 +1075,7 @@ public class CameraScreen: ViewController {
|
|||||||
private var appliedDualCam = false
|
private var appliedDualCam = false
|
||||||
private var cameraPosition: Camera.Position = .back
|
private var cameraPosition: Camera.Position = .back
|
||||||
|
|
||||||
private var pipPosition: PIPPosition = .bottomRight
|
private var pipPosition: PIPPosition = .topRight
|
||||||
|
|
||||||
fileprivate var previewBlurPromise = ValuePromise<Bool>(false)
|
fileprivate var previewBlurPromise = ValuePromise<Bool>(false)
|
||||||
private let animateFlipAction = ActionSlot<Void>()
|
private let animateFlipAction = ActionSlot<Void>()
|
||||||
@ -1941,7 +1941,9 @@ public class CameraScreen: ViewController {
|
|||||||
transition.setPosition(view: self.backgroundView, position: CGPoint(x: layout.size.width / 2.0, y: layout.size.height / 2.0))
|
transition.setPosition(view: self.backgroundView, position: CGPoint(x: layout.size.width / 2.0, y: layout.size.height / 2.0))
|
||||||
transition.setBounds(view: self.backgroundView, bounds: CGRect(origin: .zero, size: layout.size))
|
transition.setBounds(view: self.backgroundView, bounds: CGRect(origin: .zero, size: layout.size))
|
||||||
|
|
||||||
transition.setPosition(view: self.containerView, position: CGPoint(x: layout.size.width / 2.0, y: layout.size.height / 2.0))
|
if !self.hasGallery {
|
||||||
|
transition.setPosition(view: self.containerView, position: CGPoint(x: layout.size.width / 2.0, y: layout.size.height / 2.0))
|
||||||
|
}
|
||||||
transition.setBounds(view: self.containerView, bounds: CGRect(origin: .zero, size: layout.size))
|
transition.setBounds(view: self.containerView, bounds: CGRect(origin: .zero, size: layout.size))
|
||||||
|
|
||||||
transition.setFrame(view: self.transitionDimView, frame: CGRect(origin: .zero, size: layout.size))
|
transition.setFrame(view: self.transitionDimView, frame: CGRect(origin: .zero, size: layout.size))
|
||||||
@ -2293,11 +2295,16 @@ public class CameraScreen: ViewController {
|
|||||||
let transitionFraction = max(0.0, min(1.0, transitionFraction))
|
let transitionFraction = max(0.0, min(1.0, transitionFraction))
|
||||||
let offsetX = floorToScreenPixels((1.0 - transitionFraction) * self.node.frame.width * -1.0)
|
let offsetX = floorToScreenPixels((1.0 - transitionFraction) * self.node.frame.width * -1.0)
|
||||||
transition.updateTransform(layer: self.node.backgroundView.layer, transform: CGAffineTransform(translationX: offsetX, y: 0.0))
|
transition.updateTransform(layer: self.node.backgroundView.layer, transform: CGAffineTransform(translationX: offsetX, y: 0.0))
|
||||||
transition.updateTransform(layer: self.node.containerView.layer, transform: CGAffineTransform(translationX: offsetX, y: 0.0))
|
|
||||||
let scale: CGFloat = max(0.8, min(1.0, 0.8 + 0.2 * transitionFraction))
|
let scale: CGFloat = max(0.8, min(1.0, 0.8 + 0.2 * transitionFraction))
|
||||||
transition.updateSublayerTransformScaleAndOffset(layer: self.node.containerView.layer, scale: scale, offset: CGPoint(x: -offsetX * 1.0 / scale * 0.5, y: 0.0), completion: { _ in
|
if !self.node.hasGallery {
|
||||||
|
transition.updateTransform(layer: self.node.containerView.layer, transform: CGAffineTransform(translationX: offsetX, y: 0.0))
|
||||||
|
transition.updateSublayerTransformScaleAndOffset(layer: self.node.containerView.layer, scale: scale, offset: CGPoint(x: -offsetX * 1.0 / scale * 0.5, y: 0.0), completion: { _ in
|
||||||
|
completion()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
completion()
|
completion()
|
||||||
})
|
}
|
||||||
|
|
||||||
let dimAlpha = 0.6 * (1.0 - transitionFraction)
|
let dimAlpha = 0.6 * (1.0 - transitionFraction)
|
||||||
transition.updateAlpha(layer: self.node.transitionDimView.layer, alpha: dimAlpha)
|
transition.updateAlpha(layer: self.node.transitionDimView.layer, alpha: dimAlpha)
|
||||||
@ -2549,7 +2556,7 @@ private func pipPositionForLocation(layout: ContainerViewLayout, position: CGPoi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var position: CameraScreen.PIPPosition = .bottomRight
|
var position: CameraScreen.PIPPosition = .topRight
|
||||||
if result.x == 0.0 && result.y == 0.0 {
|
if result.x == 0.0 && result.y == 0.0 {
|
||||||
position = .topLeft
|
position = .topLeft
|
||||||
} else if result.x == 1.0 && result.y == 0.0 {
|
} else if result.x == 1.0 && result.y == 0.0 {
|
||||||
|
@ -271,9 +271,6 @@ private func makeEditorImageFrameComposition(context: CIContext, inputImage: CII
|
|||||||
baseScale = entityBaseScale
|
baseScale = entityBaseScale
|
||||||
} else if let baseSize = entity.baseSize {
|
} else if let baseSize = entity.baseSize {
|
||||||
baseScale = baseSize.width / image.extent.width
|
baseScale = baseSize.width / image.extent.width
|
||||||
if baseSize.width != baseSize.height {
|
|
||||||
baseScale *= min(baseSize.width, baseSize.height) / max(baseSize.width, baseSize.height)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var transform = CGAffineTransform.identity
|
var transform = CGAffineTransform.identity
|
||||||
|
@ -66,6 +66,7 @@ public final class MediaEditorDraft: Codable, Equatable {
|
|||||||
case values
|
case values
|
||||||
case caption
|
case caption
|
||||||
case privacy
|
case privacy
|
||||||
|
case timestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
public let path: String
|
public let path: String
|
||||||
@ -76,8 +77,9 @@ public final class MediaEditorDraft: Codable, Equatable {
|
|||||||
public let values: MediaEditorValues
|
public let values: MediaEditorValues
|
||||||
public let caption: NSAttributedString
|
public let caption: NSAttributedString
|
||||||
public let privacy: MediaEditorResultPrivacy?
|
public let privacy: MediaEditorResultPrivacy?
|
||||||
|
public let timestamp: Int32
|
||||||
|
|
||||||
public init(path: String, isVideo: Bool, thumbnail: UIImage, dimensions: PixelDimensions, duration: Double?, values: MediaEditorValues, caption: NSAttributedString, privacy: MediaEditorResultPrivacy?) {
|
public init(path: String, isVideo: Bool, thumbnail: UIImage, dimensions: PixelDimensions, duration: Double?, values: MediaEditorValues, caption: NSAttributedString, privacy: MediaEditorResultPrivacy?, timestamp: Int32) {
|
||||||
self.path = path
|
self.path = path
|
||||||
self.isVideo = isVideo
|
self.isVideo = isVideo
|
||||||
self.thumbnail = thumbnail
|
self.thumbnail = thumbnail
|
||||||
@ -86,6 +88,7 @@ public final class MediaEditorDraft: Codable, Equatable {
|
|||||||
self.values = values
|
self.values = values
|
||||||
self.caption = caption
|
self.caption = caption
|
||||||
self.privacy = privacy
|
self.privacy = privacy
|
||||||
|
self.timestamp = timestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(from decoder: Decoder) throws {
|
public init(from decoder: Decoder) throws {
|
||||||
@ -117,6 +120,8 @@ public final class MediaEditorDraft: Codable, Equatable {
|
|||||||
} else {
|
} else {
|
||||||
self.privacy = nil
|
self.privacy = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.timestamp = try container.decodeIfPresent(Int32.self, forKey: .timestamp) ?? 1688909663
|
||||||
}
|
}
|
||||||
|
|
||||||
public func encode(to encoder: Encoder) throws {
|
public func encode(to encoder: Encoder) throws {
|
||||||
@ -145,6 +150,7 @@ public final class MediaEditorDraft: Codable, Equatable {
|
|||||||
} else {
|
} else {
|
||||||
try container.encodeNil(forKey: .privacy)
|
try container.encodeNil(forKey: .privacy)
|
||||||
}
|
}
|
||||||
|
try container.encode(self.timestamp, forKey: .timestamp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,7 +341,7 @@ final class MediaEditorScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
dismissTextInput: {
|
dismissTextInput: {
|
||||||
|
|
||||||
},
|
},
|
||||||
insertText: { [weak self] text in
|
insertText: { [weak self] text in
|
||||||
if let self {
|
if let self {
|
||||||
@ -1719,7 +1719,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
self.gradientView = UIImageView()
|
self.gradientView = UIImageView()
|
||||||
|
|
||||||
self.entitiesContainerView = UIView(frame: CGRect(origin: .zero, size: storyDimensions))
|
self.entitiesContainerView = UIView(frame: CGRect(origin: .zero, size: storyDimensions))
|
||||||
self.entitiesView = DrawingEntitiesView(context: controller.context, size: storyDimensions)
|
self.entitiesView = DrawingEntitiesView(context: controller.context, size: storyDimensions, hasBin: true)
|
||||||
self.entitiesView.getEntityCenterPosition = {
|
self.entitiesView.getEntityCenterPosition = {
|
||||||
return CGPoint(x: storyDimensions.width / 2.0, y: storyDimensions.height / 2.0)
|
return CGPoint(x: storyDimensions.width / 2.0, y: storyDimensions.height / 2.0)
|
||||||
}
|
}
|
||||||
@ -2100,8 +2100,37 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
}).start()
|
}).start()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getCurrentImage: {
|
getCurrentImage: { [weak self] in
|
||||||
return nil
|
guard let self else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||||
|
let imageSize = CGSize(width: 1080, height: 1920)
|
||||||
|
let context = DrawingContext(size: imageSize, scale: 1.0, opaque: true, colorSpace: colorSpace)
|
||||||
|
|
||||||
|
context?.withFlippedContext { context in
|
||||||
|
if let gradientImage = self.gradientView.image?.cgImage {
|
||||||
|
context.draw(gradientImage, in: CGRect(origin: .zero, size: imageSize))
|
||||||
|
}
|
||||||
|
if let image = self.mediaEditor?.resultImage, let values = self.mediaEditor?.values {
|
||||||
|
let initialScale: CGFloat
|
||||||
|
if image.size.height > image.size.width {
|
||||||
|
initialScale = max(imageSize.width / image.size.width, imageSize.height / image.size.height)
|
||||||
|
} else {
|
||||||
|
initialScale = imageSize.width / image.size.width
|
||||||
|
}
|
||||||
|
let scale = initialScale * values.cropScale
|
||||||
|
context.translateBy(x: imageSize.width / 2.0 + values.cropOffset.x, y: imageSize.height / 2.0 - values.cropOffset.y)
|
||||||
|
context.rotate(by: -values.cropRotation)
|
||||||
|
context.scaleBy(x: scale, y: scale)
|
||||||
|
|
||||||
|
if let cgImage = image.cgImage {
|
||||||
|
context.draw(cgImage, in: CGRect(x: -image.size.width / 2.0, y: -image.size.height / 2.0, width: image.size.width, height: image.size.height))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return context?.generateImage(colorSpace: colorSpace)
|
||||||
},
|
},
|
||||||
getControllerNode: { [weak self] in
|
getControllerNode: { [weak self] in
|
||||||
return self
|
return self
|
||||||
@ -2718,6 +2747,12 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
galleryController.customModalStyleOverlayTransitionFactorUpdated = { [weak self, weak galleryController] transition in
|
||||||
|
if let self, let galleryController {
|
||||||
|
let transitionFactor = galleryController.modalStyleOverlayTransitionFactor
|
||||||
|
self.updateModalTransitionFactor(transitionFactor, transition: transition)
|
||||||
|
}
|
||||||
|
}
|
||||||
controller.push(galleryController)
|
controller.push(galleryController)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2906,36 +2941,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
existingStickerPickerInputData: self.stickerPickerInputData
|
existingStickerPickerInputData: self.stickerPickerInputData
|
||||||
)
|
)
|
||||||
controller.getCurrentImage = { [weak self] in
|
controller.getCurrentImage = { [weak self] in
|
||||||
guard let self else {
|
return self?.interaction?.getCurrentImage()
|
||||||
return nil
|
|
||||||
}
|
|
||||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
|
||||||
let imageSize = CGSize(width: 1080, height: 1920)
|
|
||||||
let context = DrawingContext(size: imageSize, scale: 1.0, opaque: true, colorSpace: colorSpace)
|
|
||||||
|
|
||||||
context?.withFlippedContext { context in
|
|
||||||
if let gradientImage = self.gradientView.image?.cgImage {
|
|
||||||
context.draw(gradientImage, in: CGRect(origin: .zero, size: imageSize))
|
|
||||||
}
|
|
||||||
if let image = self.mediaEditor?.resultImage, let values = self.mediaEditor?.values {
|
|
||||||
let initialScale: CGFloat
|
|
||||||
if image.size.height > image.size.width {
|
|
||||||
initialScale = max(imageSize.width / image.size.width, imageSize.height / image.size.height)
|
|
||||||
} else {
|
|
||||||
initialScale = imageSize.width / image.size.width
|
|
||||||
}
|
|
||||||
let scale = initialScale * values.cropScale
|
|
||||||
context.translateBy(x: imageSize.width / 2.0 + values.cropOffset.x, y: imageSize.height / 2.0 - values.cropOffset.y)
|
|
||||||
context.rotate(by: -values.cropRotation)
|
|
||||||
context.scaleBy(x: scale, y: scale)
|
|
||||||
|
|
||||||
if let cgImage = image.cgImage {
|
|
||||||
context.draw(cgImage, in: CGRect(x: -image.size.width / 2.0, y: -image.size.height / 2.0, width: image.size.width, height: image.size.height))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return context?.generateImage(colorSpace: colorSpace)
|
|
||||||
}
|
}
|
||||||
controller.updateVideoPlayback = { [weak self] play in
|
controller.updateVideoPlayback = { [weak self] play in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
@ -3592,6 +3598,13 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
let caption = self.getCaption()
|
let caption = self.getCaption()
|
||||||
let duration = mediaEditor.duration ?? 0.0
|
let duration = mediaEditor.duration ?? 0.0
|
||||||
|
|
||||||
|
var timestamp: Int32
|
||||||
|
if case let .draft(draft, _) = subject {
|
||||||
|
timestamp = draft.timestamp
|
||||||
|
} else {
|
||||||
|
timestamp = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||||
|
}
|
||||||
|
|
||||||
if let resultImage = mediaEditor.resultImage {
|
if let resultImage = mediaEditor.resultImage {
|
||||||
mediaEditor.seek(0.0, andPlay: false)
|
mediaEditor.seek(0.0, andPlay: false)
|
||||||
makeEditorImageComposition(context: self.node.ciContext, account: self.context.account, inputImage: resultImage, dimensions: storyDimensions, values: values, time: .zero, completion: { resultImage in
|
makeEditorImageComposition(context: self.node.ciContext, account: self.context.account, inputImage: resultImage, dimensions: storyDimensions, values: values, time: .zero, completion: { resultImage in
|
||||||
@ -3604,7 +3617,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
if let thumbnailImage = generateScaledImage(image: resultImage, size: fittedSize) {
|
if let thumbnailImage = generateScaledImage(image: resultImage, size: fittedSize) {
|
||||||
let path = "\(Int64.random(in: .min ... .max)).jpg"
|
let path = "\(Int64.random(in: .min ... .max)).jpg"
|
||||||
if let data = image.jpegData(compressionQuality: 0.87) {
|
if let data = image.jpegData(compressionQuality: 0.87) {
|
||||||
let draft = MediaEditorDraft(path: path, isVideo: false, thumbnail: thumbnailImage, dimensions: dimensions, duration: nil, values: values, caption: caption, privacy: privacy)
|
let draft = MediaEditorDraft(path: path, isVideo: false, thumbnail: thumbnailImage, dimensions: dimensions, duration: nil, values: values, caption: caption, privacy: privacy, timestamp: timestamp)
|
||||||
try? data.write(to: URL(fileURLWithPath: draft.fullPath()))
|
try? data.write(to: URL(fileURLWithPath: draft.fullPath()))
|
||||||
if let id {
|
if let id {
|
||||||
saveStorySource(engine: self.context.engine, item: draft, id: id)
|
saveStorySource(engine: self.context.engine, item: draft, id: id)
|
||||||
@ -3618,7 +3631,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
let saveVideoDraft: (String, PixelDimensions, Double) -> Void = { videoPath, dimensions, duration in
|
let saveVideoDraft: (String, PixelDimensions, Double) -> Void = { videoPath, dimensions, duration in
|
||||||
if let thumbnailImage = generateScaledImage(image: resultImage, size: fittedSize) {
|
if let thumbnailImage = generateScaledImage(image: resultImage, size: fittedSize) {
|
||||||
let path = "\(Int64.random(in: .min ... .max)).mp4"
|
let path = "\(Int64.random(in: .min ... .max)).mp4"
|
||||||
let draft = MediaEditorDraft(path: path, isVideo: true, thumbnail: thumbnailImage, dimensions: dimensions, duration: duration, values: values, caption: caption, privacy: privacy)
|
let draft = MediaEditorDraft(path: path, isVideo: true, thumbnail: thumbnailImage, dimensions: dimensions, duration: duration, values: values, caption: caption, privacy: privacy, timestamp: timestamp)
|
||||||
try? FileManager.default.moveItem(atPath: videoPath, toPath: draft.fullPath())
|
try? FileManager.default.moveItem(atPath: videoPath, toPath: draft.fullPath())
|
||||||
if let id {
|
if let id {
|
||||||
saveStorySource(engine: self.context.engine, item: draft, id: id)
|
saveStorySource(engine: self.context.engine, item: draft, id: id)
|
||||||
@ -3860,7 +3873,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
})
|
})
|
||||||
|
|
||||||
if case let .draft(draft, id) = subject, id == nil {
|
if case let .draft(draft, id) = subject, id == nil {
|
||||||
removeStoryDraft(engine: self.context.engine, path: draft.path, delete: !draft.isVideo)
|
removeStoryDraft(engine: self.context.engine, path: draft.path, delete: false)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let image = mediaEditor.resultImage {
|
if let image = mediaEditor.resultImage {
|
||||||
|
@ -2472,7 +2472,7 @@ final class StoryItemSetContainerSendMessage {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !hashtag.isEmpty {
|
if !hashtag.isEmpty {
|
||||||
let searchController = component.context.sharedContext.makeHashtagSearchController(context: component.context, peer: peer.flatMap(EnginePeer.init), query: hashtag)
|
let searchController = component.context.sharedContext.makeHashtagSearchController(context: component.context, peer: peer.flatMap(EnginePeer.init), query: hashtag, all: true)
|
||||||
navigationController.pushViewController(searchController)
|
navigationController.pushViewController(searchController)
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
@ -1720,8 +1720,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
return inputPanelNode
|
return inputPanelNode
|
||||||
}
|
}
|
||||||
|
|
||||||
public func makeHashtagSearchController(context: AccountContext, peer: EnginePeer?, query: String) -> ViewController {
|
public func makeHashtagSearchController(context: AccountContext, peer: EnginePeer?, query: String, all: Bool) -> ViewController {
|
||||||
return HashtagSearchController(context: context, peer: peer, query: query)
|
return HashtagSearchController(context: context, peer: peer, query: query, all: all)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func makeMyStoriesController(context: AccountContext, isArchive: Bool) -> ViewController {
|
public func makeMyStoriesController(context: AccountContext, isArchive: Bool) -> ViewController {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user