mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge commit '67f34ab53d911eb5fc64d104d7e1608f06374d11'
This commit is contained in:
commit
25e57e15c9
@ -95,11 +95,10 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent
|
||||
|
||||
self.titleLabelNode.attributedText = NSAttributedString(string: presentationData.strings.Common_Back, font: Font.regular(17.0), textColor: presentationData.theme.contextMenu.primaryColor)
|
||||
let titleSize = self.titleLabelNode.updateLayout(CGSize(width: size.width - sideInset - standardIconWidth, height: 100.0))
|
||||
self.titleLabelNode.frame = CGRect(origin: CGPoint(x: sideInset, y: floor((size.height - titleSize.height) / 2.0)), size: titleSize)
|
||||
self.titleLabelNode.frame = CGRect(origin: CGPoint(x: sideInset + 36.0, y: floor((size.height - titleSize.height) / 2.0)), size: titleSize)
|
||||
|
||||
if let iconImage = self.iconNode.image {
|
||||
let iconWidth = max(standardIconWidth, iconImage.size.width)
|
||||
let iconFrame = CGRect(origin: CGPoint(x: size.width - iconSideInset - iconWidth + floor((iconWidth - iconImage.size.width) / 2.0), y: floor((size.height - iconImage.size.height) / 2.0)), size: iconImage.size)
|
||||
let iconFrame = CGRect(origin: CGPoint(x: iconSideInset, y: floor((size.height - iconImage.size.height) / 2.0)), size: iconImage.size)
|
||||
self.iconNode.frame = iconFrame
|
||||
}
|
||||
|
||||
@ -1314,10 +1313,10 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent
|
||||
var apparentHeight = topContentHeight
|
||||
|
||||
if let interactiveTransitionState = self.interactiveTransitionState, let fromTabLayout = tabLayouts[self.currentTabIndex], let toTabLayout = tabLayouts[interactiveTransitionState.toIndex] {
|
||||
let megedTabLayoutHeight = fromTabLayout.height * (1.0 - interactiveTransitionState.progress) + toTabLayout.height * interactiveTransitionState.progress
|
||||
let mergedTabLayoutHeight = fromTabLayout.height * (1.0 - interactiveTransitionState.progress) + toTabLayout.height * interactiveTransitionState.progress
|
||||
let megedTabLayoutApparentHeight = fromTabLayout.apparentHeight * (1.0 - interactiveTransitionState.progress) + toTabLayout.apparentHeight * interactiveTransitionState.progress
|
||||
|
||||
contentSize.height += megedTabLayoutHeight
|
||||
contentSize.height += mergedTabLayoutHeight
|
||||
apparentHeight += megedTabLayoutApparentHeight
|
||||
} else if let tabLayout = tabLayouts[self.currentTabIndex] {
|
||||
contentSize.height += tabLayout.height
|
||||
|
@ -2215,12 +2215,18 @@ public final class ContextControllerReferenceViewInfo {
|
||||
}
|
||||
|
||||
public protocol ContextReferenceContentSource: AnyObject {
|
||||
var keepInPlace: Bool { get }
|
||||
|
||||
var shouldBeDismissed: Signal<Bool, NoError> { get }
|
||||
|
||||
func transitionInfo() -> ContextControllerReferenceViewInfo?
|
||||
}
|
||||
|
||||
public extension ContextReferenceContentSource {
|
||||
var keepInPlace: Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
var shouldBeDismissed: Signal<Bool, NoError> {
|
||||
return .single(false)
|
||||
}
|
||||
|
@ -671,7 +671,11 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
|
||||
if let actionsPositionLock = self.actionsStackNode.topPositionLock {
|
||||
actionsConstrainedHeight = layout.size.height - bottomInset - layout.intrinsicInsets.bottom - actionsPositionLock
|
||||
} else {
|
||||
actionsConstrainedHeight = layout.size.height - contentTopInset - contentRect.height - contentActionsSpacing - bottomInset - layout.intrinsicInsets.bottom
|
||||
if case let .reference(reference) = self.source, reference.keepInPlace {
|
||||
actionsConstrainedHeight = layout.size.height - contentRect.maxY - contentActionsSpacing - bottomInset - layout.intrinsicInsets.bottom
|
||||
} else {
|
||||
actionsConstrainedHeight = layout.size.height - contentTopInset - contentRect.height - contentActionsSpacing - bottomInset - layout.intrinsicInsets.bottom
|
||||
}
|
||||
}
|
||||
|
||||
let actionsStackPresentation: ContextControllerActionsStackNode.Presentation
|
||||
@ -755,6 +759,7 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
|
||||
var actionsFrame = CGRect(origin: CGPoint(x: actionsSideInset, y: contentRect.maxY + contentActionsSpacing), size: actionsSize)
|
||||
|
||||
var contentVerticalOffset: CGFloat = 0.0
|
||||
|
||||
if keepInPlace, case .extracted = self.source {
|
||||
actionsFrame.origin.y = contentRect.minY - contentActionsSpacing - actionsFrame.height
|
||||
let statusBarHeight = (layout.statusBarHeight ?? 0.0)
|
||||
|
@ -77,7 +77,13 @@ private func translationSettingsControllerEntries(theme: PresentationTheme, stri
|
||||
if let ignoredLanguages = settings.ignoredLanguages {
|
||||
selectedLanguages = Set(ignoredLanguages)
|
||||
} else {
|
||||
selectedLanguages = Set([strings.baseLanguageCode])
|
||||
var langCode = strings.baseLanguageCode
|
||||
if langCode == "nb" {
|
||||
langCode = "no"
|
||||
} else if langCode == "pt-br" {
|
||||
langCode = "pt"
|
||||
}
|
||||
selectedLanguages = Set([langCode])
|
||||
for language in systemLanguageCodes() {
|
||||
selectedLanguages.insert(language)
|
||||
}
|
||||
|
@ -226,7 +226,7 @@ private func twoStepVerificationUnlockSettingsControllerEntries(presentationData
|
||||
if remainingSeconds <= 0 {
|
||||
text += "[" + presentationData.strings.TwoStepAuth_ResetAction + "](reset)"
|
||||
} else {
|
||||
text.append(presentationData.strings.TwoStepAuth_ResetPendingText(timeIntervalString(strings: presentationData.strings, value: remainingSeconds)).string)
|
||||
text.append(presentationData.strings.TwoStepAuth_ResetPendingText(timeIntervalString(strings: presentationData.strings, value: remainingSeconds, usage: .afterTime)).string)
|
||||
text.append("\n[\(presentationData.strings.TwoStepAuth_CancelResetTitle)](declineReset)")
|
||||
}
|
||||
} else {
|
||||
|
@ -2,6 +2,7 @@ import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
@ -14,6 +15,7 @@ import AccountContext
|
||||
import MoreButtonNode
|
||||
import ContextUI
|
||||
import TranslateUI
|
||||
import TelegramUIPreferences
|
||||
|
||||
final class ChatTranslationPanelNode: ASDisplayNode {
|
||||
private let context: AccountContext
|
||||
@ -116,17 +118,17 @@ final class ChatTranslationPanelNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
let toLang = interfaceState.translationState?.toLang ?? languageCode
|
||||
|
||||
let key = "Translation.Language.\(toLang)"
|
||||
var toLanguage: String?
|
||||
let translateTitle: String
|
||||
if let string = interfaceState.strings.primaryComponent.dict[key] {
|
||||
toLanguage = string
|
||||
translateTitle = interfaceState.strings.Conversation_Translation_TranslateTo(string).string
|
||||
} else {
|
||||
let languageLocale = Locale(identifier: languageCode)
|
||||
toLanguage = languageLocale.localizedString(forLanguageCode: toLang) ?? ""
|
||||
let toLanguage = languageLocale.localizedString(forLanguageCode: toLang) ?? ""
|
||||
translateTitle = interfaceState.strings.Conversation_Translation_TranslateToOther(toLanguage).string
|
||||
}
|
||||
|
||||
let buttonText = interfaceState.translationState?.isEnabled == true ? interfaceState.strings.Conversation_Translation_ShowOriginal : interfaceState.strings.Conversation_Translation_TranslateTo(toLanguage ?? "").string
|
||||
let buttonText = interfaceState.translationState?.isEnabled == true ? interfaceState.strings.Conversation_Translation_ShowOriginal : translateTitle
|
||||
self.buttonTextNode.attributedText = NSAttributedString(string: buttonText, font: Font.regular(17.0), textColor: interfaceState.theme.rootController.navigationBar.accentTextColor)
|
||||
}
|
||||
|
||||
@ -174,107 +176,129 @@ final class ChatTranslationPanelNode: ASDisplayNode {
|
||||
languageCode = String(languageCode.dropLast(rawSuffix.count))
|
||||
}
|
||||
|
||||
let doNotTranslateTitle: String
|
||||
let fromLang = translationState.fromLang
|
||||
let key = "Translation.Language.\(fromLang)"
|
||||
let fromLanguage: String
|
||||
if let string = presentationData.strings.primaryComponent.dict[key] {
|
||||
fromLanguage = string
|
||||
doNotTranslateTitle = presentationData.strings.Conversation_Translation_DoNotTranslate(string).string
|
||||
} else {
|
||||
let languageLocale = Locale(identifier: languageCode)
|
||||
fromLanguage = languageLocale.localizedString(forLanguageCode: fromLang) ?? ""
|
||||
let fromLanguage = languageLocale.localizedString(forLanguageCode: fromLang) ?? ""
|
||||
doNotTranslateTitle = presentationData.strings.Conversation_Translation_DoNotTranslateOther(fromLanguage).string
|
||||
}
|
||||
|
||||
let items: Signal<ContextController.Items, NoError> = context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.translationSettings])
|
||||
|> take(1)
|
||||
|> map { sharedData -> ContextController.Items in
|
||||
let settings: TranslationSettings
|
||||
if let current = sharedData.entries[ApplicationSpecificSharedDataKeys.translationSettings]?.get(TranslationSettings.self) {
|
||||
settings = current
|
||||
} else {
|
||||
settings = TranslationSettings.defaultSettings
|
||||
}
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_Translation_ChooseLanguage, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Translate"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, _ in
|
||||
var addedLanguages = Set<String>()
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_Translation_ChooseLanguage, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Translate"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, _ in
|
||||
var subItems: [ContextMenuItem] = []
|
||||
|
||||
subItems.append(.action(ContextMenuActionItem(text: presentationData.strings.ChatList_Context_Back, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.contextMenu.primaryColor)
|
||||
}, iconPosition: .left, action: { c, _ in
|
||||
c.popItems()
|
||||
})))
|
||||
subItems.append(.separator)
|
||||
|
||||
let enLocale = Locale(identifier: "en")
|
||||
var languages: [(String, String)] = []
|
||||
var addedLanguages = Set<String>()
|
||||
|
||||
var topLanguages: [String] = []
|
||||
var langCode = languageCode
|
||||
if langCode == "nb" {
|
||||
langCode = "no"
|
||||
} else if langCode == "pt-br" {
|
||||
langCode = "pt"
|
||||
}
|
||||
topLanguages.append(langCode)
|
||||
topLanguages.append(contentsOf: popularTranslationLanguages)
|
||||
|
||||
for code in topLanguages {
|
||||
if !addedLanguages.contains(code), let title = enLocale.localizedString(forLanguageCode: code) {
|
||||
let languageLocale = Locale(identifier: code)
|
||||
let subtitle = languageLocale.localizedString(forLanguageCode: code) ?? title
|
||||
let value = (code, subtitle.capitalized)
|
||||
if code == languageCode {
|
||||
languages.insert(value, at: 0)
|
||||
} else {
|
||||
languages.append(value)
|
||||
}
|
||||
addedLanguages.insert(code)
|
||||
var topLanguages: [String] = []
|
||||
var langCode = languageCode
|
||||
if langCode == "nb" {
|
||||
langCode = "no"
|
||||
} else if langCode == "pt-br" {
|
||||
langCode = "pt"
|
||||
}
|
||||
}
|
||||
|
||||
// for code in supportedTranslationLanguages {
|
||||
// if !addedLanguages.contains(code), let title = enLocale.localizedString(forLanguageCode: code) {
|
||||
// let languageLocale = Locale(identifier: code)
|
||||
// let subtitle = languageLocale.localizedString(forLanguageCode: code) ?? title
|
||||
// let value = (code, title.capitalized, subtitle.capitalized)
|
||||
// if code == languageCode {
|
||||
// languages.insert(value, at: 0)
|
||||
// } else {
|
||||
// languages.append(value)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
for (langCode, title) in languages {
|
||||
subItems.append(.action(ContextMenuActionItem(text: title , icon: { theme in
|
||||
if translationState.toLang == langCode {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
} else {
|
||||
return nil
|
||||
|
||||
var selectedLanguages: Set<String>
|
||||
if let ignoredLanguages = settings.ignoredLanguages {
|
||||
selectedLanguages = Set(ignoredLanguages)
|
||||
} else {
|
||||
selectedLanguages = Set([langCode])
|
||||
for language in systemLanguageCodes() {
|
||||
selectedLanguages.insert(language)
|
||||
}
|
||||
}, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
||||
self?.interfaceInteraction?.changeTranslationLanguage(langCode)
|
||||
})))
|
||||
}
|
||||
}
|
||||
for code in supportedTranslationLanguages {
|
||||
if selectedLanguages.contains(code) {
|
||||
topLanguages.append(code)
|
||||
}
|
||||
}
|
||||
|
||||
topLanguages.append(contentsOf: popularTranslationLanguages)
|
||||
|
||||
var languages: [(String, String)] = []
|
||||
let languageLocale = Locale(identifier: langCode)
|
||||
|
||||
for code in topLanguages {
|
||||
if !addedLanguages.contains(code) {
|
||||
let displayTitle = languageLocale.localizedString(forLanguageCode: code) ?? ""
|
||||
let value = (code, displayTitle)
|
||||
if code == languageCode {
|
||||
languages.insert(value, at: 0)
|
||||
} else {
|
||||
languages.append(value)
|
||||
}
|
||||
addedLanguages.insert(code)
|
||||
}
|
||||
}
|
||||
|
||||
for code in supportedTranslationLanguages {
|
||||
if !addedLanguages.contains(code) {
|
||||
let displayTitle = languageLocale.localizedString(forLanguageCode: code) ?? ""
|
||||
let value = (code, displayTitle)
|
||||
if code == languageCode {
|
||||
languages.insert(value, at: 0)
|
||||
} else {
|
||||
languages.append(value)
|
||||
}
|
||||
addedLanguages.insert(code)
|
||||
}
|
||||
}
|
||||
|
||||
c.pushItems(items: .single(ContextController.Items(
|
||||
content: .custom(
|
||||
TranslationLanguagesContextMenuContent(
|
||||
context: self.context,
|
||||
languages: languages, back: { [weak c] in
|
||||
c?.popItems()
|
||||
}, selectLanguage: { [weak self, weak c] language in
|
||||
c?.dismiss(completion: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.interfaceInteraction?.changeTranslationLanguage(language)
|
||||
})
|
||||
}
|
||||
)
|
||||
)
|
||||
)))
|
||||
})))
|
||||
|
||||
c.pushItems(items: .single(ContextController.Items(content: .list(subItems))))
|
||||
})))
|
||||
|
||||
items.append(.separator)
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_Translation_DoNotTranslate(fromLanguage).string, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Restrict"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: nil)
|
||||
items.append(.separator)
|
||||
|
||||
self?.interfaceInteraction?.addDoNotTranslateLanguage(translationState.fromLang)
|
||||
})))
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_Translation_Hide, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: nil)
|
||||
items.append(.action(ContextMenuActionItem(text: doNotTranslateTitle, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Restrict"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: nil)
|
||||
|
||||
self?.interfaceInteraction?.addDoNotTranslateLanguage(translationState.fromLang)
|
||||
})))
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_Translation_Hide, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: nil)
|
||||
|
||||
self?.interfaceInteraction?.hideTranslationPanel()
|
||||
})))
|
||||
|
||||
return ContextController.Items(content: .list(items))
|
||||
}
|
||||
|
||||
self?.interfaceInteraction?.hideTranslationPanel()
|
||||
})))
|
||||
|
||||
if let controller = self.interfaceInteraction?.chatController() {
|
||||
let contextController = ContextController(account: self.context.account, presentationData: presentationData, source: .reference(TranslationContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
|
||||
let contextController = ContextController(account: self.context.account, presentationData: presentationData, source: .reference(TranslationContextReferenceContentSource(controller: controller, sourceNode: node)), items: items, gesture: gesture)
|
||||
self.interfaceInteraction?.presentGlobalOverlayController(contextController, nil)
|
||||
}
|
||||
}
|
||||
@ -284,6 +308,10 @@ private final class TranslationContextReferenceContentSource: ContextReferenceCo
|
||||
private let controller: ViewController
|
||||
private let sourceNode: ContextReferenceContentNode
|
||||
|
||||
var keepInPlace: Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
init(controller: ViewController, sourceNode: ContextReferenceContentNode) {
|
||||
self.controller = controller
|
||||
self.sourceNode = sourceNode
|
||||
@ -293,3 +321,538 @@ private final class TranslationContextReferenceContentSource: ContextReferenceCo
|
||||
return ContextControllerReferenceViewInfo(referenceView: self.sourceNode.view, contentAreaInScreenSpace: UIScreen.main.bounds)
|
||||
}
|
||||
}
|
||||
|
||||
private final class TranslationLanguagesContextMenuContent: ContextControllerItemsContent {
|
||||
private final class BackButtonNode: HighlightTrackingButtonNode {
|
||||
let highlightBackgroundNode: ASDisplayNode
|
||||
let titleLabelNode: ImmediateTextNode
|
||||
let separatorNode: ASDisplayNode
|
||||
let iconNode: ASImageNode
|
||||
|
||||
var action: (() -> Void)?
|
||||
|
||||
private var theme: PresentationTheme?
|
||||
|
||||
init() {
|
||||
self.highlightBackgroundNode = ASDisplayNode()
|
||||
self.highlightBackgroundNode.isAccessibilityElement = false
|
||||
self.highlightBackgroundNode.alpha = 0.0
|
||||
|
||||
self.titleLabelNode = ImmediateTextNode()
|
||||
self.titleLabelNode.isAccessibilityElement = false
|
||||
self.titleLabelNode.maximumNumberOfLines = 1
|
||||
self.titleLabelNode.isUserInteractionEnabled = false
|
||||
|
||||
self.iconNode = ASImageNode()
|
||||
self.iconNode.isAccessibilityElement = false
|
||||
|
||||
self.separatorNode = ASDisplayNode()
|
||||
self.separatorNode.isAccessibilityElement = false
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.separatorNode)
|
||||
self.addSubnode(self.highlightBackgroundNode)
|
||||
self.addSubnode(self.titleLabelNode)
|
||||
self.addSubnode(self.iconNode)
|
||||
|
||||
self.isAccessibilityElement = true
|
||||
|
||||
self.highligthedChanged = { [weak self] highlighted in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if highlighted {
|
||||
strongSelf.highlightBackgroundNode.alpha = 1.0
|
||||
} else {
|
||||
let previousAlpha = strongSelf.highlightBackgroundNode.alpha
|
||||
strongSelf.highlightBackgroundNode.alpha = 0.0
|
||||
strongSelf.highlightBackgroundNode.layer.animateAlpha(from: previousAlpha, to: 0.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
|
||||
self.addTarget(self, action: #selector(self.pressed), forControlEvents: .touchUpInside)
|
||||
}
|
||||
|
||||
@objc private func pressed() {
|
||||
self.action?()
|
||||
}
|
||||
|
||||
func update(size: CGSize, presentationData: PresentationData, isLast: Bool) {
|
||||
let standardIconWidth: CGFloat = 32.0
|
||||
let sideInset: CGFloat = 16.0
|
||||
let iconSideInset: CGFloat = 12.0
|
||||
|
||||
if self.theme !== presentationData.theme {
|
||||
self.theme = presentationData.theme
|
||||
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: presentationData.theme.contextMenu.primaryColor)
|
||||
|
||||
self.accessibilityLabel = presentationData.strings.Common_Back
|
||||
}
|
||||
|
||||
self.highlightBackgroundNode.backgroundColor = presentationData.theme.contextMenu.itemHighlightedBackgroundColor
|
||||
self.separatorNode.backgroundColor = presentationData.theme.contextMenu.itemSeparatorColor
|
||||
|
||||
self.highlightBackgroundNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||
|
||||
self.titleLabelNode.attributedText = NSAttributedString(string: presentationData.strings.Common_Back, font: Font.regular(17.0), textColor: presentationData.theme.contextMenu.primaryColor)
|
||||
let titleSize = self.titleLabelNode.updateLayout(CGSize(width: size.width - sideInset - standardIconWidth, height: 100.0))
|
||||
self.titleLabelNode.frame = CGRect(origin: CGPoint(x: sideInset + 36.0, y: floor((size.height - titleSize.height) / 2.0)), size: titleSize)
|
||||
|
||||
if let iconImage = self.iconNode.image {
|
||||
let iconFrame = CGRect(origin: CGPoint(x: iconSideInset, y: floor((size.height - iconImage.size.height) / 2.0)), size: iconImage.size)
|
||||
self.iconNode.frame = iconFrame
|
||||
}
|
||||
|
||||
self.separatorNode.frame = CGRect(origin: CGPoint(x: 0.0, y: size.height - UIScreenPixel), size: CGSize(width: size.width, height: UIScreenPixel))
|
||||
self.separatorNode.isHidden = isLast
|
||||
}
|
||||
}
|
||||
|
||||
private final class LanguagesListNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
private final class ItemNode: HighlightTrackingButtonNode {
|
||||
let context: AccountContext
|
||||
let highlightBackgroundNode: ASDisplayNode
|
||||
let titleLabelNode: ImmediateTextNode
|
||||
let separatorNode: ASDisplayNode
|
||||
|
||||
let action: () -> Void
|
||||
|
||||
private var language: String?
|
||||
|
||||
init(context: AccountContext, action: @escaping () -> Void) {
|
||||
self.action = action
|
||||
self.context = context
|
||||
|
||||
self.highlightBackgroundNode = ASDisplayNode()
|
||||
self.highlightBackgroundNode.isAccessibilityElement = false
|
||||
self.highlightBackgroundNode.alpha = 0.0
|
||||
|
||||
self.titleLabelNode = ImmediateTextNode()
|
||||
self.titleLabelNode.isAccessibilityElement = false
|
||||
self.titleLabelNode.maximumNumberOfLines = 1
|
||||
self.titleLabelNode.isUserInteractionEnabled = false
|
||||
|
||||
self.separatorNode = ASDisplayNode()
|
||||
self.separatorNode.isAccessibilityElement = false
|
||||
|
||||
super.init()
|
||||
|
||||
self.isAccessibilityElement = true
|
||||
|
||||
self.addSubnode(self.separatorNode)
|
||||
self.addSubnode(self.highlightBackgroundNode)
|
||||
self.addSubnode(self.titleLabelNode)
|
||||
|
||||
self.highligthedChanged = { [weak self] highlighted in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if highlighted {
|
||||
strongSelf.highlightBackgroundNode.alpha = 1.0
|
||||
} else {
|
||||
let previousAlpha = strongSelf.highlightBackgroundNode.alpha
|
||||
strongSelf.highlightBackgroundNode.alpha = 0.0
|
||||
strongSelf.highlightBackgroundNode.layer.animateAlpha(from: previousAlpha, to: 0.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
|
||||
self.addTarget(self, action: #selector(self.pressed), forControlEvents: .touchUpInside)
|
||||
}
|
||||
|
||||
@objc private func pressed() {
|
||||
self.action()
|
||||
}
|
||||
|
||||
private var displayTitle: String?
|
||||
func update(size: CGSize, presentationData: PresentationData, language: String, displayTitle: String, isLast: Bool, syncronousLoad: Bool) {
|
||||
let sideInset: CGFloat = 16.0
|
||||
|
||||
if self.language != language {
|
||||
self.language = language
|
||||
self.displayTitle = displayTitle
|
||||
|
||||
self.accessibilityLabel = "\(displayTitle)"
|
||||
}
|
||||
|
||||
self.highlightBackgroundNode.backgroundColor = presentationData.theme.contextMenu.itemHighlightedBackgroundColor
|
||||
self.separatorNode.backgroundColor = presentationData.theme.contextMenu.itemSeparatorColor
|
||||
|
||||
self.highlightBackgroundNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||
|
||||
self.titleLabelNode.attributedText = NSAttributedString(string: self.displayTitle ?? "", font: Font.regular(17.0), textColor: presentationData.theme.contextMenu.primaryColor)
|
||||
let maxTextWidth: CGFloat = size.width - sideInset
|
||||
|
||||
let titleSize = self.titleLabelNode.updateLayout(CGSize(width: maxTextWidth, height: 100.0))
|
||||
let titleFrame = CGRect(origin: CGPoint(x: sideInset, y: floor((size.height - titleSize.height) / 2.0)), size: titleSize)
|
||||
self.titleLabelNode.frame = titleFrame
|
||||
|
||||
self.separatorNode.frame = CGRect(origin: CGPoint(x: 0.0, y: size.height), size: CGSize(width: size.width, height: UIScreenPixel))
|
||||
self.separatorNode.isHidden = isLast
|
||||
}
|
||||
}
|
||||
|
||||
private let context: AccountContext
|
||||
private let languages: [(String, String)]
|
||||
private let requestUpdate: (LanguagesListNode, ContainedViewLayoutTransition) -> Void
|
||||
private let requestUpdateApparentHeight: (LanguagesListNode, ContainedViewLayoutTransition) -> Void
|
||||
private let selectLanguage: (String) -> Void
|
||||
|
||||
private let scrollNode: ASScrollNode
|
||||
private var ignoreScrolling: Bool = false
|
||||
private var animateIn: Bool = false
|
||||
private var bottomScrollInset: CGFloat = 0.0
|
||||
|
||||
private var presentationData: PresentationData?
|
||||
private var currentSize: CGSize?
|
||||
private var apparentHeight: CGFloat = 0.0
|
||||
|
||||
private var itemNodes: [Int: ItemNode] = [:]
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
languages: [(String, String)],
|
||||
requestUpdate: @escaping (LanguagesListNode, ContainedViewLayoutTransition) -> Void,
|
||||
requestUpdateApparentHeight: @escaping (LanguagesListNode, ContainedViewLayoutTransition) -> Void,
|
||||
selectLanguage: @escaping (String) -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.languages = languages
|
||||
self.requestUpdate = requestUpdate
|
||||
self.requestUpdateApparentHeight = requestUpdateApparentHeight
|
||||
self.selectLanguage = selectLanguage
|
||||
|
||||
self.scrollNode = ASScrollNode()
|
||||
self.scrollNode.canCancelAllTouchesInViews = true
|
||||
self.scrollNode.view.delaysContentTouches = false
|
||||
self.scrollNode.view.showsVerticalScrollIndicator = false
|
||||
if #available(iOS 11.0, *) {
|
||||
self.scrollNode.view.contentInsetAdjustmentBehavior = .never
|
||||
}
|
||||
self.scrollNode.clipsToBounds = false
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.scrollNode)
|
||||
self.scrollNode.view.delegate = self
|
||||
|
||||
self.clipsToBounds = true
|
||||
|
||||
// self.stateDisposable = (self.listContext.state
|
||||
// |> deliverOnMainQueue).start(next: { [weak self] state in
|
||||
// guard let strongSelf = self else {
|
||||
// return
|
||||
// }
|
||||
// let updatedState = ItemsState(listState: state, readStats: strongSelf.state.readStats)
|
||||
// var animateIn = false
|
||||
// if strongSelf.state.item(at: 0) == nil && updatedState.item(at: 0) != nil {
|
||||
// animateIn = true
|
||||
// }
|
||||
// strongSelf.state = updatedState
|
||||
// strongSelf.animateIn = true
|
||||
// strongSelf.requestUpdate(strongSelf, animateIn ? .animated(duration: 0.2, curve: .easeInOut) : .immediate)
|
||||
// if animateIn {
|
||||
// for (_, itemNode) in strongSelf.itemNodes {
|
||||
// itemNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
}
|
||||
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
if self.ignoreScrolling {
|
||||
return
|
||||
}
|
||||
self.updateVisibleItems(animated: false, syncronousLoad: false)
|
||||
|
||||
if let size = self.currentSize {
|
||||
var apparentHeight = -self.scrollNode.view.contentOffset.y + self.scrollNode.view.contentSize.height
|
||||
apparentHeight = max(apparentHeight, 44.0)
|
||||
apparentHeight = min(apparentHeight, size.height)
|
||||
if self.apparentHeight != apparentHeight {
|
||||
self.apparentHeight = apparentHeight
|
||||
|
||||
self.requestUpdateApparentHeight(self, .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func updateVisibleItems(animated: Bool, syncronousLoad: Bool) {
|
||||
guard let size = self.currentSize else {
|
||||
return
|
||||
}
|
||||
guard let presentationData = self.presentationData else {
|
||||
return
|
||||
}
|
||||
let itemHeight: CGFloat = 44.0
|
||||
let visibleBounds = self.scrollNode.bounds.insetBy(dx: 0.0, dy: -180.0)
|
||||
|
||||
var validIds = Set<Int>()
|
||||
|
||||
let minVisibleIndex = max(0, Int(floor(visibleBounds.minY / itemHeight)))
|
||||
let maxVisibleIndex = Int(ceil(visibleBounds.maxY / itemHeight))
|
||||
|
||||
if minVisibleIndex <= maxVisibleIndex {
|
||||
for index in minVisibleIndex ... maxVisibleIndex {
|
||||
let itemFrame = CGRect(origin: CGPoint(x: 0.0, y: CGFloat(index) * itemHeight), size: CGSize(width: size.width, height: itemHeight))
|
||||
|
||||
if index < self.languages.count {
|
||||
let (languageCode, displayTitle) = self.languages[index]
|
||||
validIds.insert(index)
|
||||
|
||||
let itemNode: ItemNode
|
||||
if let current = self.itemNodes[index] {
|
||||
itemNode = current
|
||||
} else {
|
||||
let selectLanguage = self.selectLanguage
|
||||
itemNode = ItemNode(context: self.context, action: {
|
||||
selectLanguage(languageCode)
|
||||
})
|
||||
self.itemNodes[index] = itemNode
|
||||
self.scrollNode.addSubnode(itemNode)
|
||||
}
|
||||
|
||||
itemNode.update(size: itemFrame.size, presentationData: presentationData, language: languageCode, displayTitle: displayTitle, isLast: index == self.languages.count - 1, syncronousLoad: syncronousLoad)
|
||||
itemNode.frame = itemFrame
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var removeIds: [Int] = []
|
||||
for (id, itemNode) in self.itemNodes {
|
||||
if !validIds.contains(id) {
|
||||
removeIds.append(id)
|
||||
itemNode.removeFromSupernode()
|
||||
}
|
||||
}
|
||||
for id in removeIds {
|
||||
self.itemNodes.removeValue(forKey: id)
|
||||
}
|
||||
}
|
||||
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
var extendedScrollNodeFrame = self.scrollNode.frame
|
||||
extendedScrollNodeFrame.size.height += self.bottomScrollInset
|
||||
|
||||
if extendedScrollNodeFrame.contains(point) {
|
||||
return self.scrollNode.view.hitTest(self.view.convert(point, to: self.scrollNode.view), with: event)
|
||||
}
|
||||
|
||||
return super.hitTest(point, with: event)
|
||||
}
|
||||
|
||||
func update(presentationData: PresentationData, constrainedSize: CGSize, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) -> (height: CGFloat, apparentHeight: CGFloat) {
|
||||
let itemHeight: CGFloat = 44.0
|
||||
|
||||
self.presentationData = presentationData
|
||||
|
||||
let size = CGSize(width: constrainedSize.width, height: CGFloat(self.languages.count) * itemHeight)
|
||||
|
||||
let containerSize = CGSize(width: size.width, height: min(constrainedSize.height, size.height))
|
||||
self.currentSize = containerSize
|
||||
|
||||
self.ignoreScrolling = true
|
||||
|
||||
if self.scrollNode.frame != CGRect(origin: CGPoint(), size: containerSize) {
|
||||
self.scrollNode.frame = CGRect(origin: CGPoint(), size: containerSize)
|
||||
}
|
||||
if self.scrollNode.view.contentInset.bottom != bottomInset {
|
||||
self.scrollNode.view.contentInset.bottom = bottomInset
|
||||
}
|
||||
self.bottomScrollInset = bottomInset
|
||||
let scrollContentSize = CGSize(width: size.width, height: size.height)
|
||||
if self.scrollNode.view.contentSize != scrollContentSize {
|
||||
self.scrollNode.view.contentSize = scrollContentSize
|
||||
}
|
||||
self.ignoreScrolling = false
|
||||
|
||||
self.updateVisibleItems(animated: transition.isAnimated, syncronousLoad: !transition.isAnimated)
|
||||
|
||||
self.animateIn = false
|
||||
|
||||
var apparentHeight = -self.scrollNode.view.contentOffset.y + self.scrollNode.view.contentSize.height
|
||||
apparentHeight = max(apparentHeight, 44.0)
|
||||
apparentHeight = min(apparentHeight, containerSize.height)
|
||||
self.apparentHeight = apparentHeight
|
||||
|
||||
return (containerSize.height, apparentHeight)
|
||||
}
|
||||
}
|
||||
|
||||
final class ItemsNode: ASDisplayNode, ContextControllerItemsNode {
|
||||
private let context: AccountContext
|
||||
private let languages: [(String, String)]
|
||||
private let requestUpdate: (ContainedViewLayoutTransition) -> Void
|
||||
private let requestUpdateApparentHeight: (ContainedViewLayoutTransition) -> Void
|
||||
|
||||
private var presentationData: PresentationData
|
||||
|
||||
private var backButtonNode: BackButtonNode?
|
||||
private var separatorNode: ASDisplayNode?
|
||||
|
||||
private let currentTabIndex: Int = 0
|
||||
private var visibleTabNodes: [Int: LanguagesListNode] = [:]
|
||||
|
||||
private let selectLanguage: (String) -> Void
|
||||
|
||||
private(set) var apparentHeight: CGFloat = 0.0
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
languages: [(String, String)],
|
||||
requestUpdate: @escaping (ContainedViewLayoutTransition) -> Void,
|
||||
requestUpdateApparentHeight: @escaping (ContainedViewLayoutTransition) -> Void,
|
||||
back: (() -> Void)?,
|
||||
selectLanguage: @escaping (String) -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.languages = languages
|
||||
self.selectLanguage = selectLanguage
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with({ $0 })
|
||||
|
||||
self.requestUpdate = requestUpdate
|
||||
self.requestUpdateApparentHeight = requestUpdateApparentHeight
|
||||
|
||||
if let back = back {
|
||||
self.backButtonNode = BackButtonNode()
|
||||
self.backButtonNode?.action = {
|
||||
back()
|
||||
}
|
||||
}
|
||||
|
||||
super.init()
|
||||
|
||||
if self.backButtonNode != nil {
|
||||
self.separatorNode = ASDisplayNode()
|
||||
}
|
||||
|
||||
if let backButtonNode = self.backButtonNode {
|
||||
self.addSubnode(backButtonNode)
|
||||
}
|
||||
if let separatorNode = self.separatorNode {
|
||||
self.addSubnode(separatorNode)
|
||||
}
|
||||
}
|
||||
|
||||
func update(presentationData: PresentationData, constrainedWidth: CGFloat, maxHeight: CGFloat, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) -> (cleanSize: CGSize, apparentHeight: CGFloat) {
|
||||
let constrainedSize = CGSize(width: min(260.0, constrainedWidth), height: min(604.0, maxHeight))
|
||||
|
||||
var topContentHeight: CGFloat = 0.0
|
||||
if let backButtonNode = self.backButtonNode {
|
||||
let backButtonFrame = CGRect(origin: CGPoint(x: 0.0, y: topContentHeight), size: CGSize(width: constrainedSize.width, height: 44.0))
|
||||
backButtonNode.update(size: backButtonFrame.size, presentationData: self.presentationData, isLast: true)
|
||||
transition.updateFrame(node: backButtonNode, frame: backButtonFrame)
|
||||
topContentHeight += backButtonFrame.height
|
||||
}
|
||||
if let separatorNode = self.separatorNode {
|
||||
let separatorFrame = CGRect(origin: CGPoint(x: 0.0, y: topContentHeight), size: CGSize(width: constrainedSize.width, height: 7.0))
|
||||
separatorNode.backgroundColor = self.presentationData.theme.contextMenu.sectionSeparatorColor
|
||||
transition.updateFrame(node: separatorNode, frame: separatorFrame)
|
||||
topContentHeight += separatorFrame.height
|
||||
}
|
||||
|
||||
var tabLayouts: [Int: (height: CGFloat, apparentHeight: CGFloat)] = [:]
|
||||
|
||||
var visibleIndices: [Int] = []
|
||||
visibleIndices.append(self.currentTabIndex)
|
||||
|
||||
let previousVisibleTabFrames: [(Int, CGRect)] = self.visibleTabNodes.map { key, value -> (Int, CGRect) in
|
||||
return (key, value.frame)
|
||||
}
|
||||
|
||||
for index in visibleIndices {
|
||||
var tabTransition = transition
|
||||
let tabNode: LanguagesListNode
|
||||
var initialReferenceFrame: CGRect?
|
||||
if let current = self.visibleTabNodes[index] {
|
||||
tabNode = current
|
||||
} else {
|
||||
for (previousIndex, previousFrame) in previousVisibleTabFrames {
|
||||
if index > previousIndex {
|
||||
initialReferenceFrame = previousFrame.offsetBy(dx: constrainedSize.width, dy: 0.0)
|
||||
} else {
|
||||
initialReferenceFrame = previousFrame.offsetBy(dx: -constrainedSize.width, dy: 0.0)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
tabNode = LanguagesListNode(
|
||||
context: self.context,
|
||||
languages: self.languages,
|
||||
requestUpdate: { [weak self] tab, transition in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if strongSelf.visibleTabNodes.contains(where: { $0.value === tab }) {
|
||||
strongSelf.requestUpdate(transition)
|
||||
}
|
||||
},
|
||||
requestUpdateApparentHeight: { [weak self] tab, transition in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if strongSelf.visibleTabNodes.contains(where: { $0.value === tab }) {
|
||||
strongSelf.requestUpdateApparentHeight(transition)
|
||||
}
|
||||
},
|
||||
selectLanguage: self.selectLanguage
|
||||
)
|
||||
self.addSubnode(tabNode)
|
||||
self.visibleTabNodes[index] = tabNode
|
||||
tabTransition = .immediate
|
||||
}
|
||||
|
||||
let tabLayout = tabNode.update(presentationData: presentationData, constrainedSize: CGSize(width: constrainedSize.width, height: constrainedSize.height - topContentHeight), bottomInset: bottomInset, transition: tabTransition)
|
||||
tabLayouts[index] = tabLayout
|
||||
let currentFractionalTabIndex = CGFloat(self.currentTabIndex)
|
||||
let xOffset: CGFloat = (CGFloat(index) - currentFractionalTabIndex) * constrainedSize.width
|
||||
let tabFrame = CGRect(origin: CGPoint(x: xOffset, y: topContentHeight), size: CGSize(width: constrainedSize.width, height: tabLayout.height))
|
||||
tabTransition.updateFrame(node: tabNode, frame: tabFrame)
|
||||
if let initialReferenceFrame = initialReferenceFrame {
|
||||
transition.animatePositionAdditive(node: tabNode, offset: CGPoint(x: initialReferenceFrame.minX - tabFrame.minX, y: 0.0))
|
||||
}
|
||||
}
|
||||
|
||||
var contentSize = CGSize(width: constrainedSize.width, height: topContentHeight)
|
||||
var apparentHeight = topContentHeight
|
||||
|
||||
if let tabLayout = tabLayouts[self.currentTabIndex] {
|
||||
contentSize.height += tabLayout.height
|
||||
apparentHeight += tabLayout.apparentHeight
|
||||
}
|
||||
|
||||
return (contentSize, apparentHeight)
|
||||
}
|
||||
}
|
||||
|
||||
let context: AccountContext
|
||||
let languages: [(String, String)]
|
||||
let back: (() -> Void)?
|
||||
let selectLanguage: (String) -> Void
|
||||
|
||||
public init(
|
||||
context: AccountContext,
|
||||
languages: [(String, String)],
|
||||
back: (() -> Void)?,
|
||||
selectLanguage: @escaping (String) -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.languages = languages
|
||||
self.back = back
|
||||
self.selectLanguage = selectLanguage
|
||||
}
|
||||
|
||||
func node(
|
||||
requestUpdate: @escaping (ContainedViewLayoutTransition) -> Void,
|
||||
requestUpdateApparentHeight: @escaping (ContainedViewLayoutTransition) -> Void
|
||||
) -> ContextControllerItemsNode {
|
||||
return ItemsNode(
|
||||
context: self.context,
|
||||
languages: self.languages,
|
||||
requestUpdate: requestUpdate,
|
||||
requestUpdateApparentHeight: requestUpdateApparentHeight,
|
||||
back: self.back,
|
||||
selectLanguage: self.selectLanguage
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -7334,6 +7334,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
completion(nil)
|
||||
}
|
||||
}
|
||||
var isFromEditor = false
|
||||
mixin.requestAvatarEditor = { [weak self] imageCompletion, videoCompletion in
|
||||
guard let strongSelf = self, let imageCompletion, let videoCompletion else {
|
||||
return
|
||||
@ -7356,6 +7357,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
controller.imageCompletion = imageCompletion
|
||||
controller.videoCompletion = videoCompletion
|
||||
(strongSelf.controller?.navigationController?.topViewController as? ViewController)?.push(controller)
|
||||
isFromEditor = true
|
||||
}
|
||||
|
||||
if let confirmationTextPhoto, let confirmationAction {
|
||||
@ -7371,7 +7373,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
if let confirmationTextVideo, let confirmationAction {
|
||||
mixin.willFinishWithVideo = { [weak self] image, commit in
|
||||
if let strongSelf = self, let image {
|
||||
let controller = photoUpdateConfirmationController(context: strongSelf.context, peer: peer, image: image, text: confirmationTextVideo, doneTitle: confirmationAction, commit: {
|
||||
let controller = photoUpdateConfirmationController(context: strongSelf.context, peer: peer, image: image, text: confirmationTextVideo, doneTitle: confirmationAction, isDark: !isFromEditor, commit: {
|
||||
commit?()
|
||||
})
|
||||
(strongSelf.controller?.navigationController?.topViewController as? ViewController)?.presentInGlobalOverlay(controller)
|
||||
|
@ -216,9 +216,12 @@ private final class PhotoUpdateConfirmationAlertContentNode: AlertContentNode {
|
||||
}
|
||||
}
|
||||
|
||||
func photoUpdateConfirmationController(context: AccountContext, peer: EnginePeer, image: UIImage, text: String, doneTitle: String, commit: @escaping () -> Void) -> AlertController {
|
||||
func photoUpdateConfirmationController(context: AccountContext, peer: EnginePeer, image: UIImage, text: String, doneTitle: String, isDark: Bool = true, commit: @escaping () -> Void) -> AlertController {
|
||||
let theme = defaultDarkColorPresentationTheme
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }.withUpdated(theme: theme)
|
||||
var presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
if isDark {
|
||||
presentationData = presentationData.withUpdated(theme: theme)
|
||||
}
|
||||
let strings = presentationData.strings
|
||||
|
||||
var dismissImpl: ((Bool) -> Void)?
|
||||
|
@ -108,7 +108,6 @@ private final class WebAppAlertContentNode: AlertContentNode {
|
||||
self.addSubnode(self.allowWriteLabelNode)
|
||||
}
|
||||
|
||||
|
||||
self.addSubnode(self.actionNodesSeparator)
|
||||
|
||||
for actionNode in self.actionNodes {
|
||||
@ -316,10 +315,14 @@ public func addWebAppToAttachmentController(context: AccountContext, peerName: S
|
||||
var contentNode: WebAppAlertContentNode?
|
||||
let actions: [TextAlertAction] = [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
|
||||
dismissImpl?(true)
|
||||
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.WebApp_AddToAttachmentAdd, action: {
|
||||
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.WebApp_AddToAttachmentAdd, action: { [weak contentNode] in
|
||||
dismissImpl?(true)
|
||||
|
||||
completion(true)
|
||||
if requestWriteAccess, let allowWriteAccess = contentNode?.allowWriteAccess {
|
||||
completion(allowWriteAccess)
|
||||
} else {
|
||||
completion(false)
|
||||
}
|
||||
})]
|
||||
|
||||
contentNode = WebAppAlertContentNode(account: context.account, theme: AlertControllerTheme(presentationData: presentationData), ptheme: theme, strings: strings, peerName: peerName, icons: icons, requestWriteAccess: requestWriteAccess, actions: actions)
|
||||
|
Loading…
x
Reference in New Issue
Block a user