diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 9adce68c74..2dccba4ca3 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -12585,6 +12585,9 @@ Sorry for the inconvenience."; "WebBrowser.Exceptions.ClearConfirmation.Text" = "Are you sure you want to clear this list?"; "WebBrowser.Exceptions.ClearConfirmation.Clear" = "Clear"; +"WebBrowser.ClearCookies.ClearConfirmation.Text" = "Are you sure you want to clear cookies?"; +"WebBrowser.ClearCookies.ClearConfirmation.Clear" = "Clear"; + "WebBrowser.Done" = "Done"; "AccessDenied.LocationWeather" = "Telegram needs access to your location so that you can add the weather widget to your stories.\n\nPlease go to Settings > Privacy > Location Services and set Telegram to ON."; @@ -12649,3 +12652,6 @@ Sorry for the inconvenience."; "Story.Cover" = "Story Cover"; "Story.SaveCover" = "Save Cover"; + +"WebBrowser.DeleteBookmark" = "Delete Bookmark"; +"WebBrowser.RemoveRecent" = "Remove from Recent"; diff --git a/submodules/BrowserUI/Sources/BrowserAddressListComponent.swift b/submodules/BrowserUI/Sources/BrowserAddressListComponent.swift index 2070587445..b22bb333e9 100644 --- a/submodules/BrowserUI/Sources/BrowserAddressListComponent.swift +++ b/submodules/BrowserUI/Sources/BrowserAddressListComponent.swift @@ -8,26 +8,36 @@ import Postbox import TelegramCore import AccountContext import TelegramPresentationData +import ContextUI final class BrowserAddressListComponent: Component { let context: AccountContext let theme: PresentationTheme let strings: PresentationStrings let insets: UIEdgeInsets - let navigateTo: (String) -> Void + let metrics: LayoutMetrics + let addressBarFrame: CGRect + let performAction: ActionSlot + let presentInGlobalOverlay: (ViewController) -> Void init( context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, insets: UIEdgeInsets, - navigateTo: @escaping (String) -> Void + metrics: LayoutMetrics, + addressBarFrame: CGRect, + performAction: ActionSlot, + presentInGlobalOverlay: @escaping (ViewController) -> Void ) { self.context = context self.theme = theme self.strings = strings self.insets = insets - self.navigateTo = navigateTo + self.metrics = metrics + self.addressBarFrame = addressBarFrame + self.performAction = performAction + self.presentInGlobalOverlay = presentInGlobalOverlay } static func ==(lhs: BrowserAddressListComponent, rhs: BrowserAddressListComponent) -> Bool { @@ -43,6 +53,12 @@ final class BrowserAddressListComponent: Component { if lhs.insets != rhs.insets { return false } + if lhs.metrics != rhs.metrics { + return false + } + if lhs.addressBarFrame != rhs.addressBarFrame { + return false + } return true } @@ -109,6 +125,8 @@ final class BrowserAddressListComponent: Component { let bookmarks: [Message] } + private let outerView = UIButton() + private let shadowView = UIImageView() private let backgroundView = UIView() private let scrollView = ScrollView() private let itemContainerView = UIView() @@ -130,13 +148,19 @@ final class BrowserAddressListComponent: Component { override init(frame: CGRect) { super.init(frame: frame) + self.backgroundView.clipsToBounds = true + self.scrollView.alwaysBounceVertical = true self.scrollView.delegate = self self.scrollView.showsVerticalScrollIndicator = false + self.addSubview(self.outerView) + self.addSubview(self.shadowView) self.addSubview(self.backgroundView) - self.addSubview(self.scrollView) + self.backgroundView.addSubview(self.scrollView) self.scrollView.addSubview(self.itemContainerView) + + self.outerView.addTarget(self, action: #selector(self.outerPressed), for: .touchUpInside) } required init?(coder: NSCoder) { @@ -147,6 +171,10 @@ final class BrowserAddressListComponent: Component { self.stateDisposable?.dispose() } + @objc private func outerPressed() { + self.component?.performAction.invoke(.closeAddressBar) + } + func scrollViewDidScroll(_ scrollView: UIScrollView) { if !self.ignoreScrolling { self.updateScrolling(transition: .immediate) @@ -155,6 +183,8 @@ final class BrowserAddressListComponent: Component { func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { self.window?.endEditing(true) + + cancelContextGestures(view: scrollView) } private func updateScrolling(transition: ComponentTransition) { @@ -230,7 +260,7 @@ final class BrowserAddressListComponent: Component { ) if let sectionHeaderView = sectionHeader.view { if sectionHeaderView.superview == nil { - self.addSubview(sectionHeaderView) + self.backgroundView.addSubview(sectionHeaderView) if !transition.animation.isImmediate { sectionHeaderView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25) @@ -289,7 +319,7 @@ final class BrowserAddressListComponent: Component { } } - let navigateTo = component.navigateTo + let performAction = component.performAction let _ = visibleItem.update( transition: itemTransition, component: AnyComponent( @@ -302,8 +332,49 @@ final class BrowserAddressListComponent: Component { insets: component.insets, action: { if let url = webPage?.content.url { - navigateTo(url) + performAction.invoke(.navigateTo(url)) } + }, + contextAction: { [weak self] webPage, message, sourceView, gesture in + guard let self, let component = self.component else { + return + } + + let presentationData = component.context.sharedContext.currentPresentationData.with { $0 } + + var itemList: [ContextMenuItem] = [] + + if let message { + itemList.append(.action(ContextMenuActionItem(text: presentationData.strings.WebBrowser_DeleteBookmark, textColor: .destructive, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) + }, action: { [weak self] _, f in + f(.dismissWithoutContent) + + if let self, let component = self.component { + let _ = component.context.engine.messages.deleteMessagesInteractively(messageIds: [message.id], type: .forEveryone).startStandalone() + } + }))) + } else { + itemList.append(.action(ContextMenuActionItem(text: presentationData.strings.WebBrowser_RemoveRecent, textColor: .destructive, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) + }, action: { [weak self] _, f in + f(.dismissWithoutContent) + + if let self, let component = self.component, let url = webPage.content.url { + let _ = removeRecentlyVisitedLink(engine: component.context.engine, url: url).startStandalone() + } + }))) + } + + let items = ContextController.Items(content: .list(itemList)) + let controller = ContextController( + presentationData: presentationData, + source: .extracted(BrowserAddressListContextExtractedContentSource(contentView: sourceView)), + items: .single(items), + recognizer: nil, + gesture: gesture + ) + component.presentInGlobalOverlay(controller) }) ), environment: {}, @@ -387,7 +458,22 @@ final class BrowserAddressListComponent: Component { self.component = component self.state = state - let resetScrolling = self.scrollView.bounds.width != availableSize.width + self.outerView.isHidden = !component.metrics.isTablet + self.outerView.frame = CGRect(origin: .zero, size: availableSize) + + let containerFrame: CGRect + if component.metrics.isTablet { + let containerSize = CGSize(width: component.addressBarFrame.width + 32.0, height: 540.0) + containerFrame = CGRect(origin: CGPoint(x: floor(component.addressBarFrame.center.x - containerSize.width / 2.0), y: 72.0), size: containerSize) + + self.backgroundView.layer.cornerRadius = 10.0 + } else { + containerFrame = CGRect(origin: .zero, size: availableSize) + + self.backgroundView.layer.cornerRadius = 0.0 + } + + let resetScrolling = self.scrollView.bounds.width != containerFrame.width if themeUpdated { self.backgroundView.backgroundColor = component.theme.list.plainBackgroundColor } @@ -402,16 +488,13 @@ final class BrowserAddressListComponent: Component { message: nil, hasNext: true, insets: .zero, - action: {} + action: {}, + contextAction: nil )), environment: {}, containerSize: CGSize(width: itemsContainerWidth, height: 1000.0) ) - let _ = resetScrolling - let _ = addressItemSize - - var sections: [ItemLayout.Section] = [] if let state = self.stateValue { if !state.recent.isEmpty { @@ -432,37 +515,50 @@ final class BrowserAddressListComponent: Component { } } - let itemLayout = ItemLayout(containerSize: availableSize, insets: .zero, sections: sections) + let itemLayout = ItemLayout(containerSize: containerFrame.size, insets: .zero, sections: sections) self.itemLayout = itemLayout - let containerWidth = availableSize.width - let scrollContentHeight = max(itemLayout.contentHeight, availableSize.height) + let containerWidth = containerFrame.size.width + let scrollContentHeight = max(itemLayout.contentHeight, containerFrame.size.height) self.ignoreScrolling = true - transition.setFrame(view: self.scrollView, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: containerWidth, height: availableSize.height))) + transition.setFrame(view: self.scrollView, frame: CGRect(origin: .zero, size: containerFrame.size)) let contentSize = CGSize(width: containerWidth, height: scrollContentHeight) if contentSize != self.scrollView.contentSize { self.scrollView.contentSize = contentSize } -// let contentInset: UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: bottomPanelHeight + bottomPanelInset, right: 0.0) -// let indicatorInset = UIEdgeInsets(top: max(itemLayout.containerInset, environment.safeInsets.top + navigationHeight), left: 0.0, bottom: contentInset.bottom, right: 0.0) -// if indicatorInset != self.scrollView.scrollIndicatorInsets { -// self.scrollView.scrollIndicatorInsets = indicatorInset -// } -// if contentInset != self.scrollView.contentInset { -// self.scrollView.contentInset = contentInset -// } if resetScrolling { - self.scrollView.bounds = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: containerWidth, height: availableSize.height)) + self.scrollView.bounds = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: containerWidth, height: containerFrame.size.height)) } self.ignoreScrolling = false self.updateScrolling(transition: transition) - transition.setFrame(view: self.backgroundView, frame: CGRect(origin: .zero, size: availableSize)) + transition.setFrame(view: self.backgroundView, frame: containerFrame) transition.setFrame(view: self.itemContainerView, frame: CGRect(origin: .zero, size: CGSize(width: containerWidth, height: scrollContentHeight))) + if component.metrics.isTablet { + transition.setFrame(view: self.shadowView, frame: containerFrame.insetBy(dx: -60.0, dy: -60.0)) + self.shadowView.isHidden = false + if self.shadowView.image == nil { + self.shadowView.image = generateShadowImage() + } + } else { + self.shadowView.isHidden = true + } + return availableSize } + + override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + let result = super.hitTest(point, with: event) + if let component = self.component, component.metrics.isTablet { + let addressFrame = CGRect(origin: CGPoint(x: self.backgroundView.frame.minX, y: self.backgroundView.frame.minY - 48.0), size: CGSize(width: self.backgroundView.frame.width, height: 48.0)) + if addressFrame.contains(point) { + return nil + } + } + return result + } } func makeView() -> View { @@ -473,3 +569,55 @@ final class BrowserAddressListComponent: Component { return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition) } } + +private func generateShadowImage() -> UIImage? { + return generateImage(CGSize(width: 140.0, height: 140.0), rotatedContext: { size, context in + context.clear(CGRect(origin: CGPoint(), size: size)) + + context.saveGState() + context.setShadow(offset: CGSize(), blur: 60.0, color: UIColor(white: 0.0, alpha: 0.4).cgColor) + + let path = UIBezierPath(roundedRect: CGRect(x: 60.0, y: 60.0, width: 20.0, height: 20.0), cornerRadius: 10.0).cgPath + context.addPath(path) + context.fillPath() + + context.restoreGState() + + context.setBlendMode(.clear) + context.addPath(path) + context.fillPath() + })?.stretchableImage(withLeftCapWidth: 70, topCapHeight: 70) +} + +private final class BrowserAddressListContextExtractedContentSource: ContextExtractedContentSource { + let keepInPlace: Bool = false + let ignoreContentTouches: Bool = false + let blurBackground: Bool = true + + private let contentView: ContextExtractedContentContainingView + + init(contentView: ContextExtractedContentContainingView) { + self.contentView = contentView + } + + func takeView() -> ContextControllerTakeViewInfo? { + return ContextControllerTakeViewInfo(containingItem: .view(self.contentView), contentAreaInScreenSpace: UIScreen.main.bounds) + } + + func putBack() -> ContextControllerPutBackViewInfo? { + return ContextControllerPutBackViewInfo(contentAreaInScreenSpace: UIScreen.main.bounds) + } +} + +private func cancelContextGestures(view: UIView) { + if let gestureRecognizers = view.gestureRecognizers { + for gesture in gestureRecognizers { + if let gesture = gesture as? ContextGesture { + gesture.cancel() + } + } + } + for subview in view.subviews { + cancelContextGestures(view: subview) + } +} diff --git a/submodules/BrowserUI/Sources/BrowserAddressListItemComponent.swift b/submodules/BrowserUI/Sources/BrowserAddressListItemComponent.swift index 23a3604a0e..2d01b5de92 100644 --- a/submodules/BrowserUI/Sources/BrowserAddressListItemComponent.swift +++ b/submodules/BrowserUI/Sources/BrowserAddressListItemComponent.swift @@ -9,6 +9,7 @@ import MultilineTextComponent import TelegramPresentationData import PhotoResources import AccountContext +import ContextUI private let iconFont = Font.with(size: 30.0, design: .round, weight: .bold) private let iconTextBackgroundImage = generateStretchableFilledCircleImage(radius: 6.0, color: UIColor(rgb: 0xFF9500)) @@ -21,6 +22,7 @@ final class BrowserAddressListItemComponent: Component { let hasNext: Bool let insets: UIEdgeInsets let action: () -> Void + let contextAction: ((TelegramMediaWebpage, Message?, ContextExtractedContentContainingView, ContextGesture) -> Void)? init( context: AccountContext, @@ -29,7 +31,8 @@ final class BrowserAddressListItemComponent: Component { message: Message?, hasNext: Bool, insets: UIEdgeInsets, - action: @escaping () -> Void + action: @escaping () -> Void, + contextAction: ((TelegramMediaWebpage, Message?, ContextExtractedContentContainingView, ContextGesture) -> Void)? ) { self.context = context self.theme = theme @@ -38,6 +41,7 @@ final class BrowserAddressListItemComponent: Component { self.hasNext = hasNext self.insets = insets self.action = action + self.contextAction = contextAction } static func ==(lhs: BrowserAddressListItemComponent, rhs: BrowserAddressListItemComponent) -> Bool { @@ -56,16 +60,19 @@ final class BrowserAddressListItemComponent: Component { return true } - final class View: UIView { - private let containerButton: HighlightTrackingButton + final class View: ContextControllerSourceView { + private let extractedContainerView = ContextExtractedContentContainingView() + private let containerButton = HighlightTrackingButton() + private let separatorLayer = SimpleLayer() + private var highlightedBackgroundLayer = SimpleLayer() private var emptyIcon: UIImageView? private var emptyLabel: ComponentView? private var icon = TransformImageNode() private let title = ComponentView() private let subtitle = ComponentView() - private let separatorLayer: SimpleLayer + private var isExtractedToContextMenu: Bool = false private var component: BrowserAddressListItemComponent? private weak var state: EmptyComponentState? @@ -73,16 +80,64 @@ final class BrowserAddressListItemComponent: Component { private var currentIconImageRepresentation: TelegramMediaImageRepresentation? override init(frame: CGRect) { - self.separatorLayer = SimpleLayer() - - self.containerButton = HighlightTrackingButton() - super.init(frame: frame) + self.addSubview(self.extractedContainerView) + self.targetViewForActivationProgress = self.extractedContainerView.contentView + + self.highlightedBackgroundLayer.opacity = 0.0 + self.layer.addSublayer(self.separatorLayer) - self.addSubview(self.containerButton) + self.layer.addSublayer(self.highlightedBackgroundLayer) + + self.extractedContainerView.contentView.addSubview(self.containerButton) self.containerButton.addTarget(self, action: #selector(self.pressed), for: .touchUpInside) + + self.containerButton.highligthedChanged = { [weak self] highlighted in + guard let self else { + return + } + if highlighted { + self.superview?.bringSubviewToFront(self) + self.highlightedBackgroundLayer.removeAnimation(forKey: "opacity") + self.highlightedBackgroundLayer.opacity = 1.0 + } else { + self.highlightedBackgroundLayer.opacity = 0.0 + self.highlightedBackgroundLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2) + } + } + + self.extractedContainerView.isExtractedToContextPreviewUpdated = { [weak self] value in + guard let self, let component = self.component else { + return + } + self.containerButton.clipsToBounds = value + self.containerButton.backgroundColor = value ? component.theme.list.plainBackgroundColor : nil + self.containerButton.layer.cornerRadius = value ? 10.0 : 0.0 + } + self.extractedContainerView.willUpdateIsExtractedToContextPreview = { [weak self] value, transition in + guard let self else { + return + } + self.isExtractedToContextMenu = value + + let mappedTransition: ComponentTransition + if value { + mappedTransition = ComponentTransition(transition) + } else { + mappedTransition = ComponentTransition(animation: .curve(duration: 0.2, curve: .easeInOut)) + } + self.state?.updated(transition: mappedTransition) + } + + self.activated = { [weak self] gesture, _ in + guard let self, let component = self.component else { + gesture.cancel() + return + } + component.contextAction?(component.webPage, component.message, self.extractedContainerView, gesture) + } } required init?(coder: NSCoder) { @@ -282,14 +337,22 @@ final class BrowserAddressListItemComponent: Component { } if themeUpdated { + self.highlightedBackgroundLayer.backgroundColor = component.theme.list.itemHighlightedBackgroundColor.cgColor self.separatorLayer.backgroundColor = component.theme.list.itemPlainSeparatorColor.cgColor } + transition.setFrame(layer: self.highlightedBackgroundLayer, frame: CGRect(origin: .zero, size: CGSize(width: availableSize.width, height: height + UIScreenPixel))) transition.setFrame(layer: self.separatorLayer, frame: CGRect(origin: CGPoint(x: leftInset, y: height), size: CGSize(width: availableSize.width - leftInset, height: UIScreenPixel))) self.separatorLayer.isHidden = !component.hasNext let containerFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: availableSize.width, height: height)) transition.setFrame(view: self.containerButton, frame: containerFrame) + transition.setFrame(view: self.extractedContainerView, frame: containerFrame) + transition.setFrame(view: self.extractedContainerView.contentView, frame: containerFrame) + self.extractedContainerView.contentRect = containerFrame + + self.isGestureEnabled = component.contextAction != nil + return CGSize(width: availableSize.width, height: height) } } diff --git a/submodules/BrowserUI/Sources/BrowserNavigationBarComponent.swift b/submodules/BrowserUI/Sources/BrowserNavigationBarComponent.swift index 674b5a7b9c..ab0d7066ce 100644 --- a/submodules/BrowserUI/Sources/BrowserNavigationBarComponent.swift +++ b/submodules/BrowserUI/Sources/BrowserNavigationBarComponent.swift @@ -21,6 +21,14 @@ final class BrowserNavigationBarEnvironment: Equatable { } final class BrowserNavigationBarComponent: CombinedComponent { + public class ExternalState { + public fileprivate(set) var centerItemFrame: CGRect + + public init() { + self.centerItemFrame = .zero + } + } + let backgroundColor: UIColor let separatorColor: UIColor let textColor: UIColor @@ -30,6 +38,7 @@ final class BrowserNavigationBarComponent: CombinedComponent { let height: CGFloat let sideInset: CGFloat let metrics: LayoutMetrics + let externalState: ExternalState? let leftItems: [AnyComponentWithIdentity] let rightItems: [AnyComponentWithIdentity] let centerItem: AnyComponentWithIdentity? @@ -48,6 +57,7 @@ final class BrowserNavigationBarComponent: CombinedComponent { height: CGFloat, sideInset: CGFloat, metrics: LayoutMetrics, + externalState: ExternalState?, leftItems: [AnyComponentWithIdentity], rightItems: [AnyComponentWithIdentity], centerItem: AnyComponentWithIdentity?, @@ -65,6 +75,7 @@ final class BrowserNavigationBarComponent: CombinedComponent { self.height = height self.sideInset = sideInset self.metrics = metrics + self.externalState = externalState self.leftItems = leftItems self.rightItems = rightItems self.centerItem = centerItem @@ -135,14 +146,14 @@ final class BrowserNavigationBarComponent: CombinedComponent { return { context in var availableWidth = context.availableSize.width - let sideInset: CGFloat = 16.0 + context.component.sideInset + let sideInset: CGFloat = (context.component.metrics.isTablet ? 20.0 : 16.0) + context.component.sideInset let collapsedHeight: CGFloat = 24.0 let expandedHeight = context.component.height let contentHeight: CGFloat = expandedHeight * (1.0 - context.component.collapseFraction) + collapsedHeight * context.component.collapseFraction let size = CGSize(width: context.availableSize.width, height: context.component.topInset + contentHeight) - let verticalOffset: CGFloat = context.component.metrics.isTablet ? -3.0 : 0.0 - let itemSpacing: CGFloat = context.component.metrics.isTablet ? 24.0 : 8.0 + let verticalOffset: CGFloat = context.component.metrics.isTablet ? -2.0 : 0.0 + let itemSpacing: CGFloat = context.component.metrics.isTablet ? 26.0 : 8.0 let background = background.update( component: Rectangle(color: context.component.backgroundColor.withAlphaComponent(1.0)), @@ -268,12 +279,15 @@ final class BrowserNavigationBarComponent: CombinedComponent { centerX = centerLeftInset + (context.availableSize.width - centerLeftInset - centerRightInset) / 2.0 } if let centerItem = centerItem { + let centerItemPosition = CGPoint(x: centerX, y: context.component.topInset + contentHeight / 2.0 + verticalOffset) context.add(centerItem - .position(CGPoint(x: centerX, y: context.component.topInset + contentHeight / 2.0 + verticalOffset)) + .position(centerItemPosition) .scale(1.0 - 0.35 * context.component.collapseFraction) .appear(.default(scale: false, alpha: true)) .disappear(.default(scale: false, alpha: true)) ) + + context.component.externalState?.centerItemFrame = centerItem.size.centered(around: centerItemPosition) } if context.component.collapseFraction == 1.0 { diff --git a/submodules/BrowserUI/Sources/BrowserScreen.swift b/submodules/BrowserUI/Sources/BrowserScreen.swift index c63dd013d7..ebd10a37e0 100644 --- a/submodules/BrowserUI/Sources/BrowserScreen.swift +++ b/submodules/BrowserUI/Sources/BrowserScreen.swift @@ -75,6 +75,8 @@ private final class BrowserScreenComponent: CombinedComponent { let toolbar = Child(BrowserToolbarComponent.self) let addressList = Child(BrowserAddressListComponent.self) + let navigationBarExternalState = BrowserNavigationBarComponent.ExternalState() + return { context in let environment = context.environment[ViewControllerComponentContainer.Environment.self].value let performAction = context.component.performAction @@ -311,6 +313,7 @@ private final class BrowserScreenComponent: CombinedComponent { height: environment.navigationHeight - environment.statusBarHeight, sideInset: environment.safeInsets.left, metrics: environment.metrics, + externalState: navigationBarExternalState, leftItems: navigationLeftItems, rightItems: navigationRightItems, centerItem: navigationContent, @@ -401,18 +404,22 @@ private final class BrowserScreenComponent: CombinedComponent { if context.component.presentationState.addressFocused { let addressListSize: CGSize if isTablet { - addressListSize = CGSize(width: 660.0, height: 420.0) + addressListSize = context.availableSize } else { addressListSize = CGSize(width: context.availableSize.width, height: context.availableSize.height - navigationBar.size.height - toolbarSize) } + let controller = environment.controller let addressList = addressList.update( component: BrowserAddressListComponent( context: context.component.context, theme: environment.theme, strings: environment.strings, insets: UIEdgeInsets(top: 0.0, left: environment.safeInsets.left, bottom: 0.0, right: environment.safeInsets.right), - navigateTo: { url in - performAction.invoke(.navigateTo(url)) + metrics: environment.metrics, + addressBarFrame: navigationBarExternalState.centerItemFrame, + performAction: performAction, + presentInGlobalOverlay: { c in + controller()?.presentInGlobalOverlay(c) } ), availableSize: addressListSize, @@ -421,9 +428,7 @@ private final class BrowserScreenComponent: CombinedComponent { if isTablet { context.add(addressList - .position(CGPoint(x: context.availableSize.width / 2.0, y: navigationBar.size.height + addressList.size.height / 2.0 - 3.0)) - .cornerRadius(10.0) - .clipsToBounds(true) + .position(CGPoint(x: context.availableSize.width / 2.0, y: context.availableSize.height / 2.0)) .appear(.default(alpha: true)) .disappear(.default(alpha: true)) ) diff --git a/submodules/DeviceAccess/Sources/DeviceAccess.swift b/submodules/DeviceAccess/Sources/DeviceAccess.swift index 9228902cc0..cfa335f52d 100644 --- a/submodules/DeviceAccess/Sources/DeviceAccess.swift +++ b/submodules/DeviceAccess/Sources/DeviceAccess.swift @@ -353,24 +353,26 @@ public final class DeviceAccess { } else { completion(true) } - } else if [.restricted, .denied].contains(status), let presentationData = presentationData { - let text: String - if case .restricted = status { - text = presentationData.strings.AccessDenied_CameraRestricted - } else { - switch cameraSubject { - case .video: - text = presentationData.strings.AccessDenied_Camera - case .videoCall: - text = presentationData.strings.AccessDenied_VideoCallCamera - case .qrCode: - text = presentationData.strings.AccessDenied_QrCamera - } - } + } else if [.restricted, .denied].contains(status) { completion(false) - present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: presentationData.strings.AccessDenied_Title, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_NotNow, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.AccessDenied_Settings, action: { - openSettings() - })]), nil) + if let presentationData = presentationData { + let text: String + if case .restricted = status { + text = presentationData.strings.AccessDenied_CameraRestricted + } else { + switch cameraSubject { + case .video: + text = presentationData.strings.AccessDenied_Camera + case .videoCall: + text = presentationData.strings.AccessDenied_VideoCallCamera + case .qrCode: + text = presentationData.strings.AccessDenied_QrCamera + } + } + present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: presentationData.strings.AccessDenied_Title, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_NotNow, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.AccessDenied_Settings, action: { + openSettings() + })]), nil) + } } else if case .authorized = status { completion(true) } else { diff --git a/submodules/SettingsUI/Sources/Data and Storage/WebBrowserSettingsController.swift b/submodules/SettingsUI/Sources/Data and Storage/WebBrowserSettingsController.swift index 29a4b1b14e..8a303cdf76 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/WebBrowserSettingsController.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/WebBrowserSettingsController.swift @@ -310,21 +310,35 @@ public func webBrowserSettingsController(context: AccountContext) -> ViewControl let controller = ItemListController(context: context, state: signal) clearCookiesImpl = { [weak controller] in - WKWebsiteDataStore.default().removeData(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(), modifiedSince: Date(timeIntervalSince1970: 0), completionHandler:{}) - let presentationData = context.sharedContext.currentPresentationData.with { $0 } - controller?.present(UndoOverlayController( - presentationData: presentationData, - content: .info( - title: nil, - text: presentationData.strings.WebBrowser_ClearCookies_Succeed, - timeout: nil, - customUndoText: nil - ), - elevatedLayout: false, - position: .bottom, - action: { _ in return false }), in: .current + + let alertController = textAlertController( + context: context, + updatedPresentationData: nil, + title: nil, + text: presentationData.strings.WebBrowser_ClearCookies_ClearConfirmation_Text, + actions: [ + TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), + TextAlertAction(type: .defaultAction, title: presentationData.strings.WebBrowser_ClearCookies_ClearConfirmation_Clear, action: { + WKWebsiteDataStore.default().removeData(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(), modifiedSince: Date(timeIntervalSince1970: 0), completionHandler:{}) + + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + controller?.present(UndoOverlayController( + presentationData: presentationData, + content: .info( + title: nil, + text: presentationData.strings.WebBrowser_ClearCookies_Succeed, + timeout: nil, + customUndoText: nil + ), + elevatedLayout: false, + position: .bottom, + action: { _ in return false }), in: .current + ) + }) + ] ) + controller?.present(alertController, in: .window(.root)) } addExceptionImpl = { [weak controller] in diff --git a/submodules/TelegramUI/Components/MediaEditor/Sources/MediaEditor.swift b/submodules/TelegramUI/Components/MediaEditor/Sources/MediaEditor.swift index e696d413e3..09b076bbd2 100644 --- a/submodules/TelegramUI/Components/MediaEditor/Sources/MediaEditor.swift +++ b/submodules/TelegramUI/Components/MediaEditor/Sources/MediaEditor.swift @@ -1124,9 +1124,8 @@ public final class MediaEditor { self.initialSeekPosition = position return } - if play { - self.renderer.setRate(1.0) - } else { + self.renderer.setRate(1.0) + if !play { self.player?.pause() self.additionalPlayer?.pause() self.audioPlayer?.pause() diff --git a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaCoverScreen.swift b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaCoverScreen.swift index 4a3c7407a8..db9dc21545 100644 --- a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaCoverScreen.swift +++ b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaCoverScreen.swift @@ -431,9 +431,6 @@ final class MediaCoverScreen: ViewController { } func animateOutToEditor(completion: @escaping () -> Void) { - self.controller?.withMediaEditor { mediaEditor in - mediaEditor.play() - } if let view = self.componentHost.view as? MediaCoverScreenComponent.View { view.animateOutToEditor(completion: completion) } diff --git a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorDrafts.swift b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorDrafts.swift index b5c74027ad..d29a7083b9 100644 --- a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorDrafts.swift +++ b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorDrafts.swift @@ -46,7 +46,7 @@ extension MediaEditorScreen { return true } - func saveDraft(id: Int64?) { + func saveDraft(id: Int64?, edit: Bool = false) { guard let subject = self.node.subject, let actualSubject = self.node.actualSubject, let mediaEditor = self.node.mediaEditor else { return } @@ -83,7 +83,9 @@ extension MediaEditorScreen { } if let resultImage = mediaEditor.resultImage { - mediaEditor.seek(0.0, andPlay: false) + if !edit { + mediaEditor.seek(0.0, andPlay: false) + } makeEditorImageComposition(context: self.node.ciContext, postbox: self.context.account.postbox, inputImage: resultImage, dimensions: storyDimensions, values: values, time: .zero, textScale: 2.0, completion: { resultImage in guard let resultImage else { return diff --git a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift index e75f6b39d4..d4f897c57e 100644 --- a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift +++ b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift @@ -6492,6 +6492,8 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate } if self.isEmbeddedEditor && !(hasAnyChanges || hasEntityChanges) { + self.saveDraft(id: randomId, edit: true) + self.completion(MediaEditorScreen.Result(media: nil, mediaAreas: [], caption: caption, coverTimestamp: mediaEditor.values.coverImageTimestamp, options: self.state.privacy, stickers: stickers, randomId: randomId), { [weak self] finished in self?.node.animateOut(finished: true, saveDraft: false, completion: { [weak self] in self?.dismiss() diff --git a/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift b/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift index 1fe793e04b..42f157d5d9 100644 --- a/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift +++ b/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift @@ -2919,7 +2919,7 @@ final class ShareWithPeersScreenComponent: Component { contentTransition.setFrame(view: self.itemContainerView, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: containerWidth, height: itemLayout.contentHeight + footersTotalHeight))) - let scrollContentHeight = max(topInset + itemLayout.contentHeight + containerInset, availableSize.height - containerInset) + let scrollContentHeight = max(topInset + itemLayout.contentHeight + containerInset + bottomPanelHeight, availableSize.height - containerInset) transition.setFrame(view: self.scrollContentView, frame: CGRect(origin: CGPoint(x: 0.0, y: topInset + containerInset), size: CGSize(width: containerWidth, height: itemLayout.contentHeight)))