diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 75fb799b54..c6e9ae24b3 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -16199,3 +16199,8 @@ Error: %8$@"; "Chat.Poll.Restriction.Country.CountriesLastDelimiter" = " and "; "Conversation.MessageGuestChatForUser" = "for %@"; + +"Settings.About.PrivacyHelpEmpty" = "A few words about you."; +"Settings.About.PrivacyHelpEveryone" = "Everyone can see your bio. [Change >]()"; +"Settings.About.PrivacyHelpContacts" = "Only uour contacts can see your bio. [Change >]()"; +"Settings.About.PrivacyHelpNobody" = "Nobody can see your bio. [Change >]()"; diff --git a/submodules/AttachmentUI/Sources/AttachmentContainer.swift b/submodules/AttachmentUI/Sources/AttachmentContainer.swift index 88fd1b7b67..25d2bf0d7d 100644 --- a/submodules/AttachmentUI/Sources/AttachmentContainer.swift +++ b/submodules/AttachmentUI/Sources/AttachmentContainer.swift @@ -479,7 +479,9 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate { if self.isDismissed { return } - self.bottomClipNode.cornerRadius = layout.deviceMetrics.screenCornerRadius - 2.0 + + let containerCornerRadius = max(24.0, layout.deviceMetrics.screenCornerRadius) + self.bottomClipNode.cornerRadius = containerCornerRadius - 2.0 self.isUpdatingState = true diff --git a/submodules/AttachmentUI/Sources/AttachmentController.swift b/submodules/AttachmentUI/Sources/AttachmentController.swift index a7d9cc47c0..b7297c4666 100644 --- a/submodules/AttachmentUI/Sources/AttachmentController.swift +++ b/submodules/AttachmentUI/Sources/AttachmentController.swift @@ -1174,7 +1174,8 @@ public class AttachmentController: ViewController, MinimizableController { localGlassView.contentView.addSubview(buttonIcon) ComponentTransition(buttonTransition).animateBlur(layer: buttonIcon.layer, fromRadius: 0.0, toRadius: 10.0) - containerView.update(bounds: CGRect(origin: .zero, size: targetFrame.size), topCornerRadius: 38.0, bottomCornerRadius: layout.deviceMetrics.screenCornerRadius - 2.0, boundsTransition: scaleTransition, cornersTransition: cornersTransition) + let containerCornerRadius = max(24.0, layout.deviceMetrics.screenCornerRadius) + containerView.update(bounds: CGRect(origin: .zero, size: targetFrame.size), topCornerRadius: 38.0, bottomCornerRadius: containerCornerRadius - 2.0, boundsTransition: scaleTransition, cornersTransition: cornersTransition) scaleTransition.animateBounds(layer: containerView.layer, from: CGRect(origin: .zero, size: CGSize(width: targetFrame.width, height: targetFrame.width))) scaleTransition.animateTransformScale(view: containerView, from: sourceButtonScale) positionTransition.animatePosition(layer: containerView.layer, from: sourceButtonFrame.center, to: containerView.center, completion: { _ in @@ -1242,7 +1243,9 @@ public class AttachmentController: ViewController, MinimizableController { if let sourceGlassView = findParentGlassBackgroundView(attachmentButton), let glassParams = sourceGlassView.params { let containerView = ClipContainerView() containerView.frame = initialFrame - containerView.update(bounds: CGRect(origin: .zero, size: initialFrame.size), topCornerRadius: 38.0, bottomCornerRadius: layout.deviceMetrics.screenCornerRadius - 2.0, boundsTransition: .immediate, cornersTransition: .immediate) + + let containerCornerRadius = max(24.0, layout.deviceMetrics.screenCornerRadius) + containerView.update(bounds: CGRect(origin: .zero, size: initialFrame.size), topCornerRadius: 38.0, bottomCornerRadius: containerCornerRadius - 2.0, boundsTransition: .immediate, cornersTransition: .immediate) self.view.addSubview(containerView) let localGlassView = GlassBackgroundView() diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 3ce4e72602..6e2cbd0c81 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -7287,7 +7287,7 @@ private final class ChatListLocationContext { dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, displayBackground: false, - content: .peer(peerView: ChatTitleContent.PeerData(peerView: peerView), customTitle: nil, customSubtitle: nil, onlineMemberCount: onlineMemberCount, isScheduledMessages: false, isMuted: nil, customMessageCount: nil, isEnabled: true), + content: .peer(peerView: ChatTitleContent.PeerData(peerView: peerView), customTitle: nil, customSubtitle: nil, onlineMemberCount: onlineMemberCount, isScheduledMessages: false, isMuted: nil, customMessageCount: nil, hidePeerStatus: false, isEnabled: true), activities: nil, networkState: nil, tapped: { [weak self] in diff --git a/submodules/ChatListUI/Sources/ChatListControllerNode.swift b/submodules/ChatListUI/Sources/ChatListControllerNode.swift index 8281e29585..a036e41e04 100644 --- a/submodules/ChatListUI/Sources/ChatListControllerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListControllerNode.swift @@ -1986,6 +1986,9 @@ final class ChatListControllerNode: ASDisplayNode, ASGestureRecognizerDelegate { contentNode.dismissSearch = { [weak self] in self?.dismissSearch?() } + contentNode.dismissSearchImmediately = { [weak self] in + self?.controller?.deactivateSearch(animated: false) + } contentNode.openAdInfo = { [weak self] node, adPeer in self?.controller?.openAdInfo(node: node, adPeer: adPeer) } diff --git a/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift b/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift index aef3f58aa0..3cdf4f11b5 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift @@ -110,6 +110,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo private let navigationController: NavigationController? var dismissSearch: (() -> Void)? + var dismissSearchImmediately: (() -> Void)? var openAdInfo: ((ASDisplayNode, AdPeer) -> Void)? private let edgeEffectView: EdgeEffectView @@ -1657,7 +1658,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo if let strongSelf = self { let proceed: (ChatController) -> Void = { chatController in chatController.purposefulAction = { [weak self] in - self?.cancel?() + self?.dismissSearchImmediately?() } if let navigationController = strongSelf.navigationController { var viewControllers = navigationController.viewControllers diff --git a/submodules/Components/ResizableSheetComponent/Sources/ResizableSheetComponent.swift b/submodules/Components/ResizableSheetComponent/Sources/ResizableSheetComponent.swift index 852881033d..d5623abed6 100644 --- a/submodules/Components/ResizableSheetComponent/Sources/ResizableSheetComponent.swift +++ b/submodules/Components/ResizableSheetComponent/Sources/ResizableSheetComponent.swift @@ -792,9 +792,10 @@ public final class ResizableSheetComponent: C if availableSize.width < availableSize.height { glassInset = 6.0 } - bottomCornerRadius = sheetEnvironment.deviceMetrics.screenCornerRadius - glassInset + let containerCornerRadius = max(24.0, sheetEnvironment.deviceMetrics.screenCornerRadius) + bottomCornerRadius = containerCornerRadius - 2.0 case .legacy: topCornerRadius = 12.0 bottomCornerRadius = 12.0 diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoVideoEditor.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoVideoEditor.h index ef21ecd0b6..97fa637d8d 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoVideoEditor.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoVideoEditor.h @@ -7,12 +7,20 @@ #import #import +@class TGModernGalleryController; + +typedef void (^ _Nonnull TGPhotoVideoEditorSchedulePickerCompletion)(int32_t time); +typedef void (^ _Nonnull TGPhotoVideoEditorSchedulePicker)(bool media, TGPhotoVideoEditorSchedulePickerCompletion _Nonnull done); +typedef void (^ _Nonnull TGPhotoVideoEditorCompletion)(id _Nonnull item, TGMediaEditingContext * _Nonnull editingContext, bool silentPosting, int32_t scheduleTime); + @interface TGPhotoVideoEditor : NSObject -+ (void)presentWithContext:(id)context parentController:(TGViewController *)parentController image:(UIImage *)image video:(NSURL *)video stickersContext:(id)stickersContext transitionView:(UIView *)transitionView senderName:(NSString *)senderName didFinishWithImage:(void (^)(UIImage *image))didFinishWithImage didFinishWithVideo:(void (^)(UIImage *image, NSURL *url, TGVideoEditAdjustments *adjustments))didFinishWithVideo dismissed:(void (^)(void))dismissed; ++ (void)presentWithContext:(id _Nonnull)context parentController:(TGViewController * _Nonnull)parentController image:(UIImage * _Nullable)image video:(NSURL * _Nullable)video stickersContext:(id _Nullable)stickersContext transitionView:(UIView * _Nullable)transitionView senderName:(NSString * _Nullable)senderName didFinishWithImage:(void (^ _Nullable)(UIImage * _Nonnull image))didFinishWithImage didFinishWithVideo:(void (^ _Nullable)(UIImage * _Nonnull image, NSURL * _Nonnull url, TGVideoEditAdjustments * _Nullable adjustments))didFinishWithVideo dismissed:(void (^ _Nonnull)(void))dismissed; -+ (void)presentWithContext:(id)context controller:(TGViewController *)controller caption:(NSAttributedString *)caption withItem:(id)item paint:(bool)paint adjustments:(bool)adjustments recipientName:(NSString *)recipientName stickersContext:(id)stickersContext fromRect:(CGRect)fromRect mainSnapshot:(UIView *)mainSnapshot snapshots:(NSArray *)snapshots immediate:(bool)immediate activateInput:(bool)activateInput isGif:(bool)isGif appeared:(void (^)(void))appeared completion:(void (^)(id, TGMediaEditingContext *))completion dismissed:(void (^)())dismissed; ++ (TGModernGalleryController * _Nonnull)controllerWithContext:(id _Nonnull)context caption:(NSAttributedString * _Nonnull)caption withItem:(id _Nonnull)item paint:(bool)paint adjustments:(bool)adjustments recipientName:(NSString * _Nonnull)recipientName stickersContext:(id _Nullable)stickersContext fromRect:(CGRect)fromRect mainSnapshot:(UIView * _Nullable)mainSnapshot snapshots:(NSArray * _Nonnull)snapshots immediate:(bool)immediate activateInput:(bool)activateInput isGif:(bool)isGif hasSilentPosting:(bool)hasSilentPosting hasSchedule:(bool)hasSchedule reminder:(bool)reminder presentSchedulePicker:(TGPhotoVideoEditorSchedulePicker _Nonnull)presentSchedulePicker appeared:(void (^ _Nonnull)(void))appeared completion:(TGPhotoVideoEditorCompletion _Nonnull)completion dismissed:(void (^ _Nonnull)(void))dismissed; -+ (void)presentEditorWithContext:(id)context controller:(TGViewController *)controller withItem:(id)item cropRect:(CGRect)cropRect adjustments:(id)adjustments referenceView:(UIView *)referenceView completion:(void (^)(UIImage *, id))completion fullSizeCompletion:(void (^)(UIImage *))fullSizeCompletion beginTransitionOut:(void (^)(bool))beginTransitionOut finishTransitionOut:(void (^)())finishTransitionOut; ++ (void)presentWithContext:(id _Nonnull)context controller:(TGViewController * _Nonnull)controller caption:(NSAttributedString * _Nonnull)caption withItem:(id _Nonnull)item paint:(bool)paint adjustments:(bool)adjustments recipientName:(NSString * _Nonnull)recipientName stickersContext:(id _Nullable)stickersContext fromRect:(CGRect)fromRect mainSnapshot:(UIView * _Nullable)mainSnapshot snapshots:(NSArray * _Nonnull)snapshots immediate:(bool)immediate activateInput:(bool)activateInput isGif:(bool)isGif hasSilentPosting:(bool)hasSilentPosting hasSchedule:(bool)hasSchedule reminder:(bool)reminder presentSchedulePicker:(TGPhotoVideoEditorSchedulePicker _Nonnull)presentSchedulePicker appeared:(void (^ _Nonnull)(void))appeared completion:(TGPhotoVideoEditorCompletion _Nonnull)completion dismissed:(void (^ _Nonnull)(void))dismissed; + ++ (void)presentEditorWithContext:(id _Nonnull)context controller:(TGViewController * _Nonnull)controller withItem:(id _Nonnull)item cropRect:(CGRect)cropRect adjustments:(id _Nullable)adjustments referenceView:(UIView * _Nonnull)referenceView completion:(void (^ _Nonnull)(UIImage * _Nonnull image, id _Nullable adjustments))completion fullSizeCompletion:(void (^ _Nonnull)(UIImage * _Nonnull image))fullSizeCompletion beginTransitionOut:(void (^ _Nullable)(bool saving))beginTransitionOut finishTransitionOut:(void (^ _Nullable)(void))finishTransitionOut; @end diff --git a/submodules/LegacyComponents/Sources/TGPhotoVideoEditor.m b/submodules/LegacyComponents/Sources/TGPhotoVideoEditor.m index 4f81c2f1fe..5ebd25410c 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoVideoEditor.m +++ b/submodules/LegacyComponents/Sources/TGPhotoVideoEditor.m @@ -5,6 +5,7 @@ #import #import +#import #import #import @@ -156,21 +157,18 @@ } } -+ (void)presentWithContext:(id)context controller:(TGViewController *)controller caption:(NSAttributedString *)caption withItem:(id)item paint:(bool)paint adjustments:(bool)adjustments recipientName:(NSString *)recipientName stickersContext:(id)stickersContext fromRect:(CGRect)fromRect mainSnapshot:(UIView *)mainSnapshot snapshots:(NSArray *)snapshots immediate:(bool)immediate activateInput:(bool)activateInput isGif:(bool)isGif appeared:(void (^)(void))appeared completion:(void (^)(id, TGMediaEditingContext *))completion dismissed:(void (^)())dismissed ++ (TGModernGalleryController *)_configuredControllerWithContext:(id _Nonnull)context caption:(NSAttributedString * _Nonnull)caption withItem:(id _Nonnull)item paint:(bool)paint adjustments:(bool)adjustments recipientName:(NSString * _Nonnull)recipientName stickersContext:(id _Nullable)stickersContext fromRect:(CGRect)fromRect mainSnapshot:(UIView * _Nullable)__unused mainSnapshot snapshots:(NSArray * _Nonnull)snapshots immediate:(bool)immediate activateInput:(bool)activateInput isGif:(bool)isGif hasSilentPosting:(bool)hasSilentPosting hasSchedule:(bool)hasSchedule reminder:(bool)reminder presentSchedulePicker:(TGPhotoVideoEditorSchedulePicker _Nonnull)presentSchedulePicker appeared:(void (^ _Nonnull)(void))appeared completion:(TGPhotoVideoEditorCompletion _Nonnull)completion completedDismiss:(void (^ _Nullable)(void))completedDismiss customDismiss:(void (^ _Nullable)(void))customDismiss { - id windowManager = [context makeOverlayWindowManager]; - id windowContext = [windowManager context]; - TGMediaEditingContext *editingContext = [[TGMediaEditingContext alloc] init]; [editingContext setForcedCaption:caption]; - TGModernGalleryController *galleryController = [[TGModernGalleryController alloc] initWithContext:windowContext]; + TGModernGalleryController *galleryController = [[TGModernGalleryController alloc] initWithContext:context]; galleryController.adjustsStatusBarVisibility = true; galleryController.animateTransition = !immediate; galleryController.finishedTransitionIn = ^(id item, TGModernGalleryItemView *itemView) { appeared(); }; - //galleryController.hasFadeOutTransition = true; + galleryController.customDismissBlock = customDismiss; id galleryItem = nil; if (item.isVideo) { @@ -181,7 +179,7 @@ galleryItem.editingContext = editingContext; galleryItem.stickersContext = stickersContext; - TGMediaPickerGalleryModel *model = [[TGMediaPickerGalleryModel alloc] initWithContext:windowContext items:@[galleryItem] focusItem:galleryItem selectionContext:nil editingContext:editingContext hasCaptions:true allowCaptionEntities:true hasTimer:false onlyCrop:false inhibitDocumentCaptions:false hasSelectionPanel:false hasCamera:false recipientName:recipientName isScheduledMessages:false hasCoverButton:false]; + TGMediaPickerGalleryModel *model = [[TGMediaPickerGalleryModel alloc] initWithContext:context items:@[galleryItem] focusItem:galleryItem selectionContext:nil editingContext:editingContext hasCaptions:true allowCaptionEntities:true hasTimer:false onlyCrop:false inhibitDocumentCaptions:false hasSelectionPanel:false hasCamera:false recipientName:recipientName isScheduledMessages:false hasCoverButton:false]; model.controller = galleryController; model.stickersContext = stickersContext; @@ -213,6 +211,7 @@ galleryController.model = model; __weak TGModernGalleryController *weakGalleryController = galleryController; + __weak TGMediaPickerGalleryModel *weakModel = model; [model.interfaceView updateSelectionInterface:1 counterVisible:false animated:false]; model.interfaceView.thumbnailSignalForItem = ^SSignal *(id item) @@ -233,10 +232,62 @@ } if (completion != nil) - completion(item.asset, editingContext); + completion(item.asset, editingContext, false, 0); [strongController dismissWhenReadyAnimated:true]; }; + model.interfaceView.doneLongPressed = ^(TGMediaPickerGalleryItem *item) + { + __strong TGModernGalleryController *strongController = weakGalleryController; + __strong TGMediaPickerGalleryModel *strongModel = weakModel; + if (strongController == nil || strongModel == nil || !(hasSilentPosting || hasSchedule)) + return; + + if (iosMajorVersion() >= 10) { + UIImpactFeedbackGenerator *generator = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleMedium]; + [generator impactOccurred]; + } + + TGMediaPickerSendActionSheetController *sendController = [[TGMediaPickerSendActionSheetController alloc] initWithContext:context isDark:true sendButtonFrame:strongModel.interfaceView.doneButtonFrame canSendSilently:hasSilentPosting canSendWhenOnline:hasSchedule canSchedule:hasSchedule reminder:reminder hasTimer:false]; + sendController.modalPresentationStyle = UIModalPresentationOverFullScreen; + sendController.customDismissBlock = ^{ + __strong TGModernGalleryController *strongController = weakGalleryController; + [strongController dismissViewControllerAnimated:false completion:nil]; + }; + void (^complete)(bool, int32_t) = ^(bool silentPosting, int32_t scheduleTime) + { + __strong TGModernGalleryController *strongController = weakGalleryController; + if (strongController == nil) + return; + + if ([item isKindOfClass:[TGMediaPickerGalleryVideoItem class]]) + { + TGMediaPickerGalleryVideoItemView *itemView = (TGMediaPickerGalleryVideoItemView *)[strongController itemViewForItem:item]; + [itemView stop]; + [itemView setPlayButtonHidden:true animated:true]; + } + + if (completion != nil) + completion(item.asset, editingContext, silentPosting, scheduleTime); + + [strongController dismissWhenReadyAnimated:true]; + }; + sendController.send = ^{ + complete(false, 0); + }; + sendController.sendSilently = ^{ + complete(true, 0); + }; + sendController.sendWhenOnline = ^{ + complete(false, 0x7ffffffe); + }; + sendController.schedule = ^{ + presentSchedulePicker(true, ^(int32_t time) { + complete(false, time); + }); + }; + [strongController presentViewController:sendController animated:false completion:nil]; + }; galleryController.beginTransitionIn = ^UIView *(__unused TGMediaPickerGalleryItem *item, __unused TGModernGalleryItemView *itemView) { @@ -247,21 +298,12 @@ { return nil; }; - - galleryController.completedTransitionOut = ^ - { - TGModernGalleryController *strongGalleryController = weakGalleryController; - if (strongGalleryController != nil && strongGalleryController.overlayWindow == nil) + if (completedDismiss != nil) { + galleryController.completedTransitionOut = ^ { - TGNavigationController *navigationController = (TGNavigationController *)strongGalleryController.navigationController; - TGOverlayControllerWindow *window = (TGOverlayControllerWindow *)navigationController.view.window; - if ([window isKindOfClass:[TGOverlayControllerWindow class]]) - [window dismiss]; - } - if (dismissed) { - dismissed(); - } - }; + completedDismiss(); + }; + } if (paint || adjustments) { [model.interfaceView immediateEditorTransitionIn]; @@ -271,8 +313,6 @@ [galleryController.view addSubview:view]; } - TGOverlayControllerWindow *controllerWindow = [[TGOverlayControllerWindow alloc] initWithManager:windowManager parentController:controller contentController:galleryController]; - controllerWindow.hidden = false; galleryController.view.clipsToBounds = true; if (isGif) { @@ -292,9 +332,33 @@ [model beginEditingCaption]; }); } + + return galleryController; } -+ (void)presentEditorWithContext:(id)context controller:(TGViewController *)controller withItem:(id)item cropRect:(CGRect)cropRect adjustments:(id)adjustments referenceView:(UIView *)referenceView completion:(void (^)(UIImage *, id))completion fullSizeCompletion:(void (^)(UIImage *))fullSizeCompletion beginTransitionOut:(void (^)(bool))beginTransitionOut finishTransitionOut:(void (^)())finishTransitionOut; ++ (TGModernGalleryController * _Nonnull)controllerWithContext:(id _Nonnull)context caption:(NSAttributedString * _Nonnull)caption withItem:(id _Nonnull)item paint:(bool)paint adjustments:(bool)adjustments recipientName:(NSString * _Nonnull)recipientName stickersContext:(id _Nullable)stickersContext fromRect:(CGRect)fromRect mainSnapshot:(UIView * _Nullable)mainSnapshot snapshots:(NSArray * _Nonnull)snapshots immediate:(bool)immediate activateInput:(bool)activateInput isGif:(bool)isGif hasSilentPosting:(bool)hasSilentPosting hasSchedule:(bool)hasSchedule reminder:(bool)reminder presentSchedulePicker:(TGPhotoVideoEditorSchedulePicker _Nonnull)presentSchedulePicker appeared:(void (^ _Nonnull)(void))appeared completion:(TGPhotoVideoEditorCompletion _Nonnull)completion dismissed:(void (^ _Nonnull)(void))dismissed +{ + TGModernGalleryController *galleryController = [self _configuredControllerWithContext:context caption:caption withItem:item paint:paint adjustments:adjustments recipientName:recipientName stickersContext:stickersContext fromRect:fromRect mainSnapshot:mainSnapshot snapshots:snapshots immediate:immediate activateInput:activateInput isGif:isGif hasSilentPosting:hasSilentPosting hasSchedule:hasSchedule reminder:reminder presentSchedulePicker:presentSchedulePicker appeared:appeared completion:completion completedDismiss:dismissed customDismiss:nil]; + galleryController.asyncTransitionIn = true; + return galleryController; +} + ++ (void)presentWithContext:(id _Nonnull)context controller:(TGViewController * _Nonnull)controller caption:(NSAttributedString * _Nonnull)caption withItem:(id _Nonnull)item paint:(bool)paint adjustments:(bool)adjustments recipientName:(NSString * _Nonnull)recipientName stickersContext:(id _Nullable)stickersContext fromRect:(CGRect)fromRect mainSnapshot:(UIView * _Nullable)mainSnapshot snapshots:(NSArray * _Nonnull)snapshots immediate:(bool)immediate activateInput:(bool)activateInput isGif:(bool)isGif hasSilentPosting:(bool)hasSilentPosting hasSchedule:(bool)hasSchedule reminder:(bool)reminder presentSchedulePicker:(TGPhotoVideoEditorSchedulePicker _Nonnull)presentSchedulePicker appeared:(void (^ _Nonnull)(void))appeared completion:(TGPhotoVideoEditorCompletion _Nonnull)completion dismissed:(void (^ _Nonnull)(void))dismissed +{ + __weak TGViewController *weakController = controller; + TGModernGalleryController *galleryController = [self _configuredControllerWithContext:context caption:caption withItem:item paint:paint adjustments:adjustments recipientName:recipientName stickersContext:stickersContext fromRect:fromRect mainSnapshot:mainSnapshot snapshots:snapshots immediate:immediate activateInput:activateInput isGif:isGif hasSilentPosting:hasSilentPosting hasSchedule:hasSchedule reminder:reminder presentSchedulePicker:presentSchedulePicker appeared:appeared completion:completion completedDismiss:nil customDismiss:^{ + __strong TGViewController *strongController = weakController; + [strongController dismissViewControllerAnimated:false completion:^{ + if (dismissed) { + dismissed(); + } + }]; + }]; + galleryController.modalPresentationStyle = UIModalPresentationFullScreen; + [controller presentViewController:galleryController animated:false completion:nil]; +} + ++ (void)presentEditorWithContext:(id _Nonnull)context controller:(TGViewController * _Nonnull)controller withItem:(id _Nonnull)item cropRect:(CGRect)cropRect adjustments:(id _Nullable)adjustments referenceView:(UIView * _Nonnull)referenceView completion:(void (^ _Nonnull)(UIImage * _Nonnull image, id _Nullable adjustments))completion fullSizeCompletion:(void (^ _Nonnull)(UIImage * _Nonnull image))fullSizeCompletion beginTransitionOut:(void (^ _Nullable)(bool saving))beginTransitionOut finishTransitionOut:(void (^ _Nullable)(void))finishTransitionOut { id windowManager = [context makeOverlayWindowManager]; diff --git a/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift b/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift index acc28dacf4..fe4a830aed 100644 --- a/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift +++ b/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift @@ -131,12 +131,12 @@ public func legacyStoryMediaEditor(context: AccountContext, item: TGMediaEditabl present(legacyController, nil) - TGPhotoVideoEditor.present(with: legacyController.context, controller: emptyController, caption: NSAttributedString(), withItem: item, paint: false, adjustments: false, recipientName: "", stickersContext: paintStickersContext, from: .zero, mainSnapshot: nil, snapshots: [] as [Any], immediate: true, activateInput: false, isGif: false, appeared: { + TGPhotoVideoEditor.present(with: legacyController.context, controller: emptyController, caption: NSAttributedString(), withItem: item, paint: false, adjustments: false, recipientName: "", stickersContext: paintStickersContext, from: .zero, mainSnapshot: nil, snapshots: [] as [Any], immediate: true, activateInput: false, isGif: false, hasSilentPosting: false, hasSchedule: false, reminder: false, presentSchedulePicker: { _, _ in }, appeared: { - }, completion: { result, editingContext in + }, completion: { result, editingContext, _, _ in var completionResult: Signal if let photo = result as? TGCameraCapturedPhoto { - if let _ = editingContext?.adjustments(for: result) { + if let _ = editingContext.adjustments(for: result) { completionResult = .single(.image(photo.existingImage)) } else { completionResult = .single(.image(photo.existingImage)) @@ -167,6 +167,10 @@ public func legacyMediaEditor( snapshots: [UIView], transitionCompletion: (() -> Void)?, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, + hasSilentPosting: Bool = false, + hasSchedule: Bool = false, + reminder: Bool = false, + presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void = { _, _ in }, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32, Bool) -> Void, present: @escaping (ViewController, Any?) -> Void ) { @@ -209,32 +213,87 @@ public func legacyMediaEditor( legacyController?.view.disablesInteractiveTransitionGestureRecognizer = true } - let emptyController = LegacyEmptyController(context: legacyController.context)! - emptyController.navigationBarShouldBeHidden = true - let navigationController = makeLegacyNavigationController(rootController: emptyController) - navigationController.setNavigationBarHidden(true, animated: false) - legacyController.bind(controller: navigationController) - - legacyController.enableSizeClassSignal = true - - present(legacyController, nil) - - TGPhotoVideoEditor.present(with: legacyController.context, controller: emptyController, caption: initialCaption, withItem: item, paint: mode == .draw, adjustments: mode == .adjustments, recipientName: recipientName, stickersContext: paintStickersContext, from: .zero, mainSnapshot: nil, snapshots: snapshots as [Any], immediate: transitionCompletion != nil, activateInput: mode == .caption, isGif: isGif, appeared: { + let schedulePicker: (Bool, @escaping (Int32) -> Void) -> Void = { media, done in + presentSchedulePicker(media, done) + } + let appeared: () -> Void = { transitionCompletion?() - }, completion: { result, editingContext in + } + let completion: (TGMediaEditableItem, TGMediaEditingContext, Bool, Int32) -> Void = { result, editingContext, silentPosting, scheduleTime in let nativeGenerator = legacyAssetPickerItemGenerator() var selectableResult: TGMediaSelectableItem? - if let result = result { - selectableResult = unsafeDowncast(result, to: TGMediaSelectableItem.self) - } + selectableResult = unsafeDowncast(result, to: TGMediaSelectableItem.self) + let signals = TGCameraController.resultSignals(for: nil, editingContext: editingContext, currentItem: selectableResult, storeAssets: false, saveEditedPhotos: false, descriptionGenerator: { _1, _2, _3 in nativeGenerator(_1, _2, _3, nil) }) - let isCaptionAbove = editingContext?.isCaptionAbove() ?? false - sendMessagesWithSignals(signals, false, 0, isCaptionAbove) - }, dismissed: { [weak legacyController] in + let isCaptionAbove = editingContext.isCaptionAbove() + sendMessagesWithSignals(signals, silentPosting, scheduleTime, isCaptionAbove) + } + let dismissed: () -> Void = { [weak legacyController] in legacyController?.dismiss() - }) + } + + legacyController.enableSizeClassSignal = true + + if isGif { + let galleryController = TGPhotoVideoEditor.controller( + with: legacyController.context, + caption: initialCaption, + withItem: item, + paint: mode == .draw, + adjustments: mode == .adjustments, + recipientName: recipientName, + stickersContext: paintStickersContext, + from: .zero, + mainSnapshot: nil, + snapshots: snapshots as [Any], + immediate: transitionCompletion != nil, + activateInput: mode == .caption, + isGif: true, + hasSilentPosting: hasSilentPosting, + hasSchedule: hasSchedule, + reminder: reminder, + presentSchedulePicker: schedulePicker, + appeared: appeared, + completion: completion, + dismissed: dismissed + ) + legacyController.bind(controller: galleryController) + present(legacyController, nil) + } else { + let emptyController = LegacyEmptyController(context: legacyController.context)! + emptyController.navigationBarShouldBeHidden = true + let navigationController = makeLegacyNavigationController(rootController: emptyController) + navigationController.setNavigationBarHidden(true, animated: false) + legacyController.bind(controller: navigationController) + + present(legacyController, nil) + + TGPhotoVideoEditor.present( + with: legacyController.context, + controller: emptyController, + caption: initialCaption, + withItem: item, + paint: mode == .draw, + adjustments: mode == .adjustments, + recipientName: recipientName, + stickersContext: paintStickersContext, + from: .zero, + mainSnapshot: nil, + snapshots: snapshots as [Any], + immediate: transitionCompletion != nil, + activateInput: mode == .caption, + isGif: false, + hasSilentPosting: hasSilentPosting, + hasSchedule: hasSchedule, + reminder: reminder, + presentSchedulePicker: schedulePicker, + appeared: appeared, + completion: completion, + dismissed: dismissed + ) + } }) } @@ -530,13 +589,11 @@ public func legacyAttachmentMenu( present(legacyController, nil) - TGPhotoVideoEditor.present(with: legacyController.context, controller: emptyController, caption: initialCaption, withItem: item, paint: false, adjustments: false, recipientName: recipientName, stickersContext: paintStickersContext, from: .zero, mainSnapshot: nil, snapshots: [], immediate: false, activateInput: false, isGif: false, appeared: { - }, completion: { result, editingContext in + TGPhotoVideoEditor.present(with: legacyController.context, controller: emptyController, caption: initialCaption, withItem: item, paint: false, adjustments: false, recipientName: recipientName, stickersContext: paintStickersContext, from: .zero, mainSnapshot: nil, snapshots: [], immediate: false, activateInput: false, isGif: false, hasSilentPosting: false, hasSchedule: false, reminder: false, presentSchedulePicker: { _, _ in }, appeared: { + }, completion: { result, editingContext, _, _ in let nativeGenerator = legacyAssetPickerItemGenerator() - var selectableResult: TGMediaSelectableItem? - if let result = result { - selectableResult = unsafeDowncast(result, to: TGMediaSelectableItem.self) - } + let selectableResult: TGMediaSelectableItem? = unsafeDowncast(result, to: TGMediaSelectableItem.self) + let signals = TGCameraController.resultSignals(for: nil, editingContext: editingContext, currentItem: selectableResult, storeAssets: false, saveEditedPhotos: false, descriptionGenerator: { _1, _2, _3 in nativeGenerator(_1, _2, _3, nil) }) diff --git a/submodules/LegacyMediaPickerUI/Sources/LegacyAvatarPicker.swift b/submodules/LegacyMediaPickerUI/Sources/LegacyAvatarPicker.swift index d367e03a9d..35a7c4da0c 100644 --- a/submodules/LegacyMediaPickerUI/Sources/LegacyAvatarPicker.swift +++ b/submodules/LegacyMediaPickerUI/Sources/LegacyAvatarPicker.swift @@ -108,11 +108,9 @@ public func legacyAvatarEditor(context: AccountContext, media: AnyMediaReference present(legacyController, nil) TGPhotoVideoEditor.present(with: legacyController.context, parentController: emptyController, image: image.0, video: video.0, stickersContext: paintStickersContext, transitionView: transitionView, senderName: senderName, didFinishWithImage: { image in - if let image = image { - imageCompletion(image) - } + imageCompletion(image) }, didFinishWithVideo: { image, url, adjustments in - if let image = image, let url = url, let adjustments = adjustments { + if let adjustments = adjustments { videoCompletion(image, url, adjustments) } }, dismissed: { [weak legacyController] in diff --git a/submodules/SearchUI/Sources/SearchDisplayController.swift b/submodules/SearchUI/Sources/SearchDisplayController.swift index 53cdd002ce..518b730a05 100644 --- a/submodules/SearchUI/Sources/SearchDisplayController.swift +++ b/submodules/SearchUI/Sources/SearchDisplayController.swift @@ -312,6 +312,11 @@ public final class SearchDisplayController { if let searchBar = self.searchBar { searchBar.deactivate(clear: false) } + if !self.searchBarIsExternal, let searchBar = self.searchBar { + searchBar.isUserInteractionEnabled = false + } + self.backgroundNode.isUserInteractionEnabled = false + self.contentNode.isUserInteractionEnabled = false if !self.searchBarIsExternal, let searchBar = self.searchBar { if let placeholder = placeholder { diff --git a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesSettings.swift b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesSettings.swift index 944b7a2ee4..2cd47b82f8 100644 --- a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesSettings.swift +++ b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesSettings.swift @@ -132,6 +132,10 @@ public struct PresentationResourcesSettings { public static let business = renderSettingsIcon(name: "Item List/Icons/Business", backgroundColors: [UIColor(rgb: 0xA95CE3), UIColor(rgb: 0xF16B80)]) public static let myProfile = renderSettingsIcon(name: "Item List/Icons/Profile", backgroundColors: [colorRed]) + public static let birthday = renderSettingsIcon(name: "Item List/Icons/Cake", backgroundColors: [colorBlue]) + public static let aiTools = renderSettingsIcon(name: "Item List/Icons/AITools", backgroundColors: [colorPurple]) + public static let yourColor = renderSettingsIcon(name: "Item List/Icons/Brush", backgroundColors: [colorLightBlue]) + public static let storageUsage = renderSettingsIcon(name: "Item List/Icons/Pie", backgroundColors: [colorOrange]) public static let dataUsage = renderSettingsIcon(name: "Item List/Icons/Stats", backgroundColors: [colorPurple]) @@ -213,48 +217,7 @@ public struct PresentationResourcesSettings { }) public static let ton = renderSettingsIcon(name: "Ads/TonAbout", backgroundColors: [UIColor(rgb: 0x32ade6)]) - -// generateImage(CGSize(width: 30.0, height: 30.0), contextGenerator: { size, context in -// let bounds = CGRect(origin: CGPoint(), size: size) -// context.clear(bounds) -// -// context.setFillColor(UIColor(rgb: 0x32ade6).cgColor) -// context.fill(bounds) -// -// if let gradientImage, let cgImage = gradientImage.cgImage { -// context.saveGState() -// context.setBlendMode(.plusLighter) -// context.draw(cgImage, in: CGRect(origin: .zero, size: size)) -// context.restoreGState() -// } -// -// if let backdropImage, let cgImage = backdropImage.cgImage { -// context.saveGState() -// context.setBlendMode(.overlay) -// context.draw(cgImage, in: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: size)) -// context.restoreGState() -// } -// -// context.setBlendMode(.normal) -// -// if let image = generateTintedImage(image: UIImage(bundleImageName: "Ads/TonAbout"), color: UIColor(rgb: 0xffffff)), let cgImage = image.cgImage { -// context.draw(cgImage, in: CGRect(origin: CGPoint(x: floorToScreenPixels((bounds.width - image.size.width) / 2.0), y: floorToScreenPixels((bounds.height - image.size.height) / 2.0)), size: image.size)) -// } -// -// let outerPath = UIBezierPath(rect: CGRect(origin: .zero, size: size)) -// let innerPath = UIBezierPath(roundedRect: CGRect(origin: .zero, size: size), cornerRadius: 8.0) -// outerPath.append(innerPath) -// -// context.saveGState() -// outerPath.usesEvenOddFillRule = true -// context.addPath(outerPath.cgPath) -// context.clip(using: .evenOdd) -// -// context.setBlendMode(.clear) -// context.fill(CGRect(origin: .zero, size: size)) -// context.restoreGState() -// }) - + public static let stars = generateImage(CGSize(width: 30.0, height: 30.0), contextGenerator: { size, context in let bounds = CGRect(origin: CGPoint(), size: size) context.clear(bounds) diff --git a/submodules/TelegramUI/Components/Chat/ChatChannelSubscriberInputPanelNode/Sources/ChatChannelSubscriberInputPanelNode.swift b/submodules/TelegramUI/Components/Chat/ChatChannelSubscriberInputPanelNode/Sources/ChatChannelSubscriberInputPanelNode.swift index 6c92a201d3..053026ef6c 100644 --- a/submodules/TelegramUI/Components/Chat/ChatChannelSubscriberInputPanelNode/Sources/ChatChannelSubscriberInputPanelNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatChannelSubscriberInputPanelNode/Sources/ChatChannelSubscriberInputPanelNode.swift @@ -174,7 +174,7 @@ public final class ChatChannelSubscriberInputPanelNode: ChatInputPanelNode { private var presentationInterfaceState: ChatPresentationInterfaceState? - private var layoutData: (CGFloat, CGFloat, CGFloat, CGFloat, UIEdgeInsets, CGFloat, CGFloat, Bool, LayoutMetrics)? + private var layoutData: (CGFloat, CGFloat, CGFloat, CGFloat, UIEdgeInsets, CGFloat, CGFloat, Bool, LayoutMetrics, DeviceMetrics)? public override init() { super.init() @@ -214,8 +214,8 @@ public final class ChatChannelSubscriberInputPanelNode: ChatInputPanelNode { switch action { case .join, .joinGroup, .applyToJoin: self.isJoining = true - if let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, isSecondary, metrics) = self.layoutData, let presentationInterfaceState = self.presentationInterfaceState { - let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, maxOverlayHeight: maxOverlayHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: presentationInterfaceState, metrics: metrics, force: true) + if let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, isSecondary, metrics, deviceMetrics) = self.layoutData, let presentationInterfaceState = self.presentationInterfaceState { + let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, maxOverlayHeight: maxOverlayHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: presentationInterfaceState, metrics: metrics, deviceMetrics: deviceMetrics, force: true) } self.actionDisposable.set((context.peerChannelMemberCategoriesContextsManager.join(engine: context.engine, peerId: peer.id, hash: nil) |> afterDisposed { [weak self] in @@ -292,8 +292,8 @@ public final class ChatChannelSubscriberInputPanelNode: ChatInputPanelNode { } } - override public func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, isMediaInputExpanded: Bool) -> CGFloat { - return self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, maxOverlayHeight: maxOverlayHeight, isSecondary: isSecondary, transition: transition, interfaceState: interfaceState, metrics: metrics, force: false) + override public func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, deviceMetrics: DeviceMetrics, isMediaInputExpanded: Bool) -> CGFloat { + return self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, maxOverlayHeight: maxOverlayHeight, isSecondary: isSecondary, transition: transition, interfaceState: interfaceState, metrics: metrics, deviceMetrics: deviceMetrics, force: false) } private var displayedGiftOrSuggestTooltip = false @@ -389,9 +389,9 @@ public final class ChatChannelSubscriberInputPanelNode: ChatInputPanelNode { }) } - private func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, force: Bool) -> CGFloat { + private func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, deviceMetrics: DeviceMetrics, force: Bool) -> CGFloat { let isFirstTime = self.layoutData == nil - self.layoutData = (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, isSecondary, metrics) + self.layoutData = (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, isSecondary, metrics, deviceMetrics) var transition = transition if !isFirstTime && !transition.isAnimated { @@ -433,10 +433,9 @@ public final class ChatChannelSubscriberInputPanelNode: ChatInputPanelNode { var leftInset = leftInset + 8.0 var rightInset = rightInset + 8.0 - if bottomInset <= 32.0 { - leftInset += 18.0 - rightInset += 18.0 - } + let compactBottomSideInset = self.compactBottomSideInset(bottomInset: bottomInset, deviceMetrics: deviceMetrics) + leftInset += compactBottomSideInset + rightInset += compactBottomSideInset var leftPanelItems: [GlassControlGroupComponent.Item] = [] if displaySuggestPost { diff --git a/submodules/TelegramUI/Components/Chat/ChatInputPanelNode/Sources/ChatInputPanelNode.swift b/submodules/TelegramUI/Components/Chat/ChatInputPanelNode/Sources/ChatInputPanelNode.swift index 25a2afaf63..c092290429 100644 --- a/submodules/TelegramUI/Components/Chat/ChatInputPanelNode/Sources/ChatInputPanelNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatInputPanelNode/Sources/ChatInputPanelNode.swift @@ -23,7 +23,15 @@ open class ChatInputPanelNode: ASDisplayNode { open func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize, transition: ContainedViewLayoutTransition) { } - open func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, isMediaInputExpanded: Bool) -> CGFloat { + public final func compactBottomSideInset(bottomInset: CGFloat, deviceMetrics: DeviceMetrics) -> CGFloat { + if bottomInset <= 32.0 && deviceMetrics.screenCornerRadius > 0.0 { + return 18.0 + } else { + return 0.0 + } + } + + open func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, deviceMetrics: DeviceMetrics, isMediaInputExpanded: Bool) -> CGFloat { return 0.0 } diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageSelectionInputPanelNode/Sources/ChatMessageSelectionInputPanelNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageSelectionInputPanelNode/Sources/ChatMessageSelectionInputPanelNode.swift index 6047a3099b..5a90c21e7f 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageSelectionInputPanelNode/Sources/ChatMessageSelectionInputPanelNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageSelectionInputPanelNode/Sources/ChatMessageSelectionInputPanelNode.swift @@ -202,7 +202,7 @@ public final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode { private let reactionOverlayContainer: ChatMessageSelectionInputPanelNodeViewForOverlayContent - private var validLayout: (width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, metrics: LayoutMetrics, isSecondary: Bool, isMediaInputExpanded: Bool)? + private var validLayout: (width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, metrics: LayoutMetrics, isSecondary: Bool, isMediaInputExpanded: Bool, deviceMetrics: DeviceMetrics)? private var presentationInterfaceState: ChatPresentationInterfaceState? private var actions: ChatAvailableMessageActions? @@ -288,8 +288,8 @@ public final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode { if self.selectedMessages.isEmpty { self.actions = nil - if let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded) = self.validLayout, let interfaceState = self.presentationInterfaceState { - let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, maxOverlayHeight: maxOverlayHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: interfaceState, metrics: metrics, isMediaInputExpanded: isMediaInputExpanded) + if let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded, deviceMetrics) = self.validLayout, let interfaceState = self.presentationInterfaceState { + let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, maxOverlayHeight: maxOverlayHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: interfaceState, metrics: metrics, deviceMetrics: deviceMetrics, isMediaInputExpanded: isMediaInputExpanded) } self.canDeleteMessagesDisposable.set(nil) } else if let context = self.context { @@ -297,8 +297,8 @@ public final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode { |> deliverOnMainQueue).startStrict(next: { [weak self] actions in if let strongSelf = self { strongSelf.actions = actions - if let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight: maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded) = strongSelf.validLayout, let interfaceState = strongSelf.presentationInterfaceState { - let _ = strongSelf.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, maxOverlayHeight: maxOverlayHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: interfaceState, metrics: metrics, isMediaInputExpanded: isMediaInputExpanded) + if let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight: maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded, deviceMetrics) = strongSelf.validLayout, let interfaceState = strongSelf.presentationInterfaceState { + let _ = strongSelf.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, maxOverlayHeight: maxOverlayHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: interfaceState, metrics: metrics, deviceMetrics: deviceMetrics, isMediaInputExpanded: isMediaInputExpanded) } } })) @@ -456,21 +456,20 @@ public final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode { } private func update(transition: ContainedViewLayoutTransition) { - if let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded) = self.validLayout, let interfaceState = self.presentationInterfaceState { - let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, maxOverlayHeight: maxOverlayHeight, isSecondary: isSecondary, transition: transition, interfaceState: interfaceState, metrics: metrics, isMediaInputExpanded: isMediaInputExpanded) + if let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded, deviceMetrics) = self.validLayout, let interfaceState = self.presentationInterfaceState { + let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, maxOverlayHeight: maxOverlayHeight, isSecondary: isSecondary, transition: transition, interfaceState: interfaceState, metrics: metrics, deviceMetrics: deviceMetrics, isMediaInputExpanded: isMediaInputExpanded) } } - override public func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, isMediaInputExpanded: Bool) -> CGFloat { - self.validLayout = (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded) + override public func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, deviceMetrics: DeviceMetrics, isMediaInputExpanded: Bool) -> CGFloat { + self.validLayout = (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded, deviceMetrics) var leftInset = leftInset + 8.0 var rightInset = rightInset + 8.0 - if bottomInset <= 32.0 { - leftInset += 18.0 - rightInset += 18.0 - } + let compactBottomSideInset = self.compactBottomSideInset(bottomInset: bottomInset, deviceMetrics: deviceMetrics) + leftInset += compactBottomSideInset + rightInset += compactBottomSideInset let panelHeight = defaultHeight(metrics: metrics) diff --git a/submodules/TelegramUI/Components/Chat/ChatRecordingPreviewInputPanelNode/Sources/ChatRecordingPreviewInputPanelNode.swift b/submodules/TelegramUI/Components/Chat/ChatRecordingPreviewInputPanelNode/Sources/ChatRecordingPreviewInputPanelNode.swift index f8c3ce8074..3004117e1e 100644 --- a/submodules/TelegramUI/Components/Chat/ChatRecordingPreviewInputPanelNode/Sources/ChatRecordingPreviewInputPanelNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatRecordingPreviewInputPanelNode/Sources/ChatRecordingPreviewInputPanelNode.swift @@ -392,7 +392,7 @@ public final class ChatRecordingPreviewInputPanelNodeImpl: ChatInputPanelNode { })*/ } - override public func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, isMediaInputExpanded: Bool) -> CGFloat { + override public func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, deviceMetrics: DeviceMetrics, isMediaInputExpanded: Bool) -> CGFloat { let waveformBackgroundFrame = CGRect(origin: CGPoint(x: 3.0, y: 3.0), size: CGSize(width: width - 3.0 * 2.0, height: 40.0 - 3.0 * 2.0)) if self.presentationInterfaceState != interfaceState { diff --git a/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelComponent.swift b/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelComponent.swift index a9434330d9..3baa7ab194 100644 --- a/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelComponent.swift +++ b/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelComponent.swift @@ -1052,6 +1052,7 @@ public final class ChatTextInputPanelComponent: Component { transition: transition.containedViewLayoutTransition, interfaceState: presentationInterfaceState, metrics: LayoutMetrics(widthClass: .compact, heightClass: .compact, orientation: nil), + deviceMetrics: DeviceMetrics.iPhone16Pro, isMediaInputExpanded: false ) diff --git a/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift index f349894a89..8edb6af71b 100644 --- a/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift @@ -300,7 +300,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg private var accessoryItemButtons: [(ChatTextInputAccessoryItem, AccessoryItemIconButton)] = [] - private var validLayout: (CGFloat, CGFloat, CGFloat, CGFloat, UIEdgeInsets, CGFloat, CGFloat, LayoutMetrics, Bool, Bool)? + private var validLayout: (CGFloat, CGFloat, CGFloat, CGFloat, UIEdgeInsets, CGFloat, CGFloat, LayoutMetrics, Bool, Bool, DeviceMetrics)? private var leftMenuInset: CGFloat = 0.0 private var rightSlowModeInset: CGFloat = 0.0 private var currentTextInputBackgroundWidthOffset: CGFloat = 0.0 @@ -872,15 +872,15 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg } self.mediaActionButtons.micButton.offsetRecordingControls = { [weak self] in if let strongSelf = self, let presentationInterfaceState = strongSelf.presentationInterfaceState { - if let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded) = strongSelf.validLayout { - let _ = strongSelf.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, maxOverlayHeight: maxOverlayHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: presentationInterfaceState, metrics: metrics, isMediaInputExpanded: isMediaInputExpanded) + if let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded, deviceMetrics) = strongSelf.validLayout { + let _ = strongSelf.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, maxOverlayHeight: maxOverlayHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: presentationInterfaceState, metrics: metrics, deviceMetrics: deviceMetrics, isMediaInputExpanded: isMediaInputExpanded) } } } self.mediaActionButtons.micButton.updateCancelTranslation = { [weak self] in if let strongSelf = self, let presentationInterfaceState = strongSelf.presentationInterfaceState { - if let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded) = strongSelf.validLayout { - let _ = strongSelf.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, maxOverlayHeight: maxOverlayHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: presentationInterfaceState, metrics: metrics, isMediaInputExpanded: isMediaInputExpanded) + if let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded, deviceMetrics) = strongSelf.validLayout { + let _ = strongSelf.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, maxOverlayHeight: maxOverlayHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: presentationInterfaceState, metrics: metrics, deviceMetrics: deviceMetrics, isMediaInputExpanded: isMediaInputExpanded) } } } @@ -1412,10 +1412,10 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg } public func requestLayout(transition: ContainedViewLayoutTransition = .immediate) { - guard let presentationInterfaceState = self.presentationInterfaceState, let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded) = self.validLayout else { + guard let presentationInterfaceState = self.presentationInterfaceState, let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded, deviceMetrics) = self.validLayout else { return } - let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, maxOverlayHeight: maxOverlayHeight, isSecondary: isSecondary, transition: transition, interfaceState: presentationInterfaceState, metrics: metrics, isMediaInputExpanded: isMediaInputExpanded) + let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, maxOverlayHeight: maxOverlayHeight, isSecondary: isSecondary, transition: transition, interfaceState: presentationInterfaceState, metrics: metrics, deviceMetrics: deviceMetrics, isMediaInputExpanded: isMediaInputExpanded) } override public func updateLayout( @@ -1430,12 +1430,13 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, + deviceMetrics: DeviceMetrics, isMediaInputExpanded: Bool ) -> CGFloat { let isFirstTime = self.validLayout == nil let previousAdditionalSideInsets = self.validLayout?.4 - self.validLayout = (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded) + self.validLayout = (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded, deviceMetrics) let defaultGlassTintColor: GlassBackgroundView.TintColor let defaultGlassTintWithInnerColor: GlassBackgroundView.TintColor @@ -1450,10 +1451,9 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg var leftInset = leftInset var rightInset = rightInset - if bottomInset <= 32.0 { - leftInset += 18.0 - rightInset += 18.0 - } + let compactBottomSideInset = self.compactBottomSideInset(bottomInset: bottomInset, deviceMetrics: deviceMetrics) + leftInset += compactBottomSideInset + rightInset += compactBottomSideInset let placeholderColor: UIColor = interfaceState.theme.chat.inputPanel.inputPlaceholderColor @@ -2897,7 +2897,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg transition.updateAlpha(layer: mediaPreviewPanelNode.tintMaskView.layer, alpha: 1.0) transition.updateFrame(view: mediaPreviewPanelNode.tintMaskView, frame: mediaPreviewPanelFrame) - let _ = mediaPreviewPanelNode.updateLayout(width: mediaPreviewPanelFrame.width, leftInset: 0.0, rightInset: 0.0, bottomInset: 0.0, additionalSideInsets: UIEdgeInsets(), maxHeight: 40.0, maxOverlayHeight: 40.0, isSecondary: false, transition: mediaPreviewPanelTransition, interfaceState: interfaceState, metrics: metrics, isMediaInputExpanded: false) + let _ = mediaPreviewPanelNode.updateLayout(width: mediaPreviewPanelFrame.width, leftInset: 0.0, rightInset: 0.0, bottomInset: 0.0, additionalSideInsets: UIEdgeInsets(), maxHeight: 40.0, maxOverlayHeight: 40.0, isSecondary: false, transition: mediaPreviewPanelTransition, interfaceState: interfaceState, metrics: metrics, deviceMetrics: deviceMetrics, isMediaInputExpanded: false) } else if let mediaPreviewPanelNode = self.mediaPreviewPanelNode { self.mediaPreviewPanelNode = nil let mediaPreviewPanelView = mediaPreviewPanelNode.view @@ -4653,13 +4653,12 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg } private func updateTextHeight(animated: Bool) { - if let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, _, metrics, _, _) = self.validLayout, let interfaceState = self.presentationInterfaceState { + if let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, _, metrics, _, _, deviceMetrics) = self.validLayout, let interfaceState = self.presentationInterfaceState { var leftInset = leftInset var rightInset = rightInset - if bottomInset <= 32.0 { - leftInset += 18.0 - rightInset += 18.0 - } + let compactBottomSideInset = self.compactBottomSideInset(bottomInset: bottomInset, deviceMetrics: deviceMetrics) + leftInset += compactBottomSideInset + rightInset += compactBottomSideInset let baseWidth = width - leftInset - self.leftMenuInset - rightInset - self.rightSlowModeInset + self.currentTextInputBackgroundWidthOffset - additionalSideInsets.right let (_, textFieldHeight, _) = self.calculateTextFieldMetrics(width: baseWidth, sendActionControlsWidth: self.sendActionButtons.bounds.width, maxHeight: maxHeight, metrics: metrics, bottomInset: bottomInset, interfaceState: interfaceState) diff --git a/submodules/TelegramUI/Components/ChatTitleView/Sources/ChatTitleComponent.swift b/submodules/TelegramUI/Components/ChatTitleView/Sources/ChatTitleComponent.swift index 64ed2c7941..c2c1e04a57 100644 --- a/submodules/TelegramUI/Components/ChatTitleView/Sources/ChatTitleComponent.swift +++ b/submodules/TelegramUI/Components/ChatTitleView/Sources/ChatTitleComponent.swift @@ -376,7 +376,7 @@ public final class ChatTitleComponent: Component { var titleStatusIcon: ChatTitleCredibilityIcon = .none var isEnabled = true switch component.content { - case let .peer(peerView, customTitle, _, _, isScheduledMessages, isMuted, _, isEnabledValue): + case let .peer(peerView, customTitle, _, _, isScheduledMessages, isMuted, _, hidePeerStatus, isEnabledValue): if peerView.peerId.isReplies { titleSegments = [AnimatedTextComponent.Item( id: AnyHashable(0), @@ -448,7 +448,7 @@ public final class ChatTitleComponent: Component { titleCredibilityIcon = .fake } else if peer.isScam { titleCredibilityIcon = .scam - } else if let emojiStatus = peer.emojiStatus { + } else if !hidePeerStatus, let emojiStatus = peer.emojiStatus { titleStatusIcon = .emojiStatus(emojiStatus) } else if peer.isPremium && !premiumConfiguration.isPremiumDisabled { titleCredibilityIcon = .premium @@ -612,7 +612,7 @@ public final class ChatTitleComponent: Component { var inputActivitiesAllowed = true switch component.content { - case let .peer(peerView, _, _, _, isScheduledMessages, _, _, _): + case let .peer(peerView, _, _, _, isScheduledMessages, _, _, _, _): if let peer = peerView.peer { if peer.id == component.context.account.peerId || isScheduledMessages || peer.id.isRepliesOrVerificationCodes { inputActivitiesAllowed = false @@ -710,7 +710,7 @@ public final class ChatTitleComponent: Component { } } else { switch component.content { - case let .peer(peerView, customTitle, customSubtitle, onlineMemberCount, isScheduledMessages, _, customMessageCount, _): + case let .peer(peerView, customTitle, customSubtitle, onlineMemberCount, isScheduledMessages, _, customMessageCount, _, _): if let customSubtitle { let string = NSAttributedString(string: customSubtitle, font: subtitleFont, textColor: component.theme.chat.inputPanel.inputControlColor) state = .info(string, .generic) diff --git a/submodules/TelegramUI/Components/ChatTitleView/Sources/ChatTitleView.swift b/submodules/TelegramUI/Components/ChatTitleView/Sources/ChatTitleView.swift index 58fffdcb90..283fc51bd4 100644 --- a/submodules/TelegramUI/Components/ChatTitleView/Sources/ChatTitleView.swift +++ b/submodules/TelegramUI/Components/ChatTitleView/Sources/ChatTitleView.swift @@ -110,14 +110,14 @@ public enum ChatTitleContent: Equatable { } } - case peer(peerView: PeerData, customTitle: String?, customSubtitle: String?, onlineMemberCount: (total: Int32?, recent: Int32?), isScheduledMessages: Bool, isMuted: Bool?, customMessageCount: Int?, isEnabled: Bool) + case peer(peerView: PeerData, customTitle: String?, customSubtitle: String?, onlineMemberCount: (total: Int32?, recent: Int32?), isScheduledMessages: Bool, isMuted: Bool?, customMessageCount: Int?, hidePeerStatus: Bool, isEnabled: Bool) case replyThread(type: ReplyThreadType, count: Int) case custom(title: [TitleTextItem], subtitle: String?, isEnabled: Bool) public static func ==(lhs: ChatTitleContent, rhs: ChatTitleContent) -> Bool { switch lhs { - case let .peer(peerView, customTitle, customSubtitle, onlineMemberCount, isScheduledMessages, isMuted, customMessageCount, isEnabled): - if case let .peer(rhsPeerView, rhsCustomTitle, rhsCustomSubtitle, rhsOnlineMemberCount, rhsIsScheduledMessages, rhsIsMuted, rhsCustomMessageCount, rhsIsEnabled) = rhs { + case let .peer(peerView, customTitle, customSubtitle, onlineMemberCount, isScheduledMessages, isMuted, customMessageCount, hidePeerStatus, isEnabled): + if case let .peer(rhsPeerView, rhsCustomTitle, rhsCustomSubtitle, rhsOnlineMemberCount, rhsIsScheduledMessages, rhsIsMuted, rhsCustomMessageCount, rhsHidePeerStatus, rhsIsEnabled) = rhs { if peerView != rhsPeerView { return false } @@ -139,6 +139,9 @@ public enum ChatTitleContent: Equatable { if customMessageCount != rhsCustomMessageCount { return false } + if hidePeerStatus != rhsHidePeerStatus { + return false + } if isEnabled != rhsIsEnabled { return false } @@ -269,7 +272,7 @@ public final class ChatTitleView: UIView, NavigationBarTitleView { var titleStatusIcon: ChatTitleCredibilityIcon = .none var isEnabled = true switch titleContent { - case let .peer(peerView, customTitle, _, _, isScheduledMessages, isMuted, _, isEnabledValue): + case let .peer(peerView, customTitle, _, _, isScheduledMessages, isMuted, _, hidePeerStatus, isEnabledValue): if peerView.peerId.isReplies { let typeText: String = self.strings.DialogList_Replies segments = [.text(0, NSAttributedString(string: typeText, font: titleFont, textColor: titleTheme.rootController.navigationBar.primaryTextColor))] @@ -306,7 +309,7 @@ public final class ChatTitleView: UIView, NavigationBarTitleView { titleCredibilityIcon = .fake } else if peer.isScam { titleCredibilityIcon = .scam - } else if let emojiStatus = peer.emojiStatus { + } else if !hidePeerStatus, let emojiStatus = peer.emojiStatus { titleStatusIcon = .emojiStatus(emojiStatus) } else if peer.isPremium && !premiumConfiguration.isPremiumDisabled { titleCredibilityIcon = .premium @@ -476,8 +479,8 @@ public final class ChatTitleView: UIView, NavigationBarTitleView { var enableAnimation = false switch titleContent { - case let .peer(_, customTitle, _, _, _, _, _, _): - if case let .peer(_, previousCustomTitle, _, _, _, _, _, _) = oldValue { + case let .peer(_, customTitle, _, _, _, _, _, _, _): + if case let .peer(_, previousCustomTitle, _, _, _, _, _, _, _) = oldValue { if customTitle != previousCustomTitle { enableAnimation = false } @@ -503,7 +506,7 @@ public final class ChatTitleView: UIView, NavigationBarTitleView { var inputActivitiesAllowed = true if let titleContent = self.titleContent { switch titleContent { - case let .peer(peerView, _, _, _, isScheduledMessages, _, _, _): + case let .peer(peerView, _, _, _, isScheduledMessages, _, _, _, _): if let peer = peerView.peer { if peer.id == self.context.account.peerId || isScheduledMessages || peer.id.isRepliesOrVerificationCodes { inputActivitiesAllowed = false @@ -604,7 +607,7 @@ public final class ChatTitleView: UIView, NavigationBarTitleView { } else { if let titleContent = self.titleContent { switch titleContent { - case let .peer(peerView, customTitle, customSubtitle, onlineMemberCount, isScheduledMessages, _, customMessageCount, _): + case let .peer(peerView, customTitle, customSubtitle, onlineMemberCount, isScheduledMessages, _, customMessageCount, _, _): if let customSubtitle { let string = NSAttributedString(string: customSubtitle, font: subtitleFont, textColor: titleTheme.rootController.navigationBar.secondaryTextColor) state = .info(string, .generic) diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift index 2a2a73c008..46ff447e9f 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift @@ -425,6 +425,7 @@ final class PeerInfoScreenData { let savedMusicContext: ProfileSavedMusicContext? let savedMusicState: ProfileSavedMusicContext.State? let managedByBot: EnginePeer? + let businessConnectedBot: EnginePeer? let _isContact: Bool var forceIsContact: Bool = false @@ -480,7 +481,8 @@ final class PeerInfoScreenData { webAppPermissions: WebAppPermissionsState?, savedMusicContext: ProfileSavedMusicContext?, savedMusicState: ProfileSavedMusicContext.State?, - managedByBot: EnginePeer? + managedByBot: EnginePeer?, + businessConnectedBot: EnginePeer? ) { self.peer = peer self.chatPeer = chatPeer @@ -525,6 +527,7 @@ final class PeerInfoScreenData { self.savedMusicContext = savedMusicContext self.savedMusicState = savedMusicState self.managedByBot = managedByBot + self.businessConnectedBot = businessConnectedBot } } @@ -931,6 +934,20 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id, let profileGiftsContext = ProfileGiftsContext(account: context.account, peerId: peerId) + let businessConnectedBot = context.engine.data.subscribe( + TelegramEngine.EngineData.Item.Peer.BusinessConnectedBot(id: context.account.peerId) + ) + |> map { bot -> EnginePeer.Id? in + return bot?.id + } + |> distinctUntilChanged + |> mapToSignal { botPeerId -> Signal in + guard let botPeerId else { + return .single(nil) + } + return context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: botPeerId)) + } + return combineLatest( context.account.viewTracker.peerView(peerId, updateData: true), accountsAndPeers, @@ -956,9 +973,10 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id, bots, peerInfoPersonalOrLinkedChannel(context: context, peerId: peerId, isSettings: true), starsState, - tonState + tonState, + businessConnectedBot ) - |> map { peerView, accountsAndPeers, accountSessions, privacySettings, sharedPreferences, notifications, stickerPacks, hasPassport, accountPreferences, suggestions, limits, hasPassword, isPowerSavingEnabled, hasStories, bots, personalChannel, starsState, tonState -> PeerInfoScreenData in + |> map { peerView, accountsAndPeers, accountSessions, privacySettings, sharedPreferences, notifications, stickerPacks, hasPassport, accountPreferences, suggestions, limits, hasPassword, isPowerSavingEnabled, hasStories, bots, personalChannel, starsState, tonState, businessConnectedBot -> PeerInfoScreenData in let (notificationExceptions, notificationsAuthorizationStatus, notificationsWarningSuppressed) = notifications let (featuredStickerPacks, archivedStickerPacks) = stickerPacks @@ -1048,7 +1066,8 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id, webAppPermissions: nil, savedMusicContext: nil, savedMusicState: nil, - managedByBot: nil + managedByBot: nil, + businessConnectedBot: businessConnectedBot ) } } @@ -1120,7 +1139,8 @@ func peerInfoScreenData( webAppPermissions: nil, savedMusicContext: nil, savedMusicState: nil, - managedByBot: nil + managedByBot: nil, + businessConnectedBot: nil )) case let .user(userPeerId, secretChatId, kind): let groupsInCommon: GroupsInCommonContext? @@ -1446,7 +1466,26 @@ func peerInfoScreenData( } let savedMusicContext = ProfileSavedMusicContext(account: context.account, peerId: peerId) - + + let businessConnectedBot: Signal + if isMyProfile { + businessConnectedBot = context.engine.data.subscribe( + TelegramEngine.EngineData.Item.Peer.BusinessConnectedBot(id: context.account.peerId) + ) + |> map { bot -> EnginePeer.Id? in + return bot?.id + } + |> distinctUntilChanged + |> mapToSignal { botPeerId -> Signal in + guard let botPeerId else { + return .single(nil) + } + return context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: botPeerId)) + } + } else { + businessConnectedBot = .single(nil) + } + return combineLatest( context.account.viewTracker.peerView(peerId, updateData: true), peerInfoAvailableMediaPanes(context: context, peerId: peerId, chatLocation: chatLocation, isMyProfile: isMyProfile, chatLocationContextHolder: chatLocationContextHolder, sharedMediaFromForumTopic: sharedMediaFromForumTopic), @@ -1468,9 +1507,10 @@ func peerInfoScreenData( revenueContextAndState, premiumGiftOptions, webAppPermissions, - savedMusicContext.state + savedMusicContext.state, + businessConnectedBot ) - |> map { peerView, availablePanes, globalNotificationSettings, encryptionKeyFingerprint, status, hasStories, hasStoryArchive, recommendedBots, accountIsPremium, savedMessagesPeer, hasSavedMessagesChats, hasSavedMessages, hasSavedMessageTags, hasBotPreviewItems, personalChannel, privacySettings, starsRevenueContextAndState, revenueContextAndState, premiumGiftOptions, webAppPermissions, savedMusicState -> PeerInfoScreenData in + |> map { peerView, availablePanes, globalNotificationSettings, encryptionKeyFingerprint, status, hasStories, hasStoryArchive, recommendedBots, accountIsPremium, savedMessagesPeer, hasSavedMessagesChats, hasSavedMessages, hasSavedMessageTags, hasBotPreviewItems, personalChannel, privacySettings, starsRevenueContextAndState, revenueContextAndState, premiumGiftOptions, webAppPermissions, savedMusicState, businessConnectedBot -> PeerInfoScreenData in var availablePanes = availablePanes if isMyProfile { availablePanes?.insert(.stories, at: 0) @@ -1616,7 +1656,8 @@ func peerInfoScreenData( webAppPermissions: webAppPermissions, savedMusicContext: savedMusicContext, savedMusicState: savedMusicState, - managedByBot: managedByBot + managedByBot: managedByBot, + businessConnectedBot: businessConnectedBot ) } case .channel: @@ -1862,7 +1903,8 @@ func peerInfoScreenData( webAppPermissions: nil, savedMusicContext: nil, savedMusicState: nil, - managedByBot: nil + managedByBot: nil, + businessConnectedBot: nil ) } case let .group(groupId): @@ -2199,7 +2241,8 @@ func peerInfoScreenData( webAppPermissions: nil, savedMusicContext: nil, savedMusicState: nil, - managedByBot: nil + managedByBot: nil, + businessConnectedBot: nil )) } } diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoInteraction.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoInteraction.swift index 0d0bdf5c72..a9a1d9c92f 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoInteraction.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoInteraction.swift @@ -83,6 +83,7 @@ final class PeerInfoInteraction { let editingOpenVerifyAccounts: () -> Void let editingToggleAutoTranslate: (Bool) -> Void let displayAutoTranslateLocked: () -> Void + let editingOpenBusinessChatBots: () -> Void let getController: () -> ViewController? init( @@ -160,6 +161,7 @@ final class PeerInfoInteraction { editingOpenVerifyAccounts: @escaping () -> Void, editingToggleAutoTranslate: @escaping (Bool) -> Void, displayAutoTranslateLocked: @escaping () -> Void, + editingOpenBusinessChatBots: @escaping () -> Void, getController: @escaping () -> ViewController? ) { self.openUsername = openUsername @@ -236,6 +238,7 @@ final class PeerInfoInteraction { self.editingOpenVerifyAccounts = editingOpenVerifyAccounts self.editingToggleAutoTranslate = editingToggleAutoTranslate self.displayAutoTranslateLocked = displayAutoTranslateLocked + self.editingOpenBusinessChatBots = editingOpenBusinessChatBots self.getController = getController } } diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index eb882686f9..4ac7ec63bc 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -682,6 +682,11 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro return } self.displayAutoTranslateLocked() + }, editingOpenBusinessChatBots: { [weak self] in + guard let self else { + return + } + self.editingOpenBusinessChatBots() }, getController: { [weak self] in return self?.controller @@ -3986,6 +3991,17 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro })) }) } + + private func editingOpenBusinessChatBots() { + let _ = (self.context.sharedContext.makeChatbotSetupScreenInitialData(context: self.context) + |> take(1) + |> deliverOnMainQueue).start(next: { [weak self] initialData in + guard let self else { + return + } + self.controller?.push(self.context.sharedContext.makeChatbotSetupScreen(context: self.context, initialData: initialData)) + }) + } private func editingOpenInviteLinksSetup() { self.controller?.push(inviteLinkListController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, peerId: self.peerId, admin: nil)) diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoSelectionPanelNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoSelectionPanelNode.swift index 78af5c091e..a07cfeaf60 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoSelectionPanelNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoSelectionPanelNode.swift @@ -199,7 +199,7 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode { self.separatorNode.backgroundColor = presentationData.theme.rootController.navigationBar.separatorColor let interfaceState = ChatPresentationInterfaceState(chatWallpaper: .color(0), theme: presentationData.theme, preferredGlassType: .default, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, limitsConfiguration: .defaultValue, fontSize: .regular, bubbleCorners: PresentationChatBubbleCorners(mainRadius: 16.0, auxiliaryRadius: 8.0, mergeBubbleCorners: true), accountPeerId: self.context.account.peerId, mode: .standard(.default), chatLocation: .peer(id: self.peerId), subject: nil, peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, threadData: nil, isGeneralThreadClosed: nil, replyMessage: nil, accountPeerColor: nil, businessIntro: nil) - let panelHeight = self.selectionPanel.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: layout.intrinsicInsets.bottom, additionalSideInsets: UIEdgeInsets(), maxHeight: layout.size.height, maxOverlayHeight: layout.size.height, isSecondary: false, transition: transition, interfaceState: interfaceState, metrics: layout.metrics, isMediaInputExpanded: false) + let panelHeight = self.selectionPanel.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: layout.intrinsicInsets.bottom, additionalSideInsets: UIEdgeInsets(), maxHeight: layout.size.height, maxOverlayHeight: layout.size.height, isSecondary: false, transition: transition, interfaceState: interfaceState, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, isMediaInputExpanded: false) transition.updateFrame(node: self.selectionPanel, frame: CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: panelHeight))) diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoSettingsItems.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoSettingsItems.swift index d4554dfec9..18b22f5d2d 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoSettingsItems.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoSettingsItems.swift @@ -370,6 +370,8 @@ func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoState, conte let ItemBirthdayRemove = 11 let ItemBirthdayHelp = 12 let ItemPeerPersonalChannel = 13 + let ItemPeerChatAutomation = 14 + let ItemPeerChatAutomationHelp = 15 items[.help]!.append(PeerInfoScreenCommentItem(id: ItemNameHelp, text: presentationData.strings.EditProfile_NameAndPhotoOrVideoHelp)) @@ -400,7 +402,7 @@ func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoState, conte } let isEditingBirthDate = state.isEditingBirthDate - items[.birthday]!.append(PeerInfoScreenDisclosureItem(id: ItemBirthday, label: .coloredText(birthDateString, isEditingBirthDate ? .accent : .generic), text: presentationData.strings.Settings_Birthday, icon: nil, hasArrow: false, action: { + items[.birthday]!.append(PeerInfoScreenDisclosureItem(id: ItemBirthday, label: .coloredText(birthDateString, isEditingBirthDate ? .accent : .generic), text: presentationData.strings.Settings_Birthday, icon: PresentationResourcesSettings.birthday, hasArrow: false, action: { interaction.updateIsEditingBirthdate(!isEditingBirthDate) })) if isEditingBirthDate, let birthday { @@ -423,7 +425,7 @@ func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoState, conte })) if let user = data.peer as? TelegramUser { - items[.info]!.append(PeerInfoScreenDisclosureItem(id: ItemPhoneNumber, label: .text(user.phone.flatMap({ formatPhoneNumber(context: context, number: $0) }) ?? ""), text: presentationData.strings.Settings_PhoneNumber, action: { + items[.info]!.append(PeerInfoScreenDisclosureItem(id: ItemPhoneNumber, label: .text(user.phone.flatMap({ formatPhoneNumber(context: context, number: $0) }) ?? ""), text: presentationData.strings.Settings_PhoneNumber, icon: PresentationResourcesSettings.recentCalls, action: { interaction.openSettings(.phoneNumber) })) } @@ -431,7 +433,7 @@ func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoState, conte if let addressName = data.peer?.addressName, !addressName.isEmpty { username = "@\(addressName)" } - items[.info]!.append(PeerInfoScreenDisclosureItem(id: ItemUsername, label: .text(username), text: presentationData.strings.Settings_Username, action: { + items[.info]!.append(PeerInfoScreenDisclosureItem(id: ItemUsername, label: .text(username), text: presentationData.strings.Settings_Username, icon: PresentationResourcesSettings.email, action: { interaction.openSettings(.username) })) @@ -452,7 +454,7 @@ func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoState, conte } let colorImage = generateSettingsMenuPeerColorsLabelIcon(colors: colors) - items[.info]!.append(PeerInfoScreenDisclosureItem(id: ItemPeerColor, label: .image(colorImage, colorImage.size), text: presentationData.strings.Settings_YourColor, icon: nil, action: { + items[.info]!.append(PeerInfoScreenDisclosureItem(id: ItemPeerColor, label: .image(colorImage, colorImage.size), text: presentationData.strings.Settings_YourColor, icon: PresentationResourcesSettings.yourColor, action: { interaction.editingOpenNameColorSetup() })) @@ -468,12 +470,26 @@ func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoState, conte personalChannelTitle = peer.compactDisplayTitle } - items[.info]!.append(PeerInfoScreenDisclosureItem(id: ItemPeerPersonalChannel, label: .text(personalChannelTitle ?? presentationData.strings.Settings_PersonalChannelEmptyValue), text: presentationData.strings.Settings_PersonalChannelItem, icon: nil, action: { + items[.info]!.append(PeerInfoScreenDisclosureItem(id: ItemPeerPersonalChannel, label: .text(personalChannelTitle ?? presentationData.strings.Settings_PersonalChannelEmptyValue), text: presentationData.strings.Settings_PersonalChannelItem, icon: PresentationResourcesSettings.channels, action: { interaction.editingOpenPersonalChannel() })) } } + if "".isEmpty { + //TODO:localize + let automationBotTitle: String + if let botPeer = data.businessConnectedBot { + automationBotTitle = "@\(botPeer.compactDisplayTitle)" + } else { + automationBotTitle = "Off" + } + items[.info]!.append(PeerInfoScreenDisclosureItem(id: ItemPeerChatAutomation, label: .text(automationBotTitle), text: "Chat Automation", icon: PresentationResourcesSettings.aiTools, action: { + interaction.editingOpenBusinessChatBots() + })) + items[.info]!.append(PeerInfoScreenCommentItem(id: ItemPeerChatAutomationHelp, text: "Add a bot to reply to messages on your behalf.")) + } + items[.account]!.append(PeerInfoScreenActionItem(id: ItemAddAccount, text: presentationData.strings.Settings_AddAnotherAccount, alignment: .center, action: { interaction.openSettings(.addAccount) })) diff --git a/submodules/TelegramUI/Components/Settings/ChatbotSetupScreen/Sources/ChatbotSetupScreen.swift b/submodules/TelegramUI/Components/Settings/ChatbotSetupScreen/Sources/ChatbotSetupScreen.swift index f6807785f5..f507350f5a 100644 --- a/submodules/TelegramUI/Components/Settings/ChatbotSetupScreen/Sources/ChatbotSetupScreen.swift +++ b/submodules/TelegramUI/Components/Settings/ChatbotSetupScreen/Sources/ChatbotSetupScreen.swift @@ -645,13 +645,13 @@ final class ChatbotSetupScreenComponent: Component { let navigationTitleSize = self.navigationTitle.update( transition: transition, component: AnyComponent(MultilineTextComponent( - text: .plain(NSAttributedString(string: environment.strings.ChatbotSetup_TitleItem, font: Font.semibold(17.0), textColor: environment.theme.rootController.navigationBar.primaryTextColor)), + text: .plain(NSAttributedString(string: environment.strings.ChatbotSetup_TitleItem, font: Font.bold(24.0), textColor: environment.theme.rootController.navigationBar.primaryTextColor)), horizontalAlignment: .center )), environment: {}, containerSize: CGSize(width: availableSize.width, height: 100.0) ) - let navigationTitleFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - navigationTitleSize.width) / 2.0), y: environment.statusBarHeight + floor((environment.navigationHeight - environment.statusBarHeight - navigationTitleSize.height) / 2.0)), size: navigationTitleSize) + let navigationTitleFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - navigationTitleSize.width) / 2.0), y: environment.navigationHeight + 76.0), size: navigationTitleSize) if let navigationTitleView = self.navigationTitle.view { if navigationTitleView.superview == nil { if let controller = self.environment?.controller(), let navigationBar = controller.navigationBar { @@ -681,7 +681,7 @@ final class ChatbotSetupScreenComponent: Component { environment: {}, containerSize: CGSize(width: 100.0, height: 100.0) ) - let iconFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - iconSize.width) * 0.5), y: contentHeight + 8.0), size: iconSize) + let iconFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - iconSize.width) * 0.5), y: contentHeight - 30.0), size: iconSize) if let iconView = self.icon.view as? LottieComponent.View { if iconView.superview == nil { self.scrollView.addSubview(iconView) @@ -691,11 +691,11 @@ final class ChatbotSetupScreenComponent: Component { iconView.bounds = CGRect(origin: CGPoint(), size: iconFrame.size) } - contentHeight += 129.0 + contentHeight += 115.0 let subtitleString = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString(environment.strings.ChatbotSetup_Text, attributes: MarkdownAttributes( - body: MarkdownAttributeSet(font: Font.regular(15.0), textColor: environment.theme.list.freeTextColor), - bold: MarkdownAttributeSet(font: Font.semibold(15.0), textColor: environment.theme.list.freeTextColor), + body: MarkdownAttributeSet(font: Font.regular(15.0), textColor: environment.theme.list.itemPrimaryTextColor), + bold: MarkdownAttributeSet(font: Font.semibold(15.0), textColor: environment.theme.list.itemPrimaryTextColor), link: MarkdownAttributeSet(font: Font.regular(15.0), textColor: environment.theme.list.itemAccentColor), linkAttribute: { attributes in return ("URL", "") @@ -732,7 +732,7 @@ final class ChatbotSetupScreenComponent: Component { } )), environment: {}, - containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 1000.0) + containerSize: CGSize(width: availableSize.width - sideInset * 2.0 - 64.0, height: 1000.0) ) let subtitleFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - subtitleSize.width) * 0.5), y: contentHeight), size: subtitleSize) if let subtitleView = self.subtitle.view { diff --git a/submodules/TelegramUI/Images.xcassets/Item List/Icons/Cake.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Item List/Icons/Cake.imageset/Contents.json new file mode 100644 index 0000000000..2cc650de69 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Item List/Icons/Cake.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "birthday.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Item List/Icons/Cake.imageset/birthday.pdf b/submodules/TelegramUI/Images.xcassets/Item List/Icons/Cake.imageset/birthday.pdf new file mode 100644 index 0000000000..c77d724ac1 Binary files /dev/null and b/submodules/TelegramUI/Images.xcassets/Item List/Icons/Cake.imageset/birthday.pdf differ diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerEditGif.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerEditGif.swift index 0a9d87e4b2..07961e1e4a 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerEditGif.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerEditGif.swift @@ -14,6 +14,8 @@ extension ChatControllerImpl { guard let peer = self.presentationInterfaceState.renderedPeer?.peer else { return } + let hasSilentPosting = peer.id != self.context.account.peerId + let hasSchedule = self.presentationInterfaceState.subject != .scheduledMessages && peer.id.namespace != Namespaces.Peer.SecretChat && self.presentationInterfaceState.sendPaidMessageStars == nil legacyMediaEditor( context: self.context, peer: peer, @@ -27,7 +29,24 @@ extension ChatControllerImpl { getCaptionPanelView: { [weak self] in return self?.getCaptionPanelView(isFile: false, hasTimer: false) }, - sendMessagesWithSignals: { [weak self] signals, _, _, isCaptionAbove in + hasSilentPosting: hasSilentPosting, + hasSchedule: hasSchedule, + reminder: peer.id == self.context.account.peerId, + presentSchedulePicker: { [weak self] _, done in + guard let self else { + return + } + self.presentScheduleTimePicker(style: .media, completion: { [weak self] time, _ in + guard let self else { + return + } + done(time) + if self.presentationInterfaceState.subject != .scheduledMessages && time != scheduleWhenOnlineTimestamp { + self.openScheduledMessages() + } + }) + }, + sendMessagesWithSignals: { [weak self] signals, silentPosting, scheduleTime, isCaptionAbove in guard let self else { return } @@ -39,8 +58,8 @@ extension ChatControllerImpl { fromGallery: false, signals: signals, originalMediaReference: file.abstract, - silentPosting: false, - scheduleTime: nil, + silentPosting: silentPosting, + scheduleTime: scheduleTime == 0 ? nil : scheduleTime, replyToSubject: nil, parameters: parameters, getAnimatedTransitionSource: nil, @@ -48,7 +67,8 @@ extension ChatControllerImpl { ) }, present: { [weak self] c, a in - self?.present(c, in: .window(.root), with: a) + c.navigationPresentation = .flatModal + self?.push(c) } ) } diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerPaste.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerPaste.swift index 31aea1e533..31d157dab2 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerPaste.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerPaste.swift @@ -23,6 +23,7 @@ extension ChatControllerImpl { if strongSelf.presentationInterfaceState.interfaceState.postSuggestionState != nil { enableMultiselection = false } + let inputText = strongSelf.presentationInterfaceState.interfaceState.effectiveInputState.inputText strongSelf.chatDisplayNode.dismissInput() let controller = mediaPasteboardScreen( @@ -32,7 +33,15 @@ extension ChatControllerImpl { subjects: subjects, presentMediaPicker: { [weak self] subject, saveEditedPhotos, bannedSendPhotos, bannedSendVideos, present in if let strongSelf = self { - strongSelf.presentMediaPicker(subject: subject, saveEditedPhotos: saveEditedPhotos, bannedSendPhotos: bannedSendPhotos, bannedSendVideos: bannedSendVideos, enableMultiselection: enableMultiselection, present: present, updateMediaPickerContext: { _ in }, completion: { [weak self] fromGallery, signals, silentPosting, scheduleTime, parameters, getAnimatedTransitionSource, completion in + strongSelf.presentMediaPicker(subject: subject, saveEditedPhotos: saveEditedPhotos, bannedSendPhotos: bannedSendPhotos, bannedSendVideos: bannedSendVideos, enableMultiselection: enableMultiselection, present: { controller, mediaPickerContext in + if !inputText.string.isEmpty { + mediaPickerContext?.setCaption(inputText) + } + present(controller, mediaPickerContext) + }, updateMediaPickerContext: { _ in }, completion: { [weak self] fromGallery, signals, silentPosting, scheduleTime, parameters, getAnimatedTransitionSource, completion in + if !inputText.string.isEmpty { + self?.clearInputText() + } self?.enqueueMediaMessages(fromGallery: fromGallery, signals: signals, silentPosting: silentPosting, scheduleTime: scheduleTime, parameters: parameters, getAnimatedTransitionSource: getAnimatedTransitionSource, completion: completion) }) } diff --git a/submodules/TelegramUI/Sources/ChatControllerContentData.swift b/submodules/TelegramUI/Sources/ChatControllerContentData.swift index 047aaf43a5..fc9d8e5b4d 100644 --- a/submodules/TelegramUI/Sources/ChatControllerContentData.swift +++ b/submodules/TelegramUI/Sources/ChatControllerContentData.swift @@ -602,7 +602,7 @@ extension ChatControllerImpl { notificationSettings: nil, peerPresences: [:], cachedData: nil - ), customTitle: nil, customSubtitle: strings.Chat_Monoforum_Subtitle, onlineMemberCount: (nil, nil), isScheduledMessages: false, isMuted: nil, customMessageCount: nil, isEnabled: true) + ), customTitle: nil, customSubtitle: strings.Chat_Monoforum_Subtitle, onlineMemberCount: (nil, nil), isScheduledMessages: false, isMuted: nil, customMessageCount: nil, hidePeerStatus: false, isEnabled: true) } else { strongSelf.state.chatTitleContent = .custom(title: [ChatTitleContent.TitleTextItem(id: AnyHashable(0), content: .text(channel.debugDisplayTitle))], subtitle: nil, isEnabled: true) } @@ -613,7 +613,7 @@ extension ChatControllerImpl { customSubtitle = "Tap to view as chats" } - strongSelf.state.chatTitleContent = .peer(peerView: ChatTitleContent.PeerData(peerView: peerView), customTitle: nil, customSubtitle: customSubtitle, onlineMemberCount: onlineMemberCount, isScheduledMessages: isScheduledMessages, isMuted: nil, customMessageCount: nil, isEnabled: hasPeerInfo) + strongSelf.state.chatTitleContent = .peer(peerView: ChatTitleContent.PeerData(peerView: peerView), customTitle: nil, customSubtitle: customSubtitle, onlineMemberCount: onlineMemberCount, isScheduledMessages: isScheduledMessages, isMuted: nil, customMessageCount: nil, hidePeerStatus: false, isEnabled: hasPeerInfo) let imageOverride: AvatarNodeImageOverride? if context.account.peerId == peer.id { @@ -1519,7 +1519,7 @@ extension ChatControllerImpl { customMessageCount = savedMessagesPeer?.messageCount ?? 0 } - strongSelf.state.chatTitleContent = .peer(peerView: mappedPeerData, customTitle: nil, customSubtitle: customSubtitle, onlineMemberCount: (nil, nil), isScheduledMessages: false, isMuted: false, customMessageCount: customMessageCount, isEnabled: true) + strongSelf.state.chatTitleContent = .peer(peerView: mappedPeerData, customTitle: nil, customSubtitle: customSubtitle, onlineMemberCount: (nil, nil), isScheduledMessages: false, isMuted: false, customMessageCount: customMessageCount, hidePeerStatus: false, isEnabled: true) strongSelf.state.peerView = peerView @@ -1613,7 +1613,7 @@ extension ChatControllerImpl { } } - strongSelf.state.chatTitleContent = .peer(peerView: ChatTitleContent.PeerData(peerView: peerView), customTitle: threadInfo.title, customSubtitle: customSubtitle, onlineMemberCount: onlineMemberCount, isScheduledMessages: false, isMuted: peerIsMuted, customMessageCount: messageAndTopic.messageCount == 0 ? nil : messageAndTopic.messageCount, isEnabled: true) + strongSelf.state.chatTitleContent = .peer(peerView: ChatTitleContent.PeerData(peerView: peerView), customTitle: threadInfo.title, customSubtitle: customSubtitle, onlineMemberCount: onlineMemberCount, isScheduledMessages: false, isMuted: peerIsMuted, customMessageCount: messageAndTopic.messageCount == 0 ? nil : messageAndTopic.messageCount, hidePeerStatus: true, isEnabled: true) let avatarContent: EmojiStatusComponent.Content if chatLocation.threadId == 1 { diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index 3d3e5a53a8..3c04c94421 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -1763,7 +1763,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { if inputTextPanelNode.isFocused { self.context.sharedContext.mainWindow?.simulateKeyboardDismiss(transition: .animated(duration: 0.5, curve: .spring)) } - let _ = inputTextPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: inputPanelBottomInset, additionalSideInsets: layout.additionalInsets, maxHeight: layout.size.height - insets.top - inputPanelBottomInset, maxOverlayHeight: layout.size.height - insets.top - inputPanelBottomInset, isSecondary: false, transition: transition, interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics, isMediaInputExpanded: self.inputPanelContainerNode.expansionFraction == 1.0) + let _ = inputTextPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: inputPanelBottomInset, additionalSideInsets: layout.additionalInsets, maxHeight: layout.size.height - insets.top - inputPanelBottomInset, maxOverlayHeight: layout.size.height - insets.top - inputPanelBottomInset, isSecondary: false, transition: transition, interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, isMediaInputExpanded: self.inputPanelContainerNode.expansionFraction == 1.0) } if let prevInputPanelNode = self.inputPanelNode, inputPanelNode.canHandleTransition(from: prevInputPanelNode) { inputPanelNodeHandlesTransition = true @@ -1775,7 +1775,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { } else { dismissedInputPanelNode = self.inputPanelNode } - let inputPanelHeight = inputPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: inputPanelBottomInset, additionalSideInsets: layout.additionalInsets, maxHeight: layout.size.height - insets.top - inputPanelBottomInset, maxOverlayHeight: layout.size.height - insets.top - inputPanelBottomInset, isSecondary: false, transition: inputPanelNode.supernode !== self ? .immediate : transition, interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics, isMediaInputExpanded: self.inputPanelContainerNode.expansionFraction == 1.0) + let inputPanelHeight = inputPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: inputPanelBottomInset, additionalSideInsets: layout.additionalInsets, maxHeight: layout.size.height - insets.top - inputPanelBottomInset, maxOverlayHeight: layout.size.height - insets.top - inputPanelBottomInset, isSecondary: false, transition: inputPanelNode.supernode !== self ? .immediate : transition, interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, isMediaInputExpanded: self.inputPanelContainerNode.expansionFraction == 1.0) inputPanelSize = CGSize(width: layout.size.width, height: inputPanelHeight) self.inputPanelNode = inputPanelNode if inputPanelNode.supernode !== self { @@ -1786,7 +1786,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { self.inputPanelOverlayNode.view.addSubview(viewForOverlayContent) } } else { - let inputPanelHeight = inputPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: inputPanelBottomInset, additionalSideInsets: layout.additionalInsets, maxHeight: layout.size.height - insets.top - inputPanelBottomInset - 120.0, maxOverlayHeight: layout.size.height - insets.top - inputPanelBottomInset, isSecondary: false, transition: transition, interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics, isMediaInputExpanded: self.inputPanelContainerNode.expansionFraction == 1.0) + let inputPanelHeight = inputPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: inputPanelBottomInset, additionalSideInsets: layout.additionalInsets, maxHeight: layout.size.height - insets.top - inputPanelBottomInset - 120.0, maxOverlayHeight: layout.size.height - insets.top - inputPanelBottomInset, isSecondary: false, transition: transition, interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, isMediaInputExpanded: self.inputPanelContainerNode.expansionFraction == 1.0) inputPanelSize = CGSize(width: layout.size.width, height: inputPanelHeight) } } else { @@ -1797,7 +1797,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { if let secondaryInputPanelNode = inputPanelNodes.secondary, !previewing { if secondaryInputPanelNode !== self.secondaryInputPanelNode { dismissedSecondaryInputPanelNode = self.secondaryInputPanelNode - let inputPanelHeight = secondaryInputPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: inputPanelBottomInset, additionalSideInsets: layout.additionalInsets, maxHeight: layout.size.height - insets.top - inputPanelBottomInset, maxOverlayHeight: layout.size.height - insets.top - inputPanelBottomInset, isSecondary: true, transition: .immediate, interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics, isMediaInputExpanded: self.inputPanelContainerNode.expansionFraction == 1.0) + let inputPanelHeight = secondaryInputPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: inputPanelBottomInset, additionalSideInsets: layout.additionalInsets, maxHeight: layout.size.height - insets.top - inputPanelBottomInset, maxOverlayHeight: layout.size.height - insets.top - inputPanelBottomInset, isSecondary: true, transition: .immediate, interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, isMediaInputExpanded: self.inputPanelContainerNode.expansionFraction == 1.0) secondaryInputPanelSize = CGSize(width: layout.size.width, height: inputPanelHeight) self.secondaryInputPanelNode = secondaryInputPanelNode if secondaryInputPanelNode.supernode == nil { @@ -1808,7 +1808,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { self.inputPanelOverlayNode.view.addSubview(viewForOverlayContent) } } else { - let inputPanelHeight = secondaryInputPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: inputPanelBottomInset, additionalSideInsets: layout.additionalInsets, maxHeight: layout.size.height - insets.top - inputPanelBottomInset, maxOverlayHeight: layout.size.height - insets.top - inputPanelBottomInset, isSecondary: true, transition: transition, interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics, isMediaInputExpanded: self.inputPanelContainerNode.expansionFraction == 1.0) + let inputPanelHeight = secondaryInputPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: inputPanelBottomInset, additionalSideInsets: layout.additionalInsets, maxHeight: layout.size.height - insets.top - inputPanelBottomInset, maxOverlayHeight: layout.size.height - insets.top - inputPanelBottomInset, isSecondary: true, transition: transition, interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, isMediaInputExpanded: self.inputPanelContainerNode.expansionFraction == 1.0) secondaryInputPanelSize = CGSize(width: layout.size.width, height: inputPanelHeight) } } else { diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index a3f7cb20b3..5ca54a5cdc 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -3362,6 +3362,11 @@ public final class ChatHistoryListNodeImpl: ListViewImpl, ChatHistoryNode, ChatH if self.chatHistoryLocationValue?.content != locationInput { self.chatHistoryLocationValue = ChatHistoryLocationInput(content: locationInput, id: self.takeNextHistoryLocationId()) } + } else if historyView.originalView.holeEarlier, case let .custom(_, _, _, _, _, loadMore) = self.source, let loadMore { + if self.chatHistoryLocationValue?.content != locationInput { + self.chatHistoryLocationValue = ChatHistoryLocationInput(content: locationInput, id: self.takeNextHistoryLocationId()) + loadMore() + } } else if case let .customChatContents(customChatContents) = self.subject, case .hashTagSearch = customChatContents.kind { if self.chatHistoryLocationValue?.content != locationInput { self.chatHistoryLocationValue = ChatHistoryLocationInput(content: locationInput, id: self.takeNextHistoryLocationId()) diff --git a/submodules/TelegramUI/Sources/ChatMessageReportInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatMessageReportInputPanelNode.swift index 48f96157ca..e9642778f8 100644 --- a/submodules/TelegramUI/Sources/ChatMessageReportInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageReportInputPanelNode.swift @@ -72,7 +72,7 @@ final class ChatMessageReportInputPanelNode: ChatInputPanelNode { } } - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, isMediaInputExpanded: Bool) -> CGFloat { + override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, deviceMetrics: DeviceMetrics, isMediaInputExpanded: Bool) -> CGFloat { if self.presentationInterfaceState != interfaceState { self.presentationInterfaceState = interfaceState diff --git a/submodules/TelegramUI/Sources/ChatPremiumRequiredInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatPremiumRequiredInputPanelNode.swift index 9cd52cba92..5dbb475afd 100644 --- a/submodules/TelegramUI/Sources/ChatPremiumRequiredInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatPremiumRequiredInputPanelNode.swift @@ -30,9 +30,10 @@ final class ChatPremiumRequiredInputPanelNode: ChatInputPanelNode { var isSecondary: Bool var interfaceState: ChatPresentationInterfaceState var metrics: LayoutMetrics + var deviceMetrics: DeviceMetrics var isMediaInputExpanded: Bool - init(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, isMediaInputExpanded: Bool) { + init(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, deviceMetrics: DeviceMetrics, isMediaInputExpanded: Bool) { self.width = width self.leftInset = leftInset self.rightInset = rightInset @@ -43,6 +44,7 @@ final class ChatPremiumRequiredInputPanelNode: ChatInputPanelNode { self.isSecondary = isSecondary self.interfaceState = interfaceState self.metrics = metrics + self.deviceMetrics = deviceMetrics self.isMediaInputExpanded = isMediaInputExpanded } } @@ -74,8 +76,8 @@ final class ChatPremiumRequiredInputPanelNode: ChatInputPanelNode { deinit { } - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, isMediaInputExpanded: Bool) -> CGFloat { - let params = Params(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, maxOverlayHeight: maxOverlayHeight, isSecondary: isSecondary, interfaceState: interfaceState, metrics: metrics, isMediaInputExpanded: isMediaInputExpanded) + override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, deviceMetrics: DeviceMetrics, isMediaInputExpanded: Bool) -> CGFloat { + let params = Params(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, maxOverlayHeight: maxOverlayHeight, isSecondary: isSecondary, interfaceState: interfaceState, metrics: metrics, deviceMetrics: deviceMetrics, isMediaInputExpanded: isMediaInputExpanded) if let currentLayout = self.currentLayout, currentLayout.params == params { return currentLayout.height } diff --git a/submodules/TelegramUI/Sources/ChatRestrictedInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatRestrictedInputPanelNode.swift index 9f76e4bc68..54fe6be26d 100644 --- a/submodules/TelegramUI/Sources/ChatRestrictedInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatRestrictedInputPanelNode.swift @@ -81,7 +81,7 @@ final class ChatRestrictedInputPanelNode: ChatInputPanelNode { self.interfaceInteraction?.openBoostToUnrestrict() } - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, isMediaInputExpanded: Bool) -> CGFloat { + override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, deviceMetrics: DeviceMetrics, isMediaInputExpanded: Bool) -> CGFloat { if self.presentationInterfaceState != interfaceState { self.presentationInterfaceState = interfaceState } diff --git a/submodules/TelegramUI/Sources/ChatTagSearchInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatTagSearchInputPanelNode.swift index 3aa6cd9d48..7ad89bff3d 100644 --- a/submodules/TelegramUI/Sources/ChatTagSearchInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTagSearchInputPanelNode.swift @@ -32,9 +32,10 @@ final class ChatTagSearchInputPanelNode: ChatInputPanelNode { var isSecondary: Bool var interfaceState: ChatPresentationInterfaceState var metrics: LayoutMetrics + var deviceMetrics: DeviceMetrics var isMediaInputExpanded: Bool - init(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, isMediaInputExpanded: Bool) { + init(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, deviceMetrics: DeviceMetrics, isMediaInputExpanded: Bool) { self.width = width self.leftInset = leftInset self.rightInset = rightInset @@ -45,6 +46,7 @@ final class ChatTagSearchInputPanelNode: ChatInputPanelNode { self.isSecondary = isSecondary self.interfaceState = interfaceState self.metrics = metrics + self.deviceMetrics = deviceMetrics self.isMediaInputExpanded = isMediaInputExpanded } } @@ -110,16 +112,15 @@ final class ChatTagSearchInputPanelNode: ChatInputPanelNode { self.totalMessageCountDisposable?.dispose() } - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, isMediaInputExpanded: Bool) -> CGFloat { + override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, deviceMetrics: DeviceMetrics, isMediaInputExpanded: Bool) -> CGFloat { var leftInset = leftInset + 8.0 var rightInset = rightInset + 8.0 - if bottomInset <= 32.0 { - leftInset += 18.0 - rightInset += 18.0 - } + let compactBottomSideInset = self.compactBottomSideInset(bottomInset: bottomInset, deviceMetrics: deviceMetrics) + leftInset += compactBottomSideInset + rightInset += compactBottomSideInset - let params = Params(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, maxOverlayHeight: maxOverlayHeight, isSecondary: isSecondary, interfaceState: interfaceState, metrics: metrics, isMediaInputExpanded: isMediaInputExpanded) + let params = Params(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, maxOverlayHeight: maxOverlayHeight, isSecondary: isSecondary, interfaceState: interfaceState, metrics: metrics, deviceMetrics: deviceMetrics, isMediaInputExpanded: isMediaInputExpanded) if let currentLayout = self.currentLayout, currentLayout.params == params { return currentLayout.height } diff --git a/submodules/TelegramUI/Sources/ChatUnblockInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatUnblockInputPanelNode.swift index a344369297..6cf9fa6767 100644 --- a/submodules/TelegramUI/Sources/ChatUnblockInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatUnblockInputPanelNode.swift @@ -91,7 +91,7 @@ final class ChatUnblockInputPanelNode: ChatInputPanelNode { self.interfaceInteraction?.unblockPeer() } - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, isMediaInputExpanded: Bool) -> CGFloat { + override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, deviceMetrics: DeviceMetrics, isMediaInputExpanded: Bool) -> CGFloat { if self.presentationInterfaceState != interfaceState { self.presentationInterfaceState = interfaceState } diff --git a/submodules/TelegramUI/Sources/DeleteChatInputPanelNode.swift b/submodules/TelegramUI/Sources/DeleteChatInputPanelNode.swift index f40a2c3a50..91071281f8 100644 --- a/submodules/TelegramUI/Sources/DeleteChatInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/DeleteChatInputPanelNode.swift @@ -36,7 +36,7 @@ final class DeleteChatInputPanelNode: ChatInputPanelNode { self.interfaceInteraction?.deleteChat() } - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, isMediaInputExpanded: Bool) -> CGFloat { + override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, deviceMetrics: DeviceMetrics, isMediaInputExpanded: Bool) -> CGFloat { if self.presentationInterfaceState != interfaceState { self.presentationInterfaceState = interfaceState diff --git a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift index 9c050cddf5..3ff655d255 100644 --- a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift +++ b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift @@ -840,7 +840,9 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu containerTransform = CATransform3DScale(containerTransform, scale, scale, scale) transition.updateTransform(layer: self.containerContainingNode.layer, transform: containerTransform) - transition.updateCornerRadius(node: self.containerContainingNode, cornerRadius: layout.deviceMetrics.screenCornerRadius) + + let containerCornerRadius = max(22.0, layout.deviceMetrics.screenCornerRadius) + transition.updateCornerRadius(node: self.containerContainingNode, cornerRadius: containerCornerRadius) } private var effectiveHeaderHeight: CGFloat { diff --git a/submodules/TelegramUI/Sources/SecretChatHandshakeStatusInputPanelNode.swift b/submodules/TelegramUI/Sources/SecretChatHandshakeStatusInputPanelNode.swift index b8ae461975..bc6d4e0115 100644 --- a/submodules/TelegramUI/Sources/SecretChatHandshakeStatusInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/SecretChatHandshakeStatusInputPanelNode.swift @@ -53,7 +53,7 @@ final class SecretChatHandshakeStatusInputPanelNode: ChatInputPanelNode { self.interfaceInteraction?.unblockPeer() } - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, isMediaInputExpanded: Bool) -> CGFloat { + override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, deviceMetrics: DeviceMetrics, isMediaInputExpanded: Bool) -> CGFloat { self.presentationInterfaceState = interfaceState var text: String? diff --git a/submodules/TelegramUI/Sources/TextLinkHandling.swift b/submodules/TelegramUI/Sources/TextLinkHandling.swift index b6e53647a7..703227e606 100644 --- a/submodules/TelegramUI/Sources/TextLinkHandling.swift +++ b/submodules/TelegramUI/Sources/TextLinkHandling.swift @@ -18,12 +18,15 @@ import UndoUI import BrowserUI func handleTextLinkActionImpl(context: AccountContext, peerId: EnginePeer.Id?, navigateDisposable: MetaDisposable, controller: ViewController, action: TextLinkItemActionType, itemLink: TextLinkItem) { + let presentationData = context.sharedContext.currentPresentationData.with({ $0 }) + let presentImpl: (ViewController, Any?) -> Void = { controllerToPresent, _ in controller.present(controllerToPresent, in: .window(.root)) } let openResolvedPeerImpl: (EnginePeer?, ChatControllerInteractionNavigateToPeer) -> Void = { [weak controller] peer, navigation in - guard let peer = peer else { + guard let peer else { + controller?.present(textAlertController(context: context, updatedPresentationData: nil, title: nil, text: presentationData.strings.Resolve_ErrorNotFound, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) return } context.sharedContext.openResolvedUrl(.peer(peer._asPeer(), navigation), context: context, urlContext: .generic, navigationController: (controller?.navigationController as? NavigationController), forceExternal: false, forceUpdate: false, openPeer: { (peer, navigation) in @@ -73,7 +76,7 @@ func handleTextLinkActionImpl(context: AccountContext, peerId: EnginePeer.Id?, n if let controller = controller { switch result { case let .externalUrl(url): - context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: url, forceExternal: false, presentationData: context.sharedContext.currentPresentationData.with({ $0 }), navigationController: controller.navigationController as? NavigationController, dismissInput: { + context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: url, forceExternal: false, presentationData: presentationData, navigationController: controller.navigationController as? NavigationController, dismissInput: { }) case let .peer(peer, navigation): openResolvedPeerImpl(peer.flatMap(EnginePeer.init), navigation) @@ -100,7 +103,7 @@ func handleTextLinkActionImpl(context: AccountContext, peerId: EnginePeer.Id?, n let sourceLocation = InstantPageSourceLocation(userLocation: peerId.flatMap(MediaResourceUserLocation.peer) ?? .other, peerType: .group) let browserController = context.sharedContext.makeInstantPageController(context: context, webPage: webPage, anchor: anchor, sourceLocation: sourceLocation) (controller.navigationController as? NavigationController)?.pushViewController(browserController, animated: true) - case .boost, .chatFolder, .join, .invoice: + case .boost, .chatFolder, .join, .invoice, .proxy: if let navigationController = controller.navigationController as? NavigationController { openResolvedUrlImpl(result, context: context, urlContext: peerId.flatMap { .chat(peerId: $0, message: nil, updatedPresentationData: nil) } ?? .generic, navigationController: navigationController, forceExternal: false, forceUpdate: false, openPeer: { peer, navigateToPeer in openResolvedPeerImpl(peer, navigateToPeer) @@ -128,7 +131,6 @@ func handleTextLinkActionImpl(context: AccountContext, peerId: EnginePeer.Id?, n })) } - let presentationData = context.sharedContext.currentPresentationData.with { $0 } switch action { case .tap: switch itemLink {