mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various improvements
This commit is contained in:
parent
a7aefe85f8
commit
9ba0743553
@ -55,7 +55,7 @@ public final class BrowserBookmarksScreen: ViewController {
|
||||
}, navigateToMessage: { _, _, _ in
|
||||
}, navigateToMessageStandalone: { _ in
|
||||
}, navigateToThreadMessage: { _, _, _ in
|
||||
}, tapMessage: nil, clickThroughMessage: {
|
||||
}, tapMessage: nil, clickThroughMessage: { _, _ in
|
||||
}, toggleMessagesSelection: { _, _ in
|
||||
}, sendCurrentMessage: { _, _ in
|
||||
}, sendMessage: { _ in
|
||||
|
@ -97,6 +97,7 @@ swift_library(
|
||||
"//submodules/ChatPresentationInterfaceState:ChatPresentationInterfaceState",
|
||||
"//submodules/StickerPackPreviewUI:StickerPackPreviewUI",
|
||||
"//submodules/TelegramUI/Components/LottieComponent",
|
||||
"//submodules/TelegramUI/Components/LottieComponentResourceContent",
|
||||
"//submodules/ImageTransparency",
|
||||
"//submodules/GalleryUI",
|
||||
"//submodules/MediaPlayer:UniversalMediaPlayer",
|
||||
|
@ -1,6 +1,7 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import ComponentFlow
|
||||
import SwiftSignalKit
|
||||
import AccountContext
|
||||
import TelegramCore
|
||||
@ -9,6 +10,8 @@ import TelegramAnimatedStickerNode
|
||||
import StickerResources
|
||||
import MediaEditor
|
||||
import TelegramStringFormatting
|
||||
import LottieComponent
|
||||
import LottieComponentResourceContent
|
||||
|
||||
private func generateIcon(style: DrawingWeatherEntity.Style) -> UIImage? {
|
||||
guard let image = UIImage(bundleImageName: "Chat/Attach Menu/Location") else {
|
||||
@ -53,9 +56,8 @@ public final class DrawingWeatherEntityView: DrawingEntityView, UITextViewDelega
|
||||
let backgroundView: UIView
|
||||
|
||||
let textView: DrawingTextView
|
||||
let iconView: UIImageView
|
||||
private let imageNode: TransformImageNode
|
||||
private var animationNode: AnimatedStickerNode?
|
||||
|
||||
private var animation = ComponentView<Empty>()
|
||||
|
||||
private var didSetUpAnimationNode = false
|
||||
private let stickerFetchedDisposable = MetaDisposable()
|
||||
@ -88,20 +90,14 @@ public final class DrawingWeatherEntityView: DrawingEntityView, UITextViewDelega
|
||||
self.textView.spellCheckingType = .no
|
||||
self.textView.textContainer.maximumNumberOfLines = 2
|
||||
self.textView.textContainer.lineBreakMode = .byTruncatingTail
|
||||
|
||||
self.iconView = UIImageView()
|
||||
self.imageNode = TransformImageNode()
|
||||
|
||||
|
||||
super.init(context: context, entity: entity)
|
||||
|
||||
self.textView.delegate = self
|
||||
self.addSubview(self.backgroundView)
|
||||
self.addSubview(self.textView)
|
||||
self.addSubview(self.iconView)
|
||||
|
||||
self.update(animated: false)
|
||||
|
||||
self.setup()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
@ -134,17 +130,35 @@ public final class DrawingWeatherEntityView: DrawingEntityView, UITextViewDelega
|
||||
let iconSize = min(80.0, floor(self.bounds.height * 0.7))
|
||||
let iconOffset: CGFloat = 0.3
|
||||
|
||||
self.iconView.frame = CGRect(origin: CGPoint(x: floorToScreenPixels(iconSize * iconOffset), y: floorToScreenPixels((self.bounds.height - iconSize) / 2.0)), size: CGSize(width: iconSize, height: iconSize))
|
||||
self.imageNode.frame = self.iconView.frame.offsetBy(dx: 0.0, dy: 2.0)
|
||||
let iconFrame = CGRect(origin: CGPoint(x: floorToScreenPixels(iconSize * iconOffset), y: floorToScreenPixels((self.bounds.height - iconSize) / 2.0)), size: CGSize(width: iconSize, height: iconSize))
|
||||
|
||||
if let animationNode = self.animationNode {
|
||||
animationNode.frame = self.iconView.frame
|
||||
animationNode.updateLayout(size: self.iconView.frame.size)
|
||||
if let icon = self.weatherEntity.icon {
|
||||
let _ = self.animation.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(
|
||||
LottieComponent(
|
||||
content: LottieComponent.ResourceContent(
|
||||
context: self.context,
|
||||
file: icon,
|
||||
attemptSynchronously: true,
|
||||
providesPlaceholder: true
|
||||
),
|
||||
color: nil,
|
||||
placeholderColor: UIColor(rgb: 0x000000, alpha: 0.1),
|
||||
loop: !["🌑", "🌒", "🌓", "🌔", "🌕", "🌖", "🌗", "🌘"].contains(self.weatherEntity.emoji)
|
||||
)
|
||||
),
|
||||
environment: {},
|
||||
containerSize: iconFrame.size
|
||||
)
|
||||
if let animationView = self.animation.view {
|
||||
if animationView.superview == nil {
|
||||
self.addSubview(animationView)
|
||||
}
|
||||
animationView.frame = iconFrame
|
||||
}
|
||||
}
|
||||
|
||||
let imageSize = CGSize(width: iconSize, height: iconSize)
|
||||
self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets()))()
|
||||
|
||||
|
||||
self.textView.frame = CGRect(origin: CGPoint(x: self.bounds.width - self.textSize.width - 6.0, y: floorToScreenPixels((self.bounds.height - self.textSize.height) / 2.0)), size: self.textSize)
|
||||
self.backgroundView.frame = self.bounds
|
||||
}
|
||||
@ -263,10 +277,8 @@ public final class DrawingWeatherEntityView: DrawingEntityView, UITextViewDelega
|
||||
|
||||
self.sizeToFit()
|
||||
|
||||
if self.currentStyle != self.weatherEntity.style {
|
||||
self.currentStyle = self.weatherEntity.style
|
||||
self.iconView.image = generateIcon(style: self.weatherEntity.style)
|
||||
}
|
||||
|
||||
self.currentStyle = self.weatherEntity.style
|
||||
|
||||
self.backgroundView.layer.cornerRadius = self.textSize.height * 0.2
|
||||
if #available(iOS 13.0, *) {
|
||||
@ -276,42 +288,6 @@ public final class DrawingWeatherEntityView: DrawingEntityView, UITextViewDelega
|
||||
super.update(animated: animated)
|
||||
}
|
||||
|
||||
private func setup() {
|
||||
if let file = self.weatherEntity.icon {
|
||||
self.iconView.isHidden = true
|
||||
self.addSubnode(self.imageNode)
|
||||
if let dimensions = file.dimensions {
|
||||
if file.isAnimatedSticker || file.isVideoSticker || file.mimeType == "video/webm" {
|
||||
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 256.0, height: 256.0))
|
||||
if self.animationNode == nil {
|
||||
let animationNode = DefaultAnimatedStickerNodeImpl()
|
||||
animationNode.autoplay = true
|
||||
self.animationNode = animationNode
|
||||
animationNode.started = { [weak self] in
|
||||
self?.imageNode.isHidden = true
|
||||
}
|
||||
animationNode.setup(source: AnimatedStickerResourceSource(account: self.context.account, resource: file.resource, isVideo: file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .direct(cachePathPrefix: nil))
|
||||
|
||||
self.addSubnode(animationNode)
|
||||
}
|
||||
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: self.context.account.postbox, userLocation: .other, file: file, small: false, size: fittedDimensions))
|
||||
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: self.context.account, userLocation: .other, fileReference: stickerPackFileReference(file), resource: file.resource).start())
|
||||
} else {
|
||||
if let animationNode = self.animationNode {
|
||||
animationNode.visibility = false
|
||||
self.animationNode = nil
|
||||
animationNode.removeFromSupernode()
|
||||
self.imageNode.isHidden = false
|
||||
self.didSetUpAnimationNode = false
|
||||
}
|
||||
self.imageNode.setSignal(chatMessageSticker(account: self.context.account, userLocation: .other, file: file, small: false, synchronousLoad: false))
|
||||
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: self.context.account, userLocation: .other, fileReference: stickerPackFileReference(file), resource: chatMessageStickerResource(file: file, small: false)).start())
|
||||
}
|
||||
self.setNeedsLayout()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func updateSelectionView() {
|
||||
guard let selectionView = self.selectionView as? DrawingWeatherEntitySelectionView else {
|
||||
return
|
||||
|
@ -86,6 +86,7 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent {
|
||||
let peers: [EnginePeer.Id: EnginePeer]
|
||||
let stateUpdated: (ComponentTransition) -> Void
|
||||
let buy: (StarsProduct) -> Void
|
||||
let openAppExamples: () -> Void
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
@ -100,7 +101,8 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent {
|
||||
expanded: Bool,
|
||||
peers: [EnginePeer.Id: EnginePeer],
|
||||
stateUpdated: @escaping (ComponentTransition) -> Void,
|
||||
buy: @escaping (StarsProduct) -> Void
|
||||
buy: @escaping (StarsProduct) -> Void,
|
||||
openAppExamples: @escaping () -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.externalState = externalState
|
||||
@ -115,6 +117,7 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent {
|
||||
self.peers = peers
|
||||
self.stateUpdated = stateUpdated
|
||||
self.buy = buy
|
||||
self.openAppExamples = openAppExamples
|
||||
}
|
||||
|
||||
static func ==(lhs: StarsPurchaseScreenContentComponent, rhs: StarsPurchaseScreenContentComponent) -> Bool {
|
||||
@ -225,15 +228,16 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent {
|
||||
state.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Settings/TextArrowRight"), color: accentColor)!, theme)
|
||||
}
|
||||
|
||||
let titleAttributedString = parseMarkdownIntoAttributedString(textString, attributes: markdownAttributes).mutableCopy() as! NSMutableAttributedString
|
||||
let textAttributedString = parseMarkdownIntoAttributedString(textString, attributes: markdownAttributes).mutableCopy() as! NSMutableAttributedString
|
||||
|
||||
if let range = titleAttributedString.string.range(of: ">"), let chevronImage = state.cachedChevronImage?.0 {
|
||||
titleAttributedString.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: titleAttributedString.string))
|
||||
if let range = textAttributedString.string.range(of: ">"), let chevronImage = state.cachedChevronImage?.0 {
|
||||
textAttributedString.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: textAttributedString.string))
|
||||
}
|
||||
|
||||
let openAppExamples = component.openAppExamples
|
||||
let text = text.update(
|
||||
component: BalancedTextComponent(
|
||||
text: .plain(titleAttributedString),
|
||||
text: .plain(textAttributedString),
|
||||
horizontalAlignment: .center,
|
||||
maximumNumberOfLines: 0,
|
||||
lineSpacing: 0.2,
|
||||
@ -246,6 +250,7 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent {
|
||||
}
|
||||
},
|
||||
tapAction: { _, _ in
|
||||
openAppExamples()
|
||||
}
|
||||
),
|
||||
environment: {},
|
||||
@ -473,6 +478,7 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
|
||||
let options: [Any]
|
||||
let purpose: StarsPurchasePurpose
|
||||
let forceDark: Bool
|
||||
let openAppExamples: () -> Void
|
||||
let updateInProgress: (Bool) -> Void
|
||||
let present: (ViewController) -> Void
|
||||
let completion: (Int64) -> Void
|
||||
@ -483,6 +489,7 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
|
||||
options: [Any],
|
||||
purpose: StarsPurchasePurpose,
|
||||
forceDark: Bool,
|
||||
openAppExamples: @escaping () -> Void,
|
||||
updateInProgress: @escaping (Bool) -> Void,
|
||||
present: @escaping (ViewController) -> Void,
|
||||
completion: @escaping (Int64) -> Void
|
||||
@ -492,6 +499,7 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
|
||||
self.options = options
|
||||
self.purpose = purpose
|
||||
self.forceDark = forceDark
|
||||
self.openAppExamples = openAppExamples
|
||||
self.updateInProgress = updateInProgress
|
||||
self.present = present
|
||||
self.completion = completion
|
||||
@ -872,7 +880,8 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
|
||||
},
|
||||
buy: { [weak state] product in
|
||||
state?.buy(product: product)
|
||||
}
|
||||
},
|
||||
openAppExamples: context.component.openAppExamples
|
||||
)),
|
||||
contentInsets: UIEdgeInsets(top: environment.navigationHeight, left: 0.0, bottom: environment.safeInsets.bottom, right: 0.0),
|
||||
contentOffsetUpdated: { [weak state] topContentOffset, bottomContentOffset in
|
||||
@ -985,6 +994,7 @@ public final class StarsPurchaseScreen: ViewControllerComponentContainer {
|
||||
self.context = context
|
||||
self.starsContext = starsContext
|
||||
|
||||
var openAppExamplesImpl: (() -> Void)?
|
||||
var updateInProgressImpl: ((Bool) -> Void)?
|
||||
var presentImpl: ((ViewController) -> Void)?
|
||||
var completionImpl: ((Int64) -> Void)?
|
||||
@ -994,6 +1004,9 @@ public final class StarsPurchaseScreen: ViewControllerComponentContainer {
|
||||
options: options,
|
||||
purpose: purpose,
|
||||
forceDark: false,
|
||||
openAppExamples: {
|
||||
openAppExamplesImpl?()
|
||||
},
|
||||
updateInProgress: { inProgress in
|
||||
updateInProgressImpl?(inProgress)
|
||||
},
|
||||
@ -1011,6 +1024,19 @@ public final class StarsPurchaseScreen: ViewControllerComponentContainer {
|
||||
self.navigationItem.setLeftBarButton(cancelItem, animated: false)
|
||||
self.navigationPresentation = .modal
|
||||
|
||||
openAppExamplesImpl = { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let _ = (context.sharedContext.makeMiniAppListScreenInitialData(context: context)
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self] initialData in
|
||||
guard let self, let navigationController = self.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
navigationController.pushViewController(context.sharedContext.makeMiniAppListScreen(context: context, initialData: initialData))
|
||||
})
|
||||
}
|
||||
|
||||
updateInProgressImpl = { [weak self] inProgress in
|
||||
if let strongSelf = self {
|
||||
strongSelf.navigationItem.leftBarButtonItem?.isEnabled = !inProgress
|
||||
|
@ -34,6 +34,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/Stars/StarsImageComponent",
|
||||
"//submodules/TelegramUI/Components/Stars/StarsAvatarComponent",
|
||||
"//submodules/GalleryUI",
|
||||
"//submodules/TelegramUI/Components/MiniAppListScreen",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -23,6 +23,7 @@ import UndoUI
|
||||
import StarsImageComponent
|
||||
import GalleryUI
|
||||
import StarsAvatarComponent
|
||||
import MiniAppListScreen
|
||||
|
||||
private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||
@ -34,6 +35,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
let openPeer: (EnginePeer) -> Void
|
||||
let openMessage: (EngineMessage.Id) -> Void
|
||||
let openMedia: ([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void
|
||||
let openAppExamples: () -> Void
|
||||
let copyTransactionId: (String) -> Void
|
||||
|
||||
init(
|
||||
@ -44,6 +46,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
openPeer: @escaping (EnginePeer) -> Void,
|
||||
openMessage: @escaping (EngineMessage.Id) -> Void,
|
||||
openMedia: @escaping ([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void,
|
||||
openAppExamples: @escaping () -> Void,
|
||||
copyTransactionId: @escaping (String) -> Void
|
||||
) {
|
||||
self.context = context
|
||||
@ -53,6 +56,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
self.openPeer = openPeer
|
||||
self.openMessage = openMessage
|
||||
self.openMedia = openMedia
|
||||
self.openAppExamples = openAppExamples
|
||||
self.copyTransactionId = copyTransactionId
|
||||
}
|
||||
|
||||
@ -345,6 +349,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
photo = nil
|
||||
isRefund = false
|
||||
isGift = true
|
||||
delayedCloseOnOpenPeer = false
|
||||
}
|
||||
if let spaceRegex {
|
||||
let nsRange = NSRange(descriptionText.startIndex..., in: descriptionText)
|
||||
@ -647,6 +652,8 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
|
||||
var descriptionSize: CGSize = .zero
|
||||
if !descriptionText.isEmpty {
|
||||
let openAppExamples = component.openAppExamples
|
||||
|
||||
if state.cachedChevronImage == nil || state.cachedChevronImage?.1 !== environment.theme {
|
||||
state.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Settings/TextArrowRight"), color: linkColor)!, theme)
|
||||
}
|
||||
@ -665,7 +672,18 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
text: .plain(attributedString),
|
||||
horizontalAlignment: .center,
|
||||
maximumNumberOfLines: 5,
|
||||
lineSpacing: 0.2
|
||||
lineSpacing: 0.2,
|
||||
highlightColor: linkColor.withAlphaComponent(0.2),
|
||||
highlightAction: { attributes in
|
||||
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] {
|
||||
return NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
},
|
||||
tapAction: { _, _ in
|
||||
openAppExamples()
|
||||
}
|
||||
),
|
||||
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0 - 60.0, height: CGFloat.greatestFiniteMagnitude),
|
||||
transition: .immediate
|
||||
@ -765,6 +783,7 @@ private final class StarsTransactionSheetComponent: CombinedComponent {
|
||||
let openPeer: (EnginePeer) -> Void
|
||||
let openMessage: (EngineMessage.Id) -> Void
|
||||
let openMedia: ([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void
|
||||
let openAppExamples: () -> Void
|
||||
let copyTransactionId: (String) -> Void
|
||||
|
||||
init(
|
||||
@ -774,6 +793,7 @@ private final class StarsTransactionSheetComponent: CombinedComponent {
|
||||
openPeer: @escaping (EnginePeer) -> Void,
|
||||
openMessage: @escaping (EngineMessage.Id) -> Void,
|
||||
openMedia: @escaping ([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void,
|
||||
openAppExamples: @escaping () -> Void,
|
||||
copyTransactionId: @escaping (String) -> Void
|
||||
) {
|
||||
self.context = context
|
||||
@ -782,6 +802,7 @@ private final class StarsTransactionSheetComponent: CombinedComponent {
|
||||
self.openPeer = openPeer
|
||||
self.openMessage = openMessage
|
||||
self.openMedia = openMedia
|
||||
self.openAppExamples = openAppExamples
|
||||
self.copyTransactionId = copyTransactionId
|
||||
}
|
||||
|
||||
@ -826,6 +847,7 @@ private final class StarsTransactionSheetComponent: CombinedComponent {
|
||||
openPeer: context.component.openPeer,
|
||||
openMessage: context.component.openMessage,
|
||||
openMedia: context.component.openMedia,
|
||||
openAppExamples: context.component.openAppExamples,
|
||||
copyTransactionId: context.component.copyTransactionId
|
||||
)),
|
||||
backgroundColor: .color(environment.theme.actionSheet.opaqueItemBackgroundColor),
|
||||
@ -915,6 +937,7 @@ public class StarsTransactionScreen: ViewControllerComponentContainer {
|
||||
var openPeerImpl: ((EnginePeer) -> Void)?
|
||||
var openMessageImpl: ((EngineMessage.Id) -> Void)?
|
||||
var openMediaImpl: (([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void)?
|
||||
var openAppExamplesImpl: (() -> Void)?
|
||||
var copyTransactionIdImpl: ((String) -> Void)?
|
||||
super.init(
|
||||
context: context,
|
||||
@ -931,6 +954,9 @@ public class StarsTransactionScreen: ViewControllerComponentContainer {
|
||||
openMedia: { media, transitionNode, addToTransitionSurface in
|
||||
openMediaImpl?(media, transitionNode, addToTransitionSurface)
|
||||
},
|
||||
openAppExamples: {
|
||||
openAppExamplesImpl?()
|
||||
},
|
||||
copyTransactionId: { transactionId in
|
||||
copyTransactionIdImpl?(transactionId)
|
||||
}
|
||||
@ -1018,6 +1044,19 @@ public class StarsTransactionScreen: ViewControllerComponentContainer {
|
||||
}))
|
||||
}
|
||||
|
||||
openAppExamplesImpl = { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let _ = (context.sharedContext.makeMiniAppListScreenInitialData(context: context)
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self] initialData in
|
||||
guard let self, let navigationController = self.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
navigationController.pushViewController(context.sharedContext.makeMiniAppListScreen(context: context, initialData: initialData))
|
||||
})
|
||||
}
|
||||
|
||||
copyTransactionIdImpl = { [weak self] transactionId in
|
||||
guard let self else {
|
||||
return
|
||||
|
Loading…
x
Reference in New Issue
Block a user