chore: migrate to new version + fixed several critical bugs

- Migrated project to latest Telegram iOS base (v12.3.2+)
- Fixed circular dependency between GhostModeManager and MiscSettingsManager
- Fixed multiple Bazel build configuration errors (select() default conditions)
- Fixed duplicate type definitions in PeerInfoScreen
- Fixed swiftmodule directory resolution in build scripts
- Added Ghostgram Settings tab in main Settings menu with all 5 features
- Cleared sensitive credentials from config.json (template-only now)
- Excluded bazel-cache from version control
This commit is contained in:
ichmagmaus 812
2026-02-23 23:04:32 +01:00
parent 703e291bcb
commit db53826061
1017 changed files with 62337 additions and 40559 deletions
+7
View File
@@ -50,6 +50,13 @@ swift_library(
"//submodules/TelegramUI/Components/ListActionItemComponent",
"//submodules/Utils/DeviceModel",
"//submodules/LegacyMediaPickerUI",
"//submodules/TelegramUI/Components/AlertComponent",
"//submodules/TelegramUI/Components/GlassBackgroundComponent",
"//submodules/TelegramUI/Components/EdgeEffect",
"//submodules/TelegramUI/Components/ButtonComponent",
"//submodules/TelegramUI/Components/GlassBarButtonComponent",
"//submodules/TelegramUI/Components/SearchInputPanelComponent",
"//submodules/TelegramUI/Components/GlassControls",
],
visibility = [
"//visibility:public",
@@ -9,6 +9,9 @@ import AccountContext
import BundleIconComponent
import MultilineTextComponent
import UrlEscaping
import GlassBackgroundComponent
import GlassBarButtonComponent
import EdgeEffect
final class AddressBarContentComponent: Component {
public typealias EnvironmentType = BrowserNavigationBarEnvironment
@@ -19,6 +22,8 @@ final class AddressBarContentComponent: Component {
let url: String
let isSecure: Bool
let isExpanded: Bool
let readingProgress: CGFloat
let loadingProgress: Double?
let performAction: ActionSlot<BrowserScreen.Action>
init(
@@ -28,6 +33,8 @@ final class AddressBarContentComponent: Component {
url: String,
isSecure: Bool,
isExpanded: Bool,
readingProgress: CGFloat,
loadingProgress: Double?,
performAction: ActionSlot<BrowserScreen.Action>
) {
self.theme = theme
@@ -36,6 +43,8 @@ final class AddressBarContentComponent: Component {
self.url = url
self.isSecure = isSecure
self.isExpanded = isExpanded
self.readingProgress = readingProgress
self.loadingProgress = loadingProgress
self.performAction = performAction
}
@@ -58,6 +67,12 @@ final class AddressBarContentComponent: Component {
if lhs.isExpanded != rhs.isExpanded {
return false
}
if lhs.readingProgress != rhs.readingProgress {
return false
}
if lhs.loadingProgress != rhs.loadingProgress {
return false
}
return true
}
@@ -85,6 +100,8 @@ final class AddressBarContentComponent: Component {
var isSecure: Bool
var collapseFraction: CGFloat
var isTablet: Bool
var readingProgress: CGFloat
var loadingProgress: Double?
static func ==(lhs: Params, rhs: Params) -> Bool {
if lhs.theme !== rhs.theme {
@@ -111,26 +128,33 @@ final class AddressBarContentComponent: Component {
if lhs.isTablet != rhs.isTablet {
return false
}
if lhs.readingProgress != rhs.readingProgress {
return false
}
if lhs.loadingProgress != rhs.loadingProgress {
return false
}
return true
}
}
private let activated: (Bool) -> Void = { _ in }
private let deactivated: (Bool) -> Void = { _ in }
private let backgroundLayer: SimpleLayer
private let iconView: UIImageView
private let backgroundView: GlassBackgroundView
private let clearIconView: UIImageView
private let clearIconButton: HighlightTrackingButton
private let cancelButtonTitle: ComponentView<Empty>
private let cancelButton: HighlightTrackingButton
private let cancelButton = ComponentView<Empty>()
private var placeholderContent = ComponentView<Empty>()
private var titleContent = ComponentView<Empty>()
private let clippingView = UIView()
private var loadingProgress = ComponentView<Empty>()
private var readingProgressView = UIView()
private var textFrame: CGRect?
private var textField: TextField?
@@ -144,50 +168,30 @@ final class AddressBarContentComponent: Component {
}
init() {
self.backgroundLayer = SimpleLayer()
self.iconView = UIImageView()
self.backgroundView = GlassBackgroundView()
self.clearIconView = UIImageView()
self.clearIconButton = HighlightableButton()
self.clearIconView.isHidden = false
self.clearIconButton.isHidden = false
self.cancelButtonTitle = ComponentView()
self.cancelButton = HighlightTrackingButton()
super.init(frame: CGRect())
self.layer.addSublayer(self.backgroundLayer)
self.clippingView.clipsToBounds = true
self.addSubview(self.iconView)
self.addSubview(self.clearIconView)
self.addSubview(self.clearIconButton)
self.addSubview(self.backgroundView)
self.backgroundView.contentView.addSubview(self.clippingView)
self.clippingView.addSubview(self.readingProgressView)
self.backgroundView.contentView.addSubview(self.clearIconView)
self.backgroundView.contentView.addSubview(self.clearIconButton)
self.addSubview(self.cancelButton)
self.clipsToBounds = true
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))
self.tapRecognizer = tapRecognizer
self.addGestureRecognizer(tapRecognizer)
self.cancelButton.highligthedChanged = { [weak self] highlighted in
if let strongSelf = self {
if highlighted {
if let cancelButtonTitleView = strongSelf.cancelButtonTitle.view {
cancelButtonTitleView.layer.removeAnimation(forKey: "opacity")
cancelButtonTitleView.alpha = 0.4
}
} else {
if let cancelButtonTitleView = strongSelf.cancelButtonTitle.view {
cancelButtonTitleView.alpha = 1.0
cancelButtonTitleView.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
}
}
}
}
self.cancelButton.addTarget(self, action: #selector(self.cancelPressed), for: .touchUpInside)
self.clearIconButton.highligthedChanged = { [weak self] highlighted in
if let strongSelf = self {
if highlighted {
@@ -263,11 +267,16 @@ final class AddressBarContentComponent: Component {
self.placeholderContent.view?.isHidden = !text.isEmpty
if let params = self.params {
self.update(theme: params.theme, strings: params.strings, size: params.size, isActive: params.isActive, title: params.title, isSecure: params.isSecure, collapseFraction: params.collapseFraction, isTablet: params.isTablet, transition: .immediate)
self.update(theme: params.theme, strings: params.strings, size: params.size, isActive: params.isActive, title: params.title, isSecure: params.isSecure, collapseFraction: params.collapseFraction, isTablet: params.isTablet, readingProgress: params.readingProgress, loadingProgress: params.loadingProgress, transition: .immediate)
}
}
func update(component: AddressBarContentComponent, availableSize: CGSize, environment: Environment<BrowserNavigationBarEnvironment>, transition: ComponentTransition) -> CGSize {
func update(
component: AddressBarContentComponent,
availableSize: CGSize,
environment: Environment<BrowserNavigationBarEnvironment>,
transition: ComponentTransition
) -> CGSize {
let collapseFraction = environment[BrowserNavigationBarEnvironment.self].fraction
let wasExpanded = self.component?.isExpanded ?? false
@@ -282,12 +291,36 @@ final class AddressBarContentComponent: Component {
let isActive = self.textField?.isFirstResponder ?? false
let title = getDisplayUrl(component.url, hostOnly: true)
self.update(theme: component.theme, strings: component.strings, size: availableSize, isActive: isActive, title: title.lowercased(), isSecure: component.isSecure, collapseFraction: collapseFraction, isTablet: component.metrics.isTablet, transition: transition)
self.update(
theme: component.theme,
strings: component.strings,
size: availableSize,
isActive: isActive,
title: title.lowercased(),
isSecure: component.isSecure,
collapseFraction: collapseFraction,
isTablet: component.metrics.isTablet,
readingProgress: component.readingProgress,
loadingProgress: component.loadingProgress,
transition: transition
)
return availableSize
}
public func update(theme: PresentationTheme, strings: PresentationStrings, size: CGSize, isActive: Bool, title: String, isSecure: Bool, collapseFraction: CGFloat, isTablet: Bool, transition: ComponentTransition) {
public func update(
theme: PresentationTheme,
strings: PresentationStrings,
size: CGSize,
isActive: Bool,
title: String,
isSecure: Bool,
collapseFraction: CGFloat,
isTablet: Bool,
readingProgress: CGFloat,
loadingProgress: Double?,
transition: ComponentTransition
) {
let params = Params(
theme: theme,
strings: strings,
@@ -296,7 +329,9 @@ final class AddressBarContentComponent: Component {
title: title,
isSecure: isSecure,
collapseFraction: collapseFraction,
isTablet: isTablet
isTablet: isTablet,
readingProgress: readingProgress,
loadingProgress: loadingProgress
)
if self.params == params {
@@ -306,8 +341,6 @@ final class AddressBarContentComponent: Component {
let isActiveWithText = self.component?.isExpanded ?? false
if self.params?.theme !== theme {
self.iconView.image = generateTintedImage(image: UIImage(bundleImageName: "Media Grid/Lock"), color: .white)?.withRenderingMode(.alwaysTemplate)
self.iconView.tintColor = theme.rootController.navigationSearchBar.inputIconColor
self.clearIconView.image = generateTintedImage(image: UIImage(bundleImageName: "Components/Search Bar/Clear"), color: .white)?.withRenderingMode(.alwaysTemplate)
self.clearIconView.tintColor = theme.rootController.navigationSearchBar.inputClearButtonColor
}
@@ -315,57 +348,9 @@ final class AddressBarContentComponent: Component {
self.params = params
let sideInset: CGFloat = 10.0
let inputHeight: CGFloat = 36.0
let inputHeight: CGFloat = 44.0
let topInset: CGFloat = (size.height - inputHeight) / 2.0
self.backgroundLayer.backgroundColor = theme.rootController.navigationSearchBar.inputFillColor.cgColor
self.backgroundLayer.cornerRadius = 10.5
transition.setAlpha(layer: self.backgroundLayer, alpha: max(0.0, min(1.0, 1.0 - collapseFraction * 1.5)))
let cancelTextSize = self.cancelButtonTitle.update(
transition: .immediate,
component: AnyComponent(Text(
text: strings.Common_Cancel,
font: Font.regular(17.0),
color: theme.rootController.navigationBar.accentTextColor
)),
environment: {},
containerSize: CGSize(width: size.width - 32.0, height: 100.0)
)
let cancelButtonSpacing: CGFloat = 8.0
var backgroundFrame = CGRect(origin: CGPoint(x: sideInset, y: topInset), size: CGSize(width: size.width - sideInset * 2.0, height: inputHeight))
if isActiveWithText && !isTablet {
backgroundFrame.size.width -= cancelTextSize.width + cancelButtonSpacing
}
transition.setFrame(layer: self.backgroundLayer, frame: backgroundFrame)
transition.setFrame(view: self.cancelButton, frame: CGRect(origin: CGPoint(x: backgroundFrame.maxX, y: 0.0), size: CGSize(width: cancelButtonSpacing + cancelTextSize.width, height: size.height)))
self.cancelButton.isUserInteractionEnabled = isActiveWithText && !isTablet
let textX: CGFloat = backgroundFrame.minX + sideInset
let textFrame = CGRect(origin: CGPoint(x: textX, y: backgroundFrame.minY), size: CGSize(width: backgroundFrame.maxX - textX, height: backgroundFrame.height))
let placeholderSize = self.placeholderContent.update(
transition: transition,
component: AnyComponent(
Text(text: strings.WebBrowser_AddressPlaceholder, font: Font.regular(17.0), color: theme.rootController.navigationSearchBar.inputPlaceholderTextColor)
),
environment: {},
containerSize: size
)
if let placeholderContentView = self.placeholderContent.view {
if placeholderContentView.superview == nil {
placeholderContentView.alpha = 0.0
placeholderContentView.isHidden = true
self.addSubview(placeholderContentView)
}
let placeholderContentFrame = CGRect(origin: CGPoint(x: textFrame.minX, y: backgroundFrame.midY - placeholderSize.height / 2.0), size: placeholderSize)
transition.setFrame(view: placeholderContentView, frame: placeholderContentFrame)
transition.setAlpha(view: placeholderContentView, alpha: isActiveWithText ? 1.0 : 0.0)
}
let titleSize = self.titleContent.update(
transition: transition,
component: AnyComponent(
@@ -379,51 +364,96 @@ final class AddressBarContentComponent: Component {
environment: {},
containerSize: CGSize(width: size.width - 36.0, height: size.height)
)
var titleContentFrame = CGRect(origin: CGPoint(x: isActiveWithText ? textFrame.minX : backgroundFrame.midX - titleSize.width / 2.0, y: backgroundFrame.midY - titleSize.height / 2.0), size: titleSize)
if isSecure && !isActiveWithText {
titleContentFrame.origin.x += 7.0
let expandedBackgroundWidth = size.width - 14.0 * 2.0
let collapsedBackgroundWidth = titleSize.width + 32.0
var backgroundSize = CGSize(width: expandedBackgroundWidth * (1.0 - collapseFraction) + collapsedBackgroundWidth * collapseFraction, height: 44.0)
let cancelButtonSpacing: CGFloat = 8.0
let cancelSize = self.cancelButton.update(
transition: transition,
component: AnyComponent(
GlassBarButtonComponent(
size: CGSize(width: 44.0, height: 44.0),
backgroundColor: nil,
isDark: theme.overallDarkAppearance,
state: .glass,
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
BundleIconComponent(name: "Navigation/Close", tintColor: theme.chat.inputPanel.panelControlColor)
)),
action: { [weak self] _ in
self?.cancelPressed()
}
)
),
environment: {},
containerSize: CGSize(width: 44.0, height: 44.0)
)
if isActiveWithText && !isTablet {
backgroundSize.width -= cancelSize.width + cancelButtonSpacing + 4.0
}
var titleSizeChanged = false
self.backgroundView.update(size: backgroundSize, cornerRadius: backgroundSize.height * 0.5, isDark: theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: UIColor(white: theme.overallDarkAppearance ? 0.0 : 1.0, alpha: 0.6)), isInteractive: true, transition: transition)
var backgroundFrame = CGRect(origin: CGPoint(x: floor((size.width - backgroundSize.width) / 2.0), y: topInset), size: backgroundSize)
if isActiveWithText && !isTablet {
backgroundFrame.origin.x = 16.0
}
transition.setFrame(view: self.backgroundView, frame: backgroundFrame)
transition.setFrame(view: self.clippingView, frame: CGRect(origin: .zero, size: backgroundFrame.size))
transition.setCornerRadius(layer: self.clippingView.layer, cornerRadius: backgroundFrame.size.height * 0.5)
let textX: CGFloat = sideInset
let textFrame = CGRect(origin: CGPoint(x: textX, y: 0.0), size: CGSize(width: backgroundFrame.maxX - textX, height: backgroundFrame.height))
let placeholderSize = self.placeholderContent.update(
transition: transition,
component: AnyComponent(
Text(text: strings.WebBrowser_AddressPlaceholder, font: Font.regular(17.0), color: theme.rootController.navigationSearchBar.inputPlaceholderTextColor)
),
environment: {},
containerSize: size
)
if let placeholderContentView = self.placeholderContent.view {
if placeholderContentView.superview == nil {
placeholderContentView.alpha = 0.0
placeholderContentView.isHidden = true
self.backgroundView.contentView.addSubview(placeholderContentView)
}
let placeholderContentFrame = CGRect(origin: CGPoint(x: textFrame.minX, y: backgroundFrame.size.height / 2.0 - placeholderSize.height / 2.0), size: placeholderSize)
transition.setFrame(view: placeholderContentView, frame: placeholderContentFrame)
transition.setAlpha(view: placeholderContentView, alpha: isActiveWithText ? 1.0 : 0.0)
}
let titleContentFrame = CGRect(origin: CGPoint(x: isActiveWithText ? textFrame.minX : backgroundFrame.width / 2.0 - titleSize.width / 2.0, y: backgroundFrame.height / 2.0 - titleSize.height / 2.0), size: titleSize)
if let titleContentView = self.titleContent.view {
if titleContentView.superview == nil {
self.addSubview(titleContentView)
}
if titleContentView.frame.width != titleContentFrame.size.width {
titleSizeChanged = true
self.backgroundView.contentView.addSubview(titleContentView)
}
transition.setPosition(view: titleContentView, position: titleContentFrame.center)
titleContentView.bounds = CGRect(origin: .zero, size: titleContentFrame.size)
transition.setAlpha(view: titleContentView, alpha: isActiveWithText ? 0.0 : 1.0)
}
if let image = self.iconView.image {
let iconFrame = CGRect(origin: CGPoint(x: titleContentFrame.minX - image.size.width - 3.0, y: backgroundFrame.minY + floor((backgroundFrame.height - image.size.height) / 2.0)), size: image.size)
var iconTransition = transition
if titleSizeChanged {
iconTransition = .immediate
}
iconTransition.setFrame(view: self.iconView, frame: iconFrame)
transition.setAlpha(view: self.iconView, alpha: isActiveWithText || !isSecure ? 0.0 : 1.0)
}
if let image = self.clearIconView.image {
let iconFrame = CGRect(origin: CGPoint(x: backgroundFrame.maxX - image.size.width - 4.0, y: backgroundFrame.minY + floor((backgroundFrame.height - image.size.height) / 2.0)), size: image.size)
let iconFrame = CGRect(origin: CGPoint(x: backgroundFrame.width - image.size.width - 4.0, y: floor((backgroundFrame.height - image.size.height) / 2.0)), size: image.size)
transition.setFrame(view: self.clearIconView, frame: iconFrame)
transition.setFrame(view: self.clearIconButton, frame: iconFrame.insetBy(dx: -8.0, dy: -10.0))
transition.setAlpha(view: self.clearIconView, alpha: isActiveWithText ? 1.0 : 0.0)
self.clearIconButton.isUserInteractionEnabled = isActiveWithText
}
if let cancelButtonTitleComponentView = self.cancelButtonTitle.view {
if cancelButtonTitleComponentView.superview == nil {
self.addSubview(cancelButtonTitleComponentView)
cancelButtonTitleComponentView.isUserInteractionEnabled = false
if let cancelButtonView = self.cancelButton.view {
if cancelButtonView.superview == nil {
self.addSubview(cancelButtonView)
}
transition.setFrame(view: cancelButtonTitleComponentView, frame: CGRect(origin: CGPoint(x: backgroundFrame.maxX + cancelButtonSpacing, y: floor((size.height - cancelTextSize.height) / 2.0)), size: cancelTextSize))
transition.setAlpha(view: cancelButtonTitleComponentView, alpha: isActiveWithText && !isTablet ? 1.0 : 0.0)
transition.setFrame(view: cancelButtonView, frame: CGRect(origin: CGPoint(x: backgroundFrame.maxX + cancelButtonSpacing, y: floor((size.height - cancelSize.height) / 2.0)), size: cancelSize))
transition.setAlpha(view: cancelButtonView, alpha: isActiveWithText && !isTablet ? 1.0 : 0.0)
}
let textFieldFrame = CGRect(origin: CGPoint(x: textFrame.minX, y: backgroundFrame.minY), size: CGSize(width: backgroundFrame.maxX - textFrame.minX, height: backgroundFrame.height))
let textFieldFrame = CGRect(origin: CGPoint(x: sideInset, y: 0.0), size: CGSize(width: backgroundFrame.width - sideInset, height: backgroundFrame.height))
let textField: TextField
if let current = self.textField {
@@ -434,7 +464,7 @@ final class AddressBarContentComponent: Component {
textField.autocorrectionType = .no
textField.keyboardType = .URL
textField.returnKeyType = .go
self.insertSubview(textField, belowSubview: self.clearIconView)
self.backgroundView.contentView.insertSubview(textField, belowSubview: self.clearIconView)
self.textField = textField
textField.delegate = self
@@ -450,9 +480,34 @@ final class AddressBarContentComponent: Component {
}
textField.textColor = theme.rootController.navigationSearchBar.inputTextColor
transition.setFrame(view: textField, frame: CGRect(origin: CGPoint(x: backgroundFrame.minX + sideInset, y: backgroundFrame.minY - UIScreenPixel), size: CGSize(width: backgroundFrame.width - sideInset - 32.0, height: backgroundFrame.height)))
transition.setFrame(view: textField, frame: CGRect(origin: CGPoint(x: sideInset, y: -UIScreenPixel), size: CGSize(width: backgroundFrame.width - sideInset - 32.0, height: backgroundFrame.height)))
transition.setAlpha(view: textField, alpha: isActiveWithText ? 1.0 : 0.0)
textField.isUserInteractionEnabled = isActiveWithText
let loadingProgressInset: CGFloat = 12.0
let loadingProgressSize = CGSize(width: backgroundSize.width - loadingProgressInset * 2.0, height: 2.0)
let _ = self.loadingProgress.update(
transition: transition,
component: AnyComponent(LoadingProgressComponent(
color: theme.rootController.navigationBar.accentTextColor,
height: loadingProgressSize.height,
value: params.loadingProgress ?? 0.0
)),
environment: {},
containerSize: loadingProgressSize
)
if let loadingProgressView = self.loadingProgress.view {
if loadingProgressView.superview == nil {
self.clippingView.addSubview(loadingProgressView)
}
transition.setFrame(view: loadingProgressView, frame: CGRect(origin: CGPoint(x: loadingProgressInset, y: backgroundSize.height - loadingProgressSize.height), size: loadingProgressSize))
transition.setAlpha(view: loadingProgressView, alpha: isActiveWithText ? 0.0 : 1.0)
}
self.readingProgressView.backgroundColor = theme.rootController.navigationBar.primaryTextColor.withMultipliedAlpha(0.07)
self.readingProgressView.frame = CGRect(origin: .zero, size: CGSize(width: backgroundSize.width * params.readingProgress, height: backgroundSize.height))
transition.setAlpha(view: self.readingProgressView, alpha: isActiveWithText ? 0.0 : 1.0)
}
}
@@ -19,6 +19,7 @@ final class BrowserAddressListComponent: Component {
let insets: UIEdgeInsets
let metrics: LayoutMetrics
let addressBarFrame: CGRect
let navigationBarHeight: CGFloat
let performAction: ActionSlot<BrowserScreen.Action>
let presentInGlobalOverlay: (ViewController) -> Void
@@ -29,6 +30,7 @@ final class BrowserAddressListComponent: Component {
insets: UIEdgeInsets,
metrics: LayoutMetrics,
addressBarFrame: CGRect,
navigationBarHeight: CGFloat,
performAction: ActionSlot<BrowserScreen.Action>,
presentInGlobalOverlay: @escaping (ViewController) -> Void
) {
@@ -38,6 +40,7 @@ final class BrowserAddressListComponent: Component {
self.insets = insets
self.metrics = metrics
self.addressBarFrame = addressBarFrame
self.navigationBarHeight = navigationBarHeight
self.performAction = performAction
self.presentInGlobalOverlay = presentInGlobalOverlay
}
@@ -61,6 +64,9 @@ final class BrowserAddressListComponent: Component {
if lhs.addressBarFrame != rhs.addressBarFrame {
return false
}
if lhs.navigationBarHeight != rhs.navigationBarHeight {
return false
}
return true
}
@@ -214,15 +220,16 @@ final class BrowserAddressListComponent: Component {
var validIds: [AnyHashable] = []
var validSectionHeaders: [AnyHashable] = []
var sectionOffset: CGFloat = 0.0
let headerOffset: CGFloat = self.scrollView.frame.minY
let sideInset: CGFloat = 0.0
let containerInset: CGFloat = 0.0
let containerInset: CGFloat = self.scrollView.frame.minY
for sectionIndex in 0 ..< itemLayout.sections.count {
let section = itemLayout.sections[sectionIndex]
do {
var sectionHeaderFrame = CGRect(origin: CGPoint(x: sideInset, y: sectionOffset - self.scrollView.bounds.minY), size: CGSize(width: itemLayout.containerSize.width, height: section.insets.top))
var sectionHeaderFrame = CGRect(origin: CGPoint(x: sideInset, y: headerOffset + sectionOffset - self.scrollView.bounds.minY), size: CGSize(width: itemLayout.containerSize.width, height: section.insets.top))
let sectionHeaderMinY = topOffset + containerInset
let sectionHeaderMaxY = containerInset + sectionOffset - self.scrollView.bounds.minY + section.totalHeight - 28.0
@@ -540,7 +547,7 @@ final class BrowserAddressListComponent: Component {
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)
containerFrame = CGRect(origin: CGPoint(x: floor(component.addressBarFrame.center.x - containerSize.width / 2.0), y: 100.0), size: containerSize)
self.backgroundView.layer.cornerRadius = 10.0
} else {
@@ -602,23 +609,28 @@ final class BrowserAddressListComponent: Component {
let itemLayout = ItemLayout(containerSize: containerFrame.size, insets: .zero, sections: sections)
self.itemLayout = itemLayout
let containerWidth = containerFrame.size.width
let scrollContentHeight = max(itemLayout.contentHeight, containerFrame.size.height)
self.ignoreScrolling = true
transition.setFrame(view: self.scrollView, frame: CGRect(origin: .zero, size: containerFrame.size))
let contentSize = CGSize(width: containerWidth, height: scrollContentHeight)
let scrollFrame: CGRect
if component.metrics.isTablet {
scrollFrame = CGRect(origin: .zero, size: containerFrame.size)
} else {
scrollFrame = CGRect(origin: CGPoint(x: 0.0, y: component.navigationBarHeight), size: CGSize(width: containerFrame.size.width, height: containerFrame.size.height - component.navigationBarHeight))
}
transition.setFrame(view: self.scrollView, frame: scrollFrame)
let contentSize = CGSize(width: scrollFrame.width, height: scrollContentHeight)
if contentSize != self.scrollView.contentSize {
self.scrollView.contentSize = contentSize
}
if resetScrolling {
self.scrollView.bounds = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: containerWidth, height: containerFrame.size.height))
self.scrollView.bounds = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: scrollFrame.size)
}
self.ignoreScrolling = false
self.updateScrolling(transition: transition)
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: scrollFrame.width, height: scrollContentHeight)))
if component.metrics.isTablet {
transition.setFrame(view: self.shadowView, frame: containerFrame.insetBy(dx: -60.0, dy: -60.0))
@@ -12,8 +12,15 @@ import AccountContext
import ContextUI
import UrlEscaping
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 iconFont = Font.with(size: 28.0, design: .round, weight: .bold)
private let iconTextBackgroundImage = generateImage(CGSize(width: 40.0, height: 40.0), contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(UIColor(rgb: 0xFF9500).cgColor)
let path = UIBezierPath(roundedRect: CGRect(origin: .zero, size: size), cornerRadius: 12.0)
context.addPath(path.cgPath)
context.fillPath()
})
final class BrowserAddressListItemComponent: Component {
let context: AccountContext
@@ -261,7 +268,7 @@ final class BrowserAddressListItemComponent: Component {
let iconImageLayout = self.icon.asyncLayout()
var iconImageApply: (() -> Void)?
if let iconImageReferenceAndRepresentation = iconImageReferenceAndRepresentation {
let imageCorners = ImageCorners(radius: 6.0)
let imageCorners = ImageCorners(radius: 12.0, curve: .continuous)
let arguments = TransformImageArguments(corners: imageCorners, imageSize: iconImageReferenceAndRepresentation.1.dimensions.cgSize.aspectFilled(iconSize), boundingSize: iconSize, intrinsicInsets: UIEdgeInsets(), emptyColor: component.theme.list.mediaPlaceholderColor)
iconImageApply = iconImageLayout(arguments)
}
@@ -18,6 +18,10 @@ import SearchBarNode
import ChatHistorySearchContainerNode
import ContextUI
import UndoUI
import ComponentFlow
import EdgeEffect
import ButtonComponent
import BundleIconComponent
public final class BrowserBookmarksScreen: ViewController {
final class Node: ViewControllerTracingNode, ASScrollViewDelegate {
@@ -196,7 +200,6 @@ public final class BrowserBookmarksScreen: ViewController {
controllerInteraction: self.controllerInteraction,
selectedMessages: .single(nil),
mode: .list(
search: false,
reversed: false,
reverseGroups: false,
displayHeaders: .none,
@@ -287,9 +290,9 @@ public final class BrowserBookmarksScreen: ViewController {
}
let tagMask: MessageTags = .webPage
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .list, placeholder: self.presentationData.strings.Common_Search, hasBackground: true, contentNode: ChatHistorySearchContainerNode(context: self.context, peerId: self.context.account.peerId, threadId: nil, tagMask: tagMask, interfaceInteraction: self.controllerInteraction), cancel: { [weak self] in
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .navigation, placeholder: self.presentationData.strings.Common_Search, hasBackground: true, contentNode: ChatHistorySearchContainerNode(context: self.context, peerId: self.context.account.peerId, threadId: nil, tagMask: tagMask, interfaceInteraction: self.controllerInteraction), cancel: { [weak self] in
self?.controller?.deactivateSearch()
})
}, fieldStyle: placeholderNode.fieldStyle)
self.searchDisplayController?.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
self.searchDisplayController?.activate(insertSubnode: { [weak self, weak placeholderNode] subnode, isSearchBar in
@@ -372,7 +375,9 @@ public final class BrowserBookmarksScreen: ViewController {
self.openUrl = openUrl
self.addBookmark = addBookmark
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData, style: .glass))
self._hasGlassStyle = true
self.navigationPresentation = .modal
self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
@@ -429,19 +434,13 @@ public final class BrowserBookmarksScreen: ViewController {
searchContentNode.updateListVisibleContentOffset(offset)
}
}
//
// self.node.historyNode.didEndScrolling = { [weak self] _ in
// if let strongSelf = self, let searchContentNode = strongSelf.searchContentNode {
// let _ = fixNavigationSearchableListNodeScrolling(strongSelf.node.historyNode, searchNode: searchContentNode)
// }
// }
self.displayNodeDidLoad()
}
private func updateThemeAndStrings() {
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData))
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData, style: .glass), transition: .immediate)
self.searchContentNode?.updateThemeAndPlaceholder(theme: self.presentationData.theme, placeholder: self.presentationData.strings.Common_Search)
}
@@ -484,10 +483,8 @@ private class BottomPanelNode: ASDisplayNode {
private let strings: PresentationStrings
private let action: () -> Void
private let separatorNode: ASDisplayNode
private let button: HighlightTrackingButtonNode
private let iconNode: ASImageNode
private let textNode: ImmediateTextNode
private let edgeEffectView = EdgeEffectView()
private let button = ComponentView<Empty>()
private var validLayout: (CGFloat, CGFloat, CGFloat)?
@@ -496,49 +493,13 @@ private class BottomPanelNode: ASDisplayNode {
self.strings = strings
self.action = action
self.separatorNode = ASDisplayNode()
self.separatorNode.backgroundColor = theme.rootController.navigationBar.separatorColor
self.iconNode = ASImageNode()
self.iconNode.displaysAsynchronously = false
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat List/AddIcon"), color: theme.rootController.navigationBar.accentTextColor)
self.iconNode.isUserInteractionEnabled = false
self.textNode = ImmediateTextNode()
self.textNode.displaysAsynchronously = false
self.textNode.attributedText = NSAttributedString(string: strings.WebBrowser_Bookmarks_BookmarkCurrent, font: Font.regular(17.0), textColor: theme.rootController.navigationBar.accentTextColor)
self.textNode.isUserInteractionEnabled = false
self.button = HighlightTrackingButtonNode()
super.init()
}
override func didLoad() {
super.didLoad()
self.backgroundColor = theme.rootController.navigationBar.opaqueBackgroundColor
self.addSubnode(self.button)
self.addSubnode(self.separatorNode)
self.addSubnode(self.iconNode)
self.addSubnode(self.textNode)
self.addSubnode(self.button)
self.button.highligthedChanged = { [weak self] highlighted in
if let self {
if highlighted {
self.iconNode.layer.removeAnimation(forKey: "opacity")
self.iconNode.alpha = 0.4
self.textNode.layer.removeAnimation(forKey: "opacity")
self.textNode.alpha = 0.4
} else {
self.iconNode.alpha = 1.0
self.iconNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
self.textNode.alpha = 1.0
self.textNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
}
}
}
self.button.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
self.view.addSubview(self.edgeEffectView)
}
@objc private func buttonPressed() {
@@ -551,26 +512,76 @@ private class BottomPanelNode: ASDisplayNode {
var bottomInset = bottomInset
bottomInset += topInset - (bottomInset.isZero ? 0.0 : 4.0)
let buttonHeight: CGFloat = 40.0
let textSize = self.textNode.updateLayout(CGSize(width: width, height: 44.0))
// let buttonHeight: CGFloat = 40.0
// let textSize = self.textNode.updateLayout(CGSize(width: width, height: 44.0))
//
// let spacing: CGFloat = 8.0
// var contentWidth = textSize.width
// var contentOriginX = floorToScreenPixels((width - contentWidth) / 2.0)
// if let icon = self.iconNode.image {
// contentWidth += icon.size.width + spacing
// contentOriginX = floorToScreenPixels((width - contentWidth) / 2.0)
// transition.updateFrame(node: self.iconNode, frame: CGRect(origin: CGPoint(x: contentOriginX, y: 12.0 + UIScreenPixel), size: icon.size))
// contentOriginX += icon.size.width + spacing
// }
// let textFrame = CGRect(origin: CGPoint(x: contentOriginX, y: 17.0), size: textSize)
// transition.updateFrame(node: self.textNode, frame: textFrame)
//
// transition.updateFrame(node: self.button, frame: textFrame.insetBy(dx: -10.0, dy: -10.0))
//
// transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: width, height: UIScreenPixel)))
//
let buttonInsets = ContainerViewLayout.concentricInsets(bottomInset: bottomInset, innerDiameter: 52.0, sideInset: 30.0)
let height: CGFloat = 52.0 + buttonInsets.bottom
let spacing: CGFloat = 8.0
var contentWidth = textSize.width
var contentOriginX = floorToScreenPixels((width - contentWidth) / 2.0)
if let icon = self.iconNode.image {
contentWidth += icon.size.width + spacing
contentOriginX = floorToScreenPixels((width - contentWidth) / 2.0)
transition.updateFrame(node: self.iconNode, frame: CGRect(origin: CGPoint(x: contentOriginX, y: 12.0 + UIScreenPixel), size: icon.size))
contentOriginX += icon.size.width + spacing
let edgeEffectHeight: CGFloat = height
let edgeEffectFrame = CGRect(origin: CGPoint(x: 0.0, y: height - edgeEffectHeight), size: CGSize(width: width, height: edgeEffectHeight))
transition.updateFrame(view: self.edgeEffectView, frame: edgeEffectFrame)
self.edgeEffectView.update(
content: self.theme.list.plainBackgroundColor,
blur: true,
rect: edgeEffectFrame,
edge: .bottom,
edgeSize: edgeEffectFrame.height,
transition: ComponentTransition(transition)
)
var buttonItems: [AnyComponentWithIdentity<Empty>] = []
buttonItems.append(AnyComponentWithIdentity(id: "icon", component: AnyComponent(BundleIconComponent(name: "Chat/Context Menu/Fave", tintColor: self.theme.list.itemCheckColors.foregroundColor))))
buttonItems.append(AnyComponentWithIdentity(id: "label", component: AnyComponent(Text(text: self.strings.WebBrowser_Bookmarks_BookmarkCurrent, font: Font.semibold(17.0), color: self.theme.list.itemCheckColors.foregroundColor))))
let buttonSize = self.button.update(
transition: .immediate,
component: AnyComponent(
ButtonComponent(
background: ButtonComponent.Background(
style: .glass,
color: self.theme.list.itemCheckColors.fillColor,
foreground: self.theme.list.itemCheckColors.foregroundColor,
pressedColor: self.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.9)
),
content: AnyComponentWithIdentity(
id: AnyHashable(0),
component: AnyComponent(HStack(buttonItems, spacing: 7.0))
),
action: { [weak self] in
self?.action()
}
)
),
environment: {},
containerSize: CGSize(width: width - sideInset * 2.0 - buttonInsets.left - buttonInsets.right, height: 52.0)
)
let buttonFrame = CGRect(origin: CGPoint(x: sideInset + buttonInsets.left, y: height - buttonInsets.bottom - buttonSize.height), size: buttonSize)
if let buttonView = self.button.view {
if buttonView.superview == nil {
self.view.addSubview(buttonView)
}
transition.updateFrame(view: buttonView, frame: buttonFrame)
}
let textFrame = CGRect(origin: CGPoint(x: contentOriginX, y: 17.0), size: textSize)
transition.updateFrame(node: self.textNode, frame: textFrame)
transition.updateFrame(node: self.button, frame: textFrame.insetBy(dx: -10.0, dy: -10.0))
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: width, height: UIScreenPixel)))
return topInset + buttonHeight + bottomInset
return height
}
}
@@ -90,12 +90,21 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg
private let updateLayoutDisposable = MetaDisposable()
private let loadProgress = ValuePromise<CGFloat>(1.0, ignoreRepeated: true)
private let readingProgress = ValuePromise<CGFloat>(1.0, ignoreRepeated: true)
private let readingProgress = ValuePromise<CGFloat>(0.0, ignoreRepeated: true)
private var containerLayout: (size: CGSize, insets: UIEdgeInsets, fullInsets: UIEdgeInsets)?
private var setupScrollOffsetOnLayout = false
init(context: AccountContext, presentationData: PresentationData, webPage: TelegramMediaWebpage, anchor: String?, url: String, sourceLocation: InstantPageSourceLocation, preloadedResouces: [Any]?, originalContent: BrowserContent? = nil) {
init(
context: AccountContext,
presentationData: PresentationData,
webPage: TelegramMediaWebpage,
anchor: String?,
url: String,
sourceLocation: InstantPageSourceLocation,
preloadedResouces: [Any]?,
originalContent: BrowserContent? = nil
) {
self.context = context
var instantPage: InstantPage?
if case let .Loaded(content) = webPage.content {
@@ -132,6 +141,8 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg
super.init(frame: .zero)
self.backgroundColor = self.theme.pageBackgroundColor
self.statePromise.set(.single(self._state)
|> then(
combineLatest(
@@ -193,6 +204,8 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg
self.presentationData = presentationData
self.theme = instantPageThemeForType(presentationData.theme.overallDarkAppearance ? .dark : .light, settings: self.settings)
self.backgroundColor = self.theme.pageBackgroundColor
self.updatePageLayout()
self.updateVisibleItems(visibleBounds: self.scrollNode.view.bounds)
}
@@ -415,8 +428,7 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg
var updateVisibleItems = false
let resetContentOffset = self.scrollNode.bounds.size.width.isZero || self.setupScrollOffsetOnLayout || !(self.initialAnchor ?? "").isEmpty
var scrollInsets = insets
scrollInsets.top = 0.0
let scrollInsets = fullInsets
if self.scrollNode.view.contentInset != scrollInsets {
self.scrollNode.view.contentInset = scrollInsets
self.scrollNode.view.scrollIndicatorInsets = scrollInsets
@@ -424,7 +436,7 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg
self.wrapperNode.frame = CGRect(origin: .zero, size: size)
let scrollFrame = CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: size.width, height: size.height - insets.top))
let scrollFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height))
let scrollFrameUpdated = self.scrollNode.bounds.size != scrollFrame.size
if scrollFrameUpdated {
let widthUpdated = self.scrollNode.bounds.size.width != scrollFrame.width
@@ -2,8 +2,10 @@ import Foundation
import UIKit
import Display
import ComponentFlow
import BlurredBackgroundComponent
import TelegramPresentationData
import ContextUI
import GlassBackgroundComponent
import EdgeEffect
final class BrowserNavigationBarEnvironment: Equatable {
public let fraction: CGFloat
@@ -20,7 +22,7 @@ final class BrowserNavigationBarEnvironment: Equatable {
}
}
final class BrowserNavigationBarComponent: CombinedComponent {
final class BrowserNavigationBarComponent: Component {
public class ExternalState {
public fileprivate(set) var centerItemFrame: CGRect
@@ -29,11 +31,7 @@ final class BrowserNavigationBarComponent: CombinedComponent {
}
}
let backgroundColor: UIColor
let separatorColor: UIColor
let textColor: UIColor
let progressColor: UIColor
let accentColor: UIColor
let theme: PresentationTheme
let topInset: CGFloat
let height: CGFloat
let sideInset: CGFloat
@@ -42,17 +40,11 @@ final class BrowserNavigationBarComponent: CombinedComponent {
let leftItems: [AnyComponentWithIdentity<Empty>]
let rightItems: [AnyComponentWithIdentity<Empty>]
let centerItem: AnyComponentWithIdentity<BrowserNavigationBarEnvironment>?
let readingProgress: CGFloat
let loadingProgress: Double?
let collapseFraction: CGFloat
let activate: () -> Void
init(
backgroundColor: UIColor,
separatorColor: UIColor,
textColor: UIColor,
progressColor: UIColor,
accentColor: UIColor,
theme: PresentationTheme,
topInset: CGFloat,
height: CGFloat,
sideInset: CGFloat,
@@ -61,16 +53,10 @@ final class BrowserNavigationBarComponent: CombinedComponent {
leftItems: [AnyComponentWithIdentity<Empty>],
rightItems: [AnyComponentWithIdentity<Empty>],
centerItem: AnyComponentWithIdentity<BrowserNavigationBarEnvironment>?,
readingProgress: CGFloat,
loadingProgress: Double?,
collapseFraction: CGFloat,
activate: @escaping () -> Void
) {
self.backgroundColor = backgroundColor
self.separatorColor = separatorColor
self.textColor = textColor
self.progressColor = progressColor
self.accentColor = accentColor
self.theme = theme
self.topInset = topInset
self.height = height
self.sideInset = sideInset
@@ -79,26 +65,12 @@ final class BrowserNavigationBarComponent: CombinedComponent {
self.leftItems = leftItems
self.rightItems = rightItems
self.centerItem = centerItem
self.readingProgress = readingProgress
self.loadingProgress = loadingProgress
self.collapseFraction = collapseFraction
self.activate = activate
}
static func ==(lhs: BrowserNavigationBarComponent, rhs: BrowserNavigationBarComponent) -> Bool {
if lhs.backgroundColor != rhs.backgroundColor {
return false
}
if lhs.separatorColor != rhs.separatorColor {
return false
}
if lhs.textColor != rhs.textColor {
return false
}
if lhs.progressColor != rhs.progressColor {
return false
}
if lhs.accentColor != rhs.accentColor {
if lhs.theme !== rhs.theme {
return false
}
if lhs.topInset != rhs.topInset {
@@ -122,203 +94,353 @@ final class BrowserNavigationBarComponent: CombinedComponent {
if lhs.centerItem != rhs.centerItem {
return false
}
if lhs.readingProgress != rhs.readingProgress {
return false
}
if lhs.loadingProgress != rhs.loadingProgress {
return false
}
if lhs.collapseFraction != rhs.collapseFraction {
return false
}
return true
}
static var body: Body {
let background = Child(Rectangle.self)
let readingProgress = Child(Rectangle.self)
let separator = Child(Rectangle.self)
let loadingProgress = Child(LoadingProgressComponent.self)
let leftItems = ChildMap(environment: Empty.self, keyedBy: AnyHashable.self)
let rightItems = ChildMap(environment: Empty.self, keyedBy: AnyHashable.self)
let centerItems = ChildMap(environment: BrowserNavigationBarEnvironment.self, keyedBy: AnyHashable.self)
let activate = Child(Button.self)
final class View: UIView {
private var edgeEffectView = EdgeEffectView()
private let containerView = GlassBackgroundContainerView()
private var leftItemsBackground: GlassBackgroundView?
private var leftItems: [AnyHashable: ComponentView<Empty>] = [:]
return { context in
var availableWidth = context.availableSize.width
let sideInset: CGFloat = (context.component.metrics.isTablet ? 20.0 : 16.0) + context.component.sideInset
private var rightItemsBackground: GlassBackgroundView?
private var rightItems: [AnyHashable: ComponentView<Empty>] = [:]
private var centerItems: [AnyHashable: ComponentView<BrowserNavigationBarEnvironment>] = [:]
private let activateButton = HighlightTrackingButton()
private var component: BrowserNavigationBarComponent?
private weak var state: EmptyComponentState?
override init(frame: CGRect) {
super.init(frame: frame)
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 ? -2.0 : 0.0
let itemSpacing: CGFloat = context.component.metrics.isTablet ? 26.0 : 8.0
self.addSubview(self.edgeEffectView)
let background = background.update(
component: Rectangle(color: context.component.backgroundColor.withAlphaComponent(1.0)),
availableSize: CGSize(width: size.width, height: size.height),
transition: context.transition
)
let readingProgress = readingProgress.update(
component: Rectangle(color: context.component.progressColor),
availableSize: CGSize(width: size.width * context.component.readingProgress, height: size.height),
transition: context.transition
)
let separator = separator.update(
component: Rectangle(color: context.component.separatorColor, height: UIScreenPixel),
availableSize: CGSize(width: size.width, height: size.height),
transition: context.transition
)
let loadingProgressHeight: CGFloat = 2.0
let loadingProgress = loadingProgress.update(
component: LoadingProgressComponent(
color: context.component.accentColor,
height: loadingProgressHeight,
value: context.component.loadingProgress ?? 0.0
),
availableSize: CGSize(width: size.width, height: size.height),
transition: context.transition
)
var leftItemList: [_UpdatedChildComponent] = []
for item in context.component.leftItems {
let item = leftItems[item.id].update(
component: item.component,
availableSize: CGSize(width: availableWidth, height: expandedHeight),
transition: context.transition
)
leftItemList.append(item)
availableWidth -= item.size.width
}
var rightItemList: [_UpdatedChildComponent] = []
for item in context.component.rightItems {
let item = rightItems[item.id].update(
component: item.component,
availableSize: CGSize(width: availableWidth, height: expandedHeight),
transition: context.transition
)
rightItemList.append(item)
availableWidth -= item.size.width
self.addSubview(self.containerView)
self.activateButton.addTarget(self, action: #selector(self.activatePressed), for: .touchUpInside)
}
required init?(coder: NSCoder) {
preconditionFailure()
}
@objc private func activatePressed() {
guard let component = self.component else {
return
}
component.activate()
}
func update(component: BrowserNavigationBarComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
self.component = component
self.state = state
var availableWidth = availableSize.width
let sideInset: CGFloat = (component.metrics.isTablet ? 20.0 : 16.0) + component.sideInset
let collapsedHeight: CGFloat = 54.0
let expandedHeight = component.height
let contentHeight: CGFloat = expandedHeight * (1.0 - component.collapseFraction) + collapsedHeight * component.collapseFraction
let size = CGSize(width: availableSize.width, height: component.topInset + contentHeight)
let verticalOffset: CGFloat = component.metrics.isTablet ? -2.0 : 0.0
let itemSpacing: CGFloat = 0.0 //component.metrics.isTablet ? 26.0 : 8.0
let panelHeight: CGFloat = 44.0
var leftItemsBackground: GlassBackgroundView?
var leftItemsBackgroundTransition = transition
if !component.leftItems.isEmpty {
if let current = self.leftItemsBackground {
leftItemsBackground = current
} else {
leftItemsBackgroundTransition = .immediate
leftItemsBackground = GlassBackgroundView()
self.containerView.contentView.addSubview(leftItemsBackground!)
self.leftItemsBackground = leftItemsBackground
context.add(background
.position(CGPoint(x: size.width / 2.0, y: size.height / 2.0))
)
var readingProgressAlpha = context.component.collapseFraction
if leftItemList.isEmpty && rightItemList.isEmpty {
readingProgressAlpha = 0.0
transition.animateScale(view: leftItemsBackground!, from: 0.1, to: 1.0)
transition.animateAlpha(view: leftItemsBackground!, from: 0.0, to: 1.0)
}
}
context.add(readingProgress
.position(CGPoint(x: readingProgress.size.width / 2.0, y: size.height / 2.0))
.opacity(readingProgressAlpha)
)
context.add(separator
.position(CGPoint(x: size.width / 2.0, y: size.height))
)
context.add(loadingProgress
.position(CGPoint(x: size.width / 2.0, y: size.height - loadingProgressHeight / 2.0))
)
var rightItemsBackground: GlassBackgroundView?
var rightItemsBackgroundTransition = transition
if !component.rightItems.isEmpty {
if let current = self.rightItemsBackground {
rightItemsBackground = current
} else {
rightItemsBackgroundTransition = .immediate
rightItemsBackground = GlassBackgroundView()
self.containerView.contentView.addSubview(rightItemsBackground!)
self.rightItemsBackground = rightItemsBackground
transition.animateScale(view: rightItemsBackground!, from: 0.1, to: 1.0)
transition.animateAlpha(view: rightItemsBackground!, from: 0.0, to: 1.0)
}
}
var validLeftItemIds: Set<AnyHashable> = Set()
var leftItemTransitions: [AnyHashable: (CGSize, ComponentTransition)] = [:]
var leftItemsWidth: CGFloat = 0.0
for item in component.leftItems {
validLeftItemIds.insert(item.id)
var itemTransition = transition
let itemView: ComponentView<Empty>
if let current = self.leftItems[item.id] {
itemView = current
} else {
itemTransition = .immediate
itemView = ComponentView<Empty>()
self.leftItems[item.id] = itemView
}
let itemSize = itemView.update(
transition: itemTransition,
component: item.component,
environment: {},
containerSize: CGSize(width: availableWidth, height: expandedHeight)
)
leftItemTransitions[item.id] = (itemSize, itemTransition)
availableWidth -= itemSize.width
leftItemsWidth += itemSize.width
}
var validRightItemIds: Set<AnyHashable> = Set()
var rightItemTransitions: [AnyHashable: (CGSize, ComponentTransition)] = [:]
var rightItemsWidth: CGFloat = 0.0
for item in component.rightItems {
validRightItemIds.insert(item.id)
var itemTransition = transition
let itemView: ComponentView<Empty>
if let current = self.rightItems[item.id] {
itemView = current
} else {
itemTransition = .immediate
itemView = ComponentView<Empty>()
self.rightItems[item.id] = itemView
}
let itemSize = itemView.update(
transition: itemTransition,
component: item.component,
environment: {},
containerSize: CGSize(width: availableWidth, height: expandedHeight)
)
rightItemTransitions[item.id] = (itemSize, itemTransition)
availableWidth -= itemSize.width
rightItemsWidth += itemSize.width
}
var centerLeftInset = sideInset
var leftItemX = sideInset
for item in leftItemList {
context.add(item
.position(CGPoint(x: leftItemX + item.size.width / 2.0 - (item.size.width / 2.0 * 0.35 * context.component.collapseFraction), y: context.component.topInset + contentHeight / 2.0 + verticalOffset))
.scale(1.0 - 0.35 * context.component.collapseFraction)
.opacity(1.0 - context.component.collapseFraction)
.appear(.default(scale: true, alpha: true))
.disappear(.default(scale: true, alpha: true))
)
leftItemX += item.size.width + itemSpacing
centerLeftInset += item.size.width + itemSpacing
var leftItemX = 0.0
for item in component.leftItems {
guard let (itemSize, itemTransition) = leftItemTransitions[item.id], let itemView = self.leftItems[item.id]?.view else {
continue
}
let itemPosition = CGPoint(x: leftItemX + itemSize.width / 2.0, y: panelHeight * 0.5)
let itemFrame = CGRect(origin: CGPoint(x: itemPosition.x - itemSize.width * 0.5, y: itemPosition.y - itemSize.height * 0.5), size: itemSize)
if itemView.superview == nil {
leftItemsBackground?.contentView.addSubview(itemView)
transition.animateAlpha(view: itemView, from: 0.0, to: 1.0)
transition.animateScale(view: itemView, from: 0.01, to: 1.0)
}
itemTransition.setBounds(view: itemView, bounds: CGRect(origin: .zero, size: itemFrame.size))
itemTransition.setPosition(view: itemView, position: itemFrame.center)
leftItemX += itemSize.width + itemSpacing
centerLeftInset += itemSize.width + itemSpacing
}
var centerRightInset = sideInset - 5.0
var rightItemX = context.availableSize.width - (sideInset - 5.0)
for item in rightItemList.reversed() {
context.add(item
.position(CGPoint(x: rightItemX - item.size.width / 2.0 + (item.size.width / 2.0 * 0.35 * context.component.collapseFraction), y: context.component.topInset + contentHeight / 2.0 + verticalOffset))
.scale(1.0 - 0.35 * context.component.collapseFraction)
.opacity(1.0 - context.component.collapseFraction)
.appear(.default(scale: true, alpha: true))
.disappear(.default(scale: true, alpha: true))
)
rightItemX -= item.size.width + itemSpacing
centerRightInset += item.size.width + itemSpacing
var centerRightInset = sideInset
var rightItemX = rightItemsWidth
for item in component.rightItems.reversed() {
guard let (itemSize, itemTransition) = rightItemTransitions[item.id], let itemView = self.rightItems[item.id]?.view else {
continue
}
let itemPosition = CGPoint(x: rightItemX - itemSize.width / 2.0, y: panelHeight * 0.5)
let itemFrame = CGRect(origin: CGPoint(x: itemPosition.x - itemSize.width * 0.5, y: itemPosition.y - itemSize.height * 0.5), size: itemSize)
if itemView.superview == nil {
rightItemsBackground?.contentView.addSubview(itemView)
transition.animateAlpha(view: itemView, from: 0.0, to: 1.0)
transition.animateScale(view: itemView, from: 0.01, to: 1.0)
}
itemTransition.setBounds(view: itemView, bounds: CGRect(origin: .zero, size: itemFrame.size))
itemTransition.setPosition(view: itemView, position: itemFrame.center)
itemTransition.setScale(view: itemView, scale: 1.0 - 0.35 * component.collapseFraction)
itemTransition.setAlpha(view: itemView, alpha: 1.0 - component.collapseFraction)
rightItemX -= itemSize.width + itemSpacing
centerRightInset += itemSize.width + itemSpacing
}
if let leftItemsBackground {
let leftItemsFrame = CGRect(origin: CGPoint(x: sideInset - (leftItemsWidth / 2.0 * 0.35 * component.collapseFraction), y: component.topInset + contentHeight / 2.0 + verticalOffset - panelHeight / 2.0), size: CGSize(width: leftItemsWidth, height: panelHeight))
leftItemsBackgroundTransition.setFrame(view: leftItemsBackground, frame: leftItemsFrame)
leftItemsBackground.update(size: leftItemsFrame.size, shape: .roundedRect(cornerRadius: leftItemsFrame.height * 0.5), isDark: component.theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: UIColor(white: component.theme.overallDarkAppearance ? 0.0 : 1.0, alpha: 0.6)), isInteractive: true, transition: leftItemsBackgroundTransition)
leftItemsBackgroundTransition.setScale(view: leftItemsBackground, scale: 1.0 - 0.999 * component.collapseFraction)
leftItemsBackgroundTransition.setAlpha(view: leftItemsBackground.contentView, alpha: 1.0 - component.collapseFraction)
} else if let leftItemsBackground = self.leftItemsBackground {
self.leftItemsBackground = nil
leftItemsBackground.removeFromSuperview()
}
if let rightItemsBackground {
let rightItemsFrame = CGRect(origin: CGPoint(x: availableSize.width - sideInset - rightItemsWidth * (1.0 - component.collapseFraction) + (rightItemsWidth / 2.0 * 0.35 * component.collapseFraction), y: component.topInset + contentHeight / 2.0 + verticalOffset - panelHeight / 2.0), size: CGSize(width: rightItemsWidth, height: panelHeight))
rightItemsBackgroundTransition.setFrame(view: rightItemsBackground, frame: rightItemsFrame)
rightItemsBackground.update(size: rightItemsFrame.size, shape: .roundedRect(cornerRadius: rightItemsFrame.height * 0.5), isDark: component.theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: UIColor(white: component.theme.overallDarkAppearance ? 0.0 : 1.0, alpha: 0.6)), isInteractive: true, transition: rightItemsBackgroundTransition)
rightItemsBackgroundTransition.setScale(view: rightItemsBackground, scale: 1.0 - 0.999 * component.collapseFraction)
rightItemsBackgroundTransition.setAlpha(view: rightItemsBackground.contentView, alpha: 1.0 - component.collapseFraction)
} else if let rightItemsBackground = self.rightItemsBackground {
self.rightItemsBackground = nil
rightItemsBackground.removeFromSuperview()
}
var removeLeftItemIds: [AnyHashable] = []
for (id, item) in self.leftItems {
if !validLeftItemIds.contains(id) {
removeLeftItemIds.append(id)
if let itemView = item.view {
transition.setScale(view: itemView, scale: 0.01)
transition.setAlpha(view: itemView, alpha: 0.0, completion: { _ in
itemView.removeFromSuperview()
})
}
}
}
for id in removeLeftItemIds {
self.leftItems.removeValue(forKey: id)
}
var removeRightItemIds: [AnyHashable] = []
for (id, item) in self.rightItems {
if !validRightItemIds.contains(id) {
removeRightItemIds.append(id)
if let itemView = item.view {
transition.setScale(view: itemView, scale: 0.01)
transition.setAlpha(view: itemView, alpha: 0.0, completion: { _ in
itemView.removeFromSuperview()
})
}
}
}
for id in removeRightItemIds {
self.rightItems.removeValue(forKey: id)
}
let maxCenterInset = max(centerLeftInset, centerRightInset)
if !leftItemList.isEmpty || !rightItemList.isEmpty {
availableWidth -= itemSpacing * CGFloat(max(0, leftItemList.count - 1)) + itemSpacing * CGFloat(max(0, rightItemList.count - 1)) + 30.0
if !component.leftItems.isEmpty || !component.rightItems.isEmpty {
availableWidth -= itemSpacing * CGFloat(max(0, component.leftItems.count - 1)) + itemSpacing * CGFloat(max(0, component.rightItems.count - 1)) + 30.0
}
availableWidth -= context.component.sideInset * 2.0
availableWidth -= component.sideInset * 2.0
let canCenter = availableWidth > 660.0
availableWidth = min(660.0, availableWidth)
let canCenter = availableWidth > 390.0
availableWidth = min(390.0, availableWidth)
let environment = BrowserNavigationBarEnvironment(fraction: context.component.collapseFraction)
let environment = BrowserNavigationBarEnvironment(fraction: component.collapseFraction)
let centerItem = context.component.centerItem.flatMap { item in
centerItems[item.id].update(
var centerX = maxCenterInset + (availableSize.width - maxCenterInset * 2.0) / 2.0
if canCenter {
centerX = availableSize.width / 2.0
} else {
centerX = centerLeftInset + (availableSize.width - centerLeftInset - centerRightInset) / 2.0
}
var validCenterItemIds: Set<AnyHashable> = Set()
if let item = component.centerItem {
validCenterItemIds.insert(item.id)
var itemTransition = transition
let itemView: ComponentView<BrowserNavigationBarEnvironment>
if let current = self.centerItems[item.id] {
itemView = current
} else {
itemTransition = .immediate
itemView = ComponentView<BrowserNavigationBarEnvironment>()
self.centerItems[item.id] = itemView
}
let itemSize = itemView.update(
transition: itemTransition,
component: item.component,
environment: { environment },
availableSize: CGSize(width: availableWidth, height: expandedHeight),
transition: context.transition
)
}
var centerX = maxCenterInset + (context.availableSize.width - maxCenterInset * 2.0) / 2.0
if "".isEmpty {
if canCenter {
centerX = context.availableSize.width / 2.0
} else {
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(centerItemPosition)
.scale(1.0 - 0.35 * context.component.collapseFraction)
.appear(.default(scale: false, alpha: true))
.disappear(.default(scale: false, alpha: true))
containerSize: CGSize(width: availableWidth, height: expandedHeight)
)
context.component.externalState?.centerItemFrame = centerItem.size.centered(around: centerItemPosition)
let itemPosition = CGPoint(x: centerX, y: component.topInset + contentHeight / 2.0 + verticalOffset)
let itemFrame = CGRect(origin: CGPoint(x: itemPosition.x - itemSize.width * 0.5, y: itemPosition.y - itemSize.height * 0.5), size: itemSize)
if let itemView = itemView.view {
if itemView.superview == nil {
self.containerView.contentView.addSubview(itemView)
transition.animateAlpha(view: itemView, from: 0.0, to: 1.0)
}
itemTransition.setBounds(view: itemView, bounds: CGRect(origin: .zero, size: itemFrame.size))
itemTransition.setPosition(view: itemView, position: itemFrame.center)
itemTransition.setScale(view: itemView, scale: 1.0 - 0.25 * component.collapseFraction)
}
component.externalState?.centerItemFrame = itemFrame
}
if context.component.collapseFraction == 1.0 {
let activateAction = context.component.activate
let activate = activate.update(
component: Button(
content: AnyComponent(Rectangle(color: UIColor(rgb: 0x000000, alpha: 0.001))),
action: {
activateAction()
}
),
availableSize: size,
transition: .immediate
)
context.add(activate
.position(CGPoint(x: size.width / 2.0, y: size.height / 2.0))
)
var removeCenterItemIds: [AnyHashable] = []
for (id, item) in self.centerItems {
if !validCenterItemIds.contains(id) {
removeCenterItemIds.append(id)
if let itemView = item.view {
transition.setAlpha(view: itemView, alpha: 0.0, completion: { _ in
itemView.removeFromSuperview()
})
}
}
}
for id in removeCenterItemIds {
self.centerItems.removeValue(forKey: id)
}
if component.collapseFraction == 1.0 {
if self.activateButton.superview == nil {
self.addSubview(self.activateButton)
}
self.activateButton.frame = CGRect(origin: .zero, size: size)
} else {
self.activateButton.removeFromSuperview()
}
self.containerView.update(size: size, isDark: component.theme.overallDarkAppearance, transition: transition)
transition.setFrame(view: self.containerView, frame: CGRect(origin: .zero, size: size))
let edgeEffectHeight: CGFloat = 80.0
let edgeEffectFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: edgeEffectHeight))
transition.setFrame(view: self.edgeEffectView, frame: edgeEffectFrame)
self.edgeEffectView.update(
content: .clear,
blur: true,
rect: edgeEffectFrame,
edge: .top,
edgeSize: edgeEffectFrame.height,
transition: transition
)
return size
}
}
public func makeView() -> View {
return View(frame: CGRect())
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}
private final class LoadingProgressComponent: Component {
final class LoadingProgressComponent: Component {
let color: UIColor
let height: CGFloat
let value: CGFloat
@@ -414,111 +536,3 @@ private final class LoadingProgressComponent: Component {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}
final class ReferenceButtonComponent: Component {
let content: AnyComponent<Empty>
let tag: AnyObject?
let action: () -> Void
init(
content: AnyComponent<Empty>,
tag: AnyObject? = nil,
action: @escaping () -> Void
) {
self.content = content
self.tag = tag
self.action = action
}
static func ==(lhs: ReferenceButtonComponent, rhs: ReferenceButtonComponent) -> Bool {
if lhs.content != rhs.content {
return false
}
if lhs.tag !== rhs.tag {
return false
}
return true
}
final class View: HighlightTrackingButton, ComponentTaggedView {
private let sourceView: ContextControllerSourceView
let referenceNode: ContextReferenceContentNode
let componentView: ComponentView<Empty>
private var component: ReferenceButtonComponent?
public func matches(tag: Any) -> Bool {
if let component = self.component, let componentTag = component.tag {
let tag = tag as AnyObject
if componentTag === tag {
return true
}
}
return false
}
init() {
self.componentView = ComponentView()
self.sourceView = ContextControllerSourceView()
self.sourceView.animateScale = false
self.referenceNode = ContextReferenceContentNode()
super.init(frame: CGRect())
self.sourceView.isUserInteractionEnabled = false
self.addSubview(self.sourceView)
self.sourceView.addSubnode(self.referenceNode)
self.highligthedChanged = { [weak self] highlighted in
if let strongSelf = self, let contentView = strongSelf.componentView.view {
if highlighted {
contentView.layer.removeAnimation(forKey: "opacity")
contentView.alpha = 0.4
} else {
contentView.alpha = 1.0
contentView.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
}
}
}
self.addTarget(self, action: #selector(self.pressed), for: .touchUpInside)
}
required init?(coder aDecoder: NSCoder) {
preconditionFailure()
}
@objc private func pressed() {
self.component?.action()
}
func update(component: ReferenceButtonComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
self.component = component
let componentSize = self.componentView.update(
transition: transition,
component: component.content,
environment: {},
containerSize: availableSize
)
if let componentView = self.componentView.view {
if componentView.superview == nil {
self.referenceNode.view.addSubview(componentView)
}
transition.setFrame(view: componentView, frame: CGRect(origin: .zero, size: componentSize))
}
transition.setFrame(view: self.sourceView, frame: CGRect(origin: .zero, size: componentSize))
self.referenceNode.frame = CGRect(origin: .zero, size: componentSize)
return componentSize
}
}
func makeView() -> View {
return View()
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}
@@ -16,6 +16,7 @@ import ShareController
import UndoUI
import UrlEscaping
import PDFKit
import GlassBackgroundComponent
final class BrowserPdfContent: UIView, BrowserContent, UIScrollViewDelegate, PDFDocumentDelegate {
private let context: AccountContext
@@ -25,7 +26,7 @@ final class BrowserPdfContent: UIView, BrowserContent, UIScrollViewDelegate, PDF
private let pdfView: PDFView
private let scrollView: UIScrollView!
private let pageIndicatorBackgorund: UIVisualEffectView
private let pageIndicatorBackground = GlassBackgroundView()
private let pageIndicator = ComponentView<Empty>()
private var pageNumber: (Int, Int)?
private var pageTimer: SwiftSignalKit.Timer?
@@ -61,11 +62,7 @@ final class BrowserPdfContent: UIView, BrowserContent, UIScrollViewDelegate, PDF
self.pdfView = PDFView()
self.pdfView.clipsToBounds = false
self.pageIndicatorBackgorund = UIVisualEffectView(effect: UIBlurEffect(style: .light))
self.pageIndicatorBackgorund.clipsToBounds = true
self.pageIndicatorBackgorund.layer.cornerRadius = 10.0
var scrollView: UIScrollView?
for view in self.pdfView.subviews {
if let view = view as? UIScrollView {
@@ -170,7 +167,7 @@ final class BrowserPdfContent: UIView, BrowserContent, UIScrollViewDelegate, PDF
return
}
let transition = ComponentTransition.easeInOut(duration: 0.25)
transition.setAlpha(view: self.pageIndicatorBackgorund, alpha: 0.0)
transition.setAlpha(view: self.pageIndicatorBackground, alpha: 0.0)
}, queue: Queue.mainQueue())
self.pageTimer?.start()
}
@@ -354,7 +351,7 @@ final class BrowserPdfContent: UIView, BrowserContent, UIScrollViewDelegate, PDF
self.validLayout = (size, insets, fullInsets)
self.previousScrollingOffset = ScrollingOffsetState(value: self.scrollView.contentOffset.y, isDraggingOrDecelerating: self.scrollView.isDragging || self.scrollView.isDecelerating)
let currentBounds = self.scrollView.bounds
let offsetToBottomEdge = max(0.0, self.scrollView.contentSize.height - currentBounds.maxY)
var bottomInset = insets.bottom
@@ -368,23 +365,24 @@ final class BrowserPdfContent: UIView, BrowserContent, UIScrollViewDelegate, PDF
let pageIndicatorSize = self.pageIndicator.update(
transition: .immediate,
component: AnyComponent(
Text(text: "\(self.pageNumber?.0 ?? 1) of \(self.pageNumber?.1 ?? 1)", font: Font.with(size: 15.0, weight: .semibold, traits: .monospacedNumbers), color: self.presentationData.theme.list.itemSecondaryTextColor)
Text(text: "\(self.pageNumber?.0 ?? 1) of \(self.pageNumber?.1 ?? 1)", font: Font.with(size: 15.0, weight: .regular, traits: .monospacedNumbers), color: self.presentationData.theme.list.itemPrimaryTextColor)
),
environment: {},
containerSize: size
)
if let view = self.pageIndicator.view {
if view.superview == nil {
self.addSubview(self.pageIndicatorBackgorund)
self.pageIndicatorBackgorund.contentView.addSubview(view)
self.addSubview(self.pageIndicatorBackground)
self.pageIndicatorBackground.contentView.addSubview(view)
}
let horizontalPadding: CGFloat = 10.0
let verticalPadding: CGFloat = 8.0
let pageBackgroundFrame = CGRect(origin: CGPoint(x: insets.left + 20.0, y: insets.top + 16.0), size: CGSize(width: horizontalPadding * 2.0 + pageIndicatorSize.width, height: verticalPadding * 2.0 + pageIndicatorSize.height))
let pageBackgroundFrame = CGRect(origin: CGPoint(x: insets.left + 16.0, y: insets.top + 16.0), size: CGSize(width: horizontalPadding * 2.0 + pageIndicatorSize.width, height: verticalPadding * 2.0 + pageIndicatorSize.height))
self.pageIndicatorBackgorund.bounds = CGRect(origin: .zero, size: pageBackgroundFrame.size)
transition.setPosition(view: self.pageIndicatorBackgorund, position: pageBackgroundFrame.center)
self.pageIndicatorBackground.update(size: pageBackgroundFrame.size, cornerRadius: pageBackgroundFrame.size.height * 0.5, isDark: self.presentationData.theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: UIColor(white: self.presentationData.theme.overallDarkAppearance ? 0.0 : 1.0, alpha: 0.6)), transition: transition)
self.pageIndicatorBackground.bounds = CGRect(origin: .zero, size: pageBackgroundFrame.size)
transition.setPosition(view: self.pageIndicatorBackground, position: pageBackgroundFrame.center)
view.frame = CGRect(origin: CGPoint(x: horizontalPadding, y: verticalPadding), size: pageIndicatorSize)
}
@@ -459,7 +457,7 @@ final class BrowserPdfContent: UIView, BrowserContent, UIScrollViewDelegate, PDF
}
let transition = ComponentTransition.easeInOut(duration: 0.1)
transition.setAlpha(view: self.pageIndicatorBackgorund, alpha: 1.0)
transition.setAlpha(view: self.pageIndicatorBackground, alpha: 1.0)
self.pageTimer?.invalidate()
self.pageTimer = nil
@@ -20,6 +20,7 @@ import InstantPageUI
import NavigationStackComponent
import LottieComponent
import WebKit
import GlassBarButtonComponent
private let settingsTag = GenericComponentViewTag()
@@ -85,6 +86,8 @@ private final class BrowserScreenComponent: CombinedComponent {
let navigationBarExternalState = BrowserNavigationBarComponent.ExternalState()
let moreButtonPlayOnce = ActionSlot<Void>()
return { context in
let environment = context.environment[ViewControllerComponentContainer.Environment.self].value
let performAction = context.component.performAction
@@ -123,6 +126,8 @@ private final class BrowserScreenComponent: CombinedComponent {
url: context.component.contentState?.url ?? "",
isSecure: context.component.contentState?.isSecure ?? false,
isExpanded: context.component.presentationState.addressFocused,
readingProgress: context.component.contentState?.readingProgress ?? 0.0,
loadingProgress: context.component.contentState?.estimatedProgress,
performAction: performAction
)
)
@@ -134,7 +139,9 @@ private final class BrowserScreenComponent: CombinedComponent {
component: AnyComponent(
TitleBarContentComponent(
theme: environment.theme,
title: title
title: title,
readingProgress: context.component.contentState?.readingProgress ?? 0.0,
loadingProgress: context.component.contentState?.estimatedProgress
)
)
)
@@ -150,37 +157,40 @@ private final class BrowserScreenComponent: CombinedComponent {
component: AnyComponent(
Button(
content: AnyComponent(
MultilineTextComponent(text: .plain(NSAttributedString(string: environment.strings.WebBrowser_Done, font: Font.semibold(17.0), textColor: environment.theme.rootController.navigationBar.accentTextColor, paragraphAlignment: .center)), horizontalAlignment: .left, maximumNumberOfLines: 1)
BundleIconComponent(
name: "Navigation/Close",
tintColor: environment.theme.chat.inputPanel.panelControlColor
)
),
action: {
performAction.invoke(.close)
}
)
).minSize(CGSize(width: 44.0, height: 44.0))
)
)
]
if isTablet {
#if DEBUG
navigationLeftItems.append(
AnyComponentWithIdentity(
id: "minimize",
component: AnyComponent(
Button(
content: AnyComponent(
BundleIconComponent(
name: "Media Gallery/PictureInPictureButton",
tintColor: environment.theme.rootController.navigationBar.accentTextColor
)
),
action: {
performAction.invoke(.close)
}
)
)
)
)
#endif
// #if DEBUG
// navigationLeftItems.append(
// AnyComponentWithIdentity(
// id: "minimize",
// component: AnyComponent(
// Button(
// content: AnyComponent(
// BundleIconComponent(
// name: "Media Gallery/PictureInPictureButton",
// tintColor: environment.theme.rootController.navigationBar.accentTextColor
// )
// ),
// action: {
// performAction.invoke(.close)
// }
// )
// )
// )
// )
// #endif
let canGoBack = context.component.contentState?.canGoBack ?? false
let canGoForward = context.component.contentState?.canGoForward ?? false
@@ -193,13 +203,13 @@ private final class BrowserScreenComponent: CombinedComponent {
content: AnyComponent(
BundleIconComponent(
name: "Instant View/Back",
tintColor: environment.theme.rootController.navigationBar.accentTextColor.withAlphaComponent(canGoBack ? 1.0 : 0.4)
tintColor: environment.theme.chat.inputPanel.panelControlColor.withAlphaComponent(canGoBack ? 1.0 : 0.4)
)
),
action: {
performAction.invoke(.navigateBack)
}
)
).minSize(CGSize(width: 44.0, height: 44.0))
)
)
)
@@ -212,13 +222,13 @@ private final class BrowserScreenComponent: CombinedComponent {
content: AnyComponent(
BundleIconComponent(
name: "Instant View/Forward",
tintColor: environment.theme.rootController.navigationBar.accentTextColor.withAlphaComponent(canGoForward ? 1.0 : 0.4)
tintColor: environment.theme.chat.inputPanel.panelControlColor.withAlphaComponent(canGoForward ? 1.0 : 0.4)
)
),
action: {
performAction.invoke(.navigateForward)
}
)
).minSize(CGSize(width: 44.0, height: 44.0))
)
)
)
@@ -228,21 +238,22 @@ private final class BrowserScreenComponent: CombinedComponent {
AnyComponentWithIdentity(
id: "settings",
component: AnyComponent(
ReferenceButtonComponent(
Button(
content: AnyComponent(
LottieComponent(
content: LottieComponent.AppBundleContent(
name: "anim_moredots"
name: "anim_morewide"
),
color: environment.theme.rootController.navigationBar.accentTextColor,
size: CGSize(width: 30.0, height: 30.0)
color: environment.theme.chat.inputPanel.panelControlColor,
size: CGSize(width: 34.0, height: 34.0),
playOnce: moreButtonPlayOnce
)
),
tag: settingsTag,
action: {
performAction.invoke(.openSettings)
moreButtonPlayOnce.invoke(Void())
}
)
).minSize(CGSize(width: 44.0, height: 44.0)).tagged(settingsTag)
)
)
]
@@ -256,13 +267,13 @@ private final class BrowserScreenComponent: CombinedComponent {
content: AnyComponent(
BundleIconComponent(
name: "Instant View/Bookmark",
tintColor: environment.theme.rootController.navigationBar.accentTextColor
tintColor: environment.theme.chat.inputPanel.panelControlColor
)
),
action: {
performAction.invoke(.openBookmarks)
}
)
).minSize(CGSize(width: 44.0, height: 44.0))
)
),
at: 0
@@ -275,14 +286,14 @@ private final class BrowserScreenComponent: CombinedComponent {
Button(
content: AnyComponent(
BundleIconComponent(
name: "Chat List/NavigationShare",
tintColor: environment.theme.rootController.navigationBar.accentTextColor
name: "Instant View/Share",
tintColor: environment.theme.chat.inputPanel.panelControlColor
)
),
action: {
performAction.invoke(.share)
}
)
).minSize(CGSize(width: 44.0, height: 44.0))
)
),
at: 0
@@ -297,13 +308,13 @@ private final class BrowserScreenComponent: CombinedComponent {
content: AnyComponent(
BundleIconComponent(
name: "Instant View/Browser",
tintColor: environment.theme.rootController.navigationBar.accentTextColor
tintColor: environment.theme.chat.inputPanel.panelControlColor
)
),
action: {
performAction.invoke(.openIn)
}
)
).minSize(CGSize(width: 44.0, height: 44.0))
)
)
)
@@ -316,21 +327,15 @@ private final class BrowserScreenComponent: CombinedComponent {
let navigationBar = navigationBar.update(
component: BrowserNavigationBarComponent(
backgroundColor: environment.theme.rootController.navigationBar.blurredBackgroundColor,
separatorColor: environment.theme.rootController.navigationBar.separatorColor,
textColor: environment.theme.rootController.navigationBar.primaryTextColor,
progressColor: environment.theme.rootController.navigationBar.segmentedBackgroundColor,
accentColor: environment.theme.rootController.navigationBar.accentTextColor,
theme: environment.theme,
topInset: environment.statusBarHeight,
height: environment.navigationHeight - environment.statusBarHeight,
height: environment.navigationHeight - environment.statusBarHeight + 8.0,
sideInset: environment.safeInsets.left,
metrics: environment.metrics,
externalState: navigationBarExternalState,
leftItems: navigationLeftItems,
rightItems: navigationRightItems,
centerItem: navigationContent,
readingProgress: context.component.contentState?.readingProgress ?? 0.0,
loadingProgress: context.component.contentState?.estimatedProgress,
collapseFraction: collapseFraction,
activate: {
performAction.invoke(.expand)
@@ -339,9 +344,6 @@ private final class BrowserScreenComponent: CombinedComponent {
availableSize: context.availableSize,
transition: context.transition
)
context.add(navigationBar
.position(CGPoint(x: context.availableSize.width / 2.0, y: navigationBar.size.height / 2.0))
)
let toolbarContent: AnyComponentWithIdentity<Empty>?
if context.component.presentationState.isSearching {
@@ -349,8 +351,8 @@ private final class BrowserScreenComponent: CombinedComponent {
id: "search",
component: AnyComponent(
SearchToolbarContentComponent(
theme: environment.theme,
strings: environment.strings,
textColor: environment.theme.rootController.navigationBar.primaryTextColor,
index: context.component.presentationState.searchResultIndex,
count: context.component.presentationState.searchResultCount,
isEmpty: context.component.presentationState.searchQueryIsEmpty,
@@ -363,8 +365,7 @@ private final class BrowserScreenComponent: CombinedComponent {
id: "navigation",
component: AnyComponent(
NavigationToolbarContentComponent(
accentColor: environment.theme.rootController.navigationBar.accentTextColor,
textColor: environment.theme.rootController.navigationBar.primaryTextColor,
theme: environment.theme,
canGoBack: context.component.contentState?.canGoBack ?? false,
canGoForward: context.component.contentState?.canGoForward ?? false,
canOpenIn: canOpenIn,
@@ -384,15 +385,12 @@ private final class BrowserScreenComponent: CombinedComponent {
toolbarBottomInset = environment.safeInsets.bottom
}
var toolbarSize: CGFloat = 0.0
if isTablet && !context.component.presentationState.isSearching {
} else {
let toolbar = toolbar.update(
component: BrowserToolbarComponent(
backgroundColor: environment.theme.rootController.navigationBar.blurredBackgroundColor,
separatorColor: environment.theme.rootController.navigationBar.separatorColor,
textColor: environment.theme.rootController.navigationBar.primaryTextColor,
theme: environment.theme,
bottomInset: toolbarBottomInset,
sideInset: environment.safeInsets.left,
item: toolbarContent,
@@ -412,16 +410,9 @@ private final class BrowserScreenComponent: CombinedComponent {
})
})
)
toolbarSize = toolbar.size.height
}
if context.component.presentationState.addressFocused {
let addressListSize: CGSize
if isTablet {
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(
@@ -431,12 +422,13 @@ private final class BrowserScreenComponent: CombinedComponent {
insets: UIEdgeInsets(top: 0.0, left: environment.safeInsets.left, bottom: 0.0, right: environment.safeInsets.right),
metrics: environment.metrics,
addressBarFrame: navigationBarExternalState.centerItemFrame,
navigationBarHeight: navigationBar.size.height,
performAction: performAction,
presentInGlobalOverlay: { c in
controller()?.presentInGlobalOverlay(c)
}
),
availableSize: addressListSize,
availableSize: context.availableSize,
transition: context.transition
)
@@ -448,7 +440,7 @@ private final class BrowserScreenComponent: CombinedComponent {
)
} else {
context.add(addressList
.position(CGPoint(x: context.availableSize.width / 2.0, y: navigationBar.size.height + addressList.size.height / 2.0))
.position(CGPoint(x: context.availableSize.width / 2.0, y: addressList.size.height / 2.0))
.clipsToBounds(true)
.appear(.default(alpha: true))
.disappear(.default(alpha: true))
@@ -456,6 +448,10 @@ private final class BrowserScreenComponent: CombinedComponent {
}
}
context.add(navigationBar
.position(CGPoint(x: context.availableSize.width / 2.0, y: navigationBar.size.height / 2.0))
)
return context.availableSize
}
}
@@ -1075,7 +1071,7 @@ public class BrowserScreen: ViewController, MinimizableController {
}
func openSettings() {
guard let referenceView = self.componentHost.findTaggedView(tag: settingsTag) as? ReferenceButtonComponent.View else {
guard let referenceView = self.componentHost.findTaggedView(tag: settingsTag) else {
return
}
@@ -1083,10 +1079,6 @@ public class BrowserScreen: ViewController, MinimizableController {
return
}
if let animationComponentView = referenceView.componentView.view as? LottieComponent.View {
animationComponentView.playOnce()
}
if let webContent = content as? BrowserWebContent {
webContent.requestInstantView()
}
@@ -1103,7 +1095,7 @@ public class BrowserScreen: ViewController, MinimizableController {
}
}
let source: ContextContentSource = .reference(BrowserReferenceContentSource(controller: controller, sourceView: referenceView.referenceNode.view))
let source: ContextContentSource = .reference(BrowserReferenceContentSource(controller: controller, sourceView: referenceView))
let items: Signal<ContextController.Items, NoError> = combineLatest(
queue: Queue.mainQueue(),
@@ -1549,6 +1541,8 @@ public class BrowserScreen: ViewController, MinimizableController {
super.init(navigationBarPresentationData: nil)
self._hasGlassStyle = true
self.navigationPresentation = .modalInCompactLayout
self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .allButUpsideDown)
@@ -1731,7 +1725,7 @@ private final class BrowserContentComponent: Component {
self.addSubview(component.content)
}
let collapsedHeight: CGFloat = 24.0
let collapsedHeight: CGFloat = 54.0
let topInset: CGFloat = component.navigationBarHeight * (1.0 - component.scrollingPanelOffsetFraction) + (component.insets.top + collapsedHeight) * component.scrollingPanelOffsetFraction
let bottomInset = component.hasBottomPanel ? (49.0 + component.insets.bottom) * (1.0 - component.scrollingPanelOffsetFraction) : 0.0
let insets = UIEdgeInsets(top: topInset, left: component.insets.left, bottom: bottomInset, right: component.insets.right)
@@ -7,6 +7,7 @@ import ComponentFlow
import TelegramPresentationData
import AccountContext
import BundleIconComponent
import SearchInputPanelComponent
final class SearchBarContentComponent: Component {
public typealias EnvironmentType = BrowserNavigationBarEnvironment
@@ -35,112 +36,16 @@ final class SearchBarContentComponent: Component {
return true
}
final class View: UIView, UITextFieldDelegate {
private final class SearchTextField: UITextField {
override func textRect(forBounds bounds: CGRect) -> CGRect {
return bounds.integral
}
}
private struct Params: Equatable {
var theme: PresentationTheme
var strings: PresentationStrings
var size: CGSize
static func ==(lhs: Params, rhs: Params) -> Bool {
if lhs.theme !== rhs.theme {
return false
}
if lhs.strings !== rhs.strings {
return false
}
if lhs.size != rhs.size {
return false
}
return true
}
}
final class View: UIView {
private let queryPromise = ValuePromise<String>()
private var queryDisposable: Disposable?
private let backgroundLayer: SimpleLayer
private let searchInput = ComponentView<Empty>()
private let iconView: UIImageView
private let clearIconView: UIImageView
private let clearIconButton: HighlightTrackingButton
private let cancelButtonTitle: ComponentView<Empty>
private let cancelButton: HighlightTrackingButton
private var placeholderContent = ComponentView<Empty>()
private var textFrame: CGRect?
private var textField: SearchTextField?
private var tapRecognizer: UITapGestureRecognizer?
private var params: Params?
private var component: SearchBarContentComponent?
init() {
self.backgroundLayer = SimpleLayer()
self.iconView = UIImageView()
self.clearIconView = UIImageView()
self.clearIconButton = HighlightableButton()
self.clearIconView.isHidden = true
self.clearIconButton.isHidden = true
self.cancelButtonTitle = ComponentView()
self.cancelButton = HighlightTrackingButton()
super.init(frame: CGRect())
self.layer.addSublayer(self.backgroundLayer)
self.addSubview(self.iconView)
self.addSubview(self.clearIconView)
self.addSubview(self.clearIconButton)
self.addSubview(self.cancelButton)
self.clipsToBounds = true
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))
self.tapRecognizer = tapRecognizer
self.addGestureRecognizer(tapRecognizer)
self.cancelButton.highligthedChanged = { [weak self] highlighted in
if let strongSelf = self {
if highlighted {
if let cancelButtonTitleView = strongSelf.cancelButtonTitle.view {
cancelButtonTitleView.layer.removeAnimation(forKey: "opacity")
cancelButtonTitleView.alpha = 0.4
}
} else {
if let cancelButtonTitleView = strongSelf.cancelButtonTitle.view {
cancelButtonTitleView.alpha = 1.0
cancelButtonTitleView.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
}
}
}
}
self.cancelButton.addTarget(self, action: #selector(self.cancelPressed), for: .touchUpInside)
self.clearIconButton.highligthedChanged = { [weak self] highlighted in
if let strongSelf = self {
if highlighted {
strongSelf.clearIconView.layer.removeAnimation(forKey: "opacity")
strongSelf.clearIconView.alpha = 0.4
} else {
strongSelf.clearIconView.alpha = 1.0
strongSelf.clearIconView.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
}
}
}
self.clearIconButton.addTarget(self, action: #selector(self.clearPressed), for: .touchUpInside)
override init(frame: CGRect) {
super.init(frame: frame)
let throttledSearchQuery = self.queryPromise.get()
|> mapToSignal { query -> Signal<String, NoError> in
@@ -164,194 +69,46 @@ final class SearchBarContentComponent: Component {
fatalError("init(coder:) has not been implemented")
}
@objc private func tapGesture(_ recognizer: UITapGestureRecognizer) {
if case .ended = recognizer.state {
self.activateTextInput()
}
}
private func activateTextInput() {
if self.textField == nil, let textFrame = self.textFrame {
let backgroundFrame = self.backgroundLayer.frame
let textFieldFrame = CGRect(origin: CGPoint(x: textFrame.minX, y: backgroundFrame.minY), size: CGSize(width: backgroundFrame.maxX - textFrame.minX - 32.0, height: backgroundFrame.height))
let textField = SearchTextField(frame: textFieldFrame)
textField.clipsToBounds = true
textField.autocorrectionType = .no
textField.returnKeyType = .search
self.textField = textField
self.insertSubview(textField, belowSubview: self.clearIconView)
textField.delegate = self
textField.addTarget(self, action: #selector(self.textFieldChanged(_:)), for: .editingChanged)
}
guard !(self.textField?.isFirstResponder ?? false) else {
return
}
self.textField?.becomeFirstResponder()
}
@objc private func cancelPressed() {
self.clearIconView.isHidden = true
self.clearIconButton.isHidden = true
let textField = self.textField
self.textField = nil
self.component?.performAction.invoke(.updateSearchActive(false))
if let textField {
textField.resignFirstResponder()
textField.removeFromSuperview()
}
}
@objc private func clearPressed() {
guard let textField = self.textField else {
return
}
textField.text = ""
self.textFieldChanged(textField)
}
func deactivate() {
if let text = self.textField?.text, !text.isEmpty {
self.textField?.endEditing(true)
} else {
self.cancelPressed()
}
}
public func textFieldDidBeginEditing(_ textField: UITextField) {
}
public func textFieldDidEndEditing(_ textField: UITextField) {
}
public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.endEditing(true)
return false
}
@objc private func textFieldChanged(_ textField: UITextField) {
let text = textField.text ?? ""
self.clearIconView.isHidden = text.isEmpty
self.clearIconButton.isHidden = text.isEmpty
self.placeholderContent.view?.isHidden = !text.isEmpty
self.queryPromise.set(text)
if let params = self.params {
self.update(theme: params.theme, strings: params.strings, size: params.size, transition: .immediate)
}
}
func update(component: SearchBarContentComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
self.component = component
self.update(theme: component.theme, strings: component.strings, size: availableSize, transition: transition)
self.activateTextInput()
return availableSize
}
public func update(theme: PresentationTheme, strings: PresentationStrings, size: CGSize, transition: ComponentTransition) {
let params = Params(
theme: theme,
strings: strings,
size: size
)
if self.params == params {
return
}
let isActiveWithText = true
if self.params?.theme !== theme {
self.iconView.image = generateTintedImage(image: UIImage(bundleImageName: "Components/Search Bar/Loupe"), color: .white)?.withRenderingMode(.alwaysTemplate)
self.iconView.tintColor = theme.rootController.navigationSearchBar.inputIconColor
self.clearIconView.image = generateTintedImage(image: UIImage(bundleImageName: "Components/Search Bar/Clear"), color: .white)?.withRenderingMode(.alwaysTemplate)
self.clearIconView.tintColor = theme.rootController.navigationSearchBar.inputClearButtonColor
}
self.params = params
let sideInset: CGFloat = 10.0
let inputHeight: CGFloat = 36.0
let topInset: CGFloat = (size.height - inputHeight) / 2.0
let sideTextInset: CGFloat = sideInset + 4.0 + 17.0
self.backgroundLayer.backgroundColor = theme.rootController.navigationSearchBar.inputFillColor.cgColor
self.backgroundLayer.cornerRadius = 10.5
let cancelTextSize = self.cancelButtonTitle.update(
transition: .immediate,
component: AnyComponent(Text(
text: strings.Common_Cancel,
font: Font.regular(17.0),
color: theme.rootController.navigationBar.accentTextColor
)),
environment: {},
containerSize: CGSize(width: size.width - 32.0, height: 100.0)
)
let cancelButtonSpacing: CGFloat = 8.0
var backgroundFrame = CGRect(origin: CGPoint(x: sideInset, y: topInset), size: CGSize(width: size.width - sideInset * 2.0, height: inputHeight))
if isActiveWithText {
backgroundFrame.size.width -= cancelTextSize.width + cancelButtonSpacing
}
transition.setFrame(layer: self.backgroundLayer, frame: backgroundFrame)
transition.setFrame(view: self.cancelButton, frame: CGRect(origin: CGPoint(x: backgroundFrame.maxX, y: 0.0), size: CGSize(width: cancelButtonSpacing + cancelTextSize.width, height: size.height)))
let textX: CGFloat = backgroundFrame.minX + sideTextInset
let textFrame = CGRect(origin: CGPoint(x: textX, y: backgroundFrame.minY), size: CGSize(width: backgroundFrame.maxX - textX, height: backgroundFrame.height))
self.textFrame = textFrame
if let image = self.iconView.image {
let iconFrame = CGRect(origin: CGPoint(x: backgroundFrame.minX + 5.0, y: backgroundFrame.minY + floor((backgroundFrame.height - image.size.height) / 2.0)), size: image.size)
transition.setFrame(view: self.iconView, frame: iconFrame)
}
let placeholderSize = self.placeholderContent.update(
let searchInputSize = self.searchInput.update(
transition: transition,
component: AnyComponent(
Text(text: strings.Common_Search, font: Font.regular(17.0), color: theme.rootController.navigationSearchBar.inputPlaceholderTextColor)
SearchInputPanelComponent(
theme: component.theme,
strings: component.strings,
metrics: .init(widthClass: .compact, heightClass: .compact, orientation: nil),
safeInsets: UIEdgeInsets(),
placeholder: component.strings.Common_Search,
hasEdgeEffect: false,
updated: { [weak self] query in
guard let self else {
return
}
self.queryPromise.set(query)
},
cancel: { [weak self] in
guard let self else {
return
}
self.component?.performAction.invoke(.updateSearchActive(false))
}
)
),
environment: {},
containerSize: size
containerSize: availableSize
)
if let placeholderContentView = self.placeholderContent.view {
if placeholderContentView.superview == nil {
self.addSubview(placeholderContentView)
if let searchInputView = self.searchInput.view as? SearchInputPanelComponent.View {
if searchInputView.superview == nil {
self.addSubview(searchInputView)
searchInputView.activateInput()
}
let placeholderContentFrame = CGRect(origin: CGPoint(x: textFrame.minX, y: backgroundFrame.midY - placeholderSize.height / 2.0), size: placeholderSize)
transition.setFrame(view: placeholderContentView, frame: placeholderContentFrame)
}
if let image = self.clearIconView.image {
let iconFrame = CGRect(origin: CGPoint(x: backgroundFrame.maxX - image.size.width - 4.0, y: backgroundFrame.minY + floor((backgroundFrame.height - image.size.height) / 2.0)), size: image.size)
transition.setFrame(view: self.clearIconView, frame: iconFrame)
transition.setFrame(view: self.clearIconButton, frame: iconFrame.insetBy(dx: -8.0, dy: -10.0))
}
if let cancelButtonTitleComponentView = self.cancelButtonTitle.view {
if cancelButtonTitleComponentView.superview == nil {
self.addSubview(cancelButtonTitleComponentView)
cancelButtonTitleComponentView.isUserInteractionEnabled = false
}
transition.setFrame(view: cancelButtonTitleComponentView, frame: CGRect(origin: CGPoint(x: backgroundFrame.maxX + cancelButtonSpacing, y: floor((size.height - cancelTextSize.height) / 2.0)), size: cancelTextSize))
}
if let textField = self.textField {
textField.textColor = theme.rootController.navigationSearchBar.inputTextColor
transition.setFrame(view: textField, frame: CGRect(origin: CGPoint(x: backgroundFrame.minX + sideTextInset, y: backgroundFrame.minY - UIScreenPixel), size: CGSize(width: backgroundFrame.width - sideTextInset - 32.0, height: backgroundFrame.height)))
transition.setFrame(view: searchInputView, frame: CGRect(origin: .zero, size: searchInputSize))
}
return availableSize
}
}
@@ -9,19 +9,26 @@ import AccountContext
import BundleIconComponent
import MultilineTextComponent
import UrlEscaping
import GlassBackgroundComponent
final class TitleBarContentComponent: Component {
public typealias EnvironmentType = BrowserNavigationBarEnvironment
let theme: PresentationTheme
let title: String
let readingProgress: CGFloat
let loadingProgress: Double?
init(
theme: PresentationTheme,
title: String
title: String,
readingProgress: CGFloat,
loadingProgress: Double?
) {
self.theme = theme
self.title = title
self.readingProgress = readingProgress
self.loadingProgress = loadingProgress
}
static func ==(lhs: TitleBarContentComponent, rhs: TitleBarContentComponent) -> Bool {
@@ -31,15 +38,30 @@ final class TitleBarContentComponent: Component {
if lhs.title != rhs.title {
return false
}
if lhs.readingProgress != rhs.readingProgress {
return false
}
if lhs.loadingProgress != rhs.loadingProgress {
return false
}
return true
}
final class View: UIView {
private let backgroundView = GlassBackgroundView()
private let clippingView = UIView()
private let readingProgressView = UIView()
private var titleContent = ComponentView<Empty>()
private var component: TitleBarContentComponent?
init() {
super.init(frame: CGRect())
self.clippingView.clipsToBounds = true
self.addSubview(self.backgroundView)
self.backgroundView.contentView.addSubview(self.clippingView)
self.clippingView.addSubview(self.readingProgressView)
}
required public init?(coder: NSCoder) {
@@ -48,7 +70,9 @@ final class TitleBarContentComponent: Component {
func update(component: TitleBarContentComponent, availableSize: CGSize, environment: Environment<BrowserNavigationBarEnvironment>, transition: ComponentTransition) -> CGSize {
self.component = component
let collapseFraction = environment[BrowserNavigationBarEnvironment.self].fraction
let titleSize = self.titleContent.update(
transition: transition,
component: AnyComponent(
@@ -60,7 +84,7 @@ final class TitleBarContentComponent: Component {
)
),
environment: {},
containerSize: CGSize(width: availableSize.width - 36.0, height: availableSize.height)
containerSize: CGSize(width: availableSize.width - 42.0, height: availableSize.height)
)
let titleContentFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - titleSize.width) / 2.0), y: floorToScreenPixels((availableSize.height - titleSize.height) / 2.0)), size: titleSize)
if let titleContentView = self.titleContent.view {
@@ -71,6 +95,18 @@ final class TitleBarContentComponent: Component {
titleContentView.bounds = CGRect(origin: .zero, size: titleContentFrame.size)
}
let expandedBackgroundWidth = availableSize.width - 14.0 * 2.0
let collapsedBackgroundWidth = titleSize.width + 32.0
let backgroundSize = CGSize(width: expandedBackgroundWidth * (1.0 - collapseFraction) + collapsedBackgroundWidth * collapseFraction, height: 44.0)
self.backgroundView.update(size: backgroundSize, cornerRadius: backgroundSize.height * 0.5, isDark: component.theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: UIColor(white: component.theme.overallDarkAppearance ? 0.0 : 1.0, alpha: 0.6)), transition: transition)
let backgroundFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - backgroundSize.width) / 2.0), y: floor((availableSize.height - backgroundSize.height) / 2.0)), size: backgroundSize)
transition.setFrame(view: self.backgroundView, frame: backgroundFrame)
transition.setFrame(view: self.clippingView, frame: CGRect(origin: .zero, size: backgroundFrame.size))
transition.setCornerRadius(layer: self.clippingView.layer, cornerRadius: backgroundFrame.size.height * 0.5)
self.readingProgressView.backgroundColor = component.theme.rootController.navigationBar.primaryTextColor.withMultipliedAlpha(0.07)
self.readingProgressView.frame = CGRect(origin: .zero, size: CGSize(width: backgroundSize.width * component.readingProgress, height: backgroundSize.height))
return availableSize
}
}
@@ -6,28 +6,24 @@ import BlurredBackgroundComponent
import BundleIconComponent
import TelegramPresentationData
import ContextReferenceButtonComponent
import GlassBackgroundComponent
import EdgeEffect
final class BrowserToolbarComponent: CombinedComponent {
let backgroundColor: UIColor
let separatorColor: UIColor
let textColor: UIColor
let theme: PresentationTheme
let bottomInset: CGFloat
let sideInset: CGFloat
let item: AnyComponentWithIdentity<Empty>?
let collapseFraction: CGFloat
init(
backgroundColor: UIColor,
separatorColor: UIColor,
textColor: UIColor,
theme: PresentationTheme,
bottomInset: CGFloat,
sideInset: CGFloat,
item: AnyComponentWithIdentity<Empty>?,
collapseFraction: CGFloat
) {
self.backgroundColor = backgroundColor
self.separatorColor = separatorColor
self.textColor = textColor
self.theme = theme
self.bottomInset = bottomInset
self.sideInset = sideInset
self.item = item
@@ -35,13 +31,7 @@ final class BrowserToolbarComponent: CombinedComponent {
}
static func ==(lhs: BrowserToolbarComponent, rhs: BrowserToolbarComponent) -> Bool {
if lhs.backgroundColor != rhs.backgroundColor {
return false
}
if lhs.separatorColor != rhs.separatorColor {
return false
}
if lhs.textColor != rhs.textColor {
if lhs.theme !== rhs.theme {
return false
}
if lhs.bottomInset != rhs.bottomInset {
@@ -60,54 +50,70 @@ final class BrowserToolbarComponent: CombinedComponent {
}
static var body: Body {
let background = Child(BlurredBackgroundComponent.self)
let separator = Child(Rectangle.self)
let edgeEffect = Child(EdgeEffectComponent.self)
let background = Child(GlassBackgroundComponent.self)
let centerItems = ChildMap(environment: Empty.self, keyedBy: AnyHashable.self)
return { context in
let contentHeight: CGFloat = 49.0
let contentHeight: CGFloat = 56.0
let totalHeight = contentHeight + context.component.bottomInset
let offset = context.component.collapseFraction * totalHeight
let size = CGSize(width: context.availableSize.width, height: totalHeight)
let background = background.update(
component: BlurredBackgroundComponent(color: context.component.backgroundColor),
availableSize: CGSize(width: size.width, height: size.height),
let backgroundHeight: CGFloat = 48.0
let edgeEffectHeight = totalHeight
let edgeEffect = edgeEffect.update(
component: EdgeEffectComponent(
color: .clear,
blur: true,
alpha: 1.0,
size: CGSize(width: size.width, height: edgeEffectHeight),
edge: .bottom,
edgeSize: edgeEffectHeight
),
availableSize: CGSize(width: size.width, height: edgeEffectHeight),
transition: context.transition
)
let separator = separator.update(
component: Rectangle(color: context.component.separatorColor, height: UIScreenPixel),
availableSize: CGSize(width: size.width, height: size.height),
transition: context.transition
context.add(edgeEffect
.position(CGPoint(x: size.width / 2.0, y: size.height / 2.0 + offset))
)
let item = context.component.item.flatMap { item in
return centerItems[item.id].update(
component: item.component,
availableSize: CGSize(width: context.availableSize.width - context.component.sideInset * 2.0, height: contentHeight),
availableSize: CGSize(width: context.availableSize.width - context.component.sideInset * 2.0, height: backgroundHeight),
transition: context.transition
)
}
let contentWidth = item?.size.width ?? 0.0
let backgroundSize = CGSize(width: contentWidth, height: backgroundHeight)
let background = background.update(
component: GlassBackgroundComponent(
size: backgroundSize,
cornerRadius: backgroundHeight * 0.5,
isDark: context.component.theme.overallDarkAppearance,
tintColor: .init(kind: .panel, color: UIColor(white: context.component.theme.overallDarkAppearance ? 0.0 : 1.0, alpha: 0.6)),
isInteractive: true
),
availableSize: backgroundSize,
transition: context.transition
)
context.add(background
.position(CGPoint(x: size.width / 2.0, y: size.height / 2.0 + offset))
.position(CGPoint(x: size.width / 2.0, y: backgroundSize.height / 2.0 + offset))
)
context.add(separator
.position(CGPoint(x: size.width / 2.0, y: 0.0 + offset))
)
if let centerItem = item {
context.add(centerItem
.position(CGPoint(x: context.availableSize.width / 2.0, y: contentHeight / 2.0 + offset))
.position(CGPoint(x: context.availableSize.width / 2.0, y: backgroundSize.height / 2.0 + offset))
.appear(ComponentTransition.Appear({ _, view, transition in
transition.animatePosition(view: view, from: CGPoint(x: 0.0, y: size.height), to: .zero, additive: true)
transition.animateBlur(layer: view.layer, fromRadius: 10.0, toRadius: 0.0)
transition.animateAlpha(view: view, from: 0.0, to: 1.0)
}))
.disappear(ComponentTransition.Disappear({ view, transition, completion in
let from = view.center
view.center = from.offsetBy(dx: 0.0, dy: size.height)
transition.animatePosition(view: view, from: from, to: view.center, completion: { _ in
transition.animateBlur(layer: view.layer, fromRadius: 0.0, toRadius: 10.0)
transition.setAlpha(view: view, alpha: 0.0, completion: { _ in
completion()
})
}))
@@ -120,8 +126,7 @@ final class BrowserToolbarComponent: CombinedComponent {
}
final class NavigationToolbarContentComponent: CombinedComponent {
let accentColor: UIColor
let textColor: UIColor
let theme: PresentationTheme
let canGoBack: Bool
let canGoForward: Bool
let canOpenIn: Bool
@@ -131,8 +136,7 @@ final class NavigationToolbarContentComponent: CombinedComponent {
let performHoldAction: (UIView, ContextGesture?, BrowserScreen.Action) -> Void
init(
accentColor: UIColor,
textColor: UIColor,
theme: PresentationTheme,
canGoBack: Bool,
canGoForward: Bool,
canOpenIn: Bool,
@@ -141,8 +145,7 @@ final class NavigationToolbarContentComponent: CombinedComponent {
performAction: ActionSlot<BrowserScreen.Action>,
performHoldAction: @escaping (UIView, ContextGesture?, BrowserScreen.Action) -> Void
) {
self.accentColor = accentColor
self.textColor = textColor
self.theme = theme
self.canGoBack = canGoBack
self.canGoForward = canGoForward
self.canOpenIn = canOpenIn
@@ -153,10 +156,7 @@ final class NavigationToolbarContentComponent: CombinedComponent {
}
static func ==(lhs: NavigationToolbarContentComponent, rhs: NavigationToolbarContentComponent) -> Bool {
if lhs.accentColor != rhs.accentColor {
return false
}
if lhs.textColor != rhs.textColor {
if lhs.theme !== rhs.theme {
return false
}
if lhs.canGoBack != rhs.canGoBack {
@@ -191,26 +191,20 @@ final class NavigationToolbarContentComponent: CombinedComponent {
let performAction = context.component.performAction
let performHoldAction = context.component.performHoldAction
let sideInset: CGFloat = 5.0
let buttonSize = CGSize(width: 50.0, height: availableSize.height)
var size = CGSize(width: 0.0, height: 48.0)
let buttonSize = CGSize(width: 50.0, height: size.height)
var buttonCount = 3
if context.component.canShare {
buttonCount += 1
}
if context.component.canOpenIn {
buttonCount += 1
}
let spacing = (availableSize.width - buttonSize.width * CGFloat(buttonCount) - sideInset * 2.0) / CGFloat(buttonCount - 1)
let sideInset: CGFloat = 34.0
let spacing: CGFloat = 66.0
let textColor = context.component.theme.rootController.navigationBar.primaryTextColor
let canShare = context.component.canShare
let share = share.update(
component: Button(
content: AnyComponent(
BundleIconComponent(
name: "Chat List/NavigationShare",
tintColor: context.component.accentColor
name: "Instant View/Share",
tintColor: textColor
)
),
action: {
@@ -224,22 +218,14 @@ final class NavigationToolbarContentComponent: CombinedComponent {
)
if context.component.isDocument {
if !context.component.canShare {
context.add(share
.position(CGPoint(x: availableSize.width / 2.0, y: 10000.0))
)
} else {
context.add(share
.position(CGPoint(x: availableSize.width / 2.0, y: availableSize.height / 2.0))
)
}
var originX: CGFloat = sideInset
let search = search.update(
component: Button(
content: AnyComponent(
BundleIconComponent(
name: "Chat List/SearchIcon",
tintColor: context.component.accentColor
name: "Instant View/Search",
tintColor: textColor
)
),
action: {
@@ -250,15 +236,27 @@ final class NavigationToolbarContentComponent: CombinedComponent {
transition: .easeInOut(duration: 0.2)
)
context.add(search
.position(CGPoint(x: sideInset + search.size.width / 2.0, y: availableSize.height / 2.0))
.position(CGPoint(x: originX, y: availableSize.height / 2.0))
)
originX += spacing
if !context.component.canShare {
context.add(share
.position(CGPoint(x: availableSize.width / 2.0, y: 10000.0))
)
} else {
context.add(share
.position(CGPoint(x: originX, y: availableSize.height / 2.0))
)
originX += spacing
}
let quickLook = quickLook.update(
component: Button(
content: AnyComponent(
BundleIconComponent(
name: "Instant View/OpenDocument",
tintColor: context.component.accentColor
tintColor: textColor
)
),
action: {
@@ -269,16 +267,19 @@ final class NavigationToolbarContentComponent: CombinedComponent {
transition: .easeInOut(duration: 0.2)
)
context.add(quickLook
.position(CGPoint(x: context.availableSize.width - sideInset - quickLook.size.width / 2.0, y: availableSize.height / 2.0))
.position(CGPoint(x: originX, y: availableSize.height / 2.0))
)
size.width = originX + sideInset
} else {
var originX: CGFloat = sideInset
let canGoBack = context.component.canGoBack
let back = back.update(
component: ContextReferenceButtonComponent(
content: AnyComponent(
BundleIconComponent(
name: "Instant View/Back",
tintColor: canGoBack ? context.component.accentColor : context.component.accentColor.withAlphaComponent(0.4)
tintColor: canGoBack ? textColor : textColor.withAlphaComponent(0.4)
)
),
minSize: buttonSize,
@@ -297,8 +298,9 @@ final class NavigationToolbarContentComponent: CombinedComponent {
transition: .easeInOut(duration: 0.2)
)
context.add(back
.position(CGPoint(x: sideInset + back.size.width / 2.0, y: availableSize.height / 2.0))
.position(CGPoint(x: sideInset, y: availableSize.height / 2.0))
)
originX += spacing
let canGoForward = context.component.canGoForward
let forward = forward.update(
@@ -306,7 +308,7 @@ final class NavigationToolbarContentComponent: CombinedComponent {
content: AnyComponent(
BundleIconComponent(
name: "Instant View/Forward",
tintColor: canGoForward ? context.component.accentColor : context.component.accentColor.withAlphaComponent(0.4)
tintColor: canGoForward ? textColor : textColor.withAlphaComponent(0.4)
)
),
minSize: buttonSize,
@@ -325,19 +327,21 @@ final class NavigationToolbarContentComponent: CombinedComponent {
transition: .easeInOut(duration: 0.2)
)
context.add(forward
.position(CGPoint(x: sideInset + back.size.width + spacing + forward.size.width / 2.0, y: availableSize.height / 2.0))
.position(CGPoint(x: originX, y: availableSize.height / 2.0))
)
originX += spacing
context.add(share
.position(CGPoint(x: sideInset + back.size.width + spacing + forward.size.width + spacing + share.size.width / 2.0, y: availableSize.height / 2.0))
.position(CGPoint(x: originX, y: availableSize.height / 2.0))
)
originX += spacing
let bookmark = bookmark.update(
component: Button(
content: AnyComponent(
BundleIconComponent(
name: "Instant View/Bookmark",
tintColor: context.component.accentColor
tintColor: textColor
)
),
action: {
@@ -348,16 +352,18 @@ final class NavigationToolbarContentComponent: CombinedComponent {
transition: .easeInOut(duration: 0.2)
)
context.add(bookmark
.position(CGPoint(x: sideInset + back.size.width + spacing + forward.size.width + spacing + share.size.width + spacing + bookmark.size.width / 2.0, y: availableSize.height / 2.0))
.position(CGPoint(x: originX, y: availableSize.height / 2.0))
)
if context.component.canOpenIn {
originX += spacing
let openIn = openIn.update(
component: Button(
content: AnyComponent(
BundleIconComponent(
name: "Instant View/Browser",
tintColor: context.component.accentColor
tintColor: textColor
)
),
action: {
@@ -368,34 +374,36 @@ final class NavigationToolbarContentComponent: CombinedComponent {
transition: .easeInOut(duration: 0.2)
)
context.add(openIn
.position(CGPoint(x: sideInset + back.size.width + spacing + forward.size.width + spacing + share.size.width + spacing + bookmark.size.width + spacing + openIn.size.width / 2.0, y: availableSize.height / 2.0))
.position(CGPoint(x: originX, y: availableSize.height / 2.0))
)
}
size.width = originX + sideInset
}
return availableSize
return size
}
}
}
final class SearchToolbarContentComponent: CombinedComponent {
let theme: PresentationTheme
let strings: PresentationStrings
let textColor: UIColor
let index: Int
let count: Int
let isEmpty: Bool
let performAction: ActionSlot<BrowserScreen.Action>
init(
theme: PresentationTheme,
strings: PresentationStrings,
textColor: UIColor,
index: Int,
count: Int,
isEmpty: Bool,
performAction: ActionSlot<BrowserScreen.Action>
) {
self.theme = theme
self.strings = strings
self.textColor = textColor
self.index = index
self.count = count
self.isEmpty = isEmpty
@@ -403,10 +411,10 @@ final class SearchToolbarContentComponent: CombinedComponent {
}
static func ==(lhs: SearchToolbarContentComponent, rhs: SearchToolbarContentComponent) -> Bool {
if lhs.strings !== rhs.strings {
if lhs.theme !== rhs.theme {
return false
}
if lhs.textColor != rhs.textColor {
if lhs.strings !== rhs.strings {
return false
}
if lhs.index != rhs.index {
@@ -430,15 +438,17 @@ final class SearchToolbarContentComponent: CombinedComponent {
let availableSize = context.availableSize
let performAction = context.component.performAction
let sideInset: CGFloat = 3.0
let sideInset: CGFloat = 60.0
let buttonSize = CGSize(width: 50.0, height: availableSize.height)
let textColor = context.component.theme.rootController.navigationBar.primaryTextColor
let down = down.update(
component: Button(
content: AnyComponent(
BundleIconComponent(
name: "Chat/Input/Search/DownButton",
tintColor: context.component.textColor
tintColor: textColor
)
),
isEnabled: context.component.count > 0,
@@ -458,7 +468,7 @@ final class SearchToolbarContentComponent: CombinedComponent {
content: AnyComponent(
BundleIconComponent(
name: "Chat/Input/Search/UpButton",
tintColor: context.component.textColor
tintColor: textColor
)
),
isEnabled: context.component.count > 0,
@@ -486,7 +496,7 @@ final class SearchToolbarContentComponent: CombinedComponent {
component: Text(
text: currentText,
font: Font.regular(15.0),
color: context.component.textColor
color: textColor
),
availableSize: availableSize,
transition: .easeInOut(duration: 0.2)
@@ -495,7 +505,7 @@ final class SearchToolbarContentComponent: CombinedComponent {
.position(CGPoint(x: availableSize.width - sideInset - down.size.width - up.size.width - text.size.width / 2.0, y: availableSize.height / 2.0))
)
return availableSize
return CGSize(width: availableSize.width - 60.0, height: 48.0)
}
}
}
@@ -23,6 +23,7 @@ import SaveProgressScreen
import DeviceModel
import LegacyMediaPickerUI
import PassKit
import AlertComponent
private final class TonSchemeHandler: NSObject, WKURLSchemeHandler {
private final class PendingTask {
@@ -1258,12 +1259,20 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
var completed = false
let alertController = textAlertController(context: self.context, updatedPresentationData: nil, title: nil, text: message, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
if !completed {
completed = true
completionHandler()
}
})])
let alertController = AlertScreen(
context: self.context,
title: nil,
text: message,
actions: [
.init(title: presentationData.strings.Common_OK, type: .default, action: {
if !completed {
completed = true
completionHandler()
}
})
]
)
alertController.dismissed = { byOutsideTap in
if byOutsideTap {
if !completed {
@@ -1278,17 +1287,26 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU
func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
var completed = false
let alertController = textAlertController(context: self.context, updatedPresentationData: nil, title: nil, text: message, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
if !completed {
completed = true
completionHandler(false)
}
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
if !completed {
completed = true
completionHandler(true)
}
})])
let alertController = AlertScreen(
context: self.context,
title: nil,
text: message,
actions: [
.init(title: presentationData.strings.Common_Cancel, action: {
if !completed {
completed = true
completionHandler(false)
}
}),
.init(title: presentationData.strings.Common_OK, type: .default, action: {
if !completed {
completed = true
completionHandler(true)
}
})
]
)
alertController.dismissed = { byOutsideTap in
if byOutsideTap {
if !completed {
@@ -1302,24 +1320,28 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU
func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
var completed = false
let promptController = promptController(sharedContext: self.context.sharedContext, updatedPresentationData: nil, text: prompt, value: defaultText, apply: { value in
if !completed {
completed = true
if let value = value {
completionHandler(value)
} else {
completionHandler(nil)
let promptController = promptController(
context: self.context,
updatedPresentationData: nil,
text: prompt,
value: defaultText,
apply: { value in
if !completed {
completed = true
if let value = value {
completionHandler(value)
} else {
completionHandler(nil)
}
}
}
})
promptController.dismissed = { byOutsideTap in
if byOutsideTap {
},
dismissed: {
if !completed {
completed = true
completionHandler(nil)
}
}
}
)
self.present(promptController, nil)
}
@@ -1356,17 +1378,25 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU
private func presentDownloadConfirmation(fileName: String, proceed: @escaping (Bool) -> Void) {
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
var completed = false
let alertController = textAlertController(context: self.context, updatedPresentationData: nil, title: nil, text: presentationData.strings.WebBrowser_Download_Confirmation(fileName).string, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
if !completed {
completed = true
proceed(false)
}
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.WebBrowser_Download_Download, action: {
if !completed {
completed = true
proceed(true)
}
})])
let alertController = AlertScreen(
context: self.context,
title: nil,
text: presentationData.strings.WebBrowser_Download_Confirmation(fileName).string,
actions: [
.init(title: presentationData.strings.Common_Cancel, action: {
if !completed {
completed = true
proceed(false)
}
}),
.init(title: presentationData.strings.WebBrowser_Download_Download, type: .default, action: {
if !completed {
completed = true
proceed(true)
}
})
]
)
alertController.dismissed = { byOutsideTap in
if byOutsideTap {
if !completed {