Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2023-09-13 17:22:04 +04:00
commit a288c543f2
9 changed files with 139 additions and 123 deletions

View File

@ -7778,6 +7778,7 @@ Sorry for the inconvenience.";
"WebApp.Settings" = "Settings";
"Bot.AccepRecurrentInfo" = "I accept the [Terms of Service]() of **%1$@**";
"Bot.AcceptTermsInfo" = "I accept the [Terms of Service]() of **%1$@**";
"Chat.AudioTranscriptionRateAction" = "Rate Transcription";
"Chat.AudioTranscriptionFeedbackTip" = "Thank you for your feedback.";

View File

@ -559,7 +559,7 @@ private final class RecurrentConfirmationNode: ASDisplayNode {
return super.hitTest(point, with: event)
}
func update(presentationData: PresentationData, botName: String, width: CGFloat, sideInset: CGFloat) -> CGFloat {
func update(presentationData: PresentationData, botName: String, isRecurrent: Bool, width: CGFloat, sideInset: CGFloat) -> CGFloat {
let spacing: CGFloat = 16.0
let topInset: CGFloat = 8.0
@ -580,7 +580,7 @@ private final class RecurrentConfirmationNode: ASDisplayNode {
self.textNode.linkHighlightColor = presentationData.theme.list.itemAccentColor.withAlphaComponent(0.2)
let attributedText = parseMarkdownIntoAttributedString(
presentationData.strings.Bot_AccepRecurrentInfo(botName).string,
isRecurrent ? presentationData.strings.Bot_AccepRecurrentInfo(botName).string : presentationData.strings.Bot_AcceptTermsInfo(botName).string,
attributes: MarkdownAttributes(
body: MarkdownAttributeSet(font: Font.regular(13.0), textColor: presentationData.theme.list.freeTextColor),
bold: MarkdownAttributeSet(font: Font.semibold(13.0), textColor: presentationData.theme.list.freeTextColor),
@ -619,7 +619,7 @@ private final class ActionButtonPanelNode: ASDisplayNode {
var height = max(layout.intrinsicInsets.bottom, layout.inputHeight ?? 0.0) + bottomPanelVerticalInset * 2.0 + BotCheckoutActionButton.height
var actionButtonOffset: CGFloat = bottomPanelVerticalInset
if let invoice = invoice, let recurrentInfo = invoice.recurrentInfo, let botName = botName {
if let invoice = invoice, let termsInfo = invoice.termsInfo, let botName = botName {
let recurrentConfirmationNode: RecurrentConfirmationNode
if let current = self.recurrentConfirmationNode {
recurrentConfirmationNode = current
@ -637,9 +637,7 @@ private final class ActionButtonPanelNode: ASDisplayNode {
self.addSubnode(recurrentConfirmationNode)
}
let _ = recurrentInfo
let recurrentConfirmationHeight = recurrentConfirmationNode.update(presentationData: presentationData, botName: botName, width: layout.size.width, sideInset: layout.safeInsets.left + 33.0)
let recurrentConfirmationHeight = recurrentConfirmationNode.update(presentationData: presentationData, botName: botName, isRecurrent: termsInfo.isRecurrent, width: layout.size.width, sideInset: layout.safeInsets.left + 33.0)
recurrentConfirmationNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: recurrentConfirmationHeight))
actionButtonOffset += recurrentConfirmationHeight
@ -776,10 +774,10 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
}
self.actionButtonPanelNode.openRecurrentTerms = { [weak self] in
guard let strongSelf = self, let paymentForm = strongSelf.paymentFormValue, let recurrentInfo = paymentForm.invoice.recurrentInfo else {
guard let strongSelf = self, let paymentForm = strongSelf.paymentFormValue, let termsInfo = paymentForm.invoice.termsInfo else {
return
}
strongSelf.context.sharedContext.openExternalUrl(context: strongSelf.context, urlContext: .generic, url: recurrentInfo.termsUrl, forceExternal: true, presentationData: context.sharedContext.currentPresentationData.with { $0 }, navigationController: nil, dismissInput: {
strongSelf.context.sharedContext.openExternalUrl(context: strongSelf.context, urlContext: .generic, url: termsInfo.termsUrl, forceExternal: true, presentationData: context.sharedContext.currentPresentationData.with { $0 }, navigationController: nil, dismissInput: {
self?.view.endEditing(true)
})
}
@ -1191,7 +1189,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
if let paymentForm = self.paymentFormValue, totalAmount > 0 {
payString = self.presentationData.strings.Checkout_PayPrice(formatCurrencyAmount(totalAmount, currency: paymentForm.invoice.currency)).string
if let _ = paymentForm.invoice.recurrentInfo {
if let _ = paymentForm.invoice.termsInfo {
if !self.actionButtonPanelNode.isAccepted {
isButtonEnabled = false
}

View File

@ -1288,7 +1288,9 @@ public final class ChatListNode: ListView {
super.init()
//self.useMainQueueTransactions = true
if case .internal = context.sharedContext.applicationBindings.appBuildType {
self.useMainQueueTransactions = true
}
self.verticalScrollIndicatorColor = theme.list.scrollIndicatorColor
self.verticalScrollIndicatorFollowsOverscroll = true

View File

@ -225,14 +225,19 @@ public final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelega
return
}
topController.viewWillDisappear(true)
topController.beginAppearanceTransition(false, animated: true)
//topController.viewWillDisappear(true)
let topNode = topController.displayNode
var bottomControllerLayout = layout
if bottomController.view.disableAutomaticKeyboardHandling.isEmpty {
bottomControllerLayout = bottomControllerLayout.withUpdatedInputHeight(nil)
}
bottomController.containerLayoutUpdated(bottomControllerLayout, transition: .immediate)
bottomController.viewWillAppear(true)
bottomController.beginAppearanceTransition(true, animated: true)
//bottomController.viewWillAppear(true)
let bottomNode = bottomController.displayNode
let navigationTransitionCoordinator = NavigationTransitionCoordinator(transition: .Pop, isInteractive: true, isFlat: self.isFlat, container: self, topNode: topNode, topNavigationBar: topController.transitionNavigationBar, bottomNode: bottomNode, bottomNavigationBar: bottomController.transitionNavigationBar, didUpdateProgress: { [weak self, weak bottomController] progress, transition, topFrame, bottomFrame in
@ -291,9 +296,12 @@ public final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelega
return
}
strongSelf.state.transition = nil
top.value.viewDidAppear(true)
transition.previous.value.viewDidDisappear(true)
top.value.endAppearanceTransition()
//top.value.viewDidAppear(true)
transition.previous.value.endAppearanceTransition()
//transition.previous.value.viewDidDisappear(true)
})
}
}
@ -452,8 +460,13 @@ public final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelega
}
fromValue.value.viewWillLeaveNavigation()
fromValue.value.viewWillDisappear(true)
toValue.value.viewWillAppear(true)
fromValue.value.beginAppearanceTransition(false, animated: true)
//fromValue.value.viewWillDisappear(true)
toValue.value.beginAppearanceTransition(true, animated: true)
//toValue.value.viewWillAppear(true)
toValue.value.setIgnoreAppearanceMethodInvocations(true)
if let layout = self.state.layout {
toValue.value.displayNode.frame = CGRect(origin: CGPoint(), size: layout.size)
@ -517,11 +530,16 @@ public final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelega
topTransition.previous.value.displayNode.removeFromSupernode()
topTransition.previous.value.setIgnoreAppearanceMethodInvocations(false)
}
topTransition.previous.value.viewDidDisappear(true)
topTransition.previous.value.endAppearanceTransition()
//topTransition.previous.value.viewDidDisappear(true)
if let toValue = strongSelf.state.top, let layout = strongSelf.state.layout {
toValue.value.displayNode.frame = CGRect(origin: CGPoint(), size: layout.size)
strongSelf.applyLayout(layout: layout, to: toValue, isMaster: true, transition: .immediate)
toValue.value.viewDidAppear(true)
toValue.value.endAppearanceTransition()
//toValue.value.viewDidAppear(true)
}
strongSelf.ignoreInputHeight = false
@ -533,24 +551,33 @@ public final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelega
}
fromValue.value.viewWillLeaveNavigation()
fromValue.value.viewWillDisappear(false)
fromValue.value.beginAppearanceTransition(false, animated: false)
//fromValue.value.viewWillDisappear(false)
self.keyboardViewManager?.dismissEditingWithoutAnimation(view: fromValue.value.view)
fromValue.value.setIgnoreAppearanceMethodInvocations(true)
fromValue.value.displayNode.removeFromSupernode()
fromValue.value.setIgnoreAppearanceMethodInvocations(false)
fromValue.value.viewDidDisappear(false)
fromValue.value.endAppearanceTransition()
//fromValue.value.viewDidDisappear(false)
}
if let toValue = toValue {
self.applyLayout(layout: layout, to: toValue, isMaster: true, transition: .immediate)
toValue.value.displayNode.frame = CGRect(origin: CGPoint(), size: layout.size)
toValue.value.viewWillAppear(false)
toValue.value.beginAppearanceTransition(true, animated: false)
//toValue.value.viewWillAppear(false)
toValue.value.setIgnoreAppearanceMethodInvocations(true)
self.addSubnode(toValue.value.displayNode)
toValue.value.setIgnoreAppearanceMethodInvocations(false)
toValue.value.displayNode.recursivelyEnsureDisplaySynchronously(true)
toValue.value.viewDidAppear(false)
toValue.value.endAppearanceTransition()
//toValue.value.viewDidAppear(false)
}
self.ignoreInputHeight = false
}

View File

@ -1188,13 +1188,13 @@ public class Account {
},
self.pendingPeerMediaUploadManager.uploadingPeerMedia |> map { uploadingPeerMedia in
if !uploadingPeerMedia.isEmpty {
print("updatingMessageMedia: true")
print("uploadingPeerMedia: true")
}
return !uploadingPeerMedia.isEmpty ? AccountRunningImportantTasks.pendingMessages : []
},
self.accountPresenceManager.isPerformingUpdate() |> map { presenceUpdate in
if presenceUpdate {
print("updatingMessageMedia: true")
print("accountPresenceManager isPerformingUpdate: true")
return []
}
return presenceUpdate ? AccountRunningImportantTasks.other : []

View File

@ -47,6 +47,7 @@ public struct BotPaymentInvoice : Equatable {
public struct RecurrentInfo: Equatable {
public var termsUrl: String
public var isRecurrent: Bool
}
public let isTest: Bool
@ -54,7 +55,7 @@ public struct BotPaymentInvoice : Equatable {
public let currency: String
public let prices: [BotPaymentPrice]
public let tip: Tip?
public let recurrentInfo: RecurrentInfo?
public let termsInfo: RecurrentInfo?
}
public struct BotPaymentNativeProvider : Equatable {
@ -144,7 +145,7 @@ public enum BotPaymentFormRequestError {
extension BotPaymentInvoice {
init(apiInvoice: Api.Invoice) {
switch apiInvoice {
case let .invoice(flags, currency, prices, maxTipAmount, suggestedTipAmounts, recurrentTermsUrl):
case let .invoice(flags, currency, prices, maxTipAmount, suggestedTipAmounts, termsUrl):
var fields = BotPaymentInvoiceFields()
if (flags & (1 << 1)) != 0 {
fields.insert(.name)
@ -167,9 +168,10 @@ extension BotPaymentInvoice {
if (flags & (1 << 7)) != 0 {
fields.insert(.emailAvailableToProvider)
}
var recurrentInfo: BotPaymentInvoice.RecurrentInfo?
if let recurrentTermsUrl = recurrentTermsUrl {
recurrentInfo = BotPaymentInvoice.RecurrentInfo(termsUrl: recurrentTermsUrl)
let isRecurrent = (flags & (1 << 9)) != 0
var termsInfo: BotPaymentInvoice.RecurrentInfo?
if let termsUrl = termsUrl {
termsInfo = BotPaymentInvoice.RecurrentInfo(termsUrl: termsUrl, isRecurrent: isRecurrent)
}
var parsedTip: BotPaymentInvoice.Tip?
if let maxTipAmount = maxTipAmount, let suggestedTipAmounts = suggestedTipAmounts {
@ -180,7 +182,7 @@ extension BotPaymentInvoice {
case let .labeledPrice(label, amount):
return BotPaymentPrice(label: label, amount: amount)
}
}, tip: parsedTip, recurrentInfo: recurrentInfo)
}, tip: parsedTip, termsInfo: termsInfo)
}
}
}

View File

@ -381,6 +381,8 @@ private final class StoryContainerScreenComponent: Component {
private let sharedViewListsContext = StoryItemSetViewListComponent.SharedListsContext()
private var didAnimateIn: Bool = false
private var isAnimatingOut: Bool = false
private var didAnimateOut: Bool = false
private var isDismissedExlusively: Bool = false
@ -429,25 +431,6 @@ private final class StoryContainerScreenComponent: Component {
})
self.addGestureRecognizer(horizontalPanRecognizer)
//TODO:move dismiss pan
/*let verticalPanRecognizer = InteractiveTransitionGestureRecognizer(target: self, action: #selector(self.dismissPanGesture(_:)), allowedDirections: { [weak self] point in
guard let self, let component = self.component, let stateValue = self.stateValue, let slice = stateValue.slice, let itemSetView = self.visibleItemSetViews[slice.peer.id], let itemSetComponentView = itemSetView.view.view as? StoryItemSetContainerComponent.View else {
return []
}
if let environment = self.environment, case .regular = environment.metrics.widthClass {
} else {
if !itemSetComponentView.isPointInsideContentArea(point: self.convert(point, to: itemSetComponentView)) {
return []
}
}
if !itemSetComponentView.allowsVerticalPanGesture() {
return []
}
return [.down]
})
self.addGestureRecognizer(verticalPanRecognizer)*/
let longPressRecognizer = StoryLongPressRecognizer(target: self, action: #selector(self.longPressGesture(_:)))
longPressRecognizer.delegate = self
longPressRecognizer.updateIsTracking = { [weak self] point in
@ -809,74 +792,6 @@ private final class StoryContainerScreenComponent: Component {
}
}
/*@objc private func dismissPanGesture(_ recognizer: UIPanGestureRecognizer) {
switch recognizer.state {
case .began:
self.dismissAllTooltips()
if let component = self.component, let stateValue = self.stateValue, let slice = stateValue.slice, let itemSetView = self.visibleItemSetViews[slice.peer.id] {
if let itemSetComponentView = itemSetView.view.view as? StoryItemSetContainerComponent.View {
if itemSetComponentView.hasActiveDeactivateableInput() {
itemSetComponentView.deactivateInput()
recognizer.isEnabled = false
recognizer.isEnabled = true
return
}
}
}
self.verticalPanState = ItemSetPanState(fraction: 0.0, didBegin: true)
self.state?.updated(transition: .immediate)
case .changed:
let translation = recognizer.translation(in: self)
self.verticalPanState = ItemSetPanState(fraction: max(-1.0, min(1.0, translation.y / self.bounds.height)), didBegin: true)
self.state?.updated(transition: .immediate)
if translation.y < -40.0 {
if let component = self.component, let stateValue = self.stateValue, let slice = stateValue.slice, let itemSetView = self.visibleItemSetViews[slice.peer.id] {
if let itemSetComponentView = itemSetView.view.view as? StoryItemSetContainerComponent.View {
if let activateInputWhileDragging = itemSetComponentView.activateInputWhileDragging() {
activateInputWhileDragging()
self.verticalPanState = nil
recognizer.state = .cancelled
self.state?.updated(transition: Transition(animation: .curve(duration: 0.3, curve: .spring)))
}
}
}
}
case .cancelled, .ended:
if self.verticalPanState != nil {
let translation = recognizer.translation(in: self)
let velocity = recognizer.velocity(in: self)
self.verticalPanState = nil
var updateState = true
if translation.y > 200.0 || (translation.y > 5.0 && velocity.y > 200.0) {
self.state?.updated(transition: Transition(animation: .curve(duration: 0.3, curve: .spring)))
self.environment?.controller()?.dismiss()
} else if translation.y < -200.0 || (translation.y < -100.0 && velocity.y < -100.0) {
if let component = self.component, let stateValue = self.stateValue, let slice = stateValue.slice, let itemSetView = self.visibleItemSetViews[slice.peer.id] {
if let itemSetComponentView = itemSetView.view.view as? StoryItemSetContainerComponent.View {
if itemSetComponentView.activateInput() {
updateState = false
}
}
}
if updateState || "".isEmpty {
self.state?.updated(transition: Transition(animation: .curve(duration: 0.3, curve: .spring)))
}
} else {
self.state?.updated(transition: Transition(animation: .curve(duration: 0.3, curve: .spring)))
}
}
default:
break
}
}*/
@objc private func longPressGesture(_ recognizer: StoryLongPressRecognizer) {
switch recognizer.state {
case .began:
@ -963,13 +878,33 @@ private final class StoryContainerScreenComponent: Component {
if let transitionIn = self.component?.transitionIn, let stateValue = self.stateValue, let slice = stateValue.slice, let itemSetView = self.visibleItemSetViews[slice.peer.id] {
if let itemSetComponentView = itemSetView.view.view as? StoryItemSetContainerComponent.View {
itemSetComponentView.animateIn(transitionIn: transitionIn)
itemSetComponentView.animateIn(transitionIn: transitionIn, completion: { [weak self] in
guard let self else {
return
}
self.didAnimateIn = true
self.state?.updated(transition: .immediate)
})
} else {
self.didAnimateIn = true
self.state?.updated(transition: .immediate)
}
} else {
self.didAnimateIn = true
self.state?.updated(transition: .immediate)
}
} else {
self.layer.allowsGroupOpacity = true
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, completion: { [weak self] _ in
self?.layer.allowsGroupOpacity = false
guard let self else {
return
}
self.layer.allowsGroupOpacity = false
self.didAnimateIn = true
self.state?.updated(transition: .immediate)
})
}
@ -1416,6 +1351,15 @@ private final class StoryContainerScreenComponent: Component {
}
}
if self.didAnimateIn && self.itemSetPanState == nil {
if i == focusedIndex - 1 {
isItemVisible = true
}
if i == focusedIndex + 1 {
isItemVisible = true
}
}
if isItemVisible {
validIds.append(slice.peer.id)
@ -1449,6 +1393,8 @@ private final class StoryContainerScreenComponent: Component {
}
itemSetView.view.parentState = self.state
let startTime = CFAbsoluteTimeGetCurrent()
let _ = itemSetView.view.update(
transition: itemSetTransition,
component: AnyComponent(StoryItemSetContainerComponent(
@ -1592,6 +1538,7 @@ private final class StoryContainerScreenComponent: Component {
if let itemSetComponentView = itemSetView.view.view as? StoryItemSetContainerComponent.View {
if itemSetView.superview == nil {
self.addSubview(itemSetView)
print("init time: \((CFAbsoluteTimeGetCurrent() - startTime) * 1000.0) ms")
}
if itemSetComponentView.superview == nil {
itemSetView.tintLayer.isDoubleSided = false

View File

@ -1937,7 +1937,7 @@ public final class StoryItemSetContainerComponent: Component {
return nil
}
func animateIn(transitionIn: StoryContainerScreen.TransitionIn) {
func animateIn(transitionIn: StoryContainerScreen.TransitionIn, completion: @escaping () -> Void) {
if let inputPanelView = self.inputPanel.view {
inputPanelView.layer.animatePosition(
from: CGPoint(x: 0.0, y: self.bounds.height - inputPanelView.frame.minY),
@ -1998,7 +1998,9 @@ public final class StoryItemSetContainerComponent: Component {
if let closeFriendIcon = self.privacyIcon?.view {
closeFriendIcon.layer.animateAlpha(from: 0.0, to: closeFriendIcon.alpha, duration: 0.25)
}
self.closeButton.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
self.closeButton.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, completion: { _ in
completion()
})
self.topContentGradientView.layer.animateAlpha(from: 0.0, to: self.topContentGradientView.alpha, duration: 0.25)
@ -2057,6 +2059,8 @@ public final class StoryItemSetContainerComponent: Component {
)
visibleItemView.layer.animateScale(from: innerScale, to: 1.0, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
}
} else {
completion()
}
}
@ -3998,6 +4002,13 @@ public final class StoryItemSetContainerComponent: Component {
self.captionItem = captionItem
}
var enableEntities = true
if case .user = component.slice.peer {
if !component.slice.peer.isService && !component.slice.peer.isPremium {
enableEntities = false
}
}
let captionSize = captionItem.view.update(
transition: captionItemTransition,
component: AnyComponent(StoryContentCaptionComponent(
@ -4006,7 +4017,7 @@ public final class StoryItemSetContainerComponent: Component {
strings: component.strings,
theme: component.theme,
text: component.slice.item.storyItem.text,
entities: component.slice.peer.isPremium ? component.slice.item.storyItem.entities : [],
entities: enableEntities ? component.slice.item.storyItem.entities : [],
entityFiles: component.slice.item.entityFiles,
action: { [weak self] action in
guard let self, let component = self.component else {

View File

@ -1476,6 +1476,15 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
let _ = self.urlSession(identifier: "\(baseAppBundleId).backroundSession")
var previousReportedMemoryConsumption = 0
let _ = Foundation.Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true, block: { _ in
let value = getMemoryConsumption()
if abs(value - previousReportedMemoryConsumption) > 1 * 1024 * 1024 {
previousReportedMemoryConsumption = value
Logger.shared.log("App \(self.episodeId)", "Memory consumption: \(value / (1024 * 1024)) MB")
}
})
return true
}
@ -2834,3 +2843,22 @@ private func downloadHTTPData(url: URL) -> Signal<Data, DownloadFileError> {
}
}
}
private func getMemoryConsumption() -> Int {
guard let memory_offset = MemoryLayout.offset(of: \task_vm_info_data_t.min_address) else {
return 0
}
let TASK_VM_INFO_COUNT = mach_msg_type_number_t(MemoryLayout<task_vm_info_data_t>.size / MemoryLayout<integer_t>.size)
let TASK_VM_INFO_REV1_COUNT = mach_msg_type_number_t(memory_offset / MemoryLayout<integer_t>.size)
var info = task_vm_info_data_t()
var count = TASK_VM_INFO_COUNT
let kr = withUnsafeMutablePointer(to: &info) { infoPtr in
infoPtr.withMemoryRebound(to: integer_t.self, capacity: Int(count)) { intPtr in
task_info(mach_task_self_, task_flavor_t(TASK_VM_INFO), intPtr, &count)
}
}
guard kr == KERN_SUCCESS, count >= TASK_VM_INFO_REV1_COUNT else {
return 0
}
return Int(info.phys_footprint)
}