mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Various fixes
This commit is contained in:
parent
c5179bc4a6
commit
cd810b940a
@ -12585,6 +12585,9 @@ Sorry for the inconvenience.";
|
|||||||
"WebBrowser.Exceptions.ClearConfirmation.Text" = "Are you sure you want to clear this list?";
|
"WebBrowser.Exceptions.ClearConfirmation.Text" = "Are you sure you want to clear this list?";
|
||||||
"WebBrowser.Exceptions.ClearConfirmation.Clear" = "Clear";
|
"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";
|
"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.";
|
"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.Cover" = "Story Cover";
|
||||||
"Story.SaveCover" = "Save Cover";
|
"Story.SaveCover" = "Save Cover";
|
||||||
|
|
||||||
|
"WebBrowser.DeleteBookmark" = "Delete Bookmark";
|
||||||
|
"WebBrowser.RemoveRecent" = "Remove from Recent";
|
||||||
|
@ -8,26 +8,36 @@ import Postbox
|
|||||||
import TelegramCore
|
import TelegramCore
|
||||||
import AccountContext
|
import AccountContext
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
|
import ContextUI
|
||||||
|
|
||||||
final class BrowserAddressListComponent: Component {
|
final class BrowserAddressListComponent: Component {
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
let strings: PresentationStrings
|
let strings: PresentationStrings
|
||||||
let insets: UIEdgeInsets
|
let insets: UIEdgeInsets
|
||||||
let navigateTo: (String) -> Void
|
let metrics: LayoutMetrics
|
||||||
|
let addressBarFrame: CGRect
|
||||||
|
let performAction: ActionSlot<BrowserScreen.Action>
|
||||||
|
let presentInGlobalOverlay: (ViewController) -> Void
|
||||||
|
|
||||||
init(
|
init(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
theme: PresentationTheme,
|
theme: PresentationTheme,
|
||||||
strings: PresentationStrings,
|
strings: PresentationStrings,
|
||||||
insets: UIEdgeInsets,
|
insets: UIEdgeInsets,
|
||||||
navigateTo: @escaping (String) -> Void
|
metrics: LayoutMetrics,
|
||||||
|
addressBarFrame: CGRect,
|
||||||
|
performAction: ActionSlot<BrowserScreen.Action>,
|
||||||
|
presentInGlobalOverlay: @escaping (ViewController) -> Void
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
self.insets = insets
|
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 {
|
static func ==(lhs: BrowserAddressListComponent, rhs: BrowserAddressListComponent) -> Bool {
|
||||||
@ -43,6 +53,12 @@ final class BrowserAddressListComponent: Component {
|
|||||||
if lhs.insets != rhs.insets {
|
if lhs.insets != rhs.insets {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.metrics != rhs.metrics {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.addressBarFrame != rhs.addressBarFrame {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,6 +125,8 @@ final class BrowserAddressListComponent: Component {
|
|||||||
let bookmarks: [Message]
|
let bookmarks: [Message]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private let outerView = UIButton()
|
||||||
|
private let shadowView = UIImageView()
|
||||||
private let backgroundView = UIView()
|
private let backgroundView = UIView()
|
||||||
private let scrollView = ScrollView()
|
private let scrollView = ScrollView()
|
||||||
private let itemContainerView = UIView()
|
private let itemContainerView = UIView()
|
||||||
@ -130,13 +148,19 @@ final class BrowserAddressListComponent: Component {
|
|||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
self.backgroundView.clipsToBounds = true
|
||||||
|
|
||||||
self.scrollView.alwaysBounceVertical = true
|
self.scrollView.alwaysBounceVertical = true
|
||||||
self.scrollView.delegate = self
|
self.scrollView.delegate = self
|
||||||
self.scrollView.showsVerticalScrollIndicator = false
|
self.scrollView.showsVerticalScrollIndicator = false
|
||||||
|
|
||||||
|
self.addSubview(self.outerView)
|
||||||
|
self.addSubview(self.shadowView)
|
||||||
self.addSubview(self.backgroundView)
|
self.addSubview(self.backgroundView)
|
||||||
self.addSubview(self.scrollView)
|
self.backgroundView.addSubview(self.scrollView)
|
||||||
self.scrollView.addSubview(self.itemContainerView)
|
self.scrollView.addSubview(self.itemContainerView)
|
||||||
|
|
||||||
|
self.outerView.addTarget(self, action: #selector(self.outerPressed), for: .touchUpInside)
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
@ -147,6 +171,10 @@ final class BrowserAddressListComponent: Component {
|
|||||||
self.stateDisposable?.dispose()
|
self.stateDisposable?.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc private func outerPressed() {
|
||||||
|
self.component?.performAction.invoke(.closeAddressBar)
|
||||||
|
}
|
||||||
|
|
||||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||||
if !self.ignoreScrolling {
|
if !self.ignoreScrolling {
|
||||||
self.updateScrolling(transition: .immediate)
|
self.updateScrolling(transition: .immediate)
|
||||||
@ -155,6 +183,8 @@ final class BrowserAddressListComponent: Component {
|
|||||||
|
|
||||||
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
|
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
|
||||||
self.window?.endEditing(true)
|
self.window?.endEditing(true)
|
||||||
|
|
||||||
|
cancelContextGestures(view: scrollView)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateScrolling(transition: ComponentTransition) {
|
private func updateScrolling(transition: ComponentTransition) {
|
||||||
@ -230,7 +260,7 @@ final class BrowserAddressListComponent: Component {
|
|||||||
)
|
)
|
||||||
if let sectionHeaderView = sectionHeader.view {
|
if let sectionHeaderView = sectionHeader.view {
|
||||||
if sectionHeaderView.superview == nil {
|
if sectionHeaderView.superview == nil {
|
||||||
self.addSubview(sectionHeaderView)
|
self.backgroundView.addSubview(sectionHeaderView)
|
||||||
|
|
||||||
if !transition.animation.isImmediate {
|
if !transition.animation.isImmediate {
|
||||||
sectionHeaderView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
|
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(
|
let _ = visibleItem.update(
|
||||||
transition: itemTransition,
|
transition: itemTransition,
|
||||||
component: AnyComponent(
|
component: AnyComponent(
|
||||||
@ -302,8 +332,49 @@ final class BrowserAddressListComponent: Component {
|
|||||||
insets: component.insets,
|
insets: component.insets,
|
||||||
action: {
|
action: {
|
||||||
if let url = webPage?.content.url {
|
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: {},
|
environment: {},
|
||||||
@ -387,7 +458,22 @@ final class BrowserAddressListComponent: Component {
|
|||||||
self.component = component
|
self.component = component
|
||||||
self.state = state
|
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 {
|
if themeUpdated {
|
||||||
self.backgroundView.backgroundColor = component.theme.list.plainBackgroundColor
|
self.backgroundView.backgroundColor = component.theme.list.plainBackgroundColor
|
||||||
}
|
}
|
||||||
@ -402,16 +488,13 @@ final class BrowserAddressListComponent: Component {
|
|||||||
message: nil,
|
message: nil,
|
||||||
hasNext: true,
|
hasNext: true,
|
||||||
insets: .zero,
|
insets: .zero,
|
||||||
action: {}
|
action: {},
|
||||||
|
contextAction: nil
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
containerSize: CGSize(width: itemsContainerWidth, height: 1000.0)
|
containerSize: CGSize(width: itemsContainerWidth, height: 1000.0)
|
||||||
)
|
)
|
||||||
|
|
||||||
let _ = resetScrolling
|
|
||||||
let _ = addressItemSize
|
|
||||||
|
|
||||||
|
|
||||||
var sections: [ItemLayout.Section] = []
|
var sections: [ItemLayout.Section] = []
|
||||||
if let state = self.stateValue {
|
if let state = self.stateValue {
|
||||||
if !state.recent.isEmpty {
|
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
|
self.itemLayout = itemLayout
|
||||||
|
|
||||||
let containerWidth = availableSize.width
|
let containerWidth = containerFrame.size.width
|
||||||
let scrollContentHeight = max(itemLayout.contentHeight, availableSize.height)
|
let scrollContentHeight = max(itemLayout.contentHeight, containerFrame.size.height)
|
||||||
|
|
||||||
self.ignoreScrolling = true
|
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)
|
let contentSize = CGSize(width: containerWidth, height: scrollContentHeight)
|
||||||
if contentSize != self.scrollView.contentSize {
|
if contentSize != self.scrollView.contentSize {
|
||||||
self.scrollView.contentSize = 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 {
|
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.ignoreScrolling = false
|
||||||
self.updateScrolling(transition: transition)
|
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)))
|
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
|
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 {
|
func makeView() -> View {
|
||||||
@ -473,3 +569,55 @@ final class BrowserAddressListComponent: Component {
|
|||||||
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -9,6 +9,7 @@ import MultilineTextComponent
|
|||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
import PhotoResources
|
import PhotoResources
|
||||||
import AccountContext
|
import AccountContext
|
||||||
|
import ContextUI
|
||||||
|
|
||||||
private let iconFont = Font.with(size: 30.0, design: .round, weight: .bold)
|
private let iconFont = Font.with(size: 30.0, design: .round, weight: .bold)
|
||||||
private let iconTextBackgroundImage = generateStretchableFilledCircleImage(radius: 6.0, color: UIColor(rgb: 0xFF9500))
|
private let iconTextBackgroundImage = generateStretchableFilledCircleImage(radius: 6.0, color: UIColor(rgb: 0xFF9500))
|
||||||
@ -21,6 +22,7 @@ final class BrowserAddressListItemComponent: Component {
|
|||||||
let hasNext: Bool
|
let hasNext: Bool
|
||||||
let insets: UIEdgeInsets
|
let insets: UIEdgeInsets
|
||||||
let action: () -> Void
|
let action: () -> Void
|
||||||
|
let contextAction: ((TelegramMediaWebpage, Message?, ContextExtractedContentContainingView, ContextGesture) -> Void)?
|
||||||
|
|
||||||
init(
|
init(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
@ -29,7 +31,8 @@ final class BrowserAddressListItemComponent: Component {
|
|||||||
message: Message?,
|
message: Message?,
|
||||||
hasNext: Bool,
|
hasNext: Bool,
|
||||||
insets: UIEdgeInsets,
|
insets: UIEdgeInsets,
|
||||||
action: @escaping () -> Void
|
action: @escaping () -> Void,
|
||||||
|
contextAction: ((TelegramMediaWebpage, Message?, ContextExtractedContentContainingView, ContextGesture) -> Void)?
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
@ -38,6 +41,7 @@ final class BrowserAddressListItemComponent: Component {
|
|||||||
self.hasNext = hasNext
|
self.hasNext = hasNext
|
||||||
self.insets = insets
|
self.insets = insets
|
||||||
self.action = action
|
self.action = action
|
||||||
|
self.contextAction = contextAction
|
||||||
}
|
}
|
||||||
|
|
||||||
static func ==(lhs: BrowserAddressListItemComponent, rhs: BrowserAddressListItemComponent) -> Bool {
|
static func ==(lhs: BrowserAddressListItemComponent, rhs: BrowserAddressListItemComponent) -> Bool {
|
||||||
@ -56,16 +60,19 @@ final class BrowserAddressListItemComponent: Component {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
final class View: UIView {
|
final class View: ContextControllerSourceView {
|
||||||
private let containerButton: HighlightTrackingButton
|
private let extractedContainerView = ContextExtractedContentContainingView()
|
||||||
|
private let containerButton = HighlightTrackingButton()
|
||||||
|
|
||||||
|
private let separatorLayer = SimpleLayer()
|
||||||
|
private var highlightedBackgroundLayer = SimpleLayer()
|
||||||
private var emptyIcon: UIImageView?
|
private var emptyIcon: UIImageView?
|
||||||
private var emptyLabel: ComponentView<Empty>?
|
private var emptyLabel: ComponentView<Empty>?
|
||||||
private var icon = TransformImageNode()
|
private var icon = TransformImageNode()
|
||||||
private let title = ComponentView<Empty>()
|
private let title = ComponentView<Empty>()
|
||||||
private let subtitle = ComponentView<Empty>()
|
private let subtitle = ComponentView<Empty>()
|
||||||
|
|
||||||
private let separatorLayer: SimpleLayer
|
private var isExtractedToContextMenu: Bool = false
|
||||||
|
|
||||||
private var component: BrowserAddressListItemComponent?
|
private var component: BrowserAddressListItemComponent?
|
||||||
private weak var state: EmptyComponentState?
|
private weak var state: EmptyComponentState?
|
||||||
@ -73,16 +80,64 @@ final class BrowserAddressListItemComponent: Component {
|
|||||||
private var currentIconImageRepresentation: TelegramMediaImageRepresentation?
|
private var currentIconImageRepresentation: TelegramMediaImageRepresentation?
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
self.separatorLayer = SimpleLayer()
|
|
||||||
|
|
||||||
self.containerButton = HighlightTrackingButton()
|
|
||||||
|
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
self.addSubview(self.extractedContainerView)
|
||||||
|
self.targetViewForActivationProgress = self.extractedContainerView.contentView
|
||||||
|
|
||||||
|
self.highlightedBackgroundLayer.opacity = 0.0
|
||||||
|
|
||||||
self.layer.addSublayer(self.separatorLayer)
|
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.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) {
|
required init?(coder: NSCoder) {
|
||||||
@ -282,14 +337,22 @@ final class BrowserAddressListItemComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if themeUpdated {
|
if themeUpdated {
|
||||||
|
self.highlightedBackgroundLayer.backgroundColor = component.theme.list.itemHighlightedBackgroundColor.cgColor
|
||||||
self.separatorLayer.backgroundColor = component.theme.list.itemPlainSeparatorColor.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)))
|
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
|
self.separatorLayer.isHidden = !component.hasNext
|
||||||
|
|
||||||
let containerFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: availableSize.width, height: height))
|
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.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)
|
return CGSize(width: availableSize.width, height: height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,14 @@ final class BrowserNavigationBarEnvironment: Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final class BrowserNavigationBarComponent: CombinedComponent {
|
final class BrowserNavigationBarComponent: CombinedComponent {
|
||||||
|
public class ExternalState {
|
||||||
|
public fileprivate(set) var centerItemFrame: CGRect
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
self.centerItemFrame = .zero
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let backgroundColor: UIColor
|
let backgroundColor: UIColor
|
||||||
let separatorColor: UIColor
|
let separatorColor: UIColor
|
||||||
let textColor: UIColor
|
let textColor: UIColor
|
||||||
@ -30,6 +38,7 @@ final class BrowserNavigationBarComponent: CombinedComponent {
|
|||||||
let height: CGFloat
|
let height: CGFloat
|
||||||
let sideInset: CGFloat
|
let sideInset: CGFloat
|
||||||
let metrics: LayoutMetrics
|
let metrics: LayoutMetrics
|
||||||
|
let externalState: ExternalState?
|
||||||
let leftItems: [AnyComponentWithIdentity<Empty>]
|
let leftItems: [AnyComponentWithIdentity<Empty>]
|
||||||
let rightItems: [AnyComponentWithIdentity<Empty>]
|
let rightItems: [AnyComponentWithIdentity<Empty>]
|
||||||
let centerItem: AnyComponentWithIdentity<BrowserNavigationBarEnvironment>?
|
let centerItem: AnyComponentWithIdentity<BrowserNavigationBarEnvironment>?
|
||||||
@ -48,6 +57,7 @@ final class BrowserNavigationBarComponent: CombinedComponent {
|
|||||||
height: CGFloat,
|
height: CGFloat,
|
||||||
sideInset: CGFloat,
|
sideInset: CGFloat,
|
||||||
metrics: LayoutMetrics,
|
metrics: LayoutMetrics,
|
||||||
|
externalState: ExternalState?,
|
||||||
leftItems: [AnyComponentWithIdentity<Empty>],
|
leftItems: [AnyComponentWithIdentity<Empty>],
|
||||||
rightItems: [AnyComponentWithIdentity<Empty>],
|
rightItems: [AnyComponentWithIdentity<Empty>],
|
||||||
centerItem: AnyComponentWithIdentity<BrowserNavigationBarEnvironment>?,
|
centerItem: AnyComponentWithIdentity<BrowserNavigationBarEnvironment>?,
|
||||||
@ -65,6 +75,7 @@ final class BrowserNavigationBarComponent: CombinedComponent {
|
|||||||
self.height = height
|
self.height = height
|
||||||
self.sideInset = sideInset
|
self.sideInset = sideInset
|
||||||
self.metrics = metrics
|
self.metrics = metrics
|
||||||
|
self.externalState = externalState
|
||||||
self.leftItems = leftItems
|
self.leftItems = leftItems
|
||||||
self.rightItems = rightItems
|
self.rightItems = rightItems
|
||||||
self.centerItem = centerItem
|
self.centerItem = centerItem
|
||||||
@ -135,14 +146,14 @@ final class BrowserNavigationBarComponent: CombinedComponent {
|
|||||||
|
|
||||||
return { context in
|
return { context in
|
||||||
var availableWidth = context.availableSize.width
|
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 collapsedHeight: CGFloat = 24.0
|
||||||
let expandedHeight = context.component.height
|
let expandedHeight = context.component.height
|
||||||
let contentHeight: CGFloat = expandedHeight * (1.0 - context.component.collapseFraction) + collapsedHeight * context.component.collapseFraction
|
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 size = CGSize(width: context.availableSize.width, height: context.component.topInset + contentHeight)
|
||||||
let verticalOffset: CGFloat = context.component.metrics.isTablet ? -3.0 : 0.0
|
let verticalOffset: CGFloat = context.component.metrics.isTablet ? -2.0 : 0.0
|
||||||
let itemSpacing: CGFloat = context.component.metrics.isTablet ? 24.0 : 8.0
|
let itemSpacing: CGFloat = context.component.metrics.isTablet ? 26.0 : 8.0
|
||||||
|
|
||||||
let background = background.update(
|
let background = background.update(
|
||||||
component: Rectangle(color: context.component.backgroundColor.withAlphaComponent(1.0)),
|
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
|
centerX = centerLeftInset + (context.availableSize.width - centerLeftInset - centerRightInset) / 2.0
|
||||||
}
|
}
|
||||||
if let centerItem = centerItem {
|
if let centerItem = centerItem {
|
||||||
|
let centerItemPosition = CGPoint(x: centerX, y: context.component.topInset + contentHeight / 2.0 + verticalOffset)
|
||||||
context.add(centerItem
|
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)
|
.scale(1.0 - 0.35 * context.component.collapseFraction)
|
||||||
.appear(.default(scale: false, alpha: true))
|
.appear(.default(scale: false, alpha: true))
|
||||||
.disappear(.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 {
|
if context.component.collapseFraction == 1.0 {
|
||||||
|
@ -75,6 +75,8 @@ private final class BrowserScreenComponent: CombinedComponent {
|
|||||||
let toolbar = Child(BrowserToolbarComponent.self)
|
let toolbar = Child(BrowserToolbarComponent.self)
|
||||||
let addressList = Child(BrowserAddressListComponent.self)
|
let addressList = Child(BrowserAddressListComponent.self)
|
||||||
|
|
||||||
|
let navigationBarExternalState = BrowserNavigationBarComponent.ExternalState()
|
||||||
|
|
||||||
return { context in
|
return { context in
|
||||||
let environment = context.environment[ViewControllerComponentContainer.Environment.self].value
|
let environment = context.environment[ViewControllerComponentContainer.Environment.self].value
|
||||||
let performAction = context.component.performAction
|
let performAction = context.component.performAction
|
||||||
@ -311,6 +313,7 @@ private final class BrowserScreenComponent: CombinedComponent {
|
|||||||
height: environment.navigationHeight - environment.statusBarHeight,
|
height: environment.navigationHeight - environment.statusBarHeight,
|
||||||
sideInset: environment.safeInsets.left,
|
sideInset: environment.safeInsets.left,
|
||||||
metrics: environment.metrics,
|
metrics: environment.metrics,
|
||||||
|
externalState: navigationBarExternalState,
|
||||||
leftItems: navigationLeftItems,
|
leftItems: navigationLeftItems,
|
||||||
rightItems: navigationRightItems,
|
rightItems: navigationRightItems,
|
||||||
centerItem: navigationContent,
|
centerItem: navigationContent,
|
||||||
@ -401,18 +404,22 @@ private final class BrowserScreenComponent: CombinedComponent {
|
|||||||
if context.component.presentationState.addressFocused {
|
if context.component.presentationState.addressFocused {
|
||||||
let addressListSize: CGSize
|
let addressListSize: CGSize
|
||||||
if isTablet {
|
if isTablet {
|
||||||
addressListSize = CGSize(width: 660.0, height: 420.0)
|
addressListSize = context.availableSize
|
||||||
} else {
|
} else {
|
||||||
addressListSize = CGSize(width: context.availableSize.width, height: context.availableSize.height - navigationBar.size.height - toolbarSize)
|
addressListSize = CGSize(width: context.availableSize.width, height: context.availableSize.height - navigationBar.size.height - toolbarSize)
|
||||||
}
|
}
|
||||||
|
let controller = environment.controller
|
||||||
let addressList = addressList.update(
|
let addressList = addressList.update(
|
||||||
component: BrowserAddressListComponent(
|
component: BrowserAddressListComponent(
|
||||||
context: context.component.context,
|
context: context.component.context,
|
||||||
theme: environment.theme,
|
theme: environment.theme,
|
||||||
strings: environment.strings,
|
strings: environment.strings,
|
||||||
insets: UIEdgeInsets(top: 0.0, left: environment.safeInsets.left, bottom: 0.0, right: environment.safeInsets.right),
|
insets: UIEdgeInsets(top: 0.0, left: environment.safeInsets.left, bottom: 0.0, right: environment.safeInsets.right),
|
||||||
navigateTo: { url in
|
metrics: environment.metrics,
|
||||||
performAction.invoke(.navigateTo(url))
|
addressBarFrame: navigationBarExternalState.centerItemFrame,
|
||||||
|
performAction: performAction,
|
||||||
|
presentInGlobalOverlay: { c in
|
||||||
|
controller()?.presentInGlobalOverlay(c)
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
availableSize: addressListSize,
|
availableSize: addressListSize,
|
||||||
@ -421,9 +428,7 @@ private final class BrowserScreenComponent: CombinedComponent {
|
|||||||
|
|
||||||
if isTablet {
|
if isTablet {
|
||||||
context.add(addressList
|
context.add(addressList
|
||||||
.position(CGPoint(x: context.availableSize.width / 2.0, y: navigationBar.size.height + addressList.size.height / 2.0 - 3.0))
|
.position(CGPoint(x: context.availableSize.width / 2.0, y: context.availableSize.height / 2.0))
|
||||||
.cornerRadius(10.0)
|
|
||||||
.clipsToBounds(true)
|
|
||||||
.appear(.default(alpha: true))
|
.appear(.default(alpha: true))
|
||||||
.disappear(.default(alpha: true))
|
.disappear(.default(alpha: true))
|
||||||
)
|
)
|
||||||
|
@ -353,24 +353,26 @@ public final class DeviceAccess {
|
|||||||
} else {
|
} else {
|
||||||
completion(true)
|
completion(true)
|
||||||
}
|
}
|
||||||
} else if [.restricted, .denied].contains(status), let presentationData = presentationData {
|
} else if [.restricted, .denied].contains(status) {
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
completion(false)
|
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: {
|
if let presentationData = presentationData {
|
||||||
openSettings()
|
let text: String
|
||||||
})]), nil)
|
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 {
|
} else if case .authorized = status {
|
||||||
completion(true)
|
completion(true)
|
||||||
} else {
|
} else {
|
||||||
|
@ -310,21 +310,35 @@ public func webBrowserSettingsController(context: AccountContext) -> ViewControl
|
|||||||
let controller = ItemListController(context: context, state: signal)
|
let controller = ItemListController(context: context, state: signal)
|
||||||
|
|
||||||
clearCookiesImpl = { [weak controller] in
|
clearCookiesImpl = { [weak controller] in
|
||||||
WKWebsiteDataStore.default().removeData(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(), modifiedSince: Date(timeIntervalSince1970: 0), completionHandler:{})
|
|
||||||
|
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
controller?.present(UndoOverlayController(
|
|
||||||
presentationData: presentationData,
|
let alertController = textAlertController(
|
||||||
content: .info(
|
context: context,
|
||||||
title: nil,
|
updatedPresentationData: nil,
|
||||||
text: presentationData.strings.WebBrowser_ClearCookies_Succeed,
|
title: nil,
|
||||||
timeout: nil,
|
text: presentationData.strings.WebBrowser_ClearCookies_ClearConfirmation_Text,
|
||||||
customUndoText: nil
|
actions: [
|
||||||
),
|
TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}),
|
||||||
elevatedLayout: false,
|
TextAlertAction(type: .defaultAction, title: presentationData.strings.WebBrowser_ClearCookies_ClearConfirmation_Clear, action: {
|
||||||
position: .bottom,
|
WKWebsiteDataStore.default().removeData(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(), modifiedSince: Date(timeIntervalSince1970: 0), completionHandler:{})
|
||||||
action: { _ in return false }), in: .current
|
|
||||||
|
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
|
addExceptionImpl = { [weak controller] in
|
||||||
|
@ -1124,9 +1124,8 @@ public final class MediaEditor {
|
|||||||
self.initialSeekPosition = position
|
self.initialSeekPosition = position
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if play {
|
self.renderer.setRate(1.0)
|
||||||
self.renderer.setRate(1.0)
|
if !play {
|
||||||
} else {
|
|
||||||
self.player?.pause()
|
self.player?.pause()
|
||||||
self.additionalPlayer?.pause()
|
self.additionalPlayer?.pause()
|
||||||
self.audioPlayer?.pause()
|
self.audioPlayer?.pause()
|
||||||
|
@ -431,9 +431,6 @@ final class MediaCoverScreen: ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func animateOutToEditor(completion: @escaping () -> Void) {
|
func animateOutToEditor(completion: @escaping () -> Void) {
|
||||||
self.controller?.withMediaEditor { mediaEditor in
|
|
||||||
mediaEditor.play()
|
|
||||||
}
|
|
||||||
if let view = self.componentHost.view as? MediaCoverScreenComponent.View {
|
if let view = self.componentHost.view as? MediaCoverScreenComponent.View {
|
||||||
view.animateOutToEditor(completion: completion)
|
view.animateOutToEditor(completion: completion)
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ extension MediaEditorScreen {
|
|||||||
return true
|
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 {
|
guard let subject = self.node.subject, let actualSubject = self.node.actualSubject, let mediaEditor = self.node.mediaEditor else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -83,7 +83,9 @@ extension MediaEditorScreen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let resultImage = mediaEditor.resultImage {
|
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
|
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 {
|
guard let resultImage else {
|
||||||
return
|
return
|
||||||
|
@ -6492,6 +6492,8 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.isEmbeddedEditor && !(hasAnyChanges || hasEntityChanges) {
|
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.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?.node.animateOut(finished: true, saveDraft: false, completion: { [weak self] in
|
||||||
self?.dismiss()
|
self?.dismiss()
|
||||||
|
@ -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)))
|
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)))
|
transition.setFrame(view: self.scrollContentView, frame: CGRect(origin: CGPoint(x: 0.0, y: topInset + containerInset), size: CGSize(width: containerWidth, height: itemLayout.contentHeight)))
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user