mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 14:20:20 +00:00
Initial in-app browser implementation
This commit is contained in:
@@ -1,17 +1,16 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import ComponentFlow
|
||||
import TelegramCore
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import Display
|
||||
import TelegramPresentationData
|
||||
import TelegramUIPreferences
|
||||
import AccountContext
|
||||
import WebKit
|
||||
import AppBundle
|
||||
|
||||
final class BrowserWebContent: ASDisplayNode, BrowserContent {
|
||||
final class BrowserWebContent: UIView, BrowserContent, UIScrollViewDelegate {
|
||||
private let webView: WKWebView
|
||||
|
||||
private var _state: BrowserContentState
|
||||
@@ -21,6 +20,8 @@ final class BrowserWebContent: ASDisplayNode, BrowserContent {
|
||||
return self.statePromise.get()
|
||||
}
|
||||
|
||||
var onScrollingUpdate: (ContentScrollingUpdate) -> Void = { _ in }
|
||||
|
||||
init(url: String) {
|
||||
let configuration = WKWebViewConfiguration()
|
||||
|
||||
@@ -40,17 +41,24 @@ final class BrowserWebContent: ASDisplayNode, BrowserContent {
|
||||
title = parsedUrl.host ?? ""
|
||||
}
|
||||
|
||||
self._state = BrowserContentState(title: title, url: url, estimatedProgress: 0.0, isInstant: false)
|
||||
self._state = BrowserContentState(title: title, url: url, estimatedProgress: 0.0, contentType: .webPage)
|
||||
self.statePromise = Promise<BrowserContentState>(self._state)
|
||||
|
||||
super.init()
|
||||
super.init(frame: .zero)
|
||||
|
||||
self.webView.allowsBackForwardNavigationGestures = true
|
||||
self.webView.scrollView.delegate = self
|
||||
self.webView.addObserver(self, forKeyPath: #keyPath(WKWebView.title), options: [], context: nil)
|
||||
self.webView.addObserver(self, forKeyPath: #keyPath(WKWebView.url), options: [], context: nil)
|
||||
self.webView.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: [], context: nil)
|
||||
self.webView.addObserver(self, forKeyPath: #keyPath(WKWebView.canGoBack), options: [], context: nil)
|
||||
self.webView.addObserver(self, forKeyPath: #keyPath(WKWebView.canGoForward), options: [], context: nil)
|
||||
|
||||
self.addSubview(self.webView)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
deinit {
|
||||
@@ -61,12 +69,6 @@ final class BrowserWebContent: ASDisplayNode, BrowserContent {
|
||||
self.webView.removeObserver(self, forKeyPath: #keyPath(WKWebView.canGoForward))
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
self.view.addSubview(self.webView)
|
||||
}
|
||||
|
||||
func setFontSize(_ fontSize: CGFloat) {
|
||||
let js = "document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust='\(Int(fontSize * 100.0))%'"
|
||||
self.webView.evaluateJavaScript(js, completionHandler: nil)
|
||||
@@ -109,7 +111,7 @@ final class BrowserWebContent: ASDisplayNode, BrowserContent {
|
||||
})
|
||||
}
|
||||
|
||||
var previousQuery: String?
|
||||
private var previousQuery: String?
|
||||
func setSearch(_ query: String?, completion: ((Int) -> Void)?) {
|
||||
guard self.previousQuery != query else {
|
||||
return
|
||||
@@ -182,8 +184,15 @@ final class BrowserWebContent: ASDisplayNode, BrowserContent {
|
||||
self.webView.scrollView.setContentOffset(CGPoint(x: 0.0, y: -self.webView.scrollView.contentInset.top), animated: true)
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, insets: UIEdgeInsets, transition: ContainedViewLayoutTransition) {
|
||||
transition.updateFrame(view: self.webView, frame: CGRect(origin: CGPoint(x: 0.0, y: 56.0), size: CGSize(width: size.width, height: size.height - 56.0)))
|
||||
func updateLayout(size: CGSize, insets: UIEdgeInsets, transition: Transition) {
|
||||
var scrollInsets = insets
|
||||
scrollInsets.top = 0.0
|
||||
if self.webView.scrollView.contentInset != insets {
|
||||
self.webView.scrollView.contentInset = scrollInsets
|
||||
self.webView.scrollView.scrollIndicatorInsets = scrollInsets
|
||||
}
|
||||
self.previousScrollingOffset = ScrollingOffsetState(value: self.webView.scrollView.contentOffset.y, isDraggingOrDecelerating: self.webView.scrollView.isDragging || self.webView.scrollView.isDecelerating)
|
||||
transition.setFrame(view: self.webView, frame: CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: size.width, height: size.height - insets.top)))
|
||||
}
|
||||
|
||||
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
||||
@@ -195,15 +204,63 @@ final class BrowserWebContent: ASDisplayNode, BrowserContent {
|
||||
|
||||
if keyPath == "title" {
|
||||
updateState { $0.withUpdatedTitle(self.webView.title ?? "") }
|
||||
} else if keyPath == "url" {
|
||||
} else if keyPath == "URL" {
|
||||
updateState { $0.withUpdatedUrl(self.webView.url?.absoluteString ?? "") }
|
||||
self.didSetupSearch = false
|
||||
} else if keyPath == "estimatedProgress" {
|
||||
updateState { $0.withUpdatedEstimatedProgress(self.webView.estimatedProgress) }
|
||||
} else if keyPath == "canGoBack" {
|
||||
updateState { $0.withUpdatedCanGoBack(self.webView.canGoBack) }
|
||||
self.webView.disablesInteractiveTransitionGestureRecognizer = self.webView.canGoBack
|
||||
} else if keyPath == "canGoForward" {
|
||||
updateState { $0.withUpdatedCanGoForward(self.webView.canGoForward) }
|
||||
}
|
||||
}
|
||||
|
||||
private struct ScrollingOffsetState: Equatable {
|
||||
var value: CGFloat
|
||||
var isDraggingOrDecelerating: Bool
|
||||
}
|
||||
|
||||
private var previousScrollingOffset: ScrollingOffsetState?
|
||||
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
self.updateScrollingOffset(isReset: false, transition: .immediate)
|
||||
}
|
||||
|
||||
private func snapScrollingOffsetToInsets() {
|
||||
let transition = Transition(animation: .curve(duration: 0.4, curve: .spring))
|
||||
self.updateScrollingOffset(isReset: false, transition: transition)
|
||||
}
|
||||
|
||||
public func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
|
||||
if !decelerate {
|
||||
self.snapScrollingOffsetToInsets()
|
||||
}
|
||||
}
|
||||
|
||||
public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
|
||||
self.snapScrollingOffsetToInsets()
|
||||
}
|
||||
|
||||
private func updateScrollingOffset(isReset: Bool, transition: Transition) {
|
||||
let scrollView = self.webView.scrollView
|
||||
let isInteracting = scrollView.isDragging || scrollView.isDecelerating
|
||||
if let previousScrollingOffsetValue = self.previousScrollingOffset {
|
||||
let currentBounds = scrollView.bounds
|
||||
let offsetToTopEdge = max(0.0, currentBounds.minY - 0.0)
|
||||
let offsetToBottomEdge = max(0.0, scrollView.contentSize.height - currentBounds.maxY)
|
||||
|
||||
let relativeOffset = scrollView.contentOffset.y - previousScrollingOffsetValue.value
|
||||
self.onScrollingUpdate(ContentScrollingUpdate(
|
||||
relativeOffset: relativeOffset,
|
||||
absoluteOffsetToTopEdge: offsetToTopEdge,
|
||||
absoluteOffsetToBottomEdge: offsetToBottomEdge,
|
||||
isReset: isReset,
|
||||
isInteracting: isInteracting,
|
||||
transition: transition
|
||||
))
|
||||
}
|
||||
self.previousScrollingOffset = ScrollingOffsetState(value: scrollView.contentOffset.y, isDraggingOrDecelerating: isInteracting)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user