Merge commit '3f9f29b7fb5b4f3dbe73800b32aafa9d4b88d3f9'

# Conflicts:
#	submodules/ChatSendMessageActionUI/BUILD
#	submodules/ChatSendMessageActionUI/Sources/ChatSendMessageActionSheetControllerNode.swift
This commit is contained in:
Ali 2022-07-24 23:33:13 +02:00
commit 2a5523b266
21 changed files with 379 additions and 193 deletions

View File

@ -810,9 +810,9 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
}
}
let openNewCard: () -> Void = { [weak self] in
let openNewCard: (String?) -> Void = { [weak self] customUrl in
if let strongSelf = self, let paymentForm = strongSelf.paymentFormValue {
if let nativeProvider = paymentForm.nativeProvider, nativeProvider.name == "stripe" {
if customUrl == nil, let nativeProvider = paymentForm.nativeProvider, nativeProvider.name == "stripe" {
guard let paramsData = nativeProvider.params.data(using: .utf8) else {
return
}
@ -891,7 +891,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
controller?.dismiss()
}
strongSelf.present(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
} else if let nativeProvider = paymentForm.nativeProvider, nativeProvider.name == "smartglocal" {
} else if customUrl == nil, let nativeProvider = paymentForm.nativeProvider, nativeProvider.name == "smartglocal" {
guard let paramsData = nativeProvider.params.data(using: .utf8) else {
return
}
@ -961,7 +961,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
strongSelf.present(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
} else {
var dismissImpl: (() -> Void)?
let controller = BotCheckoutWebInteractionController(context: context, url: paymentForm.url, intent: .addPaymentMethod({ [weak self] token in
let controller = BotCheckoutWebInteractionController(context: context, url: customUrl ?? paymentForm.url, intent: .addPaymentMethod({ [weak self] token in
dismissImpl?()
guard let strongSelf = self else {
@ -1060,12 +1060,14 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
strongSelf.controller?.view.endEditing(true)
let methods = availablePaymentMethods(form: paymentForm, current: strongSelf.currentPaymentMethod)
if methods.isEmpty {
openNewCard()
openNewCard(nil)
} else {
strongSelf.present(BotCheckoutPaymentMethodSheetController(context: strongSelf.context, currentMethod: strongSelf.currentPaymentMethod, methods: methods, applyValue: { method in
applyPaymentMethod(method)
}, newCard: {
openNewCard()
openNewCard(nil)
}, otherMethod: { url in
openNewCard(url)
}), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
}
}

View File

@ -39,7 +39,7 @@ enum BotCheckoutPaymentMethod: Equatable {
final class BotCheckoutPaymentMethodSheetController: ActionSheetController {
private var presentationDisposable: Disposable?
init(context: AccountContext, currentMethod: BotCheckoutPaymentMethod?, methods: [BotCheckoutPaymentMethod], applyValue: @escaping (BotCheckoutPaymentMethod) -> Void, newCard: @escaping () -> Void) {
init(context: AccountContext, currentMethod: BotCheckoutPaymentMethod?, methods: [BotCheckoutPaymentMethod], applyValue: @escaping (BotCheckoutPaymentMethod) -> Void, newCard: @escaping () -> Void, otherMethod: @escaping (String) -> Void) {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let strings = presentationData.strings
@ -82,7 +82,11 @@ final class BotCheckoutPaymentMethodSheetController: ActionSheetController {
value = nil
}
items.append(BotCheckoutPaymentMethodItem(title: title, icon: icon, value: value, action: { [weak self] _ in
applyValue(method)
if case let .other(method) = method {
otherMethod(method.url)
} else {
applyValue(method)
}
self?.dismissAnimated()
}))
}

View File

@ -20,7 +20,7 @@ swift_library(
"//submodules/ContextUI:ContextUI",
"//submodules/AppBundle:AppBundle",
"//submodules/TextFormat:TextFormat",
"//submodules/TelegramUI/Components/TextNodeWithEntities:TextNodeWithEntities",
"//submodules/TelegramUI/Components/EmojiTextAttachmentView:EmojiTextAttachmentView",
],
visibility = [
"//visibility:public",

View File

@ -57,7 +57,9 @@ public final class ChatSendMessageActionSheetController: ViewController {
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
if let strongSelf = self {
strongSelf.presentationData = presentationData
strongSelf.controllerNode.updatePresentationData(presentationData)
if strongSelf.isNodeLoaded {
strongSelf.controllerNode.updatePresentationData(presentationData)
}
}
})
@ -93,7 +95,7 @@ public final class ChatSendMessageActionSheetController: ViewController {
hasEntityKeyboard = true
}
self.displayNode = ChatSendMessageActionSheetControllerNode(context: self.context, presentationData: self.presentationData, reminders: reminders, gesture: gesture, sourceSendButton: self.sourceSendButton, textInputNode: self.textInputNode, attachment: self.attachment, forwardedCount: forwardedCount, hasEntityKeyboard: hasEntityKeyboard, send: { [weak self] in
self.displayNode = ChatSendMessageActionSheetControllerNode(context: self.context, presentationData: self.presentationData, reminders: reminders, gesture: gesture, sourceSendButton: self.sourceSendButton, textInputNode: self.textInputNode, attachment: self.attachment, forwardedCount: forwardedCount, hasEntityKeyboard: hasEntityKeyboard, emojiViewProvider: self.emojiViewProvider, send: { [weak self] in
self?.sendMessage(false)
self?.dismiss(cancel: false)
}, sendSilently: { [weak self] in

View File

@ -10,7 +10,7 @@ import AccountContext
import AppBundle
import ContextUI
import TextFormat
import TextNodeWithEntities
import EmojiTextAttachmentView
private let leftInset: CGFloat = 16.0
private let rightInset: CGFloat = 16.0
@ -178,6 +178,9 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
private let toMessageTextNode: EditableTextNode
private let scrollNode: ASScrollNode
private var fromCustomEmojiContainerView: CustomEmojiContainerView?
private var toCustomEmojiContainerView: CustomEmojiContainerView?
private var validLayout: ContainerViewLayout?
private var sendButtonFrame: CGRect {
@ -186,7 +189,9 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
private var animateInputField = false
init(context: AccountContext, presentationData: PresentationData, reminders: Bool, gesture: ContextGesture, sourceSendButton: ASDisplayNode, textInputNode: EditableTextNode, attachment: Bool, forwardedCount: Int?, hasEntityKeyboard: Bool, send: (() -> Void)?, sendSilently: (() -> Void)?, schedule: (() -> Void)?, cancel: (() -> Void)?) {
private var emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?
init(context: AccountContext, presentationData: PresentationData, reminders: Bool, gesture: ContextGesture, sourceSendButton: ASDisplayNode, textInputNode: EditableTextNode, attachment: Bool, forwardedCount: Int?, hasEntityKeyboard: Bool, emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?, send: (() -> Void)?, sendSilently: (() -> Void)?, schedule: (() -> Void)?, cancel: (() -> Void)?) {
self.context = context
self.presentationData = presentationData
self.sourceSendButton = sourceSendButton
@ -195,6 +200,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
self.attachment = attachment
self.forwardedCount = forwardedCount
self.hasEntityKeyboard = hasEntityKeyboard
self.emojiViewProvider = emojiViewProvider
self.send = send
self.cancel = cancel
@ -352,6 +358,64 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
}
}
func updateTextContents() {
var customEmojiRects: [(CGRect, ChatTextInputTextCustomEmojiAttribute)] = []
let textInputNode = self.fromMessageTextNode
if let attributedText = textInputNode.attributedText {
let beginning = textInputNode.textView.beginningOfDocument
attributedText.enumerateAttributes(in: NSMakeRange(0, attributedText.length), options: [], using: { attributes, range, _ in
if let value = attributes[ChatTextInputAttributes.customEmoji] as? ChatTextInputTextCustomEmojiAttribute {
if let start = textInputNode.textView.position(from: beginning, offset: range.location), let end = textInputNode.textView.position(from: start, offset: range.length), let textRange = textInputNode.textView.textRange(from: start, to: end) {
let textRects = textInputNode.textView.selectionRects(for: textRange)
for textRect in textRects {
customEmojiRects.append((textRect.rect, value))
break
}
}
}
})
}
self.updateTextContents(rects: customEmojiRects, textInputNode: self.fromMessageTextNode, from: true)
self.updateTextContents(rects: customEmojiRects, textInputNode: self.toMessageTextNode, from: false)
}
func updateTextContents(rects: [(CGRect, ChatTextInputTextCustomEmojiAttribute)], textInputNode: EditableTextNode, from: Bool) {
if !rects.isEmpty {
let customEmojiContainerView: CustomEmojiContainerView
if from, let current = self.fromCustomEmojiContainerView {
customEmojiContainerView = current
} else if !from, let current = self.toCustomEmojiContainerView {
customEmojiContainerView = current
} else {
customEmojiContainerView = CustomEmojiContainerView(emojiViewProvider: { [weak self] emoji in
guard let strongSelf = self, let emojiViewProvider = strongSelf.emojiViewProvider else {
return nil
}
return emojiViewProvider(emoji)
})
customEmojiContainerView.isUserInteractionEnabled = false
textInputNode.textView.addSubview(customEmojiContainerView)
if from {
self.fromCustomEmojiContainerView = customEmojiContainerView
} else {
self.toCustomEmojiContainerView = customEmojiContainerView
}
}
customEmojiContainerView.update(emojiRects: rects)
} else {
if from, let customEmojiContainerView = self.fromCustomEmojiContainerView {
customEmojiContainerView.removeFromSuperview()
self.fromCustomEmojiContainerView = nil
} else if !from, let customEmojiContainerView = self.toCustomEmojiContainerView {
customEmojiContainerView.removeFromSuperview()
self.fromCustomEmojiContainerView = nil
}
}
}
func updatePresentationData(_ presentationData: PresentationData) {
guard presentationData.theme !== self.presentationData.theme else {
return
@ -460,6 +524,10 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
let springDamping: CGFloat = 104.0
self.contentContainerNode.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: springDuration, initialVelocity: 0.0, damping: springDamping)
self.contentContainerNode.layer.animateSpring(from: NSValue(cgPoint: contentOffset), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, initialVelocity: 0.0, damping: springDamping, additive: true)
Queue.mainQueue().after(0.01, {
self.updateTextContents()
})
}
func animateOut(cancel: Bool, completion: @escaping () -> Void) {
@ -693,3 +761,64 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
self.send?()
}
}
final class CustomEmojiContainerView: UIView {
private let emojiViewProvider: (ChatTextInputTextCustomEmojiAttribute) -> UIView?
private var emojiLayers: [InlineStickerItemLayer.Key: UIView] = [:]
init(emojiViewProvider: @escaping (ChatTextInputTextCustomEmojiAttribute) -> UIView?) {
self.emojiViewProvider = emojiViewProvider
super.init(frame: CGRect())
}
required init(coder: NSCoder) {
preconditionFailure()
}
func update(emojiRects: [(CGRect, ChatTextInputTextCustomEmojiAttribute)]) {
var nextIndexById: [Int64: Int] = [:]
var validKeys = Set<InlineStickerItemLayer.Key>()
for (rect, emoji) in emojiRects {
let index: Int
if let nextIndex = nextIndexById[emoji.fileId] {
index = nextIndex
} else {
index = 0
}
nextIndexById[emoji.fileId] = index + 1
let key = InlineStickerItemLayer.Key(id: emoji.fileId, index: index)
let view: UIView
if let current = self.emojiLayers[key] {
view = current
} else if let newView = self.emojiViewProvider(emoji) {
view = newView
self.addSubview(newView)
self.emojiLayers[key] = view
} else {
continue
}
let size = CGSize(width: 24.0, height: 24.0)
view.frame = CGRect(origin: CGPoint(x: floor(rect.midX - size.width / 2.0), y: floor(rect.midY - size.height / 2.0)), size: size)
validKeys.insert(key)
}
var removeKeys: [InlineStickerItemLayer.Key] = []
for (key, view) in self.emojiLayers {
if !validKeys.contains(key) {
removeKeys.append(key)
view.removeFromSuperview()
}
}
for key in removeKeys {
self.emojiLayers.removeValue(forKey: key)
}
}
}

View File

@ -552,9 +552,9 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
}
itemSize.height = height
} else if let fillsRowWithDynamicHeight = item.fillsRowWithDynamicHeight {
let height = fillsRowWithDynamicHeight(gridLayout.size.width)
let height = fillsRowWithDynamicHeight(gridLayout.size.width - itemInsets.left - itemInsets.right)
nextItemOrigin.x = initialSpacing + itemInsets.left
itemSize.width = gridLayout.size.width
itemSize.width = gridLayout.size.width - itemInsets.left - itemInsets.right
itemSize.height = height
} else if index == 0 {
let itemsInRow = max(1, Int(effectiveWidth) / Int(itemSize.width))

View File

@ -122,11 +122,12 @@ private final class HapticFeedbackImpl {
}
func warning() {
if let notificationGenerator = self.notificationGenerator {
notificationGenerator.notificationOccurred(.warning)
} else {
}
AudioServicesPlaySystemSound(1102)
// if let notificationGenerator = self.notificationGenerator {
// notificationGenerator.notificationOccurred(.warning)
// } else {
//
// }
}
@objc dynamic func f() {

View File

@ -331,6 +331,7 @@ public class Window1 {
self.hostView = hostView
self.badgeView = UIImageView()
self.badgeView.image = UIImage(bundleImageName: "Components/AppBadge")
self.badgeView.isHidden = true
self.systemUserInterfaceStyle = hostView.systemUserInterfaceStyle
@ -655,7 +656,7 @@ public class Window1 {
}
}
private var forceBadgeHidden = false
private var forceBadgeHidden = true
public func setForceBadgeHidden(_ hidden: Bool) {
guard hidden != self.forceBadgeHidden else {
return

View File

@ -20,7 +20,7 @@ public enum ItemListDisclosureLabelStyle {
case text
case detailText
case coloredText(UIColor)
// case textWithIcon(UIColor)
case textWithIcon(UIImage)
case multilineDetailText
case badge(UIColor)
case color(UIColor)
@ -236,7 +236,9 @@ public class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode {
updatedLabelImage = generateFilledCircleImage(diameter: 17.0, color: color)
}
}
if case let .image(image, _) = item.labelStyle {
if case let .textWithIcon(image) = item.labelStyle {
updatedLabelImage = generateTintedImage(image: image, color: item.presentationData.theme.list.itemSecondaryTextColor)
} else if case let .image(image, _) = item.labelStyle {
updatedLabelImage = image
}
@ -474,7 +476,18 @@ public class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode {
}
strongSelf.labelNode.frame = labelFrame
if case let .image(_, size) = item.labelStyle {
if case .textWithIcon = item.labelStyle {
if let updatedLabelImage = updatedLabelImage {
strongSelf.labelImageNode.image = updatedLabelImage
}
if strongSelf.labelImageNode.supernode == nil {
strongSelf.addSubnode(strongSelf.labelImageNode)
}
if let size = strongSelf.labelImageNode.image?.size {
strongSelf.labelImageNode.frame = CGRect(origin: CGPoint(x: labelFrame.minX - size.width - 5.0, y: floor((layout.contentSize.height - size.height) / 2.0) - 1.0), size: size)
}
} else if case let .image(_, size) = item.labelStyle {
if let updatedLabelImage = updatedLabelImage {
strongSelf.labelImageNode.image = updatedLabelImage
}

View File

@ -478,7 +478,7 @@ func deleteAccountDataController(context: AccountContext, mode: DeleteAccountDat
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.step_confirmation_cancel")
dismissImpl?()
})]))
})], actionLayout: .vertical))
}
}

View File

@ -83,7 +83,7 @@ private enum PrivacyAndSecurityEntry: ItemListNodeEntry {
case voiceCallPrivacy(PresentationTheme, String, String)
case forwardPrivacy(PresentationTheme, String, String)
case groupPrivacy(PresentationTheme, String, String)
case voiceMessagePrivacy(PresentationTheme, String, String)
case voiceMessagePrivacy(PresentationTheme, String, String, Bool)
case selectivePrivacyInfo(PresentationTheme, String)
case passcode(PresentationTheme, String, Bool, String)
case twoStepVerification(PresentationTheme, String, String, TwoStepVerificationAccessConfiguration?)
@ -209,8 +209,8 @@ private enum PrivacyAndSecurityEntry: ItemListNodeEntry {
} else {
return false
}
case let .voiceMessagePrivacy(lhsTheme, lhsText, lhsValue):
if case let .voiceMessagePrivacy(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
case let .voiceMessagePrivacy(lhsTheme, lhsText, lhsValue, lhsLocked):
if case let .voiceMessagePrivacy(rhsTheme, rhsText, rhsValue, rhsLocked) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue, lhsLocked == rhsLocked {
return true
} else {
return false
@ -300,7 +300,7 @@ private enum PrivacyAndSecurityEntry: ItemListNodeEntry {
case let .privacyHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .blockedPeers(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, icon: UIImage(bundleImageName: "Settings/Menu/Blocked")?.precomposed(), title: text, label: value, sectionId: self.section, style: .blocks, action: {
return ItemListDisclosureItem(presentationData: presentationData, icon: UIImage(bundleImageName: "Chat/Stickers/Blocked")?.precomposed(), title: text, label: value, sectionId: self.section, style: .blocks, action: {
arguments.openBlockedUsers()
})
case let .phoneNumberPrivacy(_, text, value):
@ -323,8 +323,8 @@ private enum PrivacyAndSecurityEntry: ItemListNodeEntry {
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, action: {
arguments.openGroupsPrivacy()
})
case let .voiceMessagePrivacy(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, action: {
case let .voiceMessagePrivacy(_, text, value, locked):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, labelStyle: locked ? .textWithIcon(UIImage(bundleImageName: "Notification/SecretLock")!.precomposed()) : .text, sectionId: self.section, style: .blocks, action: {
arguments.openVoiceMessagePrivacy()
})
case let .selectivePrivacyInfo(_, text):
@ -411,7 +411,7 @@ private func stringForSelectiveSettings(strings: PresentationStrings, settings:
}
}
private func privacyAndSecurityControllerEntries(presentationData: PresentationData, state: PrivacyAndSecurityControllerState, privacySettings: AccountPrivacySettings?, accessChallengeData: PostboxAccessChallengeData, blockedPeerCount: Int?, activeWebsitesCount: Int, hasTwoStepAuth: Bool?, twoStepAuthData: TwoStepVerificationAccessConfiguration?, canAutoarchive: Bool) -> [PrivacyAndSecurityEntry] {
private func privacyAndSecurityControllerEntries(presentationData: PresentationData, state: PrivacyAndSecurityControllerState, privacySettings: AccountPrivacySettings?, accessChallengeData: PostboxAccessChallengeData, blockedPeerCount: Int?, activeWebsitesCount: Int, hasTwoStepAuth: Bool?, twoStepAuthData: TwoStepVerificationAccessConfiguration?, canAutoarchive: Bool, isPremium: Bool) -> [PrivacyAndSecurityEntry] {
var entries: [PrivacyAndSecurityEntry] = []
entries.append(.blockedPeers(presentationData.theme, presentationData.strings.Settings_BlockedUsers, blockedPeerCount == nil ? "" : (blockedPeerCount == 0 ? presentationData.strings.PrivacySettings_BlockedPeersEmpty : "\(blockedPeerCount!)")))
@ -449,7 +449,7 @@ private func privacyAndSecurityControllerEntries(presentationData: PresentationD
entries.append(.lastSeenPrivacy(presentationData.theme, presentationData.strings.PrivacySettings_LastSeen, stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.presence)))
entries.append(.profilePhotoPrivacy(presentationData.theme, presentationData.strings.Privacy_ProfilePhoto, stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.profilePhoto)))
entries.append(.voiceCallPrivacy(presentationData.theme, presentationData.strings.Privacy_Calls, stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.voiceCalls)))
entries.append(.voiceMessagePrivacy(presentationData.theme, presentationData.strings.Privacy_VoiceMessages, stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.voiceMessages)))
entries.append(.voiceMessagePrivacy(presentationData.theme, presentationData.strings.Privacy_VoiceMessages, stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.voiceMessages), !isPremium))
entries.append(.forwardPrivacy(presentationData.theme, presentationData.strings.Privacy_Forwards, stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.forwards)))
entries.append(.groupPrivacy(presentationData.theme, presentationData.strings.Privacy_GroupsAndChannels, stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.groupInvitations)))
@ -458,7 +458,7 @@ private func privacyAndSecurityControllerEntries(presentationData: PresentationD
entries.append(.lastSeenPrivacy(presentationData.theme, presentationData.strings.PrivacySettings_LastSeen, presentationData.strings.Channel_NotificationLoading))
entries.append(.profilePhotoPrivacy(presentationData.theme, presentationData.strings.Privacy_ProfilePhoto, presentationData.strings.Channel_NotificationLoading))
entries.append(.voiceCallPrivacy(presentationData.theme, presentationData.strings.Privacy_Calls, presentationData.strings.Channel_NotificationLoading))
entries.append(.voiceMessagePrivacy(presentationData.theme, presentationData.strings.Privacy_VoiceMessages, presentationData.strings.Channel_NotificationLoading))
entries.append(.voiceMessagePrivacy(presentationData.theme, presentationData.strings.Privacy_VoiceMessages, presentationData.strings.Channel_NotificationLoading, !isPremium))
entries.append(.forwardPrivacy(presentationData.theme, presentationData.strings.Privacy_Forwards, presentationData.strings.Channel_NotificationLoading))
entries.append(.groupPrivacy(presentationData.theme, presentationData.strings.Privacy_GroupsAndChannels, presentationData.strings.Channel_NotificationLoading))
entries.append(.selectivePrivacyInfo(presentationData.theme, presentationData.strings.PrivacyLastSeenSettings_GroupsAndChannelsHelp))
@ -944,9 +944,10 @@ public func privacyAndSecurityController(context: AccountContext, initialSetting
webSessionsContext.state,
context.sharedContext.accountManager.accessChallengeData(),
combineLatest(twoStepAuth.get(), twoStepAuthDataValue.get()),
context.engine.data.subscribe(TelegramEngine.EngineData.Item.Configuration.App())
context.engine.data.subscribe(TelegramEngine.EngineData.Item.Configuration.App()),
context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
)
|> map { presentationData, state, privacySettings, noticeView, sharedData, recentPeers, blockedPeersState, activeWebsitesState, accessChallengeData, twoStepAuth, appConfiguration -> (ItemListControllerState, (ItemListNodeState, Any)) in
|> map { presentationData, state, privacySettings, noticeView, sharedData, recentPeers, blockedPeersState, activeWebsitesState, accessChallengeData, twoStepAuth, appConfiguration, accountPeer -> (ItemListControllerState, (ItemListNodeState, Any)) in
var canAutoarchive = false
if let data = appConfiguration.data, let hasAutoarchive = data["autoarchive_setting_available"] as? Bool {
canAutoarchive = hasAutoarchive
@ -959,7 +960,9 @@ public func privacyAndSecurityController(context: AccountContext, initialSetting
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.PrivacySettings_Title), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: privacyAndSecurityControllerEntries(presentationData: presentationData, state: state, privacySettings: privacySettings, accessChallengeData: accessChallengeData.data, blockedPeerCount: blockedPeersState.totalCount, activeWebsitesCount: activeWebsitesState.sessions.count, hasTwoStepAuth: twoStepAuth.0, twoStepAuthData: twoStepAuth.1, canAutoarchive: canAutoarchive), style: .blocks, ensureVisibleItemTag: focusOnItemTag, animateChanges: false)
let isPremium = accountPeer?.isPremium ?? false
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: privacyAndSecurityControllerEntries(presentationData: presentationData, state: state, privacySettings: privacySettings, accessChallengeData: accessChallengeData.data, blockedPeerCount: blockedPeersState.totalCount, activeWebsitesCount: activeWebsitesState.sessions.count, hasTwoStepAuth: twoStepAuth.0, twoStepAuthData: twoStepAuth.1, canAutoarchive: canAutoarchive, isPremium: isPremium), style: .blocks, ensureVisibleItemTag: focusOnItemTag, animateChanges: false)
return (controllerState, (listState, arguments))
}

View File

@ -103,16 +103,14 @@ final class StickerPackEmojisItem: GridItem {
func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode {
let node = StickerPackEmojisItemNode()
node.setup(item: self)
return node
}
func update(node: GridItemNode) {
guard let node = node as? StickerPackEmojisItemNode else {
guard let _ = node as? StickerPackEmojisItemNode else {
assertionFailure()
return
}
node.setup(item: self)
}
}
@ -173,7 +171,7 @@ final class StickerPackEmojisItemNode: GridItemNode {
let shimmerHostView = PortalSourceView()
shimmerHostView.alpha = 0.0
shimmerHostView.frame = CGRect(origin: CGPoint(), size: self.frame.size)
shimmerHostView.frame = CGRect(origin: CGPoint(), size: self.size)
self.view.addSubview(shimmerHostView)
self.shimmerHostView = shimmerHostView
@ -194,10 +192,14 @@ final class StickerPackEmojisItemNode: GridItemNode {
}
self.boundsChangeTrackerLayer = boundsChangeTrackerLayer
}
private var setupTimestamp: Double?
func setup(item: StickerPackEmojisItem) {
private var size = CGSize()
override func updateLayout(item: GridItem, size: CGSize, isVisible: Bool, synchronousLoads: Bool) {
guard let item = item as? StickerPackEmojisItem else {
return
}
self.item = item
self.size = size
if let title = item.title {
let isInstalled = item.isInstalled ?? false
@ -217,9 +219,9 @@ final class StickerPackEmojisItemNode: GridItemNode {
self.setNeedsLayout()
}
func updateVisibleItems(attemptSynchronousLoads: Bool, transition: ContainedViewLayoutTransition) {
guard let item = self.item, !self.frame.width.isZero else {
guard let item = self.item, !self.size.width.isZero else {
return
}
@ -231,10 +233,10 @@ final class StickerPackEmojisItemNode: GridItemNode {
var validIds = Set<EmojiPagerContentComponent.View.ItemLayer.Key>()
let itemLayout: ItemLayout
if let current = self.itemLayout, current.width == self.frame.width && current.itemsCount == items.count && current.hasTitle == (item.title != nil) {
if let current = self.itemLayout, current.width == self.size.width && current.itemsCount == items.count && current.hasTitle == (item.title != nil) {
itemLayout = current
} else {
itemLayout = ItemLayout(width: self.frame.width, itemsCount: items.count, hasTitle: item.title != nil)
itemLayout = ItemLayout(width: self.size.width, itemsCount: items.count, hasTitle: item.title != nil)
self.itemLayout = itemLayout
}
@ -368,20 +370,20 @@ final class StickerPackEmojisItemNode: GridItemNode {
super.layout()
if let _ = self.item {
var buttonSize = self.buttonNode.calculateSizeThatFits(self.frame.size)
var buttonSize = self.buttonNode.calculateSizeThatFits(self.size)
buttonSize.width += 24.0
buttonSize.height = 28.0
let titleSize = self.titleNode.updateLayout(CGSize(width: self.frame.width - 60.0, height: self.frame.height))
let subtitleSize = self.subtitleNode.updateLayout(CGSize(width: self.frame.width - 60.0, height: self.frame.height))
let titleSize = self.titleNode.updateLayout(CGSize(width: self.size.width - 60.0, height: self.size.height))
let subtitleSize = self.subtitleNode.updateLayout(CGSize(width: self.size.width - 60.0, height: self.size.height))
self.titleNode.frame = CGRect(origin: CGPoint(x: 16.0, y: 10.0), size: titleSize)
self.subtitleNode.frame = CGRect(origin: CGPoint(x: 16.0, y: 33.0), size: subtitleSize)
self.buttonNode.frame = CGRect(origin: CGPoint(x: self.frame.width - buttonSize.width - 16.0, y: 17.0), size: buttonSize)
self.buttonNode.frame = CGRect(origin: CGPoint(x: self.size.width - buttonSize.width - 16.0, y: 17.0), size: buttonSize)
}
self.shimmerHostView?.frame = CGRect(origin: CGPoint(), size: self.frame.size)
self.shimmerHostView?.frame = CGRect(origin: CGPoint(), size: self.size)
self.updateVisibleItems(attemptSynchronousLoads: false, transition: .immediate)
}

View File

@ -911,14 +911,6 @@ private final class StickerPackContainer: ASDisplayNode {
}
if updateLayout, let (layout, _, _, _) = self.validLayout {
let cancelSize = self.cancelButtonNode.measure(CGSize(width: layout.size.width, height: .greatestFiniteMagnitude))
self.cancelButtonNode.frame = CGRect(origin: CGPoint(x: layout.safeInsets.left + 16.0, y: 18.0), size: cancelSize)
let titleSize = self.titleNode.updateLayout(CGSize(width: layout.size.width - cancelSize.width * 2.0 - 40.0, height: .greatestFiniteMagnitude))
self.titleNode.frame = CGRect(origin: CGPoint(x: floor((-titleSize.width) / 2.0), y: floor((-titleSize.height) / 2.0)), size: titleSize)
self.moreButtonNode.frame = CGRect(origin: CGPoint(x: layout.size.width - layout.safeInsets.right - 46.0, y: 5.0), size: CGSize(width: 44.0, height: 44.0))
self.updateLayout(layout: layout, transition: .immediate)
}
@ -1050,6 +1042,14 @@ private final class StickerPackContainer: ASDisplayNode {
titlePlaceholderNode.updateAbsoluteRect(titlePlaceholderNode.frame.offsetBy(dx: self.titleContainer.frame.minX, dy: self.titleContainer.frame.minY - gridInsets.top - gridFrame.minY), within: gridFrame.size)
}
let cancelSize = self.cancelButtonNode.measure(CGSize(width: layout.size.width, height: .greatestFiniteMagnitude))
self.cancelButtonNode.frame = CGRect(origin: CGPoint(x: layout.safeInsets.left + 16.0, y: 18.0), size: cancelSize)
let titleSize = self.titleNode.updateLayout(CGSize(width: layout.size.width - cancelSize.width * 2.0 - 40.0, height: .greatestFiniteMagnitude))
self.titleNode.frame = CGRect(origin: CGPoint(x: floor((-titleSize.width) / 2.0), y: floor((-titleSize.height) / 2.0)), size: titleSize)
self.moreButtonNode.frame = CGRect(origin: CGPoint(x: layout.size.width - layout.safeInsets.right - 46.0, y: 5.0), size: CGSize(width: 44.0, height: 44.0))
if firstTime {
while !self.enqueuedTransactions.isEmpty {
self.dequeueTransaction()

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -3617,7 +3617,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}, didDismiss: { [weak self] in
if let strongSelf = self {
let isFocused = strongSelf.chatDisplayNode.textInputPanelNode?.isFocused ?? false
strongSelf.chatDisplayNode.insertSubnode(strongSelf.chatDisplayNode.inputPanelContainerNode, aboveSubnode: strongSelf.chatDisplayNode.historyNodeContainer)
strongSelf.chatDisplayNode.insertSubnode(strongSelf.chatDisplayNode.inputPanelContainerNode, aboveSubnode: strongSelf.chatDisplayNode.inputContextPanelContainer)
if isFocused {
strongSelf.chatDisplayNode.textInputPanelNode?.ensureFocused()
}

View File

@ -125,7 +125,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
private var secondaryInputPanelNode: ChatInputPanelNode?
private(set) var accessoryPanelNode: AccessoryPanelNode?
private var inputContextPanelNode: ChatInputContextPanelNode?
private let inputContextPanelContainer: ChatControllerTitlePanelNodeContainer
let inputContextPanelContainer: ChatControllerTitlePanelNodeContainer
private let inputContextOverTextPanelContainer: ChatControllerTitlePanelNodeContainer
private var overlayContextPanelNode: ChatInputContextPanelNode?

View File

@ -1067,7 +1067,14 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
}
if isPremiumLocked {
let controller = PremiumIntroScreen(context: context, source: .stickers)
var replaceImpl: ((ViewController) -> Void)?
let controller = PremiumDemoScreen(context: context, subject: .animatedEmoji, action: {
let controller = PremiumIntroScreen(context: context, source: .animatedEmoji)
replaceImpl?(controller)
})
replaceImpl = { [weak controller] c in
controller?.replace(with: c)
}
controllerInteraction.navigationController()?.pushViewController(controller)
return

View File

@ -60,7 +60,7 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode {
self.addSubnode(self.iconImageNode)
switch item {
case .input, .botInput:
case .input, .botInput, .silentPost:
self.iconImageNode.isHidden = true
self.animationView = ComponentView<Empty>()
default:
@ -175,105 +175,122 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode {
self.iconImageNode.frame = imageFrame
if let animationView = self.animationView {
let iconSize: CGSize = CGSize(width: 32.0, height: 32.0)
let iconFrame = CGRect(origin: CGPoint(x: floor((size.width - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0) - bottomInset), size: iconSize)
let animationFrame = iconFrame.insetBy(dx: -4.0, dy: -4.0)
let width = AccessoryItemIconButtonNode.calculateWidth(item: item, image: image, text: "", strings: self.strings)
let iconSize = CGSize(width: width, height: width)
var previousInputMode: ChatTextInputAccessoryItem.InputMode?
var inputMode: ChatTextInputAccessoryItem.InputMode?
switch previousItem {
case let .input(_, itemInputMode), let .botInput(_, itemInputMode):
previousInputMode = itemInputMode
default:
break
}
switch item {
case let .input(_, itemInputMode), let .botInput(_, itemInputMode):
inputMode = itemInputMode
default:
break
}
let emojiColorKeys = [
"Ellipse 33.Ellipse 33.Stroke 1",
"Ellipse 34.Ellipse 34.Stroke 1",
"Oval.Oval.Fill 1",
"Oval 2.Oval.Fill 1",
"Path 85.Path 85.Stroke 1"
]
let animationFrame = CGRect(origin: CGPoint(x: floor((size.width - width) / 2.0), y: floor((size.height - width) / 2.0) - bottomInset), size: CGSize(width: width, height: width))
var colorKeys: [String] = ["__allcolors__"]
let animationName: String
var animationMode: LottieAnimationComponent.AnimationItem.Mode = .still(position: .end)
if let inputMode = inputMode {
switch inputMode {
case .keyboard:
if let previousInputMode = previousInputMode {
if case .stickers = previousInputMode {
animationName = "input_anim_stickerToKey"
animationMode = .animating(loop: false)
} else if case .emoji = previousInputMode {
animationName = "input_anim_smileToKey"
animationMode = .animating(loop: false)
} else if case .bot = previousInputMode {
animationName = "input_anim_botToKey"
animationMode = .animating(loop: false)
} else {
animationName = "input_anim_stickerToKey"
}
} else {
animationName = "input_anim_stickerToKey"
}
case .stickers:
if let previousInputMode = previousInputMode {
if case .keyboard = previousInputMode {
animationName = "input_anim_keyToSticker"
animationMode = .animating(loop: false)
} else if case .emoji = previousInputMode {
animationName = "input_anim_smileToSticker"
animationMode = .animating(loop: false)
colorKeys = emojiColorKeys
} else {
animationName = "input_anim_keyToSticker"
}
} else {
animationName = "input_anim_keyToSticker"
}
case .emoji:
if let previousInputMode = previousInputMode {
if case .keyboard = previousInputMode {
animationName = "input_anim_keyToSmile"
animationMode = .animating(loop: false)
} else if case .stickers = previousInputMode {
animationName = "input_anim_stickerToSmile"
animationMode = .animating(loop: false)
colorKeys = emojiColorKeys
} else {
animationName = "input_anim_keyToSmile"
}
} else {
animationName = "input_anim_keyToSmile"
}
case .bot:
if let previousInputMode = previousInputMode {
if case .keyboard = previousInputMode {
animationName = "input_anim_keyToBot"
animationMode = .animating(loop: false)
} else {
animationName = "input_anim_keyToBot"
}
} else {
animationName = "input_anim_keyToBot"
}
if case let .silentPost(muted) = item {
if case let .silentPost(previousMuted) = previousItem {
if muted {
animationName = "input_anim_channelMute"
} else {
animationName = "input_anim_channelUnmute"
}
if muted != previousMuted {
animationMode = .animating(loop: false)
}
} else {
animationName = "input_anim_channelMute"
}
} else {
animationName = ""
var previousInputMode: ChatTextInputAccessoryItem.InputMode?
var inputMode: ChatTextInputAccessoryItem.InputMode?
switch previousItem {
case let .input(_, itemInputMode), let .botInput(_, itemInputMode):
previousInputMode = itemInputMode
default:
break
}
switch item {
case let .input(_, itemInputMode), let .botInput(_, itemInputMode):
inputMode = itemInputMode
default:
break
}
let emojiColorKeys = [
"Ellipse 33.Ellipse 33.Stroke 1",
"Ellipse 34.Ellipse 34.Stroke 1",
"Oval.Oval.Fill 1",
"Oval 2.Oval.Fill 1",
"Path 85.Path 85.Stroke 1"
]
if let inputMode = inputMode {
switch inputMode {
case .keyboard:
if let previousInputMode = previousInputMode {
if case .stickers = previousInputMode {
animationName = "input_anim_stickerToKey"
animationMode = .animating(loop: false)
} else if case .emoji = previousInputMode {
animationName = "input_anim_smileToKey"
animationMode = .animating(loop: false)
} else if case .bot = previousInputMode {
animationName = "input_anim_botToKey"
animationMode = .animating(loop: false)
} else {
animationName = "input_anim_stickerToKey"
}
} else {
animationName = "input_anim_stickerToKey"
}
case .stickers:
if let previousInputMode = previousInputMode {
if case .keyboard = previousInputMode {
animationName = "input_anim_keyToSticker"
animationMode = .animating(loop: false)
} else if case .emoji = previousInputMode {
animationName = "input_anim_smileToSticker"
animationMode = .animating(loop: false)
colorKeys = emojiColorKeys
} else {
animationName = "input_anim_keyToSticker"
}
} else {
animationName = "input_anim_keyToSticker"
}
case .emoji:
if let previousInputMode = previousInputMode {
if case .keyboard = previousInputMode {
animationName = "input_anim_keyToSmile"
animationMode = .animating(loop: false)
} else if case .stickers = previousInputMode {
animationName = "input_anim_stickerToSmile"
animationMode = .animating(loop: false)
colorKeys = emojiColorKeys
} else {
animationName = "input_anim_keyToSmile"
}
} else {
animationName = "input_anim_keyToSmile"
}
case .bot:
if let previousInputMode = previousInputMode {
if case .keyboard = previousInputMode {
animationName = "input_anim_keyToBot"
animationMode = .animating(loop: false)
} else {
animationName = "input_anim_keyToBot"
}
} else {
animationName = "input_anim_keyToBot"
}
}
} else {
animationName = ""
}
}
var colors: [String: UIColor] = [:]
for colorKey in colorKeys {
colors[colorKey] = self.theme.chat.inputPanel.inputControlColor.blitOver(self.theme.chat.inputPanel.inputBackgroundColor, alpha: 1.0)
colors[colorKey] = self.theme.chat.inputPanel.inputControlColor
}
let animationSize = animationView.update(
@ -284,7 +301,7 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode {
mode: animationMode
),
colors: colors,
size: CGSize(width: 32.0, height: 32.0)
size: iconSize
)),
environment: {},
containerSize: animationFrame.size

View File

@ -74,11 +74,13 @@ public final class TelegramRootController: NavigationController {
}
})
self.applicationInFocusDisposable = (context.sharedContext.applicationBindings.applicationIsActive
|> distinctUntilChanged
|> deliverOn(Queue.mainQueue())).start(next: { value in
context.sharedContext.mainWindow?.setForceBadgeHidden(!value)
})
if context.sharedContext.applicationBindings.isMainApp {
self.applicationInFocusDisposable = (context.sharedContext.applicationBindings.applicationIsActive
|> distinctUntilChanged
|> deliverOn(Queue.mainQueue())).start(next: { value in
context.sharedContext.mainWindow?.setForceBadgeHidden(!value)
})
}
}
required public init(coder aDecoder: NSCoder) {

View File

@ -800,39 +800,40 @@ public final class WebAppController: ViewController, AttachmentContainable {
self.needDismissConfirmation = needConfirmation
}
case "web_app_request_phone":
let _ = (self.context.account.postbox.loadedPeerWithId(self.context.account.peerId)
|> deliverOnMainQueue).start(next: { [weak self] accountPeer in
guard let strongSelf = self else {
return
}
guard let user = accountPeer as? TelegramUser, let phoneNumber = user.phone else {
return
}
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
var items: [ActionSheetItem] = []
items.append(ActionSheetTextItem(title: strongSelf.presentationData.strings.WebApp_ShareMyPhoneNumberConfirmation(formatPhoneNumber(phoneNumber), strongSelf.controller?.botName ?? "").string, parseMarkdown: true))
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.WebApp_ShareMyPhoneNumber, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
guard let strongSelf = self else {
return
}
strongSelf.sendPhoneRequestedEvent(phone: phoneNumber)
}))
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
guard let strongSelf = self else {
return
}
strongSelf.sendPhoneRequestedEvent(phone: nil)
})
])])
strongSelf.controller?.present(actionSheet, in: .window(.root))
})
break
// let _ = (self.context.account.postbox.loadedPeerWithId(self.context.account.peerId)
// |> deliverOnMainQueue).start(next: { [weak self] accountPeer in
// guard let strongSelf = self else {
// return
// }
// guard let user = accountPeer as? TelegramUser, let phoneNumber = user.phone else {
// return
// }
//
// let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
// var items: [ActionSheetItem] = []
// items.append(ActionSheetTextItem(title: strongSelf.presentationData.strings.WebApp_ShareMyPhoneNumberConfirmation(formatPhoneNumber(phoneNumber), strongSelf.controller?.botName ?? "").string, parseMarkdown: true))
// items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.WebApp_ShareMyPhoneNumber, action: { [weak actionSheet] in
// actionSheet?.dismissAnimated()
// guard let strongSelf = self else {
// return
// }
//
// strongSelf.sendPhoneRequestedEvent(phone: phoneNumber)
// }))
//
// actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
// ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
// actionSheet?.dismissAnimated()
// guard let strongSelf = self else {
// return
// }
//
// strongSelf.sendPhoneRequestedEvent(phone: nil)
// })
// ])])
// strongSelf.controller?.present(actionSheet, in: .window(.root))
// })
default:
break
}