mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-06 17:00:13 +00:00
Merge commit '8ce13713b9fbcdd196efa4a715eaddd084e472b6'
This commit is contained in:
commit
b82b1e41e0
@ -7284,6 +7284,7 @@ Sorry for the inconvenience.";
|
||||
"Attachment.Ungrouped" = "Ungrouped";
|
||||
|
||||
"Attachment.MessagePreview" = "Message Preview";
|
||||
"Attachment.MessagesPreview" = "Messages Preview";
|
||||
"Attachment.DragToReorder" = "Drag media to reorder";
|
||||
|
||||
"Attachment.SearchWeb" = "Search Web";
|
||||
@ -7352,6 +7353,10 @@ Sorry for the inconvenience.";
|
||||
"Attachment.LocationAccessTitle" = "Access Your Location";
|
||||
"Attachment.LocationAccessText" = "Share places or your live location.";
|
||||
|
||||
"Attachment.CancelSelectionAlertText" = "Cancel selection?";
|
||||
"Attachment.CancelSelectionAlertYes" = "Yes";
|
||||
"Attachment.CancelSelectionAlertNo" = "No";
|
||||
|
||||
"ChannelInfo.CreateExternalStream" = "Stream With...";
|
||||
|
||||
"CreateExternalStream.Title" = "Stream With...";
|
||||
|
||||
@ -207,18 +207,24 @@ final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate {
|
||||
if currentOffset > 0.0, let scrollView = scrollView {
|
||||
scrollView.panGestureRecognizer.setTranslation(CGPoint(), in: scrollView)
|
||||
}
|
||||
|
||||
var bounds = self.bounds
|
||||
bounds.origin.y = -translation
|
||||
bounds.origin.y = min(0.0, bounds.origin.y)
|
||||
self.bounds = bounds
|
||||
}
|
||||
|
||||
var bounds = self.bounds
|
||||
if self.isExpanded {
|
||||
bounds.origin.y = -max(0.0, translation - edgeTopInset)
|
||||
} else {
|
||||
bounds.origin.y = -translation
|
||||
}
|
||||
bounds.origin.y = min(0.0, bounds.origin.y)
|
||||
self.bounds = bounds
|
||||
|
||||
self.update(layout: layout, controllers: controllers, coveredByModalTransition: coveredByModalTransition, transition: .immediate)
|
||||
case .ended:
|
||||
guard let (currentTopInset, panOffset, scrollView, listNode) = self.panGestureArguments else {
|
||||
return
|
||||
}
|
||||
self.panGestureArguments = nil
|
||||
|
||||
let visibleContentOffset = listNode?.visibleContentOffset()
|
||||
let contentOffset = scrollView?.contentOffset.y ?? 0.0
|
||||
|
||||
@ -236,15 +242,23 @@ final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate {
|
||||
}
|
||||
|
||||
var bounds = self.bounds
|
||||
bounds.origin.y = -translation
|
||||
if self.isExpanded {
|
||||
bounds.origin.y = -max(0.0, translation - edgeTopInset)
|
||||
} else {
|
||||
bounds.origin.y = -translation
|
||||
}
|
||||
bounds.origin.y = min(0.0, bounds.origin.y)
|
||||
|
||||
scrollView?.bounces = true
|
||||
|
||||
let offset = currentTopInset + panOffset
|
||||
let topInset: CGFloat = edgeTopInset
|
||||
if self.isExpanded {
|
||||
self.panGestureArguments = nil
|
||||
|
||||
var dismissing = false
|
||||
if bounds.minY < -60 || (bounds.minY < 0.0 && velocity.y > 300.0) || (self.isExpanded && bounds.minY.isZero && velocity.y > 600.0) {
|
||||
self.interactivelyDismissed?()
|
||||
dismissing = true
|
||||
} else if self.isExpanded {
|
||||
if velocity.y > 300.0 || offset > topInset / 2.0 {
|
||||
self.isExpanded = false
|
||||
if let listNode = listNode {
|
||||
@ -262,42 +276,34 @@ final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate {
|
||||
|
||||
self.update(layout: layout, controllers: controllers, coveredByModalTransition: coveredByModalTransition, transition: .animated(duration: 0.3, curve: .easeInOut))
|
||||
}
|
||||
} else if (velocity.y < -300.0 || offset < topInset / 2.0) {
|
||||
if velocity.y > -2200.0 && velocity.y < -300.0, let listNode = listNode {
|
||||
DispatchQueue.main.async {
|
||||
listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Default(duration: nil), directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||
}
|
||||
}
|
||||
|
||||
let initialVelocity: CGFloat = offset.isZero ? 0.0 : abs(velocity.y / offset)
|
||||
let transition = ContainedViewLayoutTransition.animated(duration: 0.45, curve: .customSpring(damping: 124.0, initialVelocity: initialVelocity))
|
||||
self.isExpanded = true
|
||||
|
||||
self.update(layout: layout, controllers: controllers, coveredByModalTransition: coveredByModalTransition, transition: transition)
|
||||
} else {
|
||||
self.panGestureArguments = nil
|
||||
|
||||
var dismissing = false
|
||||
if bounds.minY < -60 || (bounds.minY < 0.0 && velocity.y > 300.0) {
|
||||
self.interactivelyDismissed?()
|
||||
dismissing = true
|
||||
} else if (velocity.y < -300.0 || offset < topInset / 2.0) {
|
||||
if velocity.y > -2200.0 && velocity.y < -300.0, let listNode = listNode {
|
||||
DispatchQueue.main.async {
|
||||
listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Default(duration: nil), directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||
}
|
||||
}
|
||||
|
||||
let initialVelocity: CGFloat = offset.isZero ? 0.0 : abs(velocity.y / offset)
|
||||
let transition = ContainedViewLayoutTransition.animated(duration: 0.45, curve: .customSpring(damping: 124.0, initialVelocity: initialVelocity))
|
||||
self.isExpanded = true
|
||||
|
||||
self.update(layout: layout, controllers: controllers, coveredByModalTransition: coveredByModalTransition, transition: transition)
|
||||
} else {
|
||||
if let listNode = listNode {
|
||||
listNode.scroller.setContentOffset(CGPoint(), animated: false)
|
||||
} else if let scrollView = scrollView {
|
||||
scrollView.setContentOffset(CGPoint(x: 0.0, y: -scrollView.contentInset.top), animated: false)
|
||||
}
|
||||
|
||||
self.update(layout: layout, controllers: controllers, coveredByModalTransition: coveredByModalTransition, transition: .animated(duration: 0.3, curve: .easeInOut))
|
||||
if let listNode = listNode {
|
||||
listNode.scroller.setContentOffset(CGPoint(), animated: false)
|
||||
} else if let scrollView = scrollView {
|
||||
scrollView.setContentOffset(CGPoint(x: 0.0, y: -scrollView.contentInset.top), animated: false)
|
||||
}
|
||||
|
||||
if !dismissing {
|
||||
var bounds = self.bounds
|
||||
let previousBounds = bounds
|
||||
bounds.origin.y = 0.0
|
||||
self.bounds = bounds
|
||||
self.layer.animateBounds(from: previousBounds, to: self.bounds, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue)
|
||||
}
|
||||
self.update(layout: layout, controllers: controllers, coveredByModalTransition: coveredByModalTransition, transition: .animated(duration: 0.3, curve: .easeInOut))
|
||||
}
|
||||
|
||||
if !dismissing {
|
||||
var bounds = self.bounds
|
||||
let previousBounds = bounds
|
||||
bounds.origin.y = 0.0
|
||||
self.bounds = bounds
|
||||
self.layer.animateBounds(from: previousBounds, to: self.bounds, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue)
|
||||
}
|
||||
case .cancelled:
|
||||
self.panGestureArguments = nil
|
||||
|
||||
@ -28,6 +28,8 @@ public protocol AttachmentContainable: ViewController {
|
||||
|
||||
func resetForReuse()
|
||||
func prepareForReuse()
|
||||
|
||||
func requestDismiss(completion: @escaping () -> Void)
|
||||
}
|
||||
|
||||
public extension AttachmentContainable {
|
||||
@ -38,6 +40,10 @@ public extension AttachmentContainable {
|
||||
func prepareForReuse() {
|
||||
|
||||
}
|
||||
|
||||
func requestDismiss(completion: @escaping () -> Void) {
|
||||
completion()
|
||||
}
|
||||
}
|
||||
|
||||
public enum AttachmentMediaPickerSendMode {
|
||||
@ -274,7 +280,13 @@ public class AttachmentController: ViewController {
|
||||
|
||||
@objc func dimTapGesture(_ recognizer: UITapGestureRecognizer) {
|
||||
if case .ended = recognizer.state {
|
||||
self.controller?.dismiss(animated: true)
|
||||
if let controller = self.currentControllers.last {
|
||||
controller.requestDismiss(completion: { [weak self] in
|
||||
self?.controller?.dismiss(animated: true)
|
||||
})
|
||||
} else {
|
||||
self.controller?.dismiss(animated: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -184,7 +184,7 @@ public final class AvatarNode: ASDisplayNode {
|
||||
|
||||
public var font: UIFont {
|
||||
didSet {
|
||||
if oldValue !== font {
|
||||
if oldValue.pointSize != font.pointSize {
|
||||
if let parameters = self.parameters {
|
||||
self.parameters = AvatarNodeParameters(theme: parameters.theme, accountPeerId: parameters.accountPeerId, peerId: parameters.peerId, letters: parameters.letters, font: self.font, icon: parameters.icon, explicitColorIndex: parameters.explicitColorIndex, hasImage: parameters.hasImage, clipStyle: parameters.clipStyle)
|
||||
}
|
||||
|
||||
@ -519,7 +519,7 @@ public final class ComposedPoll {
|
||||
private class CreatePollControllerImpl: ItemListController, AttachmentContainable {
|
||||
public var requestAttachmentMenuExpansion: () -> Void = {}
|
||||
public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> ([AttachmentContainable], AttachmentMediaPickerContext?)) -> Void = { _ in }
|
||||
public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in }
|
||||
public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in }
|
||||
public var cancelPanGesture: () -> Void = { }
|
||||
}
|
||||
|
||||
|
||||
@ -1499,10 +1499,14 @@ public final class ContactListNode: ASDisplayNode {
|
||||
self.indexNode.update(size: indexNodeFrame.size, color: self.presentationData.theme.list.itemAccentColor, sections: indexSections, transition: transition)
|
||||
}
|
||||
|
||||
let permissionSize = CGSize(width: layout.size.width, height: layout.size.height - 160.0)
|
||||
var permissionInsets = insets
|
||||
permissionInsets.bottom += 100.0
|
||||
self.authorizationNode.updateLayout(size: permissionSize, insets: permissionInsets, transition: transition)
|
||||
if self.multipleSelection {
|
||||
let permissionSize = CGSize(width: layout.size.width, height: layout.size.height - 160.0)
|
||||
var permissionInsets = insets
|
||||
permissionInsets.bottom += 100.0
|
||||
self.authorizationNode.updateLayout(size: permissionSize, insets: permissionInsets, transition: transition)
|
||||
} else {
|
||||
self.authorizationNode.updateLayout(size: layout.size, insets: insets, transition: transition)
|
||||
}
|
||||
transition.updateFrame(node: self.authorizationNode, frame: self.bounds)
|
||||
|
||||
if !hadValidLayout {
|
||||
|
||||
@ -439,7 +439,6 @@ public final class ItemListPeerItem: ListViewItem, ItemListItem {
|
||||
}
|
||||
}
|
||||
|
||||
private let avatarFont = avatarPlaceholderFont(size: floor(40.0 * 16.0 / 37.0))
|
||||
private let badgeFont = Font.regular(15.0)
|
||||
|
||||
public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNode {
|
||||
@ -503,7 +502,7 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
||||
|
||||
self.containerNode = ContextControllerSourceNode()
|
||||
|
||||
self.avatarNode = AvatarNode(font: avatarFont)
|
||||
self.avatarNode = AvatarNode(font: avatarPlaceholderFont(size: floor(40.0 * 16.0 / 37.0)))
|
||||
//self.avatarNode.isLayerBacked = !smartInvertColorsEnabled()
|
||||
|
||||
self.titleNode = TextNode()
|
||||
@ -763,6 +762,7 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
||||
let verticalInset: CGFloat
|
||||
let verticalOffset: CGFloat
|
||||
let avatarSize: CGFloat
|
||||
let avatarFontSize: CGFloat
|
||||
switch item.height {
|
||||
case .generic:
|
||||
if case .none = item.text {
|
||||
@ -773,6 +773,7 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
||||
verticalOffset = 0.0
|
||||
avatarSize = 31.0
|
||||
leftInset = 59.0 + params.leftInset
|
||||
avatarFontSize = floor(31.0 * 16.0 / 37.0)
|
||||
case .peerList:
|
||||
if case .none = item.text {
|
||||
verticalInset = 14.0
|
||||
@ -782,6 +783,7 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
||||
verticalOffset = 0.0
|
||||
avatarSize = 40.0
|
||||
leftInset = 65.0 + params.leftInset
|
||||
avatarFontSize = floor(40.0 * 16.0 / 37.0)
|
||||
}
|
||||
|
||||
var editableControlSizeAndApply: (CGFloat, (CGFloat) -> ItemListEditableControlNode)?
|
||||
@ -887,6 +889,8 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
||||
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
|
||||
strongSelf.containerNode.isGestureEnabled = item.contextAction != nil
|
||||
|
||||
strongSelf.avatarNode.font = avatarPlaceholderFont(size: avatarFontSize)
|
||||
|
||||
strongSelf.accessibilityLabel = titleAttributedString?.string
|
||||
var combinedValueString = ""
|
||||
if let statusString = statusAttributedString?.string, !statusString.isEmpty {
|
||||
|
||||
@ -41,6 +41,7 @@
|
||||
- (SSignal *)selectionChangedSignal;
|
||||
|
||||
- (void)enumerateSelectedItems:(void (^)(id<TGMediaSelectableItem>))enumerationBlock;
|
||||
- (void)enumerateDeselectedItems:(void (^)(id<TGMediaSelectableItem>))enumerationBlock;
|
||||
|
||||
- (NSOrderedSet *)selectedItemsIdentifiers;
|
||||
- (NSArray *)selectedItems;
|
||||
|
||||
@ -140,6 +140,10 @@
|
||||
if (strongSelf == nil)
|
||||
return;
|
||||
|
||||
strongSelf->_ignoreSelectionUpdates = true;
|
||||
[strongSelf->_selectionChangedDisposable dispose];
|
||||
[strongSelf->_itemSelectedDisposable dispose];
|
||||
|
||||
[strongSelf.window endEditing:true];
|
||||
strongSelf->_portraitToolbarView.doneButton.userInteractionEnabled = false;
|
||||
strongSelf->_landscapeToolbarView.doneButton.userInteractionEnabled = false;
|
||||
|
||||
@ -188,7 +188,7 @@
|
||||
if (enumerationBlock == nil)
|
||||
return;
|
||||
|
||||
for (NSArray *identifier in _selectedIdentifiers)
|
||||
for (NSString *identifier in _selectedIdentifiers)
|
||||
{
|
||||
NSObject<TGMediaSelectableItem> *item = _selectionMap[identifier];
|
||||
if (item != nil) {
|
||||
@ -197,6 +197,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)enumerateDeselectedItems:(void (^)(id<TGMediaSelectableItem>))enumerationBlock
|
||||
{
|
||||
if (enumerationBlock == nil || _savedSelectedIdentifiers == nil)
|
||||
return;
|
||||
|
||||
for (NSString *identifier in _savedSelectedIdentifiers)
|
||||
{
|
||||
if (![_selectedIdentifiers containsObject:identifier]) {
|
||||
NSObject<TGMediaSelectableItem> *item = _selectionMap[identifier];
|
||||
if (item != nil) {
|
||||
enumerationBlock(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (NSOrderedSet *)selectedItemsIdentifiers
|
||||
{
|
||||
return [[NSOrderedSet alloc] initWithArray:_selectedIdentifiers];
|
||||
|
||||
@ -191,7 +191,6 @@
|
||||
UIView *contentView = [itemView transitionContentView];
|
||||
UIView *snapshotView = [contentView snapshotViewAfterScreenUpdates:true];
|
||||
snapshotView.frame = [contentView convertRect:contentView.bounds toView:nil];
|
||||
// snapshotView.frame = CGRectOffset([contentView convertRect:contentView.bounds toView:nil], 0.0, -self.view.frame.size.height);
|
||||
return snapshotView;
|
||||
}
|
||||
}
|
||||
|
||||
@ -379,12 +379,14 @@ static const CGFloat swipeDistanceThreshold = 128.0f;
|
||||
completion();
|
||||
}];
|
||||
|
||||
[UIView animateWithDuration:ABS(distance / velocity) animations:^
|
||||
{
|
||||
[UIView animateWithDuration:0.15 animations:^{
|
||||
_interfaceView.alpha = 0.0f;
|
||||
_overlayContainerView.alpha = 0.0f;
|
||||
}];
|
||||
|
||||
[UIView animateWithDuration:0.35 animations:^{
|
||||
self.backgroundColor = UIColorRGBA(0x000000, 0.0f);
|
||||
} completion:nil];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)transitionInWithDuration:(NSTimeInterval)duration
|
||||
|
||||
@ -88,8 +88,7 @@ public final class LocationPickerController: ViewController, AttachmentContainab
|
||||
|
||||
self.title = self.presentationData.strings.Map_ChooseLocationTitle
|
||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed))
|
||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationCompactSearchIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.searchPressed))
|
||||
self.navigationItem.rightBarButtonItem?.accessibilityLabel = self.presentationData.strings.Common_Search
|
||||
self.updateBarButtons()
|
||||
|
||||
self.presentationDataDisposable = ((updatedPresentationData?.signal ?? context.sharedContext.presentationData)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
|
||||
@ -100,7 +99,8 @@ public final class LocationPickerController: ViewController, AttachmentContainab
|
||||
|
||||
strongSelf.navigationBar?.updatePresentationData(NavigationBarPresentationData(theme: NavigationBarTheme(rootControllerTheme: strongSelf.presentationData.theme).withUpdatedSeparatorColor(.clear), strings: NavigationBarStrings(presentationStrings: strongSelf.presentationData.strings)))
|
||||
strongSelf.searchNavigationContentNode?.updatePresentationData(strongSelf.presentationData)
|
||||
strongSelf.navigationItem.rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationCompactSearchIcon(strongSelf.presentationData.theme), style: .plain, target: strongSelf, action: #selector(strongSelf.searchPressed))
|
||||
|
||||
strongSelf.updateBarButtons()
|
||||
|
||||
if strongSelf.isNodeLoaded {
|
||||
strongSelf.controllerNode.updatePresentationData(presentationData)
|
||||
@ -288,6 +288,16 @@ public final class LocationPickerController: ViewController, AttachmentContainab
|
||||
self.isSearchingDisposable.dispose()
|
||||
}
|
||||
|
||||
private var locationAccessDenied = false
|
||||
private func updateBarButtons() {
|
||||
if self.locationAccessDenied {
|
||||
self.navigationItem.rightBarButtonItem = nil
|
||||
} else {
|
||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationCompactSearchIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.searchPressed))
|
||||
self.navigationItem.rightBarButtonItem?.accessibilityLabel = self.presentationData.strings.Common_Search
|
||||
}
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
super.loadDisplayNode()
|
||||
guard let interaction = self.interaction else {
|
||||
@ -299,6 +309,10 @@ public final class LocationPickerController: ViewController, AttachmentContainab
|
||||
self.controllerNode.beganInteractiveDragging = { [weak self] in
|
||||
self?.requestAttachmentMenuExpansion()
|
||||
}
|
||||
self.controllerNode.locationAccessDeniedUpdated = { [weak self] denied in
|
||||
self?.locationAccessDenied = denied
|
||||
self?.updateBarButtons()
|
||||
}
|
||||
|
||||
self.permissionDisposable = (DeviceAccess.authorizationStatus(subject: .location(.send))
|
||||
|> deliverOnMainQueue).start(next: { [weak self] next in
|
||||
|
||||
@ -313,6 +313,7 @@ final class LocationPickerControllerNode: ViewControllerTracingNode, CLLocationM
|
||||
private var listOffset: CGFloat?
|
||||
|
||||
var beganInteractiveDragging: () -> Void = {}
|
||||
var locationAccessDeniedUpdated: (Bool) -> Void = { _ in }
|
||||
|
||||
init(controller: LocationPickerController, context: AccountContext, presentationData: PresentationData, mode: LocationPickerMode, interaction: LocationPickerInteraction, locationManager: LocationManager) {
|
||||
self.controller = controller
|
||||
@ -639,11 +640,13 @@ final class LocationPickerControllerNode: ViewControllerTracingNode, CLLocationM
|
||||
if [.denied, .restricted].contains(access) {
|
||||
if !strongSelf.locationAccessDenied {
|
||||
strongSelf.locationAccessDenied = true
|
||||
strongSelf.locationAccessDeniedUpdated(true)
|
||||
updateLayout = true
|
||||
}
|
||||
} else {
|
||||
if strongSelf.locationAccessDenied {
|
||||
strongSelf.locationAccessDenied = false
|
||||
strongSelf.locationAccessDeniedUpdated(false)
|
||||
updateLayout = true
|
||||
}
|
||||
}
|
||||
@ -998,6 +1001,8 @@ final class LocationPickerControllerNode: ViewControllerTracingNode, CLLocationM
|
||||
self.placeholderBackgroundNode = nil
|
||||
placeholderBackgroundNode.removeFromSupernode()
|
||||
}
|
||||
|
||||
self.controller?.navigationBar?.updateBackgroundAlpha(1.0, transition: .immediate)
|
||||
self.controller?.updateTabBarAlpha(1.0, .immediate)
|
||||
}
|
||||
|
||||
|
||||
@ -19,6 +19,7 @@ import ContextUI
|
||||
import WebSearchUI
|
||||
import SparseItemGrid
|
||||
import UndoUI
|
||||
import PresentationDataUtils
|
||||
|
||||
let overflowInset: CGFloat = 0.0
|
||||
|
||||
@ -687,7 +688,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
return
|
||||
}
|
||||
self.controller?.legacyCompletion(signals, silently, scheduleTime, { [weak self] identifier in
|
||||
return self?.getItemSnapshot(identifier)
|
||||
return !asFile ? self?.getItemSnapshot(identifier) : nil
|
||||
}, { [weak self] in
|
||||
completion()
|
||||
self?.controller?.dismiss(animated: animated)
|
||||
@ -1155,7 +1156,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
selectionState.setItem(item, selected: value)
|
||||
|
||||
if showUndo {
|
||||
strongSelf.showSelectionUndo(item: item, count: Int32(selectionState.savedStateDifference()))
|
||||
strongSelf.showSelectionUndo(item: item)
|
||||
}
|
||||
}
|
||||
}, sendSelected: { [weak self] currentItem, silently, scheduleTime, animated, completion in
|
||||
@ -1198,7 +1199,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
}
|
||||
|
||||
private weak var undoOverlayController: UndoOverlayController?
|
||||
private func showSelectionUndo(item: TGMediaSelectableItem, count: Int32) {
|
||||
private func showSelectionUndo(item: TGMediaSelectableItem) {
|
||||
var asset: PHAsset?
|
||||
if let item = item as? TGMediaAsset {
|
||||
asset = item.backingAsset
|
||||
@ -1218,12 +1219,36 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
return
|
||||
}
|
||||
|
||||
var photosCount = 0
|
||||
var videosCount = 0
|
||||
strongSelf.interaction?.selectionState?.enumerateDeselectedItems({ item in
|
||||
if let item = item as? TGMediaAsset {
|
||||
if item.isVideo {
|
||||
videosCount += 1
|
||||
} else {
|
||||
photosCount += 1
|
||||
}
|
||||
} else if let _ = item as? TGCameraCapturedVideo {
|
||||
videosCount += 1
|
||||
}
|
||||
})
|
||||
let totalCount = Int32(photosCount + videosCount)
|
||||
|
||||
let presentationData = strongSelf.presentationData
|
||||
let text: String
|
||||
if photosCount > 0 && videosCount > 0 {
|
||||
text = presentationData.strings.Attachment_DeselectedItems(totalCount)
|
||||
} else if photosCount > 0 {
|
||||
text = presentationData.strings.Attachment_DeselectedPhotos(totalCount)
|
||||
} else if videosCount > 0 {
|
||||
text = presentationData.strings.Attachment_DeselectedVideos(totalCount)
|
||||
} else {
|
||||
text = presentationData.strings.Attachment_DeselectedItems(totalCount)
|
||||
}
|
||||
|
||||
if let undoOverlayController = strongSelf.undoOverlayController {
|
||||
let text = presentationData.strings.Attachment_DeselectedItems(count)
|
||||
undoOverlayController.content = .image(image: image ?? UIImage(), text: text)
|
||||
} else {
|
||||
let text = presentationData.strings.Attachment_DeselectedItems(count)
|
||||
let undoOverlayController = UndoOverlayController(presentationData: presentationData, content: .image(image: image ?? UIImage(), text: text), elevatedLayout: true, action: { [weak self] action in
|
||||
guard let strongSelf = self else {
|
||||
return true
|
||||
@ -1282,8 +1307,23 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
self.undoOverlayController?.dismissWithCommitAction()
|
||||
}
|
||||
|
||||
public func requestDismiss(completion: @escaping () -> Void) {
|
||||
if let selectionState = self.interaction?.selectionState, selectionState.count() > 0 {
|
||||
let controller = textAlertController(context: self.context, title: nil, text: self.presentationData.strings.Attachment_CancelSelectionAlertText, actions: [TextAlertAction(type: .genericAction, title: self.presentationData.strings.Attachment_CancelSelectionAlertNo, action: {
|
||||
|
||||
}), TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Attachment_CancelSelectionAlertYes, action: { [weak self] in
|
||||
self?.dismissAllTooltips()
|
||||
completion()
|
||||
})])
|
||||
self.present(controller, in: .window(.root))
|
||||
} else {
|
||||
completion()
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func cancelPressed() {
|
||||
self.dismissAllTooltips()
|
||||
|
||||
self.dismiss()
|
||||
}
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
import TelegramStringFormatting
|
||||
import LegacyComponents
|
||||
import CheckNode
|
||||
import MosaicLayout
|
||||
@ -13,7 +14,6 @@ import WallpaperBackgroundNode
|
||||
import AccountContext
|
||||
import ChatMessageBackground
|
||||
|
||||
|
||||
private class MediaPickerSelectedItemNode: ASDisplayNode {
|
||||
let asset: TGMediaAsset
|
||||
private let interaction: MediaPickerInteraction?
|
||||
@ -23,6 +23,8 @@ private class MediaPickerSelectedItemNode: ASDisplayNode {
|
||||
private var durationBackgroundNode: ASDisplayNode?
|
||||
private var durationTextNode: ImmediateTextNode?
|
||||
|
||||
private var adjustmentsDisposable: Disposable?
|
||||
|
||||
private var theme: PresentationTheme?
|
||||
|
||||
private var validLayout: CGSize?
|
||||
@ -49,6 +51,8 @@ private class MediaPickerSelectedItemNode: ASDisplayNode {
|
||||
return self.readyPromise.get()
|
||||
}
|
||||
|
||||
private var videoDuration: Double?
|
||||
|
||||
init(asset: TGMediaAsset, interaction: MediaPickerInteraction?) {
|
||||
self.imageNode = ImageNode()
|
||||
self.imageNode.contentMode = .scaleAspectFill
|
||||
@ -63,6 +67,44 @@ private class MediaPickerSelectedItemNode: ASDisplayNode {
|
||||
self.clipsToBounds = true
|
||||
|
||||
self.addSubnode(self.imageNode)
|
||||
|
||||
if asset.isVideo, let editingState = interaction?.editingState {
|
||||
func adjustmentsChangedSignal(editingState: TGMediaEditingContext) -> Signal<TGMediaEditAdjustments?, NoError> {
|
||||
return Signal { subscriber in
|
||||
let disposable = editingState.adjustmentsSignal(for: asset).start(next: { next in
|
||||
if let next = next as? TGMediaEditAdjustments {
|
||||
subscriber.putNext(next)
|
||||
} else if next == nil {
|
||||
subscriber.putNext(nil)
|
||||
}
|
||||
}, error: nil, completed: {})
|
||||
return ActionDisposable {
|
||||
disposable?.dispose()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.adjustmentsDisposable = (adjustmentsChangedSignal(editingState: editingState)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] adjustments in
|
||||
if let strongSelf = self {
|
||||
let duration: Double
|
||||
if let adjustments = adjustments as? TGVideoEditAdjustments, adjustments.trimApplied() {
|
||||
duration = adjustments.trimEndValue - adjustments.trimStartValue
|
||||
} else {
|
||||
duration = asset.videoDuration
|
||||
}
|
||||
strongSelf.videoDuration = duration
|
||||
|
||||
if let size = strongSelf.validLayout {
|
||||
strongSelf.updateLayout(size: size, transition: .immediate)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.adjustmentsDisposable?.dispose()
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
@ -158,6 +200,13 @@ private class MediaPickerSelectedItemNode: ASDisplayNode {
|
||||
if let checkNode = self.checkNode, checkNode.alpha > 0.0 {
|
||||
checkNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
|
||||
if let durationTextNode = self.durationTextNode, durationTextNode.alpha > 0.0 {
|
||||
durationTextNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
if let durationBackgroundNode = self.durationBackgroundNode, durationBackgroundNode.alpha > 0.0 {
|
||||
durationBackgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -182,6 +231,42 @@ private class MediaPickerSelectedItemNode: ASDisplayNode {
|
||||
if let checkNode = self.checkNode {
|
||||
transition.updateFrame(node: checkNode, frame: CGRect(origin: CGPoint(x: size.width - checkSize.width - 3.0, y: 3.0), size: checkSize))
|
||||
}
|
||||
|
||||
if let duration = self.videoDuration {
|
||||
let textNode: ImmediateTextNode
|
||||
let backgroundNode: ASDisplayNode
|
||||
if let currentTextNode = self.durationTextNode, let currentBackgroundNode = self.durationBackgroundNode {
|
||||
textNode = currentTextNode
|
||||
backgroundNode = currentBackgroundNode
|
||||
} else {
|
||||
backgroundNode = ASDisplayNode()
|
||||
backgroundNode.backgroundColor = UIColor(rgb: 0x000000, alpha: 0.5)
|
||||
backgroundNode.cornerRadius = 9.0
|
||||
self.addSubnode(backgroundNode)
|
||||
self.durationBackgroundNode = backgroundNode
|
||||
|
||||
textNode = ImmediateTextNode()
|
||||
textNode.displaysAsynchronously = false
|
||||
self.addSubnode(textNode)
|
||||
self.durationTextNode = textNode
|
||||
}
|
||||
|
||||
textNode.attributedText = NSAttributedString(string: stringForDuration(Int32(duration)), font: Font.with(size: 11.0, design: .regular, weight: .regular, traits: .monospacedNumbers), textColor: .white)
|
||||
|
||||
let textSize = textNode.updateLayout(size)
|
||||
let backgroundFrame = CGRect(x: 6.0, y: 6.0, width: ceil(textSize.width) + 14.0, height: 18.0)
|
||||
backgroundNode.frame = backgroundFrame
|
||||
textNode.frame = CGRect(origin: CGPoint(x: backgroundFrame.minX + floorToScreenPixels((backgroundFrame.size.width - textSize.width) / 2.0), y: backgroundFrame.minY + floorToScreenPixels((backgroundFrame.size.height - textSize.height) / 2.0)), size: textSize)
|
||||
} else {
|
||||
if let durationTextNode = self.durationTextNode {
|
||||
self.durationTextNode = nil
|
||||
durationTextNode.removeFromSupernode()
|
||||
}
|
||||
if let durationBackgroundNode = self.durationBackgroundNode {
|
||||
self.durationBackgroundNode = nil
|
||||
durationBackgroundNode.removeFromSupernode()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func transitionView() -> UIView {
|
||||
@ -203,6 +288,9 @@ private class MediaPickerSelectedItemNode: ASDisplayNode {
|
||||
let frame = view.convert(view.bounds, to: self.supernode?.view)
|
||||
let targetFrame = self.frame
|
||||
|
||||
self.durationTextNode?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
self.durationBackgroundNode?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
|
||||
self.updateLayout(size: frame.size, transition: .immediate)
|
||||
self.updateLayout(size: targetFrame.size, transition: .animated(duration: 0.25, curve: .spring))
|
||||
self.layer.animateFrame(from: frame, to: targetFrame, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring, completion: { [weak view] _ in
|
||||
@ -218,11 +306,17 @@ private class MediaPickerSelectedItemNode: ASDisplayNode {
|
||||
|
||||
let corners = self.corners
|
||||
|
||||
self.durationTextNode?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
self.durationBackgroundNode?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
|
||||
self.corners = []
|
||||
self.updateLayout(size: targetFrame.size, transition: .animated(duration: 0.25, curve: .spring))
|
||||
self.layer.animateFrame(from: frame, to: targetFrame, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { [weak view, weak self] _ in
|
||||
view?.alpha = 1.0
|
||||
|
||||
self?.durationTextNode?.layer.removeAllAnimations()
|
||||
self?.durationBackgroundNode?.layer.removeAllAnimations()
|
||||
|
||||
var animateCheckNode = false
|
||||
if let strongSelf = self, let checkNode = strongSelf.checkNode, checkNode.alpha.isZero {
|
||||
animateCheckNode = true
|
||||
@ -541,53 +635,7 @@ final class MediaPickerSelectedListNode: ASDisplayNode, UIScrollViewDelegate, UI
|
||||
|
||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(1))
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
peers[peerId] = TelegramUser(id: peerId, accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
|
||||
let previewMessage = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [TelegramMediaAction(action: .customText(text: presentationData.strings.Attachment_MessagePreview, entities: []))], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
let previewItem = self.context.sharedContext.makeChatMessagePreviewItem(context: context, messages: [previewMessage], theme: theme, strings: presentationData.strings, wallpaper: wallpaper, fontSize: presentationData.chatFontSize, chatBubbleCorners: bubbleCorners, dateTimeFormat: presentationData.dateTimeFormat, nameOrder: presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.wallpaperBackgroundNode, availableReactions: nil, isCentered: true)
|
||||
|
||||
let dragMessage = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [TelegramMediaAction(action: .customText(text: presentationData.strings.Attachment_DragToReorder, entities: []))], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
let dragItem = self.context.sharedContext.makeChatMessagePreviewItem(context: context, messages: [dragMessage], theme: theme, strings: presentationData.strings, wallpaper: wallpaper, fontSize: presentationData.chatFontSize, chatBubbleCorners: bubbleCorners, dateTimeFormat: presentationData.dateTimeFormat, nameOrder: presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.wallpaperBackgroundNode, availableReactions: nil, isCentered: true)
|
||||
|
||||
let headerItems: [ListViewItem] = [previewItem, dragItem]
|
||||
|
||||
let params = ListViewItemLayoutParams(width: size.width, leftInset: insets.left, rightInset: insets.right, availableHeight: size.height)
|
||||
if let messageNodes = self.messageNodes {
|
||||
for i in 0 ..< headerItems.count {
|
||||
let itemNode = messageNodes[i]
|
||||
headerItems[i].updateNode(async: { $0() }, node: {
|
||||
return itemNode
|
||||
}, params: params, previousItem: nil, nextItem: nil, animation: .None, completion: { (layout, apply) in
|
||||
let nodeFrame = CGRect(origin: itemNode.frame.origin, size: CGSize(width: size.width, height: layout.size.height))
|
||||
|
||||
itemNode.contentSize = layout.contentSize
|
||||
itemNode.insets = layout.insets
|
||||
itemNode.frame = nodeFrame
|
||||
itemNode.isUserInteractionEnabled = false
|
||||
|
||||
apply(ListViewItemApply(isOnScreen: true))
|
||||
})
|
||||
}
|
||||
} else {
|
||||
var messageNodes: [ListViewItemNode] = []
|
||||
for i in 0 ..< headerItems.count {
|
||||
var itemNode: ListViewItemNode?
|
||||
headerItems[i].nodeConfiguredForParams(async: { $0() }, params: params, synchronousLoads: false, previousItem: nil, nextItem: nil, completion: { node, apply in
|
||||
itemNode = node
|
||||
apply().1(ListViewItemApply(isOnScreen: true))
|
||||
})
|
||||
itemNode!.subnodeTransform = CATransform3DMakeRotation(CGFloat.pi, 0.0, 0.0, 1.0)
|
||||
itemNode!.isUserInteractionEnabled = false
|
||||
messageNodes.append(itemNode!)
|
||||
self.scrollNode.addSubnode(itemNode!)
|
||||
}
|
||||
self.messageNodes = messageNodes
|
||||
}
|
||||
|
||||
var itemSizes: [CGSize] = []
|
||||
|
||||
let sideInset: CGFloat = 34.0
|
||||
let boundingWidth = min(320.0, size.width - insets.left - insets.right - sideInset * 2.0)
|
||||
|
||||
@ -672,6 +720,53 @@ final class MediaPickerSelectedListNode: ASDisplayNode, UIScrollViewDelegate, UI
|
||||
}
|
||||
}
|
||||
|
||||
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(1))
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
peers[peerId] = TelegramUser(id: peerId, accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
|
||||
let previewText = groupLayouts.count > 1 ? presentationData.strings.Attachment_MessagesPreview : presentationData.strings.Attachment_MessagePreview
|
||||
|
||||
let previewMessage = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [TelegramMediaAction(action: .customText(text: previewText, entities: []))], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
let previewItem = self.context.sharedContext.makeChatMessagePreviewItem(context: context, messages: [previewMessage], theme: theme, strings: presentationData.strings, wallpaper: wallpaper, fontSize: presentationData.chatFontSize, chatBubbleCorners: bubbleCorners, dateTimeFormat: presentationData.dateTimeFormat, nameOrder: presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.wallpaperBackgroundNode, availableReactions: nil, isCentered: true)
|
||||
|
||||
let dragMessage = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [TelegramMediaAction(action: .customText(text: presentationData.strings.Attachment_DragToReorder, entities: []))], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
let dragItem = self.context.sharedContext.makeChatMessagePreviewItem(context: context, messages: [dragMessage], theme: theme, strings: presentationData.strings, wallpaper: wallpaper, fontSize: presentationData.chatFontSize, chatBubbleCorners: bubbleCorners, dateTimeFormat: presentationData.dateTimeFormat, nameOrder: presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.wallpaperBackgroundNode, availableReactions: nil, isCentered: true)
|
||||
|
||||
let headerItems: [ListViewItem] = [previewItem, dragItem]
|
||||
|
||||
let params = ListViewItemLayoutParams(width: size.width, leftInset: insets.left, rightInset: insets.right, availableHeight: size.height)
|
||||
if let messageNodes = self.messageNodes {
|
||||
for i in 0 ..< headerItems.count {
|
||||
let itemNode = messageNodes[i]
|
||||
headerItems[i].updateNode(async: { $0() }, node: {
|
||||
return itemNode
|
||||
}, params: params, previousItem: nil, nextItem: nil, animation: .None, completion: { (layout, apply) in
|
||||
let nodeFrame = CGRect(origin: itemNode.frame.origin, size: CGSize(width: size.width, height: layout.size.height))
|
||||
|
||||
itemNode.contentSize = layout.contentSize
|
||||
itemNode.insets = layout.insets
|
||||
itemNode.frame = nodeFrame
|
||||
itemNode.isUserInteractionEnabled = false
|
||||
|
||||
apply(ListViewItemApply(isOnScreen: true))
|
||||
})
|
||||
}
|
||||
} else {
|
||||
var messageNodes: [ListViewItemNode] = []
|
||||
for i in 0 ..< headerItems.count {
|
||||
var itemNode: ListViewItemNode?
|
||||
headerItems[i].nodeConfiguredForParams(async: { $0() }, params: params, synchronousLoads: false, previousItem: nil, nextItem: nil, completion: { node, apply in
|
||||
itemNode = node
|
||||
apply().1(ListViewItemApply(isOnScreen: true))
|
||||
})
|
||||
itemNode!.subnodeTransform = CATransform3DMakeRotation(CGFloat.pi, 0.0, 0.0, 1.0)
|
||||
itemNode!.isUserInteractionEnabled = false
|
||||
messageNodes.append(itemNode!)
|
||||
self.scrollNode.addSubnode(itemNode!)
|
||||
}
|
||||
self.messageNodes = messageNodes
|
||||
}
|
||||
|
||||
let spacing: CGFloat = 8.0
|
||||
var contentHeight: CGFloat = 60.0
|
||||
|
||||
|
||||
@ -13,6 +13,7 @@ swift_library(
|
||||
"//submodules/Display:Display",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
"//submodules/LegacyComponents:LegacyComponents",
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
||||
@ -3,6 +3,7 @@ import UIKit
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import LegacyComponents
|
||||
import SwiftSignalKit
|
||||
|
||||
private final class RadialProgressContentCancelNodeParameters: NSObject {
|
||||
let color: UIColor
|
||||
@ -159,23 +160,28 @@ private final class RadialProgressContentSpinnerNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
private var hierarchyVersion: Int = 0
|
||||
override func willEnterHierarchy() {
|
||||
super.willEnterHierarchy()
|
||||
|
||||
if self.animateRotation {
|
||||
let basicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
|
||||
basicAnimation.duration = 1.5
|
||||
var fromValue = Float.pi + 0.58
|
||||
if let presentation = self.layer.presentation(), let value = (presentation.value(forKeyPath: "transform.rotation.z") as? NSNumber)?.floatValue {
|
||||
fromValue = value
|
||||
}
|
||||
basicAnimation.fromValue = NSNumber(value: fromValue)
|
||||
basicAnimation.toValue = NSNumber(value: fromValue + Float.pi * 2.0)
|
||||
basicAnimation.repeatCount = Float.infinity
|
||||
basicAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
|
||||
basicAnimation.beginTime = 0.0
|
||||
self.hierarchyVersion += 1
|
||||
|
||||
self.layer.add(basicAnimation, forKey: "progressRotation")
|
||||
if self.layer.animation(forKey: "progressRotation") == nil {
|
||||
let basicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
|
||||
basicAnimation.duration = 1.5
|
||||
var fromValue = Float.pi + 0.58
|
||||
if let presentation = self.layer.presentation(), let value = (presentation.value(forKeyPath: "transform.rotation.z") as? NSNumber)?.floatValue {
|
||||
fromValue = value
|
||||
}
|
||||
basicAnimation.fromValue = NSNumber(value: fromValue)
|
||||
basicAnimation.toValue = NSNumber(value: fromValue + Float.pi * 2.0)
|
||||
basicAnimation.repeatCount = Float.infinity
|
||||
basicAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
|
||||
basicAnimation.beginTime = 0.0
|
||||
|
||||
self.layer.add(basicAnimation, forKey: "progressRotation")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -183,7 +189,12 @@ private final class RadialProgressContentSpinnerNode: ASDisplayNode {
|
||||
super.didExitHierarchy()
|
||||
|
||||
if self.animateRotation {
|
||||
self.layer.removeAnimation(forKey: "progressRotation")
|
||||
let version = self.hierarchyVersion
|
||||
Queue.mainQueue().after(0.1, {
|
||||
if self.hierarchyVersion == version {
|
||||
self.layer.removeAnimation(forKey: "progressRotation")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,7 +181,7 @@ class ForwardPrivacyChatPreviewItemNode: ListViewItemNode {
|
||||
|
||||
var authorNameCenter: CGFloat?
|
||||
|
||||
let forwardedString = item.strings.Message_ForwardedMessage("").string
|
||||
let forwardedString = item.strings.Message_ForwardedMessageShort("").string
|
||||
var fromString: String?
|
||||
if let newlineRange = forwardedString.range(of: "\n") {
|
||||
let from = forwardedString[newlineRange.upperBound...]
|
||||
|
||||
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Hidden.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Hidden.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "attach_hidden.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
105
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Hidden.imageset/attach_hidden.pdf
vendored
Normal file
105
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Hidden.imageset/attach_hidden.pdf
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 3.315430 8.007324 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
23.041992 0.435059 m
|
||||
23.364258 0.102051 23.879883 0.080566 24.212891 0.435059 c
|
||||
24.567383 0.789551 24.535156 1.272949 24.212891 1.605957 c
|
||||
6.251953 19.556152 l
|
||||
5.929688 19.878418 5.403320 19.878418 5.070312 19.556152 c
|
||||
4.758789 19.244629 4.758789 18.696777 5.070312 18.385254 c
|
||||
23.041992 0.435059 l
|
||||
h
|
||||
14.684570 18.943848 m
|
||||
12.815430 18.943848 11.118164 18.621582 9.539062 18.095215 c
|
||||
10.957031 16.687988 l
|
||||
12.138672 17.042480 13.352539 17.246582 14.684570 17.246582 c
|
||||
21.752930 17.246582 27.478516 11.016113 27.478516 9.737793 c
|
||||
27.478516 8.867676 25.598633 6.525879 22.623047 4.699707 c
|
||||
23.944336 3.378418 l
|
||||
27.338867 5.580566 29.358398 8.470215 29.358398 9.737793 c
|
||||
29.358398 11.939941 23.364258 18.943848 14.684570 18.943848 c
|
||||
h
|
||||
14.684570 0.531738 m
|
||||
16.682617 0.531738 18.508789 0.886230 20.173828 1.455566 c
|
||||
18.766602 2.862793 l
|
||||
17.488281 2.465332 16.134766 2.229004 14.684570 2.229004 c
|
||||
7.605469 2.229004 1.879883 8.223145 1.879883 9.737793 c
|
||||
1.879883 10.489746 3.867188 12.992676 7.036133 14.894043 c
|
||||
5.704102 16.226074 l
|
||||
2.126953 14.013184 0.000000 11.037598 0.000000 9.737793 c
|
||||
0.000000 7.546387 6.112305 0.531738 14.684570 0.531738 c
|
||||
h
|
||||
20.195312 7.385254 m
|
||||
20.528320 8.104980 20.710938 8.910645 20.710938 9.737793 c
|
||||
20.710938 13.100098 18.025391 15.753418 14.684570 15.753418 c
|
||||
13.835938 15.753418 13.041016 15.570801 12.321289 15.259277 c
|
||||
20.195312 7.385254 l
|
||||
h
|
||||
14.684570 3.722168 m
|
||||
15.629883 3.722168 16.521484 3.958496 17.316406 4.345215 c
|
||||
9.259766 12.401855 l
|
||||
8.862305 11.606934 8.636719 10.704590 8.636719 9.737793 c
|
||||
8.647461 6.461426 11.322266 3.722168 14.684570 3.722168 c
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
1716
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 36.000000 36.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000001806 00000 n
|
||||
0000001829 00000 n
|
||||
0000002002 00000 n
|
||||
0000002076 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
2135
|
||||
%%EOF
|
||||
@ -10269,7 +10269,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let storeEditedPhotos = settings.storeEditedPhotos
|
||||
let inputText = strongSelf.presentationInterfaceState.interfaceState.effectiveInputState.inputText
|
||||
|
||||
presentedLegacyCamera(context: strongSelf.context, peer: peer, chatLocation: strongSelf.chatLocation, cameraView: cameraView, menuController: nil, parentController: strongSelf, attachmentController: self?.attachmentController, editingMedia: false, saveCapturedPhotos: storeEditedPhotos, mediaGrouping: true, initialCaption: inputText.string, hasSchedule: strongSelf.presentationInterfaceState.subject != .scheduledMessages && peer.id.namespace != Namespaces.Peer.SecretChat, photoOnly: photoOnly, sendMessagesWithSignals: { [weak self] signals, silentPosting, scheduleTime in
|
||||
presentedLegacyCamera(context: strongSelf.context, peer: peer, chatLocation: strongSelf.chatLocation, cameraView: cameraView, menuController: nil, parentController: strongSelf, attachmentController: self?.attachmentController, editingMedia: false, saveCapturedPhotos: storeEditedPhotos, mediaGrouping: true, initialCaption: inputText, hasSchedule: strongSelf.presentationInterfaceState.subject != .scheduledMessages && peer.id.namespace != Namespaces.Peer.SecretChat, photoOnly: photoOnly, sendMessagesWithSignals: { [weak self] signals, silentPosting, scheduleTime in
|
||||
if let strongSelf = self {
|
||||
strongSelf.enqueueMediaMessages(signals: signals, silentPosting: silentPosting, scheduleTime: scheduleTime > 0 ? scheduleTime : nil)
|
||||
if !inputText.string.isEmpty {
|
||||
@ -10755,7 +10755,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
photoOnly = true
|
||||
}
|
||||
|
||||
presentedLegacyCamera(context: strongSelf.context, peer: peer, chatLocation: strongSelf.chatLocation, cameraView: cameraView, menuController: menuController, parentController: strongSelf, editingMedia: editMediaOptions != nil, saveCapturedPhotos: settings.storeEditedPhotos, mediaGrouping: true, initialCaption: inputText.string, hasSchedule: strongSelf.presentationInterfaceState.subject != .scheduledMessages && peer.id.namespace != Namespaces.Peer.SecretChat, photoOnly: photoOnly, sendMessagesWithSignals: { [weak self] signals, silentPosting, scheduleTime in
|
||||
presentedLegacyCamera(context: strongSelf.context, peer: peer, chatLocation: strongSelf.chatLocation, cameraView: cameraView, menuController: menuController, parentController: strongSelf, editingMedia: editMediaOptions != nil, saveCapturedPhotos: settings.storeEditedPhotos, mediaGrouping: true, initialCaption: inputText, hasSchedule: strongSelf.presentationInterfaceState.subject != .scheduledMessages && peer.id.namespace != Namespaces.Peer.SecretChat, photoOnly: photoOnly, sendMessagesWithSignals: { [weak self] signals, silentPosting, scheduleTime in
|
||||
if let strongSelf = self {
|
||||
if editMediaOptions != nil {
|
||||
strongSelf.editMessageMediaWithLegacySignals(signals!)
|
||||
|
||||
@ -191,14 +191,12 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
var telegramDice: TelegramMediaDice?
|
||||
private let disposable = MetaDisposable()
|
||||
private let disposables = DisposableSet()
|
||||
|
||||
private var forwardInfoNode: ChatMessageForwardInfoNode?
|
||||
private var forwardBackgroundNode: NavigationBackgroundNode?
|
||||
|
||||
|
||||
private var viaBotNode: TextNode?
|
||||
private let dateAndStatusNode: ChatMessageDateAndStatusNode
|
||||
private var replyInfoNode: ChatMessageReplyInfoNode?
|
||||
private var replyBackgroundNode: NavigationBackgroundNode?
|
||||
private var forwardInfoNode: ChatMessageForwardInfoNode?
|
||||
|
||||
private var actionButtonsNode: ChatMessageActionButtonsNode?
|
||||
private var reactionButtonsNode: ChatMessageReactionButtonsNode?
|
||||
@ -991,11 +989,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if replyInfoApply != nil || viaBotApply != nil {
|
||||
needsReplyBackground = true
|
||||
}
|
||||
|
||||
|
||||
var updatedShareButtonNode: ChatMessageShareButton?
|
||||
if needsShareButton {
|
||||
if let currentShareButtonNode = currentShareButtonNode {
|
||||
@ -1013,7 +1007,6 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
var forwardPsaType: String?
|
||||
|
||||
var forwardInfoSizeApply: (CGSize, (CGFloat) -> ChatMessageForwardInfoNode)?
|
||||
var needsForwardBackground = false
|
||||
|
||||
if !ignoreForward, let forwardInfo = item.message.forwardInfo {
|
||||
forwardPsaType = forwardInfo.psaType
|
||||
@ -1038,8 +1031,10 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
}
|
||||
let availableWidth = max(60.0, availableContentWidth + 6.0)
|
||||
forwardInfoSizeApply = makeForwardInfoLayout(item.presentationData, item.presentationData.strings, .standalone, forwardSource, forwardAuthorSignature, forwardPsaType, CGSize(width: availableWidth, height: CGFloat.greatestFiniteMagnitude))
|
||||
|
||||
needsForwardBackground = true
|
||||
}
|
||||
|
||||
if replyInfoApply != nil || viaBotApply != nil || forwardInfoSizeApply != nil {
|
||||
needsReplyBackground = true
|
||||
}
|
||||
|
||||
var maxContentWidth = imageSize.width
|
||||
@ -1194,22 +1189,59 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
replyBackgroundNode.removeFromSupernode()
|
||||
}
|
||||
|
||||
if let (viaBotLayout, viaBotApply) = viaBotApply {
|
||||
var messageInfoSize = CGSize()
|
||||
if let (viaBotLayout, _) = viaBotApply, forwardInfoSizeApply == nil {
|
||||
messageInfoSize = CGSize(width: viaBotLayout.size.width + 1.0, height: 0.0)
|
||||
}
|
||||
if let (forwardInfoSize, _) = forwardInfoSizeApply {
|
||||
messageInfoSize = CGSize(width: max(messageInfoSize.width, forwardInfoSize.width + 2.0), height: 0.0)
|
||||
}
|
||||
if let (replyInfoSize, _) = replyInfoApply {
|
||||
messageInfoSize = CGSize(width: max(messageInfoSize.width, replyInfoSize.width), height: 0.0)
|
||||
}
|
||||
|
||||
if let (viaBotLayout, viaBotApply) = viaBotApply, forwardInfoSizeApply == nil {
|
||||
let viaBotNode = viaBotApply()
|
||||
if strongSelf.viaBotNode == nil {
|
||||
strongSelf.viaBotNode = viaBotNode
|
||||
strongSelf.contextSourceNode.contentNode.addSubnode(viaBotNode)
|
||||
}
|
||||
let viaBotFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 15.0) : (params.width - params.rightInset - viaBotLayout.size.width - layoutConstants.bubble.edgeInset - 14.0)), y: 8.0), size: viaBotLayout.size)
|
||||
let viaBotFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 11.0) : (params.width - params.rightInset - messageInfoSize.width - layoutConstants.bubble.edgeInset - 9.0)), y: 8.0), size: viaBotLayout.size)
|
||||
viaBotNode.frame = viaBotFrame
|
||||
if let replyBackgroundNode = strongSelf.replyBackgroundNode {
|
||||
replyBackgroundNode.frame = CGRect(origin: CGPoint(x: viaBotFrame.minX - 6.0, y: viaBotFrame.minY - 2.0 - UIScreenPixel), size: CGSize(width: viaBotFrame.size.width + 11.0, height: viaBotFrame.size.height + 5.0))
|
||||
replyBackgroundNode.update(size: replyBackgroundNode.bounds.size, cornerRadius: 8.0, transition: .immediate)
|
||||
}
|
||||
|
||||
messageInfoSize = CGSize(width: messageInfoSize.width, height: viaBotLayout.size.height)
|
||||
} else if let viaBotNode = strongSelf.viaBotNode {
|
||||
viaBotNode.removeFromSupernode()
|
||||
strongSelf.viaBotNode = nil
|
||||
}
|
||||
|
||||
if let (forwardInfoSize, forwardInfoApply) = forwardInfoSizeApply {
|
||||
let forwardInfoNode = forwardInfoApply(forwardInfoSize.width)
|
||||
if strongSelf.forwardInfoNode == nil {
|
||||
strongSelf.forwardInfoNode = forwardInfoNode
|
||||
strongSelf.contextSourceNode.contentNode.addSubnode(forwardInfoNode)
|
||||
|
||||
if animation.isAnimated {
|
||||
forwardInfoNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
let forwardInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 12.0) : (params.width - params.rightInset - messageInfoSize.width - layoutConstants.bubble.edgeInset - 8.0)), y: 8.0 + messageInfoSize.height), size: forwardInfoSize)
|
||||
forwardInfoNode.frame = forwardInfoFrame
|
||||
|
||||
messageInfoSize = CGSize(width: messageInfoSize.width, height: messageInfoSize.height + forwardInfoSize.height - 1.0)
|
||||
} else if let forwardInfoNode = strongSelf.forwardInfoNode {
|
||||
if animation.isAnimated {
|
||||
if let forwardInfoNode = strongSelf.forwardInfoNode {
|
||||
strongSelf.forwardInfoNode = nil
|
||||
forwardInfoNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false, completion: { [weak forwardInfoNode] _ in
|
||||
forwardInfoNode?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
} else {
|
||||
forwardInfoNode.removeFromSupernode()
|
||||
strongSelf.forwardInfoNode = nil
|
||||
}
|
||||
}
|
||||
|
||||
if let (replyInfoSize, replyInfoApply) = replyInfoApply {
|
||||
let replyInfoNode = replyInfoApply()
|
||||
@ -1217,31 +1249,29 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
strongSelf.replyInfoNode = replyInfoNode
|
||||
strongSelf.contextSourceNode.contentNode.addSubnode(replyInfoNode)
|
||||
}
|
||||
var viaBotSize = CGSize()
|
||||
if let viaBotNode = strongSelf.viaBotNode {
|
||||
viaBotSize = viaBotNode.frame.size
|
||||
}
|
||||
let replyInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 10.0) : (params.width - params.rightInset - max(replyInfoSize.width, viaBotSize.width) - layoutConstants.bubble.edgeInset - 10.0)), y: 8.0 + viaBotSize.height), size: replyInfoSize)
|
||||
if let viaBotNode = strongSelf.viaBotNode {
|
||||
if replyInfoFrame.minX < viaBotNode.frame.minX {
|
||||
viaBotNode.frame = viaBotNode.frame.offsetBy(dx: replyInfoFrame.minX - viaBotNode.frame.minX, dy: 0.0)
|
||||
}
|
||||
}
|
||||
let replyInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 11.0) : (params.width - params.rightInset - messageInfoSize.width - layoutConstants.bubble.edgeInset - 9.0)), y: 8.0 + messageInfoSize.height), size: replyInfoSize)
|
||||
replyInfoNode.frame = replyInfoFrame
|
||||
if let replyBackgroundNode = strongSelf.replyBackgroundNode {
|
||||
replyBackgroundNode.frame = CGRect(origin: CGPoint(x: replyInfoFrame.minX - 4.0, y: replyInfoFrame.minY - viaBotSize.height - 2.0), size: CGSize(width: max(replyInfoFrame.size.width, viaBotSize.width) + 8.0, height: replyInfoFrame.size.height + viaBotSize.height + 5.0))
|
||||
replyBackgroundNode.update(size: replyBackgroundNode.bounds.size, cornerRadius: 8.0, transition: .immediate)
|
||||
}
|
||||
|
||||
if let _ = item.controllerInteraction.selectionState, isEmoji {
|
||||
replyInfoNode.alpha = 0.0
|
||||
strongSelf.replyBackgroundNode?.alpha = 0.0
|
||||
}
|
||||
messageInfoSize = CGSize(width: max(messageInfoSize.width, replyInfoSize.width), height: messageInfoSize.height + replyInfoSize.height)
|
||||
} else if let replyInfoNode = strongSelf.replyInfoNode {
|
||||
replyInfoNode.removeFromSupernode()
|
||||
strongSelf.replyInfoNode = nil
|
||||
}
|
||||
|
||||
|
||||
if let replyBackgroundNode = strongSelf.replyBackgroundNode {
|
||||
replyBackgroundNode.frame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 10.0) : (params.width - params.rightInset - messageInfoSize.width - layoutConstants.bubble.edgeInset - 10.0)) - 4.0, y: 6.0), size: CGSize(width: messageInfoSize.width + 8.0, height: messageInfoSize.height + 5.0))
|
||||
|
||||
let cornerRadius = replyBackgroundNode.frame.height <= 22.0 ? replyBackgroundNode.frame.height / 2.0 : 8.0
|
||||
replyBackgroundNode.update(size: replyBackgroundNode.bounds.size, cornerRadius: cornerRadius, transition: .immediate)
|
||||
}
|
||||
|
||||
let panelsAlpha: CGFloat = item.controllerInteraction.selectionState == nil ? 1.0 : 0.0
|
||||
strongSelf.replyInfoNode?.alpha = panelsAlpha
|
||||
strongSelf.viaBotNode?.alpha = panelsAlpha
|
||||
strongSelf.forwardInfoNode?.alpha = panelsAlpha
|
||||
strongSelf.replyBackgroundNode?.alpha = panelsAlpha
|
||||
|
||||
if isFailed {
|
||||
let deliveryFailedNode: ChatMessageDeliveryFailedNode
|
||||
var isAppearing = false
|
||||
@ -1272,61 +1302,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
deliveryFailedNode?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
|
||||
if needsForwardBackground {
|
||||
if let forwardBackgroundNode = strongSelf.forwardBackgroundNode {
|
||||
forwardBackgroundNode.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
|
||||
} else {
|
||||
let forwardBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
|
||||
strongSelf.forwardBackgroundNode = forwardBackgroundNode
|
||||
strongSelf.contextSourceNode.contentNode.addSubnode(forwardBackgroundNode)
|
||||
|
||||
if animation.isAnimated {
|
||||
forwardBackgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
} else if let forwardBackgroundNode = strongSelf.forwardBackgroundNode {
|
||||
if animation.isAnimated {
|
||||
strongSelf.forwardBackgroundNode = nil
|
||||
forwardBackgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false, completion: { [weak forwardBackgroundNode] _ in
|
||||
forwardBackgroundNode?.removeFromSupernode()
|
||||
})
|
||||
} else {
|
||||
forwardBackgroundNode.removeFromSupernode()
|
||||
strongSelf.forwardBackgroundNode = nil
|
||||
}
|
||||
}
|
||||
|
||||
if let (forwardInfoSize, forwardInfoApply) = forwardInfoSizeApply {
|
||||
let forwardInfoNode = forwardInfoApply(forwardInfoSize.width)
|
||||
if strongSelf.forwardInfoNode == nil {
|
||||
strongSelf.forwardInfoNode = forwardInfoNode
|
||||
strongSelf.contextSourceNode.contentNode.addSubnode(forwardInfoNode)
|
||||
|
||||
if animation.isAnimated {
|
||||
forwardInfoNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
let forwardInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 12.0) : (params.width - params.rightInset - forwardInfoSize.width - layoutConstants.bubble.edgeInset - 12.0)), y: 8.0), size: forwardInfoSize)
|
||||
forwardInfoNode.frame = forwardInfoFrame
|
||||
if let forwardBackgroundNode = strongSelf.forwardBackgroundNode {
|
||||
forwardBackgroundNode.frame = CGRect(origin: CGPoint(x: forwardInfoFrame.minX - 6.0, y: forwardInfoFrame.minY - 2.0), size: CGSize(width: forwardInfoFrame.size.width + 10.0, height: forwardInfoFrame.size.height + 4.0))
|
||||
forwardBackgroundNode.update(size: forwardBackgroundNode.bounds.size, cornerRadius: 8.0, transition: .immediate)
|
||||
}
|
||||
} else if let forwardInfoNode = strongSelf.forwardInfoNode {
|
||||
if animation.isAnimated {
|
||||
if let forwardInfoNode = strongSelf.forwardInfoNode {
|
||||
strongSelf.forwardInfoNode = nil
|
||||
forwardInfoNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false, completion: { [weak forwardInfoNode] _ in
|
||||
forwardInfoNode?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
} else {
|
||||
forwardInfoNode.removeFromSupernode()
|
||||
strongSelf.forwardInfoNode = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if let actionButtonsSizeAndApply = actionButtonsSizeAndApply {
|
||||
let actionButtonsNode = actionButtonsSizeAndApply.1(animation)
|
||||
let previousFrame = actionButtonsNode.frame
|
||||
@ -2057,12 +2033,18 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
}
|
||||
|
||||
let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.2, curve: .easeInOut) : .immediate
|
||||
let replyAlpha: CGFloat = item.controllerInteraction.selectionState == nil ? 1.0 : 0.0
|
||||
let panelsAlpha: CGFloat = item.controllerInteraction.selectionState == nil ? 1.0 : 0.0
|
||||
if let replyInfoNode = self.replyInfoNode {
|
||||
transition.updateAlpha(node: replyInfoNode, alpha: replyAlpha)
|
||||
transition.updateAlpha(node: replyInfoNode, alpha: panelsAlpha)
|
||||
}
|
||||
if let viaBotNode = self.viaBotNode {
|
||||
transition.updateAlpha(node: viaBotNode, alpha: panelsAlpha)
|
||||
}
|
||||
if let forwardInfoNode = self.forwardInfoNode {
|
||||
transition.updateAlpha(node: forwardInfoNode, alpha: panelsAlpha)
|
||||
}
|
||||
if let replyBackgroundNode = self.replyBackgroundNode {
|
||||
transition.updateAlpha(node: replyBackgroundNode, alpha: replyAlpha)
|
||||
transition.updateAlpha(node: replyBackgroundNode, alpha: panelsAlpha)
|
||||
}
|
||||
|
||||
if let selectionState = item.controllerInteraction.selectionState {
|
||||
|
||||
@ -805,7 +805,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
||||
var rects: [CGRect] = []
|
||||
for contentNode in self.contentNodes {
|
||||
if let contentNode = contentNode as? ChatMessageMediaBubbleContentNode {
|
||||
rects.append(contentNode.frame.offsetBy(dx: -76.0, dy: 0.0))
|
||||
rects.append(contentNode.frame.offsetBy(dx: -self.clippingNode.frame.minX, dy: 0.0))
|
||||
}
|
||||
}
|
||||
return rects
|
||||
|
||||
@ -148,7 +148,7 @@ class ChatMessageForwardInfoNode: ASDisplayNode {
|
||||
}
|
||||
} else {
|
||||
titleColor = incoming ? presentationData.theme.theme.chat.message.incoming.accentTextColor : presentationData.theme.theme.chat.message.outgoing.accentTextColor
|
||||
completeSourceString = strings.Message_ForwardedMessage(peerString)
|
||||
completeSourceString = strings.Message_ForwardedMessageShort(peerString)
|
||||
}
|
||||
case .standalone:
|
||||
let serviceColor = serviceMessageColorComponents(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
|
||||
|
||||
@ -42,12 +42,10 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
|
||||
return self.apparentHeightTransition != nil
|
||||
}
|
||||
|
||||
private var forwardInfoNode: ChatMessageForwardInfoNode?
|
||||
private var forwardBackgroundNode: NavigationBackgroundNode?
|
||||
|
||||
private var viaBotNode: TextNode?
|
||||
private var replyInfoNode: ChatMessageReplyInfoNode?
|
||||
private var replyBackgroundNode: NavigationBackgroundNode?
|
||||
private var forwardInfoNode: ChatMessageForwardInfoNode?
|
||||
|
||||
private var actionButtonsNode: ChatMessageActionButtonsNode?
|
||||
private var reactionButtonsNode: ChatMessageReactionButtonsNode?
|
||||
@ -259,7 +257,6 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
|
||||
let currentShareButtonNode = self.shareButtonNode
|
||||
|
||||
let makeForwardInfoLayout = ChatMessageForwardInfoNode.asyncLayout(self.forwardInfoNode)
|
||||
let currentForwardBackgroundNode = self.forwardBackgroundNode
|
||||
|
||||
let actionButtonsLayout = ChatMessageActionButtonsNode.asyncLayout(self.actionButtonsNode)
|
||||
let reactionButtonsLayout = ChatMessageReactionButtonsNode.asyncLayout(self.reactionButtonsNode)
|
||||
@ -472,17 +469,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
|
||||
replyMarkup = attribute
|
||||
}
|
||||
}
|
||||
|
||||
if replyInfoApply != nil || viaBotApply != nil {
|
||||
if let currentReplyBackgroundNode = currentReplyBackgroundNode {
|
||||
updatedReplyBackgroundNode = currentReplyBackgroundNode
|
||||
} else {
|
||||
updatedReplyBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
|
||||
}
|
||||
|
||||
updatedReplyBackgroundNode?.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
|
||||
}
|
||||
|
||||
|
||||
var updatedShareButtonNode: ChatMessageShareButton?
|
||||
if needsShareButton {
|
||||
if currentShareButtonNode != nil {
|
||||
@ -499,7 +486,6 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
|
||||
var forwardAuthorSignature: String?
|
||||
|
||||
var forwardInfoSizeApply: (CGSize, (CGFloat) -> ChatMessageForwardInfoNode)?
|
||||
var updatedForwardBackgroundNode: NavigationBackgroundNode?
|
||||
|
||||
if !ignoreForward, let forwardInfo = item.message.forwardInfo {
|
||||
let forwardPsaType = forwardInfo.psaType
|
||||
@ -524,14 +510,16 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
|
||||
}
|
||||
let availableWidth = max(60.0, availableContentWidth - normalDisplaySize.width + 6.0)
|
||||
forwardInfoSizeApply = makeForwardInfoLayout(item.presentationData, item.presentationData.strings, .standalone, forwardSource, forwardAuthorSignature, forwardPsaType, CGSize(width: availableWidth, height: CGFloat.greatestFiniteMagnitude))
|
||||
|
||||
if let currentForwardBackgroundNode = currentForwardBackgroundNode {
|
||||
updatedForwardBackgroundNode = currentForwardBackgroundNode
|
||||
}
|
||||
|
||||
if replyInfoApply != nil || viaBotApply != nil || forwardInfoSizeApply != nil {
|
||||
if let currentReplyBackgroundNode = currentReplyBackgroundNode {
|
||||
updatedReplyBackgroundNode = currentReplyBackgroundNode
|
||||
} else {
|
||||
updatedForwardBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
|
||||
updatedReplyBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
|
||||
}
|
||||
|
||||
updatedForwardBackgroundNode?.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
|
||||
updatedReplyBackgroundNode?.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
|
||||
}
|
||||
|
||||
var maxContentWidth = normalDisplaySize.width
|
||||
@ -657,21 +645,59 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
|
||||
strongSelf.replyBackgroundNode = nil
|
||||
}
|
||||
|
||||
if let (viaBotLayout, viaBotApply) = viaBotApply {
|
||||
var messageInfoSize = CGSize()
|
||||
if let (viaBotLayout, _) = viaBotApply, forwardInfoSizeApply == nil {
|
||||
messageInfoSize = CGSize(width: viaBotLayout.size.width + 1.0, height: 0.0)
|
||||
}
|
||||
if let (forwardInfoSize, _) = forwardInfoSizeApply {
|
||||
messageInfoSize = CGSize(width: max(messageInfoSize.width, forwardInfoSize.width + 2.0), height: 0.0)
|
||||
}
|
||||
if let (replyInfoSize, _) = replyInfoApply {
|
||||
messageInfoSize = CGSize(width: max(messageInfoSize.width, replyInfoSize.width), height: 0.0)
|
||||
}
|
||||
|
||||
if let (viaBotLayout, viaBotApply) = viaBotApply, forwardInfoSizeApply == nil {
|
||||
let viaBotNode = viaBotApply()
|
||||
if strongSelf.viaBotNode == nil {
|
||||
strongSelf.viaBotNode = viaBotNode
|
||||
strongSelf.contextSourceNode.contentNode.addSubnode(viaBotNode)
|
||||
}
|
||||
let viaBotFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 10.0) : (params.width - params.rightInset - viaBotLayout.size.width - layoutConstants.bubble.edgeInset - 10.0)), y: 8.0), size: viaBotLayout.size)
|
||||
let viaBotFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 11.0) : (params.width - params.rightInset - messageInfoSize.width - layoutConstants.bubble.edgeInset - 9.0)), y: 8.0), size: viaBotLayout.size)
|
||||
viaBotNode.frame = viaBotFrame
|
||||
let replyBackgroundFrame = CGRect(origin: CGPoint(x: viaBotFrame.minX - 4.0, y: viaBotFrame.minY - 2.0), size: CGSize(width: viaBotFrame.size.width + 8.0, height: viaBotFrame.size.height + 5.0))
|
||||
strongSelf.replyBackgroundNode?.frame = replyBackgroundFrame
|
||||
strongSelf.replyBackgroundNode?.update(size: replyBackgroundFrame.size, cornerRadius: 8.0, transition: .immediate)
|
||||
|
||||
messageInfoSize = CGSize(width: messageInfoSize.width, height: viaBotLayout.size.height)
|
||||
} else if let viaBotNode = strongSelf.viaBotNode {
|
||||
viaBotNode.removeFromSupernode()
|
||||
strongSelf.viaBotNode = nil
|
||||
}
|
||||
|
||||
if let (forwardInfoSize, forwardInfoApply) = forwardInfoSizeApply {
|
||||
let forwardInfoNode = forwardInfoApply(forwardInfoSize.width)
|
||||
if strongSelf.forwardInfoNode == nil {
|
||||
strongSelf.forwardInfoNode = forwardInfoNode
|
||||
strongSelf.contextSourceNode.contentNode.addSubnode(forwardInfoNode)
|
||||
|
||||
if animation.isAnimated {
|
||||
forwardInfoNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
let forwardInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 12.0) : (params.width - params.rightInset - messageInfoSize.width - layoutConstants.bubble.edgeInset - 8.0)), y: 8.0 + messageInfoSize.height), size: forwardInfoSize)
|
||||
forwardInfoNode.frame = forwardInfoFrame
|
||||
|
||||
messageInfoSize = CGSize(width: messageInfoSize.width, height: messageInfoSize.height + forwardInfoSize.height - 1.0)
|
||||
} else if let forwardInfoNode = strongSelf.forwardInfoNode {
|
||||
if animation.isAnimated {
|
||||
if let forwardInfoNode = strongSelf.forwardInfoNode {
|
||||
strongSelf.forwardInfoNode = nil
|
||||
forwardInfoNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false, completion: { [weak forwardInfoNode] _ in
|
||||
forwardInfoNode?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
} else {
|
||||
forwardInfoNode.removeFromSupernode()
|
||||
strongSelf.forwardInfoNode = nil
|
||||
}
|
||||
}
|
||||
|
||||
if let (replyInfoSize, replyInfoApply) = replyInfoApply {
|
||||
let replyInfoNode = replyInfoApply()
|
||||
@ -679,25 +705,23 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
|
||||
strongSelf.replyInfoNode = replyInfoNode
|
||||
strongSelf.contextSourceNode.contentNode.addSubnode(replyInfoNode)
|
||||
}
|
||||
var viaBotSize = CGSize()
|
||||
if let viaBotNode = strongSelf.viaBotNode {
|
||||
viaBotSize = viaBotNode.frame.size
|
||||
}
|
||||
let replyInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 10.0) : (params.width - params.rightInset - max(replyInfoSize.width, viaBotSize.width) - layoutConstants.bubble.edgeInset - 10.0)), y: 8.0 + viaBotSize.height), size: replyInfoSize)
|
||||
if let viaBotNode = strongSelf.viaBotNode {
|
||||
if replyInfoFrame.minX < viaBotNode.frame.minX {
|
||||
viaBotNode.frame = viaBotNode.frame.offsetBy(dx: replyInfoFrame.minX - viaBotNode.frame.minX, dy: 0.0)
|
||||
}
|
||||
}
|
||||
let replyInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 11.0) : (params.width - params.rightInset - messageInfoSize.width - layoutConstants.bubble.edgeInset - 9.0)), y: 8.0 + messageInfoSize.height), size: replyInfoSize)
|
||||
replyInfoNode.frame = replyInfoFrame
|
||||
let replyBackgroundFrame = CGRect(origin: CGPoint(x: replyInfoFrame.minX - 4.0, y: replyInfoFrame.minY - viaBotSize.height - 2.0), size: CGSize(width: max(replyInfoFrame.size.width, viaBotSize.width) + 8.0, height: replyInfoFrame.size.height + viaBotSize.height + 5.0))
|
||||
strongSelf.replyBackgroundNode?.frame = replyBackgroundFrame
|
||||
strongSelf.replyBackgroundNode?.update(size: replyBackgroundFrame.size, cornerRadius: 8.0, transition: .immediate)
|
||||
|
||||
messageInfoSize = CGSize(width: max(messageInfoSize.width, replyInfoSize.width), height: messageInfoSize.height + replyInfoSize.height)
|
||||
} else if let replyInfoNode = strongSelf.replyInfoNode {
|
||||
replyInfoNode.removeFromSupernode()
|
||||
strongSelf.replyInfoNode = nil
|
||||
}
|
||||
|
||||
|
||||
if let replyBackgroundNode = strongSelf.replyBackgroundNode {
|
||||
replyBackgroundNode.frame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 10.0) : (params.width - params.rightInset - messageInfoSize.width - layoutConstants.bubble.edgeInset - 10.0)) - 4.0, y: 6.0), size: CGSize(width: messageInfoSize.width + 8.0, height: messageInfoSize.height + 5.0))
|
||||
|
||||
let cornerRadius = replyBackgroundNode.frame.height <= 22.0 ? replyBackgroundNode.frame.height / 2.0 : 8.0
|
||||
replyBackgroundNode.update(size: replyBackgroundNode.bounds.size, cornerRadius: cornerRadius, transition: .immediate)
|
||||
}
|
||||
|
||||
if isFailed {
|
||||
let deliveryFailedNode: ChatMessageDeliveryFailedNode
|
||||
var isAppearing = false
|
||||
@ -728,63 +752,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
|
||||
deliveryFailedNode?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
|
||||
if let updatedForwardBackgroundNode = updatedForwardBackgroundNode {
|
||||
if strongSelf.forwardBackgroundNode == nil {
|
||||
strongSelf.forwardBackgroundNode = updatedForwardBackgroundNode
|
||||
strongSelf.contextSourceNode.contentNode.addSubnode(updatedForwardBackgroundNode)
|
||||
|
||||
if animation.isAnimated {
|
||||
updatedForwardBackgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
} else if let forwardBackgroundNode = strongSelf.forwardBackgroundNode {
|
||||
if animation.isAnimated {
|
||||
strongSelf.forwardBackgroundNode = nil
|
||||
forwardBackgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false, completion: { [weak forwardBackgroundNode] _ in
|
||||
forwardBackgroundNode?.removeFromSupernode()
|
||||
})
|
||||
} else {
|
||||
forwardBackgroundNode.removeFromSupernode()
|
||||
strongSelf.forwardBackgroundNode = nil
|
||||
}
|
||||
}
|
||||
|
||||
if let (forwardInfoSize, forwardInfoApply) = forwardInfoSizeApply {
|
||||
let forwardInfoNode = forwardInfoApply(forwardInfoSize.width)
|
||||
if strongSelf.forwardInfoNode == nil {
|
||||
strongSelf.forwardInfoNode = forwardInfoNode
|
||||
strongSelf.contextSourceNode.contentNode.addSubnode(forwardInfoNode)
|
||||
forwardInfoNode.openPsa = { [weak strongSelf] type, sourceNode in
|
||||
guard let strongSelf = strongSelf, let item = strongSelf.item else {
|
||||
return
|
||||
}
|
||||
item.controllerInteraction.displayPsa(type, sourceNode)
|
||||
}
|
||||
|
||||
if animation.isAnimated {
|
||||
forwardInfoNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
let forwardInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 12.0) : (params.width - params.rightInset - forwardInfoSize.width - layoutConstants.bubble.edgeInset - 12.0)), y: 8.0), size: forwardInfoSize)
|
||||
forwardInfoNode.frame = forwardInfoFrame
|
||||
let forwardBackgroundFrame = CGRect(origin: CGPoint(x: forwardInfoFrame.minX - 6.0, y: forwardInfoFrame.minY - 2.0), size: CGSize(width: forwardInfoFrame.size.width + 10.0, height: forwardInfoFrame.size.height + 4.0))
|
||||
strongSelf.forwardBackgroundNode?.frame = forwardBackgroundFrame
|
||||
strongSelf.forwardBackgroundNode?.update(size: forwardBackgroundFrame.size, cornerRadius: 8.0, transition: .immediate)
|
||||
} else if let forwardInfoNode = strongSelf.forwardInfoNode {
|
||||
if animation.isAnimated {
|
||||
if let forwardInfoNode = strongSelf.forwardInfoNode {
|
||||
strongSelf.forwardInfoNode = nil
|
||||
forwardInfoNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false, completion: { [weak forwardInfoNode] _ in
|
||||
forwardInfoNode?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
} else {
|
||||
forwardInfoNode.removeFromSupernode()
|
||||
strongSelf.forwardInfoNode = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if let reactionButtonsSizeAndApply = reactionButtonsSizeAndApply {
|
||||
let reactionButtonsNode = reactionButtonsSizeAndApply.1(animation)
|
||||
var reactionButtonsFrame = CGRect(origin: CGPoint(x: videoFrame.minX, y: videoFrame.maxY + 6.0), size: reactionButtonsSizeAndApply.0)
|
||||
@ -869,9 +837,6 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
|
||||
}
|
||||
|
||||
let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut)
|
||||
if let forwardBackgroundNode = strongSelf.forwardBackgroundNode {
|
||||
transition.updateAlpha(node: forwardBackgroundNode, alpha: isPlaying ? 0.0 : 1.0)
|
||||
}
|
||||
if let replyBackgroundNode = strongSelf.replyBackgroundNode {
|
||||
transition.updateAlpha(node: replyBackgroundNode, alpha: isPlaying ? 0.0 : 1.0)
|
||||
}
|
||||
@ -1312,28 +1277,28 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
|
||||
shareButtonNode.frame = CGRect(origin: CGPoint(x: min(params.width - buttonSize.width - 8.0, videoFrame.maxX - 7.0), y: videoFrame.maxY - 24.0 - buttonSize.height), size: buttonSize)
|
||||
}
|
||||
|
||||
if let viaBotNode = self.viaBotNode {
|
||||
let viaBotLayout = viaBotNode.frame
|
||||
let viaBotFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 10.0) : (params.width - params.rightInset - viaBotLayout.size.width - layoutConstants.bubble.edgeInset - 10.0)), y: 8.0), size: viaBotLayout.size)
|
||||
viaBotNode.frame = viaBotFrame
|
||||
self.replyBackgroundNode?.frame = CGRect(origin: CGPoint(x: viaBotFrame.minX - 4.0, y: viaBotFrame.minY - 2.0), size: CGSize(width: viaBotFrame.size.width + 8.0, height: viaBotFrame.size.height + 5.0))
|
||||
}
|
||||
|
||||
if let replyInfoNode = self.replyInfoNode {
|
||||
var viaBotSize = CGSize()
|
||||
if let viaBotNode = self.viaBotNode {
|
||||
viaBotSize = viaBotNode.frame.size
|
||||
}
|
||||
let replyInfoSize = replyInfoNode.frame.size
|
||||
let replyInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 10.0) : (params.width - params.rightInset - max(replyInfoSize.width, viaBotSize.width) - layoutConstants.bubble.edgeInset - 10.0)), y: 8.0 + viaBotSize.height), size: replyInfoSize)
|
||||
if let viaBotNode = self.viaBotNode {
|
||||
if replyInfoFrame.minX < viaBotNode.frame.minX {
|
||||
viaBotNode.frame = viaBotNode.frame.offsetBy(dx: replyInfoFrame.minX - viaBotNode.frame.minX, dy: 0.0)
|
||||
}
|
||||
}
|
||||
replyInfoNode.frame = replyInfoFrame
|
||||
self.replyBackgroundNode?.frame = CGRect(origin: CGPoint(x: replyInfoFrame.minX - 4.0, y: replyInfoFrame.minY - viaBotSize.height - 2.0), size: CGSize(width: max(replyInfoFrame.size.width, viaBotSize.width) + 8.0, height: replyInfoFrame.size.height + viaBotSize.height + 5.0))
|
||||
}
|
||||
// if let viaBotNode = self.viaBotNode {
|
||||
// let viaBotLayout = viaBotNode.frame
|
||||
// let viaBotFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 10.0) : (params.width - params.rightInset - viaBotLayout.size.width - layoutConstants.bubble.edgeInset - 10.0)), y: 8.0), size: viaBotLayout.size)
|
||||
// viaBotNode.frame = viaBotFrame
|
||||
// self.replyBackgroundNode?.frame = CGRect(origin: CGPoint(x: viaBotFrame.minX - 4.0, y: viaBotFrame.minY - 2.0), size: CGSize(width: viaBotFrame.size.width + 8.0, height: viaBotFrame.size.height + 5.0))
|
||||
// }
|
||||
//
|
||||
// if let replyInfoNode = self.replyInfoNode {
|
||||
// var viaBotSize = CGSize()
|
||||
// if let viaBotNode = self.viaBotNode {
|
||||
// viaBotSize = viaBotNode.frame.size
|
||||
// }
|
||||
// let replyInfoSize = replyInfoNode.frame.size
|
||||
// let replyInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 10.0) : (params.width - params.rightInset - max(replyInfoSize.width, viaBotSize.width) - layoutConstants.bubble.edgeInset - 10.0)), y: 8.0 + viaBotSize.height), size: replyInfoSize)
|
||||
// if let viaBotNode = self.viaBotNode {
|
||||
// if replyInfoFrame.minX < viaBotNode.frame.minX {
|
||||
// viaBotNode.frame = viaBotNode.frame.offsetBy(dx: replyInfoFrame.minX - viaBotNode.frame.minX, dy: 0.0)
|
||||
// }
|
||||
// }
|
||||
// replyInfoNode.frame = replyInfoFrame
|
||||
// self.replyBackgroundNode?.frame = CGRect(origin: CGPoint(x: replyInfoFrame.minX - 4.0, y: replyInfoFrame.minY - viaBotSize.height - 2.0), size: CGSize(width: max(replyInfoFrame.size.width, viaBotSize.width) + 8.0, height: replyInfoFrame.size.height + viaBotSize.height + 5.0))
|
||||
// }
|
||||
|
||||
if let deliveryFailedNode = self.deliveryFailedNode {
|
||||
let deliveryFailedSize = deliveryFailedNode.frame.size
|
||||
@ -1341,12 +1306,11 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
|
||||
deliveryFailedNode.frame = deliveryFailedFrame
|
||||
}
|
||||
|
||||
if let forwardInfoNode = self.forwardInfoNode {
|
||||
let forwardInfoSize = forwardInfoNode.frame.size
|
||||
let forwardInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 12.0) : (params.width - params.rightInset - forwardInfoSize.width - layoutConstants.bubble.edgeInset - 12.0)), y: 8.0), size: forwardInfoSize)
|
||||
forwardInfoNode.frame = forwardInfoFrame
|
||||
self.forwardBackgroundNode?.frame = CGRect(origin: CGPoint(x: forwardInfoFrame.minX - 6.0, y: forwardInfoFrame.minY - 2.0), size: CGSize(width: forwardInfoFrame.size.width + 10.0, height: forwardInfoFrame.size.height + 4.0))
|
||||
}
|
||||
// if let forwardInfoNode = self.forwardInfoNode {
|
||||
// let forwardInfoSize = forwardInfoNode.frame.size
|
||||
// let forwardInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 12.0) : (params.width - params.rightInset - forwardInfoSize.width - layoutConstants.bubble.edgeInset - 12.0)), y: 8.0), size: forwardInfoSize)
|
||||
// forwardInfoNode.frame = forwardInfoFrame
|
||||
// }
|
||||
|
||||
if let actionButtonsNode = self.actionButtonsNode {
|
||||
let actionButtonsSize = actionButtonsNode.frame.size
|
||||
|
||||
@ -46,7 +46,6 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
class func asyncLayout(_ maybeNode: ChatMessageReplyInfoNode?) -> (_ theme: ChatPresentationData, _ strings: PresentationStrings, _ context: AccountContext, _ type: ChatMessageReplyInfoType, _ message: Message, _ constrainedSize: CGSize) -> (CGSize, () -> ChatMessageReplyInfoNode) {
|
||||
|
||||
let titleNodeLayout = TextNode.asyncLayout(maybeNode?.titleNode)
|
||||
let textNodeLayout = TextNode.asyncLayout(maybeNode?.textNode)
|
||||
let imageNodeLayout = TransformImageNode.asyncLayout(maybeNode?.imageNode)
|
||||
@ -57,7 +56,13 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
|
||||
let titleFont = Font.medium(fontSize)
|
||||
let textFont = Font.regular(fontSize)
|
||||
|
||||
var titleString = message.effectiveAuthor.flatMap(EnginePeer.init)?.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder) ?? strings.User_DeletedAccount
|
||||
var author: Peer?
|
||||
if let forwardAuthor = message.forwardInfo?.author {
|
||||
author = forwardAuthor
|
||||
} else {
|
||||
author = message.effectiveAuthor
|
||||
}
|
||||
var titleString = author.flatMap(EnginePeer.init)?.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder) ?? strings.User_DeletedAccount
|
||||
|
||||
if let forwardInfo = message.forwardInfo, forwardInfo.flags.contains(.isImported) {
|
||||
if let author = forwardInfo.author {
|
||||
@ -242,9 +247,9 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
|
||||
}
|
||||
node.imageNode?.captureProtected = message.isCopyProtected()
|
||||
|
||||
titleNode.frame = CGRect(origin: CGPoint(x: leftInset - textInsets.left, y: spacing - textInsets.top), size: titleLayout.size)
|
||||
titleNode.frame = CGRect(origin: CGPoint(x: leftInset - textInsets.left - 2.0, y: spacing - textInsets.top + 1.0), size: titleLayout.size)
|
||||
|
||||
let textFrame = CGRect(origin: CGPoint(x: leftInset - textInsets.left, y: titleNode.frame.maxY - textInsets.bottom + spacing - textInsets.top), size: textLayout.size)
|
||||
let textFrame = CGRect(origin: CGPoint(x: leftInset - textInsets.left - 2.0, y: titleNode.frame.maxY - textInsets.bottom + spacing - textInsets.top - 2.0), size: textLayout.size)
|
||||
textNode.frame = textFrame
|
||||
|
||||
if !textLayout.spoilers.isEmpty {
|
||||
@ -265,7 +270,7 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
node.lineNode.image = lineImage
|
||||
node.lineNode.frame = CGRect(origin: CGPoint(x: 1.0, y: 3.0), size: CGSize(width: 2.0, height: max(0.0, size.height - 5.0)))
|
||||
node.lineNode.frame = CGRect(origin: CGPoint(x: 1.0, y: 3.0), size: CGSize(width: 2.0, height: max(0.0, size.height - 4.0)))
|
||||
|
||||
node.contentNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||
|
||||
|
||||
@ -36,13 +36,11 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
var telegramFile: TelegramMediaFile?
|
||||
private let fetchDisposable = MetaDisposable()
|
||||
|
||||
private var forwardInfoNode: ChatMessageForwardInfoNode?
|
||||
private var forwardBackgroundNode: NavigationBackgroundNode?
|
||||
|
||||
private var viaBotNode: TextNode?
|
||||
private let dateAndStatusNode: ChatMessageDateAndStatusNode
|
||||
private var replyInfoNode: ChatMessageReplyInfoNode?
|
||||
private var replyBackgroundNode: NavigationBackgroundNode?
|
||||
private var forwardInfoNode: ChatMessageForwardInfoNode?
|
||||
|
||||
private var actionButtonsNode: ChatMessageActionButtonsNode?
|
||||
private var reactionButtonsNode: ChatMessageReactionButtonsNode?
|
||||
@ -588,12 +586,6 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
}
|
||||
}
|
||||
|
||||
var needsReplyBackground = false
|
||||
|
||||
if replyInfoApply != nil || viaBotApply != nil {
|
||||
needsReplyBackground = true
|
||||
}
|
||||
|
||||
var updatedShareButtonNode: ChatMessageShareButton?
|
||||
if needsShareButton {
|
||||
if let currentShareButtonNode = currentShareButtonNode {
|
||||
@ -611,7 +603,6 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
var forwardPsaType: String?
|
||||
|
||||
var forwardInfoSizeApply: (CGSize, (CGFloat) -> ChatMessageForwardInfoNode)?
|
||||
var needsForwardBackground = false
|
||||
|
||||
if !ignoreForward, let forwardInfo = item.message.forwardInfo {
|
||||
forwardPsaType = forwardInfo.psaType
|
||||
@ -636,8 +627,11 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
}
|
||||
let availableForwardWidth = max(60.0, availableWidth + 6.0)
|
||||
forwardInfoSizeApply = makeForwardInfoLayout(item.presentationData, item.presentationData.strings, .standalone, forwardSource, forwardAuthorSignature, forwardPsaType, CGSize(width: availableForwardWidth, height: CGFloat.greatestFiniteMagnitude))
|
||||
|
||||
needsForwardBackground = true
|
||||
}
|
||||
|
||||
var needsReplyBackground = false
|
||||
if replyInfoApply != nil || viaBotApply != nil || forwardInfoSizeApply != nil {
|
||||
needsReplyBackground = true
|
||||
}
|
||||
|
||||
var maxContentWidth = imageSize.width
|
||||
@ -829,48 +823,89 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
strongSelf.replyBackgroundNode = nil
|
||||
}
|
||||
|
||||
if let (_, viaBotApply) = viaBotApply, let viaBotFrame = viaBotFrame {
|
||||
var messageInfoSize = CGSize()
|
||||
if let (viaBotLayout, _) = viaBotApply, forwardInfoSizeApply == nil {
|
||||
messageInfoSize = CGSize(width: viaBotLayout.size.width + 1.0, height: 0.0)
|
||||
}
|
||||
if let (forwardInfoSize, _) = forwardInfoSizeApply {
|
||||
messageInfoSize = CGSize(width: max(messageInfoSize.width, forwardInfoSize.width + 2.0), height: 0.0)
|
||||
}
|
||||
if let (replyInfoSize, _) = replyInfoApply {
|
||||
messageInfoSize = CGSize(width: max(messageInfoSize.width, replyInfoSize.width), height: 0.0)
|
||||
}
|
||||
|
||||
if let (viaBotLayout, viaBotApply) = viaBotApply, forwardInfoSizeApply == nil {
|
||||
let viaBotNode = viaBotApply()
|
||||
if strongSelf.viaBotNode == nil {
|
||||
strongSelf.viaBotNode = viaBotNode
|
||||
strongSelf.contextSourceNode.contentNode.addSubnode(viaBotNode)
|
||||
}
|
||||
let viaBotFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 11.0) : (params.width - params.rightInset - messageInfoSize.width - layoutConstants.bubble.edgeInset - 9.0)), y: 8.0), size: viaBotLayout.size)
|
||||
viaBotNode.frame = viaBotFrame
|
||||
if let replyBackgroundNode = strongSelf.replyBackgroundNode {
|
||||
replyBackgroundNode.frame = CGRect(origin: CGPoint(x: viaBotFrame.minX - 6.0, y: viaBotFrame.minY - 2.0 - UIScreenPixel), size: CGSize(width: viaBotFrame.size.width + 11.0, height: viaBotFrame.size.height + 5.0))
|
||||
replyBackgroundNode.update(size: replyBackgroundNode.bounds.size, cornerRadius: 8.0, transition: .immediate)
|
||||
}
|
||||
|
||||
messageInfoSize = CGSize(width: messageInfoSize.width, height: viaBotLayout.size.height)
|
||||
} else if let viaBotNode = strongSelf.viaBotNode {
|
||||
viaBotNode.removeFromSupernode()
|
||||
strongSelf.viaBotNode = nil
|
||||
}
|
||||
|
||||
if let (forwardInfoSize, forwardInfoApply) = forwardInfoSizeApply {
|
||||
let forwardInfoNode = forwardInfoApply(forwardInfoSize.width)
|
||||
if strongSelf.forwardInfoNode == nil {
|
||||
strongSelf.forwardInfoNode = forwardInfoNode
|
||||
strongSelf.contextSourceNode.contentNode.addSubnode(forwardInfoNode)
|
||||
|
||||
if animation.isAnimated {
|
||||
forwardInfoNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
let forwardInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 12.0) : (params.width - params.rightInset - messageInfoSize.width - layoutConstants.bubble.edgeInset - 8.0)), y: 8.0 + messageInfoSize.height), size: forwardInfoSize)
|
||||
forwardInfoNode.frame = forwardInfoFrame
|
||||
|
||||
messageInfoSize = CGSize(width: messageInfoSize.width, height: messageInfoSize.height + forwardInfoSize.height - 1.0)
|
||||
} else if let forwardInfoNode = strongSelf.forwardInfoNode {
|
||||
if animation.isAnimated {
|
||||
if let forwardInfoNode = strongSelf.forwardInfoNode {
|
||||
strongSelf.forwardInfoNode = nil
|
||||
forwardInfoNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false, completion: { [weak forwardInfoNode] _ in
|
||||
forwardInfoNode?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
} else {
|
||||
forwardInfoNode.removeFromSupernode()
|
||||
strongSelf.forwardInfoNode = nil
|
||||
}
|
||||
}
|
||||
|
||||
if let (_, replyInfoApply) = replyInfoApply, let replyInfoFrame = replyInfoFrame {
|
||||
if let (replyInfoSize, replyInfoApply) = replyInfoApply {
|
||||
let replyInfoNode = replyInfoApply()
|
||||
if strongSelf.replyInfoNode == nil {
|
||||
strongSelf.replyInfoNode = replyInfoNode
|
||||
strongSelf.contextSourceNode.contentNode.addSubnode(replyInfoNode)
|
||||
}
|
||||
let replyInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 11.0) : (params.width - params.rightInset - messageInfoSize.width - layoutConstants.bubble.edgeInset - 9.0)), y: 8.0 + messageInfoSize.height), size: replyInfoSize)
|
||||
replyInfoNode.frame = replyInfoFrame
|
||||
if let replyBackgroundNode = strongSelf.replyBackgroundNode, let replyBackgroundFrame = replyBackgroundFrame {
|
||||
replyBackgroundNode.frame = replyBackgroundFrame
|
||||
replyBackgroundNode.update(size: replyBackgroundNode.bounds.size, cornerRadius: 8.0, transition: .immediate)
|
||||
}
|
||||
|
||||
if isEmoji && !incoming {
|
||||
if let _ = item.controllerInteraction.selectionState {
|
||||
replyInfoNode.alpha = 0.0
|
||||
strongSelf.replyBackgroundNode?.alpha = 0.0
|
||||
} else {
|
||||
replyInfoNode.alpha = 1.0
|
||||
strongSelf.replyBackgroundNode?.alpha = 1.0
|
||||
}
|
||||
}
|
||||
messageInfoSize = CGSize(width: max(messageInfoSize.width, replyInfoSize.width), height: messageInfoSize.height + replyInfoSize.height)
|
||||
} else if let replyInfoNode = strongSelf.replyInfoNode {
|
||||
replyInfoNode.removeFromSupernode()
|
||||
strongSelf.replyInfoNode = nil
|
||||
}
|
||||
|
||||
|
||||
if let replyBackgroundNode = strongSelf.replyBackgroundNode {
|
||||
replyBackgroundNode.frame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 10.0) : (params.width - params.rightInset - messageInfoSize.width - layoutConstants.bubble.edgeInset - 10.0)) - 4.0, y: 6.0), size: CGSize(width: messageInfoSize.width + 8.0, height: messageInfoSize.height + 5.0))
|
||||
|
||||
let cornerRadius = replyBackgroundNode.frame.height <= 22.0 ? replyBackgroundNode.frame.height / 2.0 : 8.0
|
||||
replyBackgroundNode.update(size: replyBackgroundNode.bounds.size, cornerRadius: cornerRadius, transition: .immediate)
|
||||
}
|
||||
|
||||
let panelsAlpha: CGFloat = item.controllerInteraction.selectionState == nil ? 1.0 : 0.0
|
||||
strongSelf.replyInfoNode?.alpha = panelsAlpha
|
||||
strongSelf.viaBotNode?.alpha = panelsAlpha
|
||||
strongSelf.forwardInfoNode?.alpha = panelsAlpha
|
||||
strongSelf.replyBackgroundNode?.alpha = panelsAlpha
|
||||
|
||||
if isFailed {
|
||||
let deliveryFailedNode: ChatMessageDeliveryFailedNode
|
||||
var isAppearing = false
|
||||
@ -901,61 +936,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
deliveryFailedNode?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
|
||||
if needsForwardBackground {
|
||||
if let forwardBackgroundNode = strongSelf.forwardBackgroundNode {
|
||||
forwardBackgroundNode.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
|
||||
} else {
|
||||
let forwardBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
|
||||
strongSelf.forwardBackgroundNode = forwardBackgroundNode
|
||||
strongSelf.contextSourceNode.contentNode.addSubnode(forwardBackgroundNode)
|
||||
|
||||
if animation.isAnimated {
|
||||
forwardBackgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
} else if let forwardBackgroundNode = strongSelf.forwardBackgroundNode {
|
||||
if animation.isAnimated {
|
||||
strongSelf.forwardBackgroundNode = nil
|
||||
forwardBackgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false, completion: { [weak forwardBackgroundNode] _ in
|
||||
forwardBackgroundNode?.removeFromSupernode()
|
||||
})
|
||||
} else {
|
||||
forwardBackgroundNode.removeFromSupernode()
|
||||
strongSelf.forwardBackgroundNode = nil
|
||||
}
|
||||
}
|
||||
|
||||
if let (forwardInfoSize, forwardInfoApply) = forwardInfoSizeApply {
|
||||
let forwardInfoNode = forwardInfoApply(forwardInfoSize.width)
|
||||
if strongSelf.forwardInfoNode == nil {
|
||||
strongSelf.forwardInfoNode = forwardInfoNode
|
||||
strongSelf.contextSourceNode.contentNode.addSubnode(forwardInfoNode)
|
||||
|
||||
if animation.isAnimated {
|
||||
forwardInfoNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
let forwardInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 12.0) : (params.width - params.rightInset - forwardInfoSize.width - layoutConstants.bubble.edgeInset - 12.0)), y: 8.0), size: forwardInfoSize)
|
||||
forwardInfoNode.frame = forwardInfoFrame
|
||||
if let forwardBackgroundNode = strongSelf.forwardBackgroundNode {
|
||||
forwardBackgroundNode.frame = CGRect(origin: CGPoint(x: forwardInfoFrame.minX - 6.0, y: forwardInfoFrame.minY - 2.0), size: CGSize(width: forwardInfoFrame.size.width + 10.0, height: forwardInfoFrame.size.height + 4.0))
|
||||
forwardBackgroundNode.update(size: forwardBackgroundNode.bounds.size, cornerRadius: 8.0, transition: .immediate)
|
||||
}
|
||||
} else if let forwardInfoNode = strongSelf.forwardInfoNode {
|
||||
if animation.isAnimated {
|
||||
if let forwardInfoNode = strongSelf.forwardInfoNode {
|
||||
strongSelf.forwardInfoNode = nil
|
||||
forwardInfoNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false, completion: { [weak forwardInfoNode] _ in
|
||||
forwardInfoNode?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
} else {
|
||||
forwardInfoNode.removeFromSupernode()
|
||||
strongSelf.forwardInfoNode = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if let actionButtonsSizeAndApply = actionButtonsSizeAndApply {
|
||||
let actionButtonsNode = actionButtonsSizeAndApply.1(animation)
|
||||
let previousFrame = actionButtonsNode.frame
|
||||
@ -1333,12 +1314,18 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
}
|
||||
|
||||
let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.2, curve: .easeInOut) : .immediate
|
||||
let replyAlpha: CGFloat = item.controllerInteraction.selectionState == nil ? 1.0 : 0.0
|
||||
let panelsAlpha: CGFloat = item.controllerInteraction.selectionState == nil ? 1.0 : 0.0
|
||||
if let replyInfoNode = self.replyInfoNode {
|
||||
transition.updateAlpha(node: replyInfoNode, alpha: replyAlpha)
|
||||
transition.updateAlpha(node: replyInfoNode, alpha: panelsAlpha)
|
||||
}
|
||||
if let viaBotNode = self.viaBotNode {
|
||||
transition.updateAlpha(node: viaBotNode, alpha: panelsAlpha)
|
||||
}
|
||||
if let forwardInfoNode = self.forwardInfoNode {
|
||||
transition.updateAlpha(node: forwardInfoNode, alpha: panelsAlpha)
|
||||
}
|
||||
if let replyBackgroundNode = self.replyBackgroundNode {
|
||||
transition.updateAlpha(node: replyBackgroundNode, alpha: replyAlpha)
|
||||
transition.updateAlpha(node: replyBackgroundNode, alpha: panelsAlpha)
|
||||
}
|
||||
|
||||
if let selectionState = item.controllerInteraction.selectionState {
|
||||
|
||||
@ -521,6 +521,62 @@ public final class ChatMessageTransitionNode: ASDisplayNode {
|
||||
}
|
||||
case let .mediaInput(mediaInput):
|
||||
if let snapshotView = mediaInput.extractSnapshot() {
|
||||
Queue.mainQueue().justDispatch {
|
||||
if let itemNode = self.itemNode as? ChatMessageBubbleItemNode {
|
||||
itemNode.cancelInsertionAnimations()
|
||||
|
||||
self.contextSourceNode.isExtractedToContextPreview = true
|
||||
self.contextSourceNode.isExtractedToContextPreviewUpdated?(true)
|
||||
|
||||
self.containerNode.addSubnode(self.contextSourceNode.contentNode)
|
||||
|
||||
let targetAbsoluteRect = self.contextSourceNode.view.convert(self.contextSourceNode.contentRect, to: self.view)
|
||||
let sourceBackgroundAbsoluteRect = snapshotView.frame
|
||||
let sourceAbsoluteRect = CGRect(origin: CGPoint(x: sourceBackgroundAbsoluteRect.midX - self.contextSourceNode.contentRect.size.width / 2.0, y: sourceBackgroundAbsoluteRect.midY - self.contextSourceNode.contentRect.size.height / 2.0), size: self.contextSourceNode.contentRect.size)
|
||||
|
||||
let combinedTransition = CombinedTransition(horizontal: .animated(duration: horizontalDuration, curve: ChatMessageTransitionNode.horizontalAnimationCurve), vertical: .animated(duration: verticalDuration, curve: ChatMessageTransitionNode.verticalAnimationCurve))
|
||||
|
||||
if let itemNode = self.itemNode as? ChatMessageBubbleItemNode {
|
||||
itemNode.animateContentFromMediaInput(snapshotView: snapshotView, transition: combinedTransition)
|
||||
}
|
||||
|
||||
self.containerNode.frame = targetAbsoluteRect.offsetBy(dx: -self.contextSourceNode.contentRect.minX, dy: -self.contextSourceNode.contentRect.minY)
|
||||
|
||||
snapshotView.center = targetAbsoluteRect.center.offsetBy(dx: -self.containerNode.frame.minX, dy: -self.containerNode.frame.minY)
|
||||
self.containerNode.view.addSubview(snapshotView)
|
||||
|
||||
self.contextSourceNode.updateAbsoluteRect?(self.containerNode.frame, UIScreen.main.bounds.size)
|
||||
|
||||
self.containerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: sourceAbsoluteRect.midY - targetAbsoluteRect.midY), to: CGPoint(), duration: horizontalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNode.horizontalAnimationCurve.mediaTimingFunction, additive: true, force: true)
|
||||
self.containerNode.layer.animatePosition(from: CGPoint(x: sourceAbsoluteRect.midX - targetAbsoluteRect.midX, y: 0.0), to: CGPoint(), duration: verticalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNode.verticalAnimationCurve.mediaTimingFunction, additive: true, force: true, completion: { [weak self] _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.endAnimation()
|
||||
})
|
||||
|
||||
combinedTransition.horizontal.animateTransformScale(node: self.contextSourceNode.contentNode, from: CGPoint(x: sourceBackgroundAbsoluteRect.width / targetAbsoluteRect.width, y: sourceBackgroundAbsoluteRect.height / targetAbsoluteRect.height))
|
||||
|
||||
combinedTransition.horizontal.updateTransformScale(layer: snapshotView.layer, scale: CGPoint(x: 1.0 / (sourceBackgroundAbsoluteRect.width / targetAbsoluteRect.width), y: 1.0 / (sourceBackgroundAbsoluteRect.height / targetAbsoluteRect.height)))
|
||||
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.12, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotView?.removeFromSuperview()
|
||||
})
|
||||
|
||||
self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: sourceAbsoluteRect.minX - targetAbsoluteRect.minX, y: 0.0), ChatMessageTransitionNode.horizontalAnimationCurve, horizontalDuration)
|
||||
self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: 0.0, y: sourceAbsoluteRect.maxY - targetAbsoluteRect.maxY), ChatMessageTransitionNode.verticalAnimationCurve, verticalDuration)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.endAnimation()
|
||||
}
|
||||
case let .groupedMediaInput(groupedMediaInput):
|
||||
let snapshotViews = groupedMediaInput.extractSnapshots()
|
||||
if snapshotViews.isEmpty {
|
||||
self.endAnimation()
|
||||
return
|
||||
}
|
||||
Queue.mainQueue().justDispatch {
|
||||
if let itemNode = self.itemNode as? ChatMessageBubbleItemNode {
|
||||
itemNode.cancelInsertionAnimations()
|
||||
|
||||
@ -529,20 +585,43 @@ public final class ChatMessageTransitionNode: ASDisplayNode {
|
||||
|
||||
self.containerNode.addSubnode(self.contextSourceNode.contentNode)
|
||||
|
||||
let targetAbsoluteRect = self.contextSourceNode.view.convert(self.contextSourceNode.contentRect, to: self.view)
|
||||
let sourceBackgroundAbsoluteRect = snapshotView.frame
|
||||
let sourceAbsoluteRect = CGRect(origin: CGPoint(x: sourceBackgroundAbsoluteRect.midX - self.contextSourceNode.contentRect.size.width / 2.0, y: sourceBackgroundAbsoluteRect.midY - self.contextSourceNode.contentRect.size.height / 2.0), size: self.contextSourceNode.contentRect.size)
|
||||
|
||||
let combinedTransition = CombinedTransition(horizontal: .animated(duration: horizontalDuration, curve: ChatMessageTransitionNode.horizontalAnimationCurve), vertical: .animated(duration: verticalDuration, curve: ChatMessageTransitionNode.verticalAnimationCurve))
|
||||
|
||||
var targetContentRects: [CGRect] = []
|
||||
if let itemNode = self.itemNode as? ChatMessageBubbleItemNode {
|
||||
itemNode.animateContentFromMediaInput(snapshotView: snapshotView, transition: combinedTransition)
|
||||
targetContentRects = itemNode.animateContentFromGroupedMediaInput(transition: combinedTransition)
|
||||
}
|
||||
|
||||
let targetAbsoluteRect = self.contextSourceNode.view.convert(self.contextSourceNode.contentRect, to: self.view)
|
||||
|
||||
func boundingRect(for views: [UIView]) -> CGRect {
|
||||
var minX: CGFloat = .greatestFiniteMagnitude
|
||||
var minY: CGFloat = .greatestFiniteMagnitude
|
||||
var maxX: CGFloat = .leastNonzeroMagnitude
|
||||
var maxY: CGFloat = .leastNonzeroMagnitude
|
||||
|
||||
for view in views {
|
||||
let rect = view.frame
|
||||
if rect.minX < minX {
|
||||
minX = rect.minX
|
||||
}
|
||||
if rect.minY < minY {
|
||||
minY = rect.minY
|
||||
}
|
||||
if rect.maxX > maxX {
|
||||
maxX = rect.maxX
|
||||
}
|
||||
if rect.maxY > maxY {
|
||||
maxY = rect.maxY
|
||||
}
|
||||
}
|
||||
return CGRect(origin: CGPoint(x: minX, y: minY), size: CGSize(width: maxX - minX, height: maxY - minY))
|
||||
}
|
||||
|
||||
self.containerNode.frame = targetAbsoluteRect.offsetBy(dx: -self.contextSourceNode.contentRect.minX, dy: -self.contextSourceNode.contentRect.minY)
|
||||
let sourceBackgroundAbsoluteRect = boundingRect(for: snapshotViews)
|
||||
let sourceAbsoluteRect = CGRect(origin: CGPoint(x: sourceBackgroundAbsoluteRect.midX - self.contextSourceNode.contentRect.size.width / 2.0, y: sourceBackgroundAbsoluteRect.midY - self.contextSourceNode.contentRect.size.height / 2.0), size: self.contextSourceNode.contentRect.size)
|
||||
|
||||
snapshotView.center = targetAbsoluteRect.center.offsetBy(dx: -self.containerNode.frame.minX, dy: -self.containerNode.frame.minY)
|
||||
self.containerNode.view.addSubview(snapshotView)
|
||||
self.containerNode.frame = targetAbsoluteRect.offsetBy(dx: -self.contextSourceNode.contentRect.minX, dy: -self.contextSourceNode.contentRect.minY)
|
||||
|
||||
self.contextSourceNode.updateAbsoluteRect?(self.containerNode.frame, UIScreen.main.bounds.size)
|
||||
|
||||
@ -556,101 +635,26 @@ public final class ChatMessageTransitionNode: ASDisplayNode {
|
||||
|
||||
combinedTransition.horizontal.animateTransformScale(node: self.contextSourceNode.contentNode, from: CGPoint(x: sourceBackgroundAbsoluteRect.width / targetAbsoluteRect.width, y: sourceBackgroundAbsoluteRect.height / targetAbsoluteRect.height))
|
||||
|
||||
combinedTransition.horizontal.updateTransformScale(layer: snapshotView.layer, scale: CGPoint(x: 1.0 / (sourceBackgroundAbsoluteRect.width / targetAbsoluteRect.width), y: 1.0 / (sourceBackgroundAbsoluteRect.height / targetAbsoluteRect.height)))
|
||||
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.12, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotView?.removeFromSuperview()
|
||||
})
|
||||
|
||||
var index = 0
|
||||
for snapshotView in snapshotViews {
|
||||
let targetContentRect = targetContentRects[index]
|
||||
let targetAbsoluteContentRect = targetContentRect.offsetBy(dx: targetAbsoluteRect.minX, dy: targetAbsoluteRect.minY)
|
||||
|
||||
snapshotView.center = targetAbsoluteContentRect.center.offsetBy(dx: -self.containerNode.frame.minX, dy: -self.containerNode.frame.minY)
|
||||
self.containerNode.view.addSubview(snapshotView)
|
||||
|
||||
combinedTransition.horizontal.updateTransformScale(layer: snapshotView.layer, scale: CGPoint(x: 1.0 / (snapshotView.frame.width / targetContentRect.width), y: 1.0 / (snapshotView.frame.height / targetContentRect.height)))
|
||||
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.12, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotView?.removeFromSuperview()
|
||||
})
|
||||
|
||||
index += 1
|
||||
}
|
||||
|
||||
self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: sourceAbsoluteRect.minX - targetAbsoluteRect.minX, y: 0.0), ChatMessageTransitionNode.horizontalAnimationCurve, horizontalDuration)
|
||||
self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: 0.0, y: sourceAbsoluteRect.maxY - targetAbsoluteRect.maxY), ChatMessageTransitionNode.verticalAnimationCurve, verticalDuration)
|
||||
}
|
||||
} else {
|
||||
self.endAnimation()
|
||||
}
|
||||
case let .groupedMediaInput(groupedMediaInput):
|
||||
let snapshotViews = groupedMediaInput.extractSnapshots()
|
||||
if snapshotViews.isEmpty {
|
||||
self.endAnimation()
|
||||
return
|
||||
}
|
||||
if let itemNode = self.itemNode as? ChatMessageBubbleItemNode {
|
||||
itemNode.cancelInsertionAnimations()
|
||||
|
||||
self.contextSourceNode.isExtractedToContextPreview = true
|
||||
self.contextSourceNode.isExtractedToContextPreviewUpdated?(true)
|
||||
|
||||
self.containerNode.addSubnode(self.contextSourceNode.contentNode)
|
||||
|
||||
let combinedTransition = CombinedTransition(horizontal: .animated(duration: horizontalDuration, curve: ChatMessageTransitionNode.horizontalAnimationCurve), vertical: .animated(duration: verticalDuration, curve: ChatMessageTransitionNode.verticalAnimationCurve))
|
||||
|
||||
var targetContentRects: [CGRect] = []
|
||||
if let itemNode = self.itemNode as? ChatMessageBubbleItemNode {
|
||||
targetContentRects = itemNode.animateContentFromGroupedMediaInput(transition: combinedTransition)
|
||||
}
|
||||
|
||||
let targetAbsoluteRect = self.contextSourceNode.view.convert(self.contextSourceNode.contentRect, to: self.view)
|
||||
|
||||
func boundingRect(for views: [UIView]) -> CGRect {
|
||||
var minX: CGFloat = .greatestFiniteMagnitude
|
||||
var minY: CGFloat = .greatestFiniteMagnitude
|
||||
var maxX: CGFloat = .leastNonzeroMagnitude
|
||||
var maxY: CGFloat = .leastNonzeroMagnitude
|
||||
|
||||
for view in views {
|
||||
let rect = view.frame
|
||||
if rect.minX < minX {
|
||||
minX = rect.minX
|
||||
}
|
||||
if rect.minY < minY {
|
||||
minY = rect.minY
|
||||
}
|
||||
if rect.maxX > maxX {
|
||||
maxX = rect.maxX
|
||||
}
|
||||
if rect.maxY > maxY {
|
||||
maxY = rect.maxY
|
||||
}
|
||||
}
|
||||
return CGRect(origin: CGPoint(x: minX, y: minY), size: CGSize(width: maxX - minX, height: maxY - minY))
|
||||
}
|
||||
|
||||
let sourceBackgroundAbsoluteRect = boundingRect(for: snapshotViews)
|
||||
let sourceAbsoluteRect = CGRect(origin: CGPoint(x: sourceBackgroundAbsoluteRect.midX - self.contextSourceNode.contentRect.size.width / 2.0, y: sourceBackgroundAbsoluteRect.midY - self.contextSourceNode.contentRect.size.height / 2.0), size: self.contextSourceNode.contentRect.size)
|
||||
|
||||
self.containerNode.frame = targetAbsoluteRect.offsetBy(dx: -self.contextSourceNode.contentRect.minX, dy: -self.contextSourceNode.contentRect.minY)
|
||||
|
||||
self.contextSourceNode.updateAbsoluteRect?(self.containerNode.frame, UIScreen.main.bounds.size)
|
||||
|
||||
self.containerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: sourceAbsoluteRect.midY - targetAbsoluteRect.midY), to: CGPoint(), duration: horizontalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNode.horizontalAnimationCurve.mediaTimingFunction, additive: true, force: true)
|
||||
self.containerNode.layer.animatePosition(from: CGPoint(x: sourceAbsoluteRect.midX - targetAbsoluteRect.midX, y: 0.0), to: CGPoint(), duration: verticalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNode.verticalAnimationCurve.mediaTimingFunction, additive: true, force: true, completion: { [weak self] _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.endAnimation()
|
||||
})
|
||||
|
||||
combinedTransition.horizontal.animateTransformScale(node: self.contextSourceNode.contentNode, from: CGPoint(x: sourceBackgroundAbsoluteRect.width / targetAbsoluteRect.width, y: sourceBackgroundAbsoluteRect.height / targetAbsoluteRect.height))
|
||||
|
||||
var index = 0
|
||||
for snapshotView in snapshotViews {
|
||||
let targetContentRect = targetContentRects[index]
|
||||
let targetAbsoluteContentRect = targetContentRect.offsetBy(dx: targetAbsoluteRect.minX, dy: targetAbsoluteRect.minY)
|
||||
|
||||
snapshotView.center = targetAbsoluteContentRect.center.offsetBy(dx: -self.containerNode.frame.minX, dy: -self.containerNode.frame.minY)
|
||||
self.containerNode.view.addSubview(snapshotView)
|
||||
|
||||
combinedTransition.horizontal.updateTransformScale(layer: snapshotView.layer, scale: CGPoint(x: 1.0 / (snapshotView.frame.width / targetContentRect.width), y: 1.0 / (snapshotView.frame.height / targetContentRect.height)))
|
||||
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.12, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotView?.removeFromSuperview()
|
||||
})
|
||||
|
||||
index += 1
|
||||
}
|
||||
|
||||
self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: sourceAbsoluteRect.minX - targetAbsoluteRect.minX, y: 0.0), ChatMessageTransitionNode.horizontalAnimationCurve, horizontalDuration)
|
||||
self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: 0.0, y: sourceAbsoluteRect.maxY - targetAbsoluteRect.maxY), ChatMessageTransitionNode.verticalAnimationCurve, verticalDuration)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ import ShareController
|
||||
import LegacyUI
|
||||
import LegacyMediaPickerUI
|
||||
|
||||
func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: ChatLocation, cameraView: TGAttachmentCameraView?, menuController: TGMenuSheetController?, parentController: ViewController, attachmentController: ViewController? = nil, editingMedia: Bool, saveCapturedPhotos: Bool, mediaGrouping: Bool, initialCaption: String, hasSchedule: Bool, photoOnly: Bool, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, recognizedQRCode: @escaping (String) -> Void = { _ in }, presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, dismissedWithResult: @escaping () -> Void = {}, finishedTransitionIn: @escaping () -> Void = {}) {
|
||||
func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: ChatLocation, cameraView: TGAttachmentCameraView?, menuController: TGMenuSheetController?, parentController: ViewController, attachmentController: ViewController? = nil, editingMedia: Bool, saveCapturedPhotos: Bool, mediaGrouping: Bool, initialCaption: NSAttributedString, hasSchedule: Bool, photoOnly: Bool, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, recognizedQRCode: @escaping (String) -> Void = { _ in }, presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, dismissedWithResult: @escaping () -> Void = {}, finishedTransitionIn: @escaping () -> Void = {}) {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme)
|
||||
legacyController.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .portrait, compactSize: .portrait)
|
||||
@ -28,6 +28,10 @@ func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: Ch
|
||||
}
|
||||
controller.inhibitMultipleCapture = editingMedia
|
||||
|
||||
if !initialCaption.string.isEmpty {
|
||||
controller.forcedCaption = initialCaption
|
||||
}
|
||||
|
||||
controller.presentScheduleController = { _, done in
|
||||
presentSchedulePicker(true, { time in
|
||||
done?(time)
|
||||
|
||||
@ -251,20 +251,56 @@ public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEnti
|
||||
break
|
||||
}
|
||||
|
||||
var addedAttributes: [(NSRange, ChatTextFontAttributes)] = []
|
||||
func addFont(ranges: [NSRange], fontAttributes: ChatTextFontAttributes) {
|
||||
for range in ranges {
|
||||
var font: UIFont?
|
||||
if fontAttributes == [.bold, .italic] {
|
||||
font = boldItalicFont
|
||||
} else if fontAttributes == [.bold] {
|
||||
font = boldFont
|
||||
addedAttributes.append((range, fontAttributes))
|
||||
} else if fontAttributes == [.italic] {
|
||||
font = italicFont
|
||||
addedAttributes.append((range, fontAttributes))
|
||||
}
|
||||
if let font = font {
|
||||
string.addAttribute(NSAttributedString.Key.font, value: font, range: range)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (range, fontAttributes) in fontAttributes {
|
||||
var font: UIFont?
|
||||
if fontAttributes.contains(.blockQuote) {
|
||||
font = blockQuoteFont
|
||||
} else if fontAttributes == [.bold, .italic] {
|
||||
font = boldItalicFont
|
||||
} else if fontAttributes == [.bold] {
|
||||
font = boldFont
|
||||
} else if fontAttributes == [.italic] {
|
||||
font = italicFont
|
||||
}
|
||||
if let font = font {
|
||||
string.addAttribute(NSAttributedString.Key.font, value: font, range: range)
|
||||
var ranges = [range]
|
||||
var fontAttributes = fontAttributes
|
||||
if fontAttributes != [.bold, .italic] {
|
||||
for (existingRange, existingAttributes) in addedAttributes {
|
||||
if let intersection = existingRange.intersection(range) {
|
||||
if intersection.length == range.length {
|
||||
if existingAttributes == .bold || existingAttributes == .italic {
|
||||
fontAttributes.insert(existingAttributes)
|
||||
}
|
||||
} else {
|
||||
var fontAttributes = fontAttributes
|
||||
if existingAttributes == .bold || existingAttributes == .italic {
|
||||
fontAttributes.insert(existingAttributes)
|
||||
}
|
||||
addFont(ranges: [intersection], fontAttributes: fontAttributes)
|
||||
|
||||
ranges = []
|
||||
if range.upperBound > existingRange.lowerBound {
|
||||
ranges.append(NSRange(location: range.lowerBound, length: existingRange.lowerBound - range.lowerBound))
|
||||
}
|
||||
if range.upperBound > existingRange.upperBound {
|
||||
ranges.append(NSRange(location: existingRange.upperBound, length: range.upperBound - existingRange.upperBound))
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addFont(ranges: ranges, fontAttributes: fontAttributes)
|
||||
}
|
||||
}
|
||||
return string
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user