mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Merge commit 'f199fe9641e29a7e1061cf559c434dffbf6fc49f'
This commit is contained in:
commit
2a95160bf5
@ -12067,10 +12067,13 @@ Sorry for the inconvenience.";
|
||||
"Login.EnterPhraseHint" = "You can copy and paste the phrase here.";
|
||||
"Login.BackToWord" = "Back to entering the word";
|
||||
"Login.BackToPhrase" = "Back to entering the phrase";
|
||||
"Login.BackToCode" = "Back to entering the code";
|
||||
|
||||
"Login.WrongPhraseError" = "Incorrect, please try again.";
|
||||
"Login.Paste" = "Paste";
|
||||
|
||||
"Login.ReturnToWord" = "Return to entering the word";
|
||||
"Login.ReturnToPhrase" = "Return to entering the phrase";
|
||||
"Login.ReturnToCode" = "Return to entering the code";
|
||||
|
||||
"Map.LiveLocationPrivateNewDescription" = "Choose for how long **%@** will see your accurate location, including when the app is closed.";
|
||||
@ -12110,3 +12113,24 @@ Sorry for the inconvenience.";
|
||||
"ReportPeer.ReportReaction.Text" = "Are you sure you want to report reactions from this user?";
|
||||
"ReportPeer.ReportReaction.BanAndReport" = "Ban and Report";
|
||||
"ReportPeer.ReportReaction.Report" = "Report Reaction";
|
||||
|
||||
"StoryFeed.ViewAnonymously" = "View Anonymously";
|
||||
|
||||
"Channel.AdminLogFilter.EventsAdminRights" = "New Admin Rights";
|
||||
"Channel.AdminLogFilter.EventsExceptions" = "New Exceptions";
|
||||
"Channel.AdminLogFilter.EventsLeavingGroup" = "Members Left the Group";
|
||||
"Channel.AdminLogFilter.EventsLeavingChannel" = "Subscribers Removed";
|
||||
|
||||
"Channel.AdminLogFilter.RecentActionsTitle" = "Recent Actions";
|
||||
"Channel.AdminLogFilter.FilterActionsTypeTitle" = "FILTER ACTIONS BY TYPE";
|
||||
"Channel.AdminLogFilter.FilterActionsAdminsTitle" = "FILTER ACTIONS BY ADMINS";
|
||||
"Channel.AdminLogFilter.ShowAllAdminsActions" = "Show Actions by All Admins";
|
||||
"Channel.AdminLogFilter.ApplyFilter" = "Apply Filter";
|
||||
|
||||
"Channel.AdminLogFilter.Section.MembersGroup" = "Members and Admins";
|
||||
"Channel.AdminLogFilter.Section.MembersChannel" = "Subscribers and Admins";
|
||||
"Channel.AdminLogFilter.Section.SettingsGroup" = "Group Settings";
|
||||
"Channel.AdminLogFilter.Section.SettingsChannel" = "Channel Settings";
|
||||
"Channel.AdminLogFilter.Section.Messages" = "Messages";
|
||||
|
||||
"Premium.Gift.ContactSelection.AddBirthday" = "Add Your Birthday";
|
||||
|
@ -93,7 +93,7 @@ public final class ContactMultiselectionControllerParams {
|
||||
public let context: AccountContext
|
||||
public let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
|
||||
public let mode: ContactMultiselectionControllerMode
|
||||
public let options: [ContactListAdditionalOption]
|
||||
public let options: Signal<[ContactListAdditionalOption], NoError>
|
||||
public let filters: [ContactListFilter]
|
||||
public let onlyWriteable: Bool
|
||||
public let isGroupInvitation: Bool
|
||||
@ -105,7 +105,7 @@ public final class ContactMultiselectionControllerParams {
|
||||
public let openProfile: ((EnginePeer) -> Void)?
|
||||
public let sendMessage: ((EnginePeer) -> Void)?
|
||||
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, mode: ContactMultiselectionControllerMode, options: [ContactListAdditionalOption], filters: [ContactListFilter] = [.excludeSelf], onlyWriteable: Bool = false, isGroupInvitation: Bool = false, isPeerEnabled: ((EnginePeer) -> Bool)? = nil, attemptDisabledItemSelection: ((EnginePeer, ChatListDisabledPeerReason) -> Void)? = nil, alwaysEnabled: Bool = false, limit: Int32? = nil, reachedLimit: ((Int32) -> Void)? = nil, openProfile: ((EnginePeer) -> Void)? = nil, sendMessage: ((EnginePeer) -> Void)? = nil) {
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, mode: ContactMultiselectionControllerMode, options: Signal<[ContactListAdditionalOption], NoError> = .single([]), filters: [ContactListFilter] = [.excludeSelf], onlyWriteable: Bool = false, isGroupInvitation: Bool = false, isPeerEnabled: ((EnginePeer) -> Bool)? = nil, attemptDisabledItemSelection: ((EnginePeer, ChatListDisabledPeerReason) -> Void)? = nil, alwaysEnabled: Bool = false, limit: Int32? = nil, reachedLimit: ((Int32) -> Void)? = nil, openProfile: ((EnginePeer) -> Void)? = nil, sendMessage: ((EnginePeer) -> Void)? = nil) {
|
||||
self.context = context
|
||||
self.updatedPresentationData = updatedPresentationData
|
||||
self.mode = mode
|
||||
|
@ -27,7 +27,7 @@ public final class AuthorizationSequenceCodeEntryController: ViewController {
|
||||
var resetEmail: (() -> Void)?
|
||||
var retryResetEmail: (() -> Void)?
|
||||
|
||||
var data: (String, String?, SentAuthorizationCodeType, AuthorizationCodeNextType?, Int32?, Bool, Bool)?
|
||||
var data: (String, String?, SentAuthorizationCodeType, AuthorizationCodeNextType?, Int32?, SentAuthorizationCodeType?, Bool)?
|
||||
var termsOfService: (UnauthorizedAccountTermsOfService, Bool)?
|
||||
|
||||
private let hapticFeedback = HapticFeedback()
|
||||
@ -41,17 +41,8 @@ public final class AuthorizationSequenceCodeEntryController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
var isWordOrPhrase: Bool {
|
||||
if let type = self.data?.2 {
|
||||
switch type {
|
||||
case .word, .phrase:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
var isPrevious: Bool {
|
||||
return self.data?.6 ?? false
|
||||
}
|
||||
|
||||
public init(presentationData: PresentationData, back: @escaping () -> Void) {
|
||||
@ -141,12 +132,12 @@ public final class AuthorizationSequenceCodeEntryController: ViewController {
|
||||
self?.present(c, in: .window(.root), with: a)
|
||||
}
|
||||
|
||||
if let (number, email, codeType, nextType, timeout, hasPreviousCode, previousIsPhrase) = self.data {
|
||||
if let (number, email, codeType, nextType, timeout, previousCodeType, isPrevious) = self.data {
|
||||
var appleSignInAllowed = false
|
||||
if case let .email(_, _, _, _, appleSignInAllowedValue, _) = codeType {
|
||||
appleSignInAllowed = appleSignInAllowedValue
|
||||
}
|
||||
self.controllerNode.updateData(number: number, email: email, codeType: codeType, nextType: nextType, timeout: timeout, appleSignInAllowed: appleSignInAllowed, hasPreviousCode: hasPreviousCode, previousIsPhrase: previousIsPhrase)
|
||||
self.controllerNode.updateData(number: number, email: email, codeType: codeType, nextType: nextType, timeout: timeout, appleSignInAllowed: appleSignInAllowed, previousCodeType: previousCodeType, isPrevious: isPrevious)
|
||||
}
|
||||
}
|
||||
|
||||
@ -194,10 +185,10 @@ public final class AuthorizationSequenceCodeEntryController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
public func updateData(number: String, email: String?, codeType: SentAuthorizationCodeType, nextType: AuthorizationCodeNextType?, timeout: Int32?, termsOfService: (UnauthorizedAccountTermsOfService, Bool)?, hasPreviousCode: Bool, previousIsPhrase: Bool) {
|
||||
public func updateData(number: String, email: String?, codeType: SentAuthorizationCodeType, nextType: AuthorizationCodeNextType?, timeout: Int32?, termsOfService: (UnauthorizedAccountTermsOfService, Bool)?, previousCodeType: SentAuthorizationCodeType?, isPrevious: Bool) {
|
||||
self.termsOfService = termsOfService
|
||||
if self.data?.0 != number || self.data?.1 != email || self.data?.2 != codeType || self.data?.3 != nextType || self.data?.4 != timeout || self.data?.5 != hasPreviousCode || self.data?.6 != previousIsPhrase {
|
||||
self.data = (number, email, codeType, nextType, timeout, hasPreviousCode, previousIsPhrase)
|
||||
if self.data?.0 != number || self.data?.1 != email || self.data?.2 != codeType || self.data?.3 != nextType || self.data?.4 != timeout || self.data?.5 != previousCodeType || self.data?.6 != isPrevious {
|
||||
self.data = (number, email, codeType, nextType, timeout, previousCodeType, isPrevious)
|
||||
|
||||
var appleSignInAllowed = false
|
||||
if case let .email(_, _, _, _, appleSignInAllowedValue, _) = codeType {
|
||||
@ -205,7 +196,7 @@ public final class AuthorizationSequenceCodeEntryController: ViewController {
|
||||
}
|
||||
|
||||
if self.isNodeLoaded {
|
||||
self.controllerNode.updateData(number: number, email: email, codeType: codeType, nextType: nextType, timeout: timeout, appleSignInAllowed: appleSignInAllowed, hasPreviousCode: hasPreviousCode, previousIsPhrase: previousIsPhrase)
|
||||
self.controllerNode.updateData(number: number, email: email, codeType: codeType, nextType: nextType, timeout: timeout, appleSignInAllowed: appleSignInAllowed, previousCodeType: previousCodeType, isPrevious: isPrevious)
|
||||
self.requestLayout(transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
@ -59,8 +59,9 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
|
||||
private var layoutArguments: (ContainerViewLayout, CGFloat)?
|
||||
|
||||
private var appleSignInAllowed = false
|
||||
private var hasPreviousCode = false
|
||||
private var previousIsPhrase = false
|
||||
|
||||
private var previousCodeType: SentAuthorizationCodeType?
|
||||
private var isPrevious = false
|
||||
|
||||
var phoneNumber: String = "" {
|
||||
didSet {
|
||||
@ -403,12 +404,12 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
|
||||
self.codeInputView.text = ""
|
||||
}
|
||||
|
||||
func updateData(number: String, email: String?, codeType: SentAuthorizationCodeType, nextType: AuthorizationCodeNextType?, timeout: Int32?, appleSignInAllowed: Bool, hasPreviousCode: Bool, previousIsPhrase: Bool) {
|
||||
func updateData(number: String, email: String?, codeType: SentAuthorizationCodeType, nextType: AuthorizationCodeNextType?, timeout: Int32?, appleSignInAllowed: Bool, previousCodeType: SentAuthorizationCodeType?, isPrevious: Bool) {
|
||||
self.codeType = codeType
|
||||
self.phoneNumber = number.replacingOccurrences(of: " ", with: "\u{00A0}").replacingOccurrences(of: "-", with: "\u{2011}")
|
||||
self.email = email
|
||||
self.hasPreviousCode = hasPreviousCode
|
||||
self.previousIsPhrase = previousIsPhrase
|
||||
self.previousCodeType = previousCodeType
|
||||
self.isPrevious = isPrevious
|
||||
|
||||
var appleSignInAllowed = appleSignInAllowed
|
||||
if #available(iOS 13.0, *) {
|
||||
@ -441,7 +442,7 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
|
||||
if let strongSelf = self {
|
||||
if let currentTimeoutTime = strongSelf.currentTimeoutTime, currentTimeoutTime > 0 {
|
||||
strongSelf.currentTimeoutTime = currentTimeoutTime - 1
|
||||
let (nextOptionText, nextOptionActive) = authorizationNextOptionText(currentType: codeType, nextType: nextType, returnToCode: hasPreviousCode, timeout: strongSelf.currentTimeoutTime, strings: strongSelf.strings, primaryColor: strongSelf.theme.list.itemSecondaryTextColor, accentColor: strongSelf.theme.list.itemAccentColor)
|
||||
let (nextOptionText, nextOptionActive) = authorizationNextOptionText(currentType: codeType, nextType: nextType, previousCodeType: isPrevious ? previousCodeType : nil, timeout: strongSelf.currentTimeoutTime, strings: strongSelf.strings, primaryColor: strongSelf.theme.list.itemSecondaryTextColor, accentColor: strongSelf.theme.list.itemAccentColor)
|
||||
strongSelf.nextOptionTitleNode.attributedText = nextOptionText
|
||||
strongSelf.nextOptionButtonNode.isUserInteractionEnabled = nextOptionActive
|
||||
strongSelf.nextOptionButtonNode.accessibilityLabel = nextOptionText.string
|
||||
@ -482,7 +483,7 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
|
||||
self.countdownDisposable.set(nil)
|
||||
}
|
||||
|
||||
let (nextOptionText, nextOptionActive) = authorizationNextOptionText(currentType: codeType, nextType: nextType, returnToCode: hasPreviousCode, timeout: self.currentTimeoutTime, strings: self.strings, primaryColor: self.theme.list.itemSecondaryTextColor, accentColor: self.theme.list.itemAccentColor)
|
||||
let (nextOptionText, nextOptionActive) = authorizationNextOptionText(currentType: codeType, nextType: nextType, previousCodeType: isPrevious ? previousCodeType : nil, timeout: self.currentTimeoutTime, strings: self.strings, primaryColor: self.theme.list.itemSecondaryTextColor, accentColor: self.theme.list.itemAccentColor)
|
||||
self.nextOptionTitleNode.attributedText = nextOptionText
|
||||
self.nextOptionButtonNode.isUserInteractionEnabled = nextOptionActive
|
||||
self.nextOptionButtonNode.accessibilityLabel = nextOptionText.string
|
||||
@ -492,12 +493,7 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
|
||||
self.nextOptionButtonNode.accessibilityTraits = [.button, .notEnabled]
|
||||
}
|
||||
|
||||
switch codeType {
|
||||
case .word, .phrase:
|
||||
self.nextOptionArrowNode.isHidden = !hasPreviousCode
|
||||
default:
|
||||
self.nextOptionArrowNode.isHidden = true
|
||||
}
|
||||
self.nextOptionArrowNode.isHidden = previousCodeType == nil || !isPrevious
|
||||
|
||||
if let layoutArguments = self.layoutArguments {
|
||||
self.containerLayoutUpdated(layoutArguments.0, navigationBarHeight: layoutArguments.1, transition: .immediate)
|
||||
@ -807,7 +803,38 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
|
||||
|
||||
if let codeType = self.codeType {
|
||||
let yOffset: CGFloat = layout.size.width > 320.0 ? 18.0 : 5.0
|
||||
if case .phrase = codeType {
|
||||
if let previousCodeType = self.previousCodeType, !self.isPrevious {
|
||||
self.hintButtonNode.alpha = 1.0
|
||||
self.hintButtonNode.isUserInteractionEnabled = true
|
||||
|
||||
let actionTitle: String
|
||||
switch previousCodeType {
|
||||
case .word:
|
||||
actionTitle = self.strings.Login_BackToWord
|
||||
case .phrase:
|
||||
actionTitle = self.strings.Login_BackToPhrase
|
||||
default:
|
||||
actionTitle = self.strings.Login_BackToCode
|
||||
}
|
||||
|
||||
self.hintTextNode.attributedText = NSAttributedString(string: actionTitle, font: Font.regular(13.0), textColor: self.theme.list.itemAccentColor, paragraphAlignment: .center)
|
||||
|
||||
let originY: CGFloat
|
||||
if !self.codeInputView.isHidden {
|
||||
originY = self.codeInputView.frame.maxY + 6.0
|
||||
} else {
|
||||
originY = self.textField.frame.maxY
|
||||
}
|
||||
|
||||
let hintTextSize = self.hintTextNode.updateLayout(CGSize(width: layout.size.width - 48.0, height: .greatestFiniteMagnitude))
|
||||
transition.updateFrame(node: self.hintButtonNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - hintTextSize.width) / 2.0), y: originY + yOffset), size: hintTextSize))
|
||||
self.hintTextNode.frame = CGRect(origin: .zero, size: hintTextSize)
|
||||
|
||||
if let icon = self.hintArrowNode.image {
|
||||
self.hintArrowNode.frame = CGRect(origin: CGPoint(x: self.hintTextNode.frame.minX - icon.size.width - 5.0, y: self.hintTextNode.frame.midY - icon.size.height / 2.0), size: icon.size)
|
||||
}
|
||||
self.hintArrowNode.isHidden = false
|
||||
} else if case .phrase = codeType {
|
||||
if self.errorTextNode.alpha.isZero {
|
||||
self.hintButtonNode.alpha = 1.0
|
||||
}
|
||||
@ -827,20 +854,10 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
|
||||
self.hintButtonNode.alpha = 0.0
|
||||
self.hintButtonNode.isUserInteractionEnabled = false
|
||||
self.hintArrowNode.isHidden = true
|
||||
} else if self.hasPreviousCode {
|
||||
self.hintButtonNode.alpha = 1.0
|
||||
self.hintButtonNode.isUserInteractionEnabled = true
|
||||
|
||||
self.hintTextNode.attributedText = NSAttributedString(string: self.previousIsPhrase ? self.strings.Login_BackToPhrase : self.strings.Login_BackToWord, font: Font.regular(13.0), textColor: self.theme.list.itemAccentColor, paragraphAlignment: .center)
|
||||
|
||||
let hintTextSize = self.hintTextNode.updateLayout(CGSize(width: layout.size.width - 48.0, height: .greatestFiniteMagnitude))
|
||||
transition.updateFrame(node: self.hintButtonNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - hintTextSize.width) / 2.0), y: self.codeInputView.frame.maxY + yOffset + 6.0), size: hintTextSize))
|
||||
self.hintTextNode.frame = CGRect(origin: .zero, size: hintTextSize)
|
||||
|
||||
if let icon = self.hintArrowNode.image {
|
||||
self.hintArrowNode.frame = CGRect(origin: CGPoint(x: self.hintTextNode.frame.minX - icon.size.width - 5.0, y: self.hintTextNode.frame.midY - icon.size.height / 2.0), size: icon.size)
|
||||
}
|
||||
self.hintArrowNode.isHidden = false
|
||||
let pasteSize = self.pasteButton.measure(layout.size)
|
||||
let pasteButtonSize = CGSize(width: pasteSize.width + 16.0, height: 24.0)
|
||||
transition.updateFrame(node: self.pasteButton, frame: CGRect(origin: CGPoint(x: layout.size.width - 40.0 - pasteButtonSize.width, y: self.textField.frame.midY - pasteButtonSize.height / 2.0), size: pasteButtonSize))
|
||||
} else {
|
||||
self.hintButtonNode.alpha = 0.0
|
||||
self.hintButtonNode.isUserInteractionEnabled = false
|
||||
@ -1002,7 +1019,11 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
|
||||
var updated = textField.text ?? ""
|
||||
updated.replaceSubrange(updated.index(updated.startIndex, offsetBy: range.lowerBound) ..< updated.index(updated.startIndex, offsetBy: range.upperBound), with: string)
|
||||
|
||||
return checkValidity(text: updated) && !updated.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
||||
if updated.isEmpty {
|
||||
return true
|
||||
} else {
|
||||
return checkValidity(text: updated) && !updated.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
||||
}
|
||||
}
|
||||
|
||||
func checkValidity(text: String) -> Bool {
|
||||
@ -1019,7 +1040,7 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
|
||||
if let startsWith, !text.isEmpty {
|
||||
let firstWord = text.components(separatedBy: " ").first ?? ""
|
||||
if !firstWord.isEmpty && !startsWith.hasPrefix(firstWord) {
|
||||
if self.errorTextNode.alpha.isZero {
|
||||
if self.errorTextNode.alpha.isZero, text.count < 4 {
|
||||
self.animateError(text: self.strings.Login_WrongPhraseError)
|
||||
}
|
||||
return false
|
||||
|
@ -312,7 +312,7 @@ public final class AuthorizationSequenceController: NavigationController, ASAuth
|
||||
return controller
|
||||
}
|
||||
|
||||
private func codeEntryController(number: String, phoneCodeHash: String, email: String?, type: SentAuthorizationCodeType, nextType: AuthorizationCodeNextType?, timeout: Int32?, hasPreviousCode: Bool, previousIsPhrase: Bool, termsOfService: (UnauthorizedAccountTermsOfService, Bool)?) -> AuthorizationSequenceCodeEntryController {
|
||||
private func codeEntryController(number: String, phoneCodeHash: String, email: String?, type: SentAuthorizationCodeType, nextType: AuthorizationCodeNextType?, timeout: Int32?, previousCodeType: SentAuthorizationCodeType?, isPrevious: Bool, termsOfService: (UnauthorizedAccountTermsOfService, Bool)?) -> AuthorizationSequenceCodeEntryController {
|
||||
var currentController: AuthorizationSequenceCodeEntryController?
|
||||
for c in self.viewControllers {
|
||||
if let c = c as? AuthorizationSequenceCodeEntryController {
|
||||
@ -584,14 +584,9 @@ public final class AuthorizationSequenceController: NavigationController, ASAuth
|
||||
}
|
||||
controller.requestNextOption = { [weak self, weak controller] in
|
||||
if let strongSelf = self {
|
||||
switch type {
|
||||
case .word, .phrase:
|
||||
if hasPreviousCode {
|
||||
strongSelf.actionDisposable.set(togglePreviousCodeEntry(account: strongSelf.account).start())
|
||||
return
|
||||
}
|
||||
default:
|
||||
break
|
||||
if previousCodeType != nil && isPrevious {
|
||||
strongSelf.actionDisposable.set(togglePreviousCodeEntry(account: strongSelf.account).start())
|
||||
return
|
||||
}
|
||||
|
||||
if nextType == nil {
|
||||
@ -677,7 +672,7 @@ public final class AuthorizationSequenceController: NavigationController, ASAuth
|
||||
strongSelf.sharedContext.applicationBindings.openUrl(url)
|
||||
}
|
||||
}
|
||||
controller.updateData(number: formatPhoneNumber(number), email: email, codeType: type, nextType: nextType, timeout: timeout, termsOfService: termsOfService, hasPreviousCode: hasPreviousCode, previousIsPhrase: previousIsPhrase)
|
||||
controller.updateData(number: formatPhoneNumber(number), email: email, codeType: type, nextType: nextType, timeout: timeout, termsOfService: termsOfService, previousCodeType: previousCodeType, isPrevious: isPrevious)
|
||||
return controller
|
||||
}
|
||||
|
||||
@ -1237,25 +1232,19 @@ public final class AuthorizationSequenceController: NavigationController, ASAuth
|
||||
controllers.append(self.emailSetupController(number: number, appleSignInAllowed: self.appleSignInAllowed))
|
||||
}
|
||||
|
||||
if let previousCodeEntry, case let .confirmationCodeEntry(number, type, phoneCodeHash, timeout, nextType, _, _, _) = previousCodeEntry, usePrevious {
|
||||
var previousIsPhrase = false
|
||||
if case .phrase = type {
|
||||
previousIsPhrase = true
|
||||
}
|
||||
controllers.append(self.codeEntryController(number: number, phoneCodeHash: phoneCodeHash, email: self.currentEmail, type: type, nextType: nextType, timeout: timeout, hasPreviousCode: true, previousIsPhrase: previousIsPhrase, termsOfService: nil))
|
||||
if let previousCodeEntry, case let .confirmationCodeEntry(number, previousType, phoneCodeHash, timeout, nextType, _, _, _) = previousCodeEntry, usePrevious {
|
||||
controllers.append(self.codeEntryController(number: number, phoneCodeHash: phoneCodeHash, email: self.currentEmail, type: previousType, nextType: nextType, timeout: timeout, previousCodeType: type, isPrevious: true, termsOfService: nil))
|
||||
isGoingBack = true
|
||||
} else {
|
||||
var previousIsPhrase = false
|
||||
var previousCodeType: SentAuthorizationCodeType?
|
||||
if let previousCodeEntry, case let .confirmationCodeEntry(_, type, _, _, _, _, _, _) = previousCodeEntry {
|
||||
if case .phrase = type {
|
||||
previousIsPhrase = true
|
||||
}
|
||||
previousCodeType = type
|
||||
}
|
||||
controllers.append(self.codeEntryController(number: number, phoneCodeHash: phoneCodeHash, email: self.currentEmail, type: type, nextType: nextType, timeout: timeout, hasPreviousCode: previousCodeEntry != nil, previousIsPhrase: previousIsPhrase, termsOfService: nil))
|
||||
controllers.append(self.codeEntryController(number: number, phoneCodeHash: phoneCodeHash, email: self.currentEmail, type: type, nextType: nextType, timeout: timeout, previousCodeType: previousCodeType, isPrevious: false, termsOfService: nil))
|
||||
}
|
||||
}
|
||||
|
||||
if isGoingBack, let currentLastController = self.viewControllers.last as? AuthorizationSequenceCodeEntryController, !currentLastController.isWordOrPhrase {
|
||||
if isGoingBack, let currentLastController = self.viewControllers.last as? AuthorizationSequenceCodeEntryController, !currentLastController.isPrevious {
|
||||
var tempControllers = controllers
|
||||
tempControllers.append(currentLastController)
|
||||
self.setViewControllers(tempControllers, animated: false)
|
||||
|
@ -56,18 +56,20 @@ public func authorizationCurrentOptionText(_ type: SentAuthorizationCodeType, ph
|
||||
}
|
||||
}
|
||||
|
||||
public func authorizationNextOptionText(currentType: SentAuthorizationCodeType, nextType: AuthorizationCodeNextType?, returnToCode: Bool = false, timeout: Int32?, strings: PresentationStrings, primaryColor: UIColor, accentColor: UIColor) -> (NSAttributedString, Bool) {
|
||||
public func authorizationNextOptionText(currentType: SentAuthorizationCodeType, nextType: AuthorizationCodeNextType?, previousCodeType: SentAuthorizationCodeType? = nil, timeout: Int32?, strings: PresentationStrings, primaryColor: UIColor, accentColor: UIColor) -> (NSAttributedString, Bool) {
|
||||
let font = Font.regular(16.0)
|
||||
|
||||
switch currentType {
|
||||
case .word, .phrase:
|
||||
if returnToCode {
|
||||
if let previousCodeType {
|
||||
switch previousCodeType {
|
||||
case .word:
|
||||
return (NSAttributedString(string: strings.Login_ReturnToWord, font: font, textColor: accentColor, paragraphAlignment: .center), true)
|
||||
case .phrase:
|
||||
return (NSAttributedString(string: strings.Login_ReturnToPhrase, font: font, textColor: accentColor, paragraphAlignment: .center), true)
|
||||
default:
|
||||
return (NSAttributedString(string: strings.Login_ReturnToCode, font: font, textColor: accentColor, paragraphAlignment: .center), true)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
if let nextType = nextType, let timeout = timeout, timeout > 0 {
|
||||
let minutes = timeout / 60
|
||||
let seconds = timeout % 60
|
||||
|
@ -3082,6 +3082,21 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
}
|
||||
})))
|
||||
|
||||
// items.append(.action(ContextMenuActionItem(text: presentationData.strings.StoryFeed_ViewAnonymously, icon: { theme in
|
||||
// return generateTintedImage(image: UIImage(bundleImageName: self.context.isPremium ? "Chat/Context Menu/Eye" : "Chat/Context Menu/EyeLocked"), color: theme.contextMenu.primaryColor)
|
||||
// }, action: { [weak self] _, a in
|
||||
// a(.default)
|
||||
//
|
||||
// guard let self else {
|
||||
// return
|
||||
// }
|
||||
// if self.context.isPremium {
|
||||
//// self.sendMessageContext.requestStealthMode(view: self)
|
||||
// } else {
|
||||
//// self.presentStealthModeUpgradeScreen()
|
||||
// }
|
||||
// })))
|
||||
|
||||
let hideText: String
|
||||
if self.location == .chatList(groupId: .archive) {
|
||||
hideText = self.presentationData.strings.StoryFeed_ContextUnarchive
|
||||
|
@ -760,7 +760,7 @@ private func internalChatListFilterAddChatsController(context: AccountContext, f
|
||||
selectedChats: Set(filterData.includePeers.peers),
|
||||
additionalCategories: ContactMultiselectionControllerAdditionalCategories(categories: additionalCategories, selectedCategories: selectedCategories),
|
||||
chatListFilters: allFilters
|
||||
)), options: [], filters: [], alwaysEnabled: true, limit: isPremium ? premiumLimit : limit, reachedLimit: { count in
|
||||
)), filters: [], alwaysEnabled: true, limit: isPremium ? premiumLimit : limit, reachedLimit: { count in
|
||||
if count >= premiumLimit {
|
||||
let limitController = PremiumLimitScreen(context: context, subject: .chatsPerFolder, count: min(premiumLimit, count), action: {
|
||||
return true
|
||||
@ -913,7 +913,7 @@ private func internalChatListFilterExcludeChatsController(context: AccountContex
|
||||
selectedChats: Set(filterData.excludePeers),
|
||||
additionalCategories: ContactMultiselectionControllerAdditionalCategories(categories: additionalCategories, selectedCategories: selectedCategories),
|
||||
chatListFilters: allFilters
|
||||
)), options: [], filters: [], alwaysEnabled: true, limit: 100))
|
||||
)), filters: [], alwaysEnabled: true, limit: 100))
|
||||
controller.navigationPresentation = .modal
|
||||
let _ = (controller.result
|
||||
|> take(1)
|
||||
|
@ -1770,25 +1770,32 @@ public final class ContactListNode: ASDisplayNode {
|
||||
if (authorizationStatus == .notDetermined || authorizationStatus == .denied) && peers.isEmpty {
|
||||
isEmpty = true
|
||||
}
|
||||
|
||||
let entries = contactListNodeEntries(accountPeer: view.1, peers: peers, presences: presences, presentation: presentation, selectionState: selectionState, theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, sortOrder: presentationData.nameSortOrder, displayOrder: presentationData.nameDisplayOrder, disabledPeerIds: disabledPeerIds, peerRequiresPremiumForMessaging: view.2, authorizationStatus: authorizationStatus, warningSuppressed: warningSuppressed, displaySortOptions: displaySortOptions, displayCallIcons: displayCallIcons, storySubscriptions: storySubscriptions, topPeers: topPeers.map { $0.peer }, topPeersPresentation: displayTopPeers, interaction: interaction)
|
||||
let previous = previousEntries.swap(entries)
|
||||
let previousSelection = previousSelectionState.swap(selectionState)
|
||||
let previousPendingRemovalPeerIds = previousPendingRemovalPeerIds.swap(pendingRemovalPeerIds)
|
||||
|
||||
var hadPermissionInfo = false
|
||||
var previousOptionsCount = 0
|
||||
if let previous = previous {
|
||||
for entry in previous {
|
||||
if case .permissionInfo = entry {
|
||||
hadPermissionInfo = true
|
||||
break
|
||||
}
|
||||
if case .option = entry {
|
||||
previousOptionsCount += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
var hasPermissionInfo = false
|
||||
var optionsCount = 0
|
||||
for entry in entries {
|
||||
if case .permissionInfo = entry {
|
||||
hasPermissionInfo = true
|
||||
break
|
||||
}
|
||||
if case .option = entry {
|
||||
optionsCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
@ -1799,6 +1806,8 @@ public final class ContactListNode: ASDisplayNode {
|
||||
animation = .insertion
|
||||
} else if hadPermissionInfo != hasPermissionInfo {
|
||||
animation = .insertion
|
||||
} else if optionsCount < previousOptionsCount {
|
||||
animation = .insertion
|
||||
} else {
|
||||
animation = .none
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ private struct LocationViewTransaction {
|
||||
let updates: [ListViewUpdateItem]
|
||||
let gotTravelTimes: Bool
|
||||
let count: Int
|
||||
let animated: Bool
|
||||
}
|
||||
|
||||
private enum LocationViewEntryId: Hashable {
|
||||
@ -197,14 +198,14 @@ private enum LocationViewEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
|
||||
private func preparedTransition(from fromEntries: [LocationViewEntry], to toEntries: [LocationViewEntry], context: AccountContext, presentationData: PresentationData, interaction: LocationViewInteraction?, gotTravelTimes: Bool) -> LocationViewTransaction {
|
||||
private func preparedTransition(from fromEntries: [LocationViewEntry], to toEntries: [LocationViewEntry], context: AccountContext, presentationData: PresentationData, interaction: LocationViewInteraction?, gotTravelTimes: Bool, animated: Bool) -> LocationViewTransaction {
|
||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||
|
||||
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, interaction: interaction), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, interaction: interaction), directionHint: nil) }
|
||||
|
||||
return LocationViewTransaction(deletions: deletions, insertions: insertions, updates: updates, gotTravelTimes: gotTravelTimes, count: toEntries.count)
|
||||
return LocationViewTransaction(deletions: deletions, insertions: insertions, updates: updates, gotTravelTimes: gotTravelTimes, count: toEntries.count, animated: animated)
|
||||
}
|
||||
|
||||
enum LocationViewLocation: Equatable {
|
||||
@ -573,7 +574,27 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
|
||||
let previousState = previousState.swap(state)
|
||||
let previousHadTravelTimes = previousHadTravelTimes.swap(!travelTimes.isEmpty)
|
||||
|
||||
let transition = preparedTransition(from: previousEntries ?? [], to: entries, context: context, presentationData: presentationData, interaction: strongSelf.interaction, gotTravelTimes: !travelTimes.isEmpty && !previousHadTravelTimes)
|
||||
var animated = false
|
||||
var previousActionsCount = 0
|
||||
var actionsCount = 0
|
||||
if let previousEntries {
|
||||
for entry in previousEntries {
|
||||
if case .toggleLiveLocation = entry {
|
||||
previousActionsCount += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
for entry in entries {
|
||||
if case .toggleLiveLocation = entry {
|
||||
actionsCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
if actionsCount < previousActionsCount {
|
||||
animated = true
|
||||
}
|
||||
|
||||
let transition = preparedTransition(from: previousEntries ?? [], to: entries, context: context, presentationData: presentationData, interaction: strongSelf.interaction, gotTravelTimes: !travelTimes.isEmpty && !previousHadTravelTimes, animated: animated)
|
||||
strongSelf.enqueueTransition(transition)
|
||||
|
||||
strongSelf.headerNode.updateState(mapMode: state.mapMode, trackingMode: state.trackingMode, displayingMapModeOptions: state.displayingMapModeOptions, displayingPlacesButton: false, proximityNotification: proximityNotification, animated: false)
|
||||
@ -787,7 +808,10 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
|
||||
scrollToItem = nil
|
||||
}
|
||||
|
||||
let options = ListViewDeleteAndInsertOptions()
|
||||
var options = ListViewDeleteAndInsertOptions()
|
||||
if transition.animated {
|
||||
options.insert(.AnimateInsertion)
|
||||
}
|
||||
self.listNode.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, scrollToItem: scrollToItem, updateSizeAndInsets: nil, updateOpaqueState: nil, completion: { _ in
|
||||
})
|
||||
}
|
||||
|
@ -518,7 +518,7 @@ public func channelMembersController(context: AccountContext, updatedPresentatio
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { chatPeer, exportedInvitation, members in
|
||||
let disabledIds = members?.compactMap({$0.peer.id}) ?? []
|
||||
let contactsController = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, updatedPresentationData: updatedPresentationData, mode: .peerSelection(searchChatList: false, searchGroups: false, searchChannels: false), options: [], filters: [.excludeSelf, .disable(disabledIds)], onlyWriteable: true, isGroupInvitation: true))
|
||||
let contactsController = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, updatedPresentationData: updatedPresentationData, mode: .peerSelection(searchChatList: false, searchGroups: false, searchChannels: false), filters: [.excludeSelf, .disable(disabledIds)], onlyWriteable: true, isGroupInvitation: true))
|
||||
|
||||
addMembersDisposable.set((
|
||||
contactsController.result
|
||||
|
@ -2276,7 +2276,7 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
||||
nextImpl = { [weak controller] in
|
||||
if let controller = controller {
|
||||
if case .initialSetup = mode {
|
||||
let selectionController = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, updatedPresentationData: updatedPresentationData, mode: .channelCreation, options: [], onlyWriteable: true))
|
||||
let selectionController = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, updatedPresentationData: updatedPresentationData, mode: .channelCreation, onlyWriteable: true))
|
||||
(controller.navigationController as? NavigationController)?.replaceAllButRootController(selectionController, animated: true)
|
||||
let _ = (selectionController.result
|
||||
|> deliverOnMainQueue).start(next: { [weak selectionController] result in
|
||||
|
@ -108,7 +108,7 @@ public func ChangePhoneNumberController(context: AccountContext) -> ViewControll
|
||||
codeController.openFragment = { url in
|
||||
context.sharedContext.applicationBindings.openUrl(url)
|
||||
}
|
||||
codeController.updateData(number: formatPhoneNumber(context: context, number: phoneNumber), email: nil, codeType: next.type, nextType: nil, timeout: next.timeout, termsOfService: nil, hasPreviousCode: false, previousIsPhrase: false)
|
||||
codeController.updateData(number: formatPhoneNumber(context: context, number: phoneNumber), email: nil, codeType: next.type, nextType: nil, timeout: next.timeout, termsOfService: nil, previousCodeType: nil, isPrevious: false)
|
||||
dismissImpl = { [weak codeController] in
|
||||
codeController?.dismiss()
|
||||
}
|
||||
|
@ -315,7 +315,6 @@ public func globalAutoremoveScreen(context: AccountContext, initialValue: Int32,
|
||||
chatListFilters: nil,
|
||||
displayAutoremoveTimeout: true
|
||||
)),
|
||||
options: [],
|
||||
filters: [.excludeSelf],
|
||||
isPeerEnabled: { peer in
|
||||
var canManage = false
|
||||
|
@ -1446,7 +1446,7 @@ public func privacyAndSecurityController(
|
||||
emailChangeCompletion(codeController)
|
||||
}))
|
||||
}
|
||||
codeController.updateData(number: "", email: email, codeType: .email(emailPattern: "", length: data.length, resetAvailablePeriod: nil, resetPendingDate: nil, appleSignInAllowed: false, setup: true), nextType: nil, timeout: nil, termsOfService: nil, hasPreviousCode: false, previousIsPhrase: false)
|
||||
codeController.updateData(number: "", email: email, codeType: .email(emailPattern: "", length: data.length, resetAvailablePeriod: nil, resetPendingDate: nil, appleSignInAllowed: false, setup: true), nextType: nil, timeout: nil, termsOfService: nil, previousCodeType: nil, isPrevious: false)
|
||||
pushControllerImpl?(codeController, true)
|
||||
dismissCodeControllerImpl = { [weak codeController] in
|
||||
codeController?.dismiss()
|
||||
|
@ -1141,7 +1141,7 @@ public func selectivePrivacySettingsController(
|
||||
onlyUsers: false,
|
||||
disableChannels: true,
|
||||
disableBots: false
|
||||
)), options: [], filters: [.excludeSelf]))
|
||||
)), filters: [.excludeSelf]))
|
||||
addPeerDisposable.set((controller.result
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak controller] result in
|
||||
|
@ -355,7 +355,7 @@ public func selectivePrivacyPeersController(context: AccountContext, title: Stri
|
||||
onlyUsers: false,
|
||||
disableChannels: true,
|
||||
disableBots: false
|
||||
)), options: [], alwaysEnabled: true))
|
||||
)), alwaysEnabled: true))
|
||||
addPeerDisposable.set((controller.result
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak controller] result in
|
||||
|
@ -1401,11 +1401,11 @@ private func monetizationEntries(
|
||||
isCreator = true
|
||||
}
|
||||
entries.append(.adsBalanceTitle(presentationData.theme, presentationData.strings.Monetization_BalanceTitle))
|
||||
entries.append(.adsBalance(presentationData.theme, data, isCreator && data.availableBalance > 0, monetizationConfiguration.withdrawalAvailable, diamond))
|
||||
entries.append(.adsBalance(presentationData.theme, data, isCreator && data.balances.availableBalance > 0, monetizationConfiguration.withdrawalAvailable, diamond))
|
||||
|
||||
if isCreator {
|
||||
let withdrawalInfoText: String
|
||||
if data.availableBalance == 0 {
|
||||
if data.balances.availableBalance == 0 {
|
||||
withdrawalInfoText = presentationData.strings.Monetization_Balance_ZeroInfo
|
||||
} else if monetizationConfiguration.withdrawalAvailable {
|
||||
withdrawalInfoText = presentationData.strings.Monetization_Balance_AvailableInfo
|
||||
@ -1579,7 +1579,7 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
|
||||
|
||||
let boostsContext = ChannelBoostersContext(account: context.account, peerId: peerId, gift: false)
|
||||
let giftsContext = ChannelBoostersContext(account: context.account, peerId: peerId, gift: true)
|
||||
let revenueContext = RevenueStatsContext(postbox: context.account.postbox, network: context.account.network, peerId: peerId)
|
||||
let revenueContext = RevenueStatsContext(account: context.account, peerId: peerId)
|
||||
let revenueState = Promise<RevenueStatsContextState?>()
|
||||
revenueState.set(.single(nil) |> then(revenueContext.state |> map(Optional.init)))
|
||||
|
||||
@ -2127,11 +2127,9 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
|
||||
|> deliverOnMainQueue).start(error: { error in
|
||||
let controller = revenueWithdrawalController(context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, initialError: error, present: { c, _ in
|
||||
presentImpl?(c)
|
||||
}, completion: { [weak revenueContext] url in
|
||||
}, completion: { url in
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: url, forceExternal: true, presentationData: presentationData, navigationController: nil, dismissInput: {})
|
||||
|
||||
revenueContext?.reload()
|
||||
})
|
||||
presentImpl?(controller)
|
||||
}))
|
||||
|
@ -158,13 +158,13 @@ final class MonetizationBalanceItemNode: ListViewItemNode, ItemListItemNode {
|
||||
let integralFont = Font.with(size: 48.0, design: .round, weight: .semibold)
|
||||
let fractionalFont = Font.with(size: 24.0, design: .round, weight: .semibold)
|
||||
|
||||
let cryptoValue = formatBalanceText(item.stats.availableBalance, decimalSeparator: item.presentationData.dateTimeFormat.decimalSeparator)
|
||||
let cryptoValue = formatBalanceText(item.stats.balances.availableBalance, decimalSeparator: item.presentationData.dateTimeFormat.decimalSeparator)
|
||||
|
||||
let amountString = amountAttributedString(cryptoValue, integralFont: integralFont, fractionalFont: fractionalFont, color: item.presentationData.theme.list.itemPrimaryTextColor)
|
||||
|
||||
let (balanceLayout, balanceApply) = makeBalanceTextLayout(TextNodeLayoutArguments(attributedString: amountString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .middle, constrainedSize: CGSize(width: constrainedWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
let value = item.stats.availableBalance == 0 ? "" : "≈\(formatUsdValue(item.stats.availableBalance, rate: item.stats.usdRate))"
|
||||
let value = item.stats.balances.availableBalance == 0 ? "" : "≈\(formatUsdValue(item.stats.balances.availableBalance, rate: item.stats.usdRate))"
|
||||
let (valueLayout, valueApply) = makeValueTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: value, font: Font.regular(17.0), textColor: item.presentationData.theme.list.itemSecondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .middle, constrainedSize: CGSize(width: constrainedWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
let verticalInset: CGFloat = 13.0
|
||||
|
@ -732,9 +732,9 @@ class StatsOverviewItemNode: ListViewItemNode {
|
||||
item.context,
|
||||
params.width,
|
||||
item.presentationData,
|
||||
formatBalanceText(stats.availableBalance, decimalSeparator: item.presentationData.dateTimeFormat.decimalSeparator),
|
||||
formatBalanceText(stats.balances.availableBalance, decimalSeparator: item.presentationData.dateTimeFormat.decimalSeparator),
|
||||
item.presentationData.strings.Monetization_Overview_Available,
|
||||
(stats.availableBalance == 0 ? "" : "≈\(formatUsdValue(stats.availableBalance, rate: stats.usdRate))", .generic),
|
||||
(stats.balances.availableBalance == 0 ? "" : "≈\(formatUsdValue(stats.balances.availableBalance, rate: stats.usdRate))", .generic),
|
||||
true
|
||||
)
|
||||
|
||||
@ -742,9 +742,9 @@ class StatsOverviewItemNode: ListViewItemNode {
|
||||
item.context,
|
||||
params.width,
|
||||
item.presentationData,
|
||||
formatBalanceText(stats.currentBalance, decimalSeparator: item.presentationData.dateTimeFormat.decimalSeparator),
|
||||
formatBalanceText(stats.balances.currentBalance, decimalSeparator: item.presentationData.dateTimeFormat.decimalSeparator),
|
||||
item.presentationData.strings.Monetization_Overview_Current,
|
||||
(stats.currentBalance == 0 ? "" : "≈\(formatUsdValue(stats.currentBalance, rate: stats.usdRate))", .generic),
|
||||
(stats.balances.currentBalance == 0 ? "" : "≈\(formatUsdValue(stats.balances.currentBalance, rate: stats.usdRate))", .generic),
|
||||
true
|
||||
)
|
||||
|
||||
@ -752,9 +752,9 @@ class StatsOverviewItemNode: ListViewItemNode {
|
||||
item.context,
|
||||
params.width,
|
||||
item.presentationData,
|
||||
formatBalanceText(stats.overallRevenue, decimalSeparator: item.presentationData.dateTimeFormat.decimalSeparator),
|
||||
formatBalanceText(stats.balances.overallRevenue, decimalSeparator: item.presentationData.dateTimeFormat.decimalSeparator),
|
||||
item.presentationData.strings.Monetization_Overview_Total,
|
||||
(stats.overallRevenue == 0 ? "" : "≈\(formatUsdValue(stats.overallRevenue, rate: stats.usdRate))", .generic),
|
||||
(stats.balances.overallRevenue == 0 ? "" : "≈\(formatUsdValue(stats.balances.overallRevenue, rate: stats.usdRate))", .generic),
|
||||
true
|
||||
)
|
||||
|
||||
|
@ -1362,7 +1362,7 @@ public extension Api {
|
||||
return parser(reader)
|
||||
}
|
||||
else {
|
||||
telegramApiLog("Type constructor \(String(UInt32(bitPattern: signature), radix: 16, uppercase: false)) not found")
|
||||
telegramApiLog("Type constructor \(String(signature, radix: 16, uppercase: false)) not found")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -128,6 +128,7 @@ enum AccountStateMutationOperation {
|
||||
case UpdateStorySentReaction(peerId: PeerId, id: Int32, reaction: Api.Reaction)
|
||||
case UpdateNewAuthorization(isUnconfirmed: Bool, hash: Int64, date: Int32, device: String, location: String)
|
||||
case UpdateWallpaper(peerId: PeerId, wallpaper: TelegramWallpaper?)
|
||||
case UpdateRevenueBalances(RevenueStats.Balances)
|
||||
}
|
||||
|
||||
struct HoleFromPreviousState {
|
||||
@ -524,7 +525,7 @@ struct AccountMutableState {
|
||||
mutating func updatePeersNearby(_ peersNearby: [PeerNearby]) {
|
||||
self.addOperation(.UpdatePeersNearby(peersNearby))
|
||||
}
|
||||
|
||||
|
||||
mutating func updateTheme(_ theme: TelegramTheme) {
|
||||
self.addOperation(.UpdateTheme(theme))
|
||||
}
|
||||
@ -673,9 +674,13 @@ struct AccountMutableState {
|
||||
self.addOperation(.UpdateNewAuthorization(isUnconfirmed: isUnconfirmed, hash: hash, date: date, device: device, location: location))
|
||||
}
|
||||
|
||||
mutating func updateRevenueBalances(_ balances: RevenueStats.Balances) {
|
||||
self.addOperation(.UpdateRevenueBalances(balances))
|
||||
}
|
||||
|
||||
mutating func addOperation(_ operation: AccountStateMutationOperation) {
|
||||
switch operation {
|
||||
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .UpdateWallpaper, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization:
|
||||
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .UpdateWallpaper, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateRevenueBalances:
|
||||
break
|
||||
case let .AddMessages(messages, location):
|
||||
for message in messages {
|
||||
@ -819,6 +824,7 @@ struct AccountReplayedFinalState {
|
||||
let updatedOutgoingThreadReadStates: [MessageId: MessageId.Id]
|
||||
let updateConfig: Bool
|
||||
let isPremiumUpdated: Bool
|
||||
let updatedRevenueBalances: RevenueStats.Balances?
|
||||
}
|
||||
|
||||
struct AccountFinalStateEvents {
|
||||
@ -845,12 +851,13 @@ struct AccountFinalStateEvents {
|
||||
let updatedOutgoingThreadReadStates: [MessageId: MessageId.Id]
|
||||
let updateConfig: Bool
|
||||
let isPremiumUpdated: Bool
|
||||
let updatedRevenueBalances: RevenueStats.Balances?
|
||||
|
||||
var isEmpty: Bool {
|
||||
return self.addedIncomingMessageIds.isEmpty && self.addedReactionEvents.isEmpty && self.wasScheduledMessageIds.isEmpty && self.deletedMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.addedCallSignalingData.isEmpty && self.updatedGroupCallParticipants.isEmpty && self.storyUpdates.isEmpty && self.updatedPeersNearby?.isEmpty ?? true && self.isContactUpdates.isEmpty && self.displayAlerts.isEmpty && self.dismissBotWebViews.isEmpty && self.delayNotificatonsUntil == nil && self.updatedMaxMessageId == nil && self.updatedQts == nil && self.externallyUpdatedPeerId.isEmpty && !authorizationListUpdated && self.updatedIncomingThreadReadStates.isEmpty && self.updatedOutgoingThreadReadStates.isEmpty && !self.updateConfig && !isPremiumUpdated
|
||||
return self.addedIncomingMessageIds.isEmpty && self.addedReactionEvents.isEmpty && self.wasScheduledMessageIds.isEmpty && self.deletedMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.addedCallSignalingData.isEmpty && self.updatedGroupCallParticipants.isEmpty && self.storyUpdates.isEmpty && self.updatedPeersNearby?.isEmpty ?? true && self.isContactUpdates.isEmpty && self.displayAlerts.isEmpty && self.dismissBotWebViews.isEmpty && self.delayNotificatonsUntil == nil && self.updatedMaxMessageId == nil && self.updatedQts == nil && self.externallyUpdatedPeerId.isEmpty && !authorizationListUpdated && self.updatedIncomingThreadReadStates.isEmpty && self.updatedOutgoingThreadReadStates.isEmpty && !self.updateConfig && !self.isPremiumUpdated && self.updatedRevenueBalances == nil
|
||||
}
|
||||
|
||||
init(addedIncomingMessageIds: [MessageId] = [], addedReactionEvents: [(reactionAuthor: Peer, reaction: MessageReaction.Reaction, message: Message, timestamp: Int32)] = [], wasScheduledMessageIds: [MessageId] = [], deletedMessageIds: [DeletedMessageId] = [], updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]] = [:], updatedWebpages: [MediaId: TelegramMediaWebpage] = [:], updatedCalls: [Api.PhoneCall] = [], addedCallSignalingData: [(Int64, Data)] = [], updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.Update)] = [], storyUpdates: [InternalStoryUpdate] = [], updatedPeersNearby: [PeerNearby]? = nil, isContactUpdates: [(PeerId, Bool)] = [], displayAlerts: [(text: String, isDropAuth: Bool)] = [], dismissBotWebViews: [Int64] = [], delayNotificatonsUntil: Int32? = nil, updatedMaxMessageId: Int32? = nil, updatedQts: Int32? = nil, externallyUpdatedPeerId: Set<PeerId> = Set(), authorizationListUpdated: Bool = false, updatedIncomingThreadReadStates: [MessageId: MessageId.Id] = [:], updatedOutgoingThreadReadStates: [MessageId: MessageId.Id] = [:], updateConfig: Bool = false, isPremiumUpdated: Bool = false) {
|
||||
init(addedIncomingMessageIds: [MessageId] = [], addedReactionEvents: [(reactionAuthor: Peer, reaction: MessageReaction.Reaction, message: Message, timestamp: Int32)] = [], wasScheduledMessageIds: [MessageId] = [], deletedMessageIds: [DeletedMessageId] = [], updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]] = [:], updatedWebpages: [MediaId: TelegramMediaWebpage] = [:], updatedCalls: [Api.PhoneCall] = [], addedCallSignalingData: [(Int64, Data)] = [], updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.Update)] = [], storyUpdates: [InternalStoryUpdate] = [], updatedPeersNearby: [PeerNearby]? = nil, isContactUpdates: [(PeerId, Bool)] = [], displayAlerts: [(text: String, isDropAuth: Bool)] = [], dismissBotWebViews: [Int64] = [], delayNotificatonsUntil: Int32? = nil, updatedMaxMessageId: Int32? = nil, updatedQts: Int32? = nil, externallyUpdatedPeerId: Set<PeerId> = Set(), authorizationListUpdated: Bool = false, updatedIncomingThreadReadStates: [MessageId: MessageId.Id] = [:], updatedOutgoingThreadReadStates: [MessageId: MessageId.Id] = [:], updateConfig: Bool = false, isPremiumUpdated: Bool = false, updatedRevenueBalances: RevenueStats.Balances? = nil) {
|
||||
self.addedIncomingMessageIds = addedIncomingMessageIds
|
||||
self.addedReactionEvents = addedReactionEvents
|
||||
self.wasScheduledMessageIds = wasScheduledMessageIds
|
||||
@ -874,6 +881,7 @@ struct AccountFinalStateEvents {
|
||||
self.updatedOutgoingThreadReadStates = updatedOutgoingThreadReadStates
|
||||
self.updateConfig = updateConfig
|
||||
self.isPremiumUpdated = isPremiumUpdated
|
||||
self.updatedRevenueBalances = updatedRevenueBalances
|
||||
}
|
||||
|
||||
init(state: AccountReplayedFinalState) {
|
||||
@ -900,6 +908,7 @@ struct AccountFinalStateEvents {
|
||||
self.updatedOutgoingThreadReadStates = state.updatedOutgoingThreadReadStates
|
||||
self.updateConfig = state.updateConfig
|
||||
self.isPremiumUpdated = state.isPremiumUpdated
|
||||
self.updatedRevenueBalances = state.updatedRevenueBalances
|
||||
}
|
||||
|
||||
func union(with other: AccountFinalStateEvents) -> AccountFinalStateEvents {
|
||||
@ -929,6 +938,6 @@ struct AccountFinalStateEvents {
|
||||
|
||||
let isPremiumUpdated = self.isPremiumUpdated || other.isPremiumUpdated
|
||||
|
||||
return AccountFinalStateEvents(addedIncomingMessageIds: self.addedIncomingMessageIds + other.addedIncomingMessageIds, addedReactionEvents: self.addedReactionEvents + other.addedReactionEvents, wasScheduledMessageIds: self.wasScheduledMessageIds + other.wasScheduledMessageIds, deletedMessageIds: self.deletedMessageIds + other.deletedMessageIds, updatedTypingActivities: self.updatedTypingActivities, updatedWebpages: self.updatedWebpages, updatedCalls: self.updatedCalls + other.updatedCalls, addedCallSignalingData: self.addedCallSignalingData + other.addedCallSignalingData, updatedGroupCallParticipants: self.updatedGroupCallParticipants + other.updatedGroupCallParticipants, storyUpdates: self.storyUpdates + other.storyUpdates, isContactUpdates: self.isContactUpdates + other.isContactUpdates, displayAlerts: self.displayAlerts + other.displayAlerts, dismissBotWebViews: self.dismissBotWebViews + other.dismissBotWebViews, delayNotificatonsUntil: delayNotificatonsUntil, updatedMaxMessageId: updatedMaxMessageId, updatedQts: updatedQts, externallyUpdatedPeerId: externallyUpdatedPeerId, authorizationListUpdated: authorizationListUpdated, updatedIncomingThreadReadStates: self.updatedIncomingThreadReadStates.merging(other.updatedIncomingThreadReadStates, uniquingKeysWith: { lhs, _ in lhs }), updateConfig: updateConfig, isPremiumUpdated: isPremiumUpdated)
|
||||
return AccountFinalStateEvents(addedIncomingMessageIds: self.addedIncomingMessageIds + other.addedIncomingMessageIds, addedReactionEvents: self.addedReactionEvents + other.addedReactionEvents, wasScheduledMessageIds: self.wasScheduledMessageIds + other.wasScheduledMessageIds, deletedMessageIds: self.deletedMessageIds + other.deletedMessageIds, updatedTypingActivities: self.updatedTypingActivities, updatedWebpages: self.updatedWebpages, updatedCalls: self.updatedCalls + other.updatedCalls, addedCallSignalingData: self.addedCallSignalingData + other.addedCallSignalingData, updatedGroupCallParticipants: self.updatedGroupCallParticipants + other.updatedGroupCallParticipants, storyUpdates: self.storyUpdates + other.storyUpdates, isContactUpdates: self.isContactUpdates + other.isContactUpdates, displayAlerts: self.displayAlerts + other.displayAlerts, dismissBotWebViews: self.dismissBotWebViews + other.dismissBotWebViews, delayNotificatonsUntil: delayNotificatonsUntil, updatedMaxMessageId: updatedMaxMessageId, updatedQts: updatedQts, externallyUpdatedPeerId: externallyUpdatedPeerId, authorizationListUpdated: authorizationListUpdated, updatedIncomingThreadReadStates: self.updatedIncomingThreadReadStates.merging(other.updatedIncomingThreadReadStates, uniquingKeysWith: { lhs, _ in lhs }), updateConfig: updateConfig, isPremiumUpdated: isPremiumUpdated, updatedRevenueBalances: self.updatedRevenueBalances != nil ? self.updatedRevenueBalances : other.updatedRevenueBalances)
|
||||
}
|
||||
}
|
||||
|
@ -269,6 +269,7 @@ public func sendAuthorizationCode(accountManager: AccountManager<TelegramAccount
|
||||
case let .sentCode(sentCode):
|
||||
switch sentCode {
|
||||
case let .sentCode(_, type, phoneCodeHash, nextType, codeTimeout):
|
||||
let parsedType = SentAuthorizationCodeType(apiType: type)
|
||||
var parsedNextType: AuthorizationCodeNextType?
|
||||
if let nextType = nextType {
|
||||
parsedNextType = AuthorizationCodeNextType(apiType: nextType)
|
||||
@ -316,11 +317,16 @@ public func sendAuthorizationCode(accountManager: AccountManager<TelegramAccount
|
||||
case .word, .phrase:
|
||||
previousCodeEntry = state.contents
|
||||
default:
|
||||
break
|
||||
switch parsedType {
|
||||
case .word, .phrase:
|
||||
previousCodeEntry = state.contents
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .confirmationCodeEntry(number: phoneNumber, type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: codeTimeout, nextType: parsedNextType, syncContacts: syncContacts, previousCodeEntry: previousCodeEntry, usePrevious: false)))
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .confirmationCodeEntry(number: phoneNumber, type: parsedType, hash: phoneCodeHash, timeout: codeTimeout, nextType: parsedNextType, syncContacts: syncContacts, previousCodeEntry: previousCodeEntry, usePrevious: false)))
|
||||
|
||||
return .sentCode(account)
|
||||
}
|
||||
@ -331,7 +337,7 @@ public func sendAuthorizationCode(accountManager: AccountManager<TelegramAccount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var previousCodeEntry: UnauthorizedAccountStateContents?
|
||||
if let state = transaction.getState() as? UnauthorizedAccountState, case let .confirmationCodeEntry(_, type, _, _, _, _, previousCodeEntryValue, _) = state.contents {
|
||||
if let previousCodeEntryValue {
|
||||
@ -341,11 +347,16 @@ public func sendAuthorizationCode(accountManager: AccountManager<TelegramAccount
|
||||
case .word, .phrase:
|
||||
previousCodeEntry = state.contents
|
||||
default:
|
||||
break
|
||||
switch parsedType {
|
||||
case .word, .phrase:
|
||||
previousCodeEntry = state.contents
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .confirmationCodeEntry(number: phoneNumber, type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: codeTimeout, nextType: parsedNextType, syncContacts: syncContacts, previousCodeEntry: previousCodeEntry, usePrevious: false)))
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .confirmationCodeEntry(number: phoneNumber, type: parsedType, hash: phoneCodeHash, timeout: codeTimeout, nextType: parsedNextType, syncContacts: syncContacts, previousCodeEntry: previousCodeEntry, usePrevious: false)))
|
||||
case let .sentCodeSuccess(authorization):
|
||||
switch authorization {
|
||||
case let .authorization(_, otherwiseReloginDays, _, futureAuthToken, user):
|
||||
@ -404,6 +415,7 @@ private func internalResendAuthorizationCode(accountManager: AccountManager<Tele
|
||||
return account.postbox.transaction { transaction -> Signal<SendAuthorizationCodeResult, AuthorizationCodeRequestError> in
|
||||
switch sentCode {
|
||||
case let .sentCode(_, type, phoneCodeHash, nextType, codeTimeout):
|
||||
let parsedType = SentAuthorizationCodeType(apiType: type)
|
||||
var parsedNextType: AuthorizationCodeNextType?
|
||||
if let nextType = nextType {
|
||||
parsedNextType = AuthorizationCodeNextType(apiType: nextType)
|
||||
@ -451,11 +463,16 @@ private func internalResendAuthorizationCode(accountManager: AccountManager<Tele
|
||||
case .word, .phrase:
|
||||
previousCodeEntry = state.contents
|
||||
default:
|
||||
break
|
||||
switch parsedType {
|
||||
case .word, .phrase:
|
||||
previousCodeEntry = state.contents
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .confirmationCodeEntry(number: number, type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: codeTimeout, nextType: parsedNextType, syncContacts: syncContacts, previousCodeEntry: previousCodeEntry, usePrevious: false)))
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .confirmationCodeEntry(number: number, type: parsedType, hash: phoneCodeHash, timeout: codeTimeout, nextType: parsedNextType, syncContacts: syncContacts, previousCodeEntry: previousCodeEntry, usePrevious: false)))
|
||||
|
||||
return .sentCode(account)
|
||||
}
|
||||
@ -476,7 +493,12 @@ private func internalResendAuthorizationCode(accountManager: AccountManager<Tele
|
||||
case .word, .phrase:
|
||||
previousCodeEntry = state.contents
|
||||
default:
|
||||
break
|
||||
switch parsedType {
|
||||
case .word, .phrase:
|
||||
previousCodeEntry = state.contents
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -498,17 +520,6 @@ public func resendAuthorizationCode(accountManager: AccountManager<TelegramAccou
|
||||
switch state.contents {
|
||||
case let .confirmationCodeEntry(number, type, hash, _, nextType, syncContacts, previousCodeEntryValue, _):
|
||||
if nextType != nil {
|
||||
var previousCodeEntry: UnauthorizedAccountStateContents?
|
||||
if let previousCodeEntryValue {
|
||||
previousCodeEntry = previousCodeEntryValue
|
||||
} else {
|
||||
switch type {
|
||||
case .word, .phrase:
|
||||
previousCodeEntry = state.contents
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
return account.network.request(Api.functions.auth.resendCode(phoneNumber: number, phoneCodeHash: hash), automaticFloodWait: false)
|
||||
|> mapError { error -> AuthorizationCodeRequestError in
|
||||
if error.errorDescription.hasPrefix("FLOOD_WAIT") {
|
||||
@ -528,13 +539,31 @@ public func resendAuthorizationCode(accountManager: AccountManager<TelegramAccou
|
||||
|> mapToSignal { sentCode -> Signal<Void, AuthorizationCodeRequestError> in
|
||||
return account.postbox.transaction { transaction -> Signal<Void, AuthorizationCodeRequestError> in
|
||||
switch sentCode {
|
||||
case let .sentCode(_, type, phoneCodeHash, nextType, codeTimeout):
|
||||
case let .sentCode(_, newType, phoneCodeHash, nextType, codeTimeout):
|
||||
let parsedType = SentAuthorizationCodeType(apiType: newType)
|
||||
var previousCodeEntry: UnauthorizedAccountStateContents?
|
||||
if let previousCodeEntryValue {
|
||||
previousCodeEntry = previousCodeEntryValue
|
||||
} else {
|
||||
switch type {
|
||||
case .word, .phrase:
|
||||
previousCodeEntry = state.contents
|
||||
default:
|
||||
switch parsedType {
|
||||
case .word, .phrase:
|
||||
previousCodeEntry = state.contents
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var parsedNextType: AuthorizationCodeNextType?
|
||||
if let nextType = nextType {
|
||||
parsedNextType = AuthorizationCodeNextType(apiType: nextType)
|
||||
}
|
||||
|
||||
if case let .sentCodeTypeFirebaseSms(_, _, receipt, pushTimeout, _) = type {
|
||||
if case let .sentCodeTypeFirebaseSms(_, _, receipt, pushTimeout, _) = newType {
|
||||
return firebaseSecretStream
|
||||
|> map { mapping -> String? in
|
||||
guard let receipt = receipt else {
|
||||
@ -567,7 +596,7 @@ public func resendAuthorizationCode(accountManager: AccountManager<TelegramAccou
|
||||
|> mapToSignal { success -> Signal<SendAuthorizationCodeResult, AuthorizationCodeRequestError> in
|
||||
if success {
|
||||
return account.postbox.transaction { transaction -> SendAuthorizationCodeResult in
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .confirmationCodeEntry(number: number, type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: codeTimeout, nextType: parsedNextType, syncContacts: syncContacts, previousCodeEntry: previousCodeEntry, usePrevious: false)))
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .confirmationCodeEntry(number: number, type: parsedType, hash: phoneCodeHash, timeout: codeTimeout, nextType: parsedNextType, syncContacts: syncContacts, previousCodeEntry: previousCodeEntry, usePrevious: false)))
|
||||
|
||||
return .sentCode(account)
|
||||
}
|
||||
@ -580,7 +609,7 @@ public func resendAuthorizationCode(accountManager: AccountManager<TelegramAccou
|
||||
|> map { _ -> Void in return Void() }
|
||||
}
|
||||
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .confirmationCodeEntry(number: number, type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: codeTimeout, nextType: parsedNextType, syncContacts: syncContacts, previousCodeEntry: previousCodeEntry, usePrevious: false)))
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .confirmationCodeEntry(number: number, type: parsedType, hash: phoneCodeHash, timeout: codeTimeout, nextType: parsedNextType, syncContacts: syncContacts, previousCodeEntry: previousCodeEntry, usePrevious: false)))
|
||||
case .sentCodeSuccess:
|
||||
break
|
||||
}
|
||||
|
@ -1776,6 +1776,8 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox:
|
||||
updatedState.updateNewAuthorization(isUnconfirmed: isUnconfirmed, hash: hash, date: date ?? 0, device: device ?? "", location: location ?? "")
|
||||
case let .updatePeerWallpaper(_, peer, wallpaper):
|
||||
updatedState.updateWallpaper(peerId: peer.peerId, wallpaper: wallpaper.flatMap { TelegramWallpaper(apiWallpaper: $0) })
|
||||
case let .updateBroadcastRevenueTransactions(balances):
|
||||
updatedState.updateRevenueBalances(RevenueStats.Balances(apiRevenueBalances: balances))
|
||||
default:
|
||||
break
|
||||
}
|
||||
@ -3267,7 +3269,7 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation])
|
||||
var currentAddQuickReplyMessages: OptimizeAddMessagesState?
|
||||
for operation in operations {
|
||||
switch operation {
|
||||
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateWallpaper:
|
||||
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateWallpaper, .UpdateRevenueBalances:
|
||||
if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty {
|
||||
result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location))
|
||||
}
|
||||
@ -3400,6 +3402,7 @@ func replayFinalState(
|
||||
var deletedMessageIds: [DeletedMessageId] = []
|
||||
var syncAttachMenuBots = false
|
||||
var updateConfig = false
|
||||
var updatedRevenueBalances: RevenueStats.Balances?
|
||||
|
||||
var holesFromPreviousStateMessageIds: [MessageId] = []
|
||||
var clearHolesFromPreviousStateForChannelMessagesWithPts: [PeerIdAndMessageNamespace: Int32] = [:]
|
||||
@ -4825,6 +4828,8 @@ func replayFinalState(
|
||||
} else {
|
||||
transaction.removeOrderedItemListItem(collectionId: Namespaces.OrderedItemList.NewSessionReviews, itemId: id.rawValue)
|
||||
}
|
||||
case let .UpdateRevenueBalances(balances):
|
||||
updatedRevenueBalances = balances
|
||||
}
|
||||
}
|
||||
|
||||
@ -5319,5 +5324,5 @@ func replayFinalState(
|
||||
}
|
||||
}
|
||||
|
||||
return AccountReplayedFinalState(state: finalState, addedIncomingMessageIds: addedIncomingMessageIds, addedReactionEvents: addedReactionEvents, wasScheduledMessageIds: wasScheduledMessageIds, addedSecretMessageIds: addedSecretMessageIds, deletedMessageIds: deletedMessageIds, updatedTypingActivities: updatedTypingActivities, updatedWebpages: updatedWebpages, updatedCalls: updatedCalls, addedCallSignalingData: addedCallSignalingData, updatedGroupCallParticipants: updatedGroupCallParticipants, storyUpdates: storyUpdates, updatedPeersNearby: updatedPeersNearby, isContactUpdates: isContactUpdates, delayNotificatonsUntil: delayNotificatonsUntil, updatedIncomingThreadReadStates: updatedIncomingThreadReadStates, updatedOutgoingThreadReadStates: updatedOutgoingThreadReadStates, updateConfig: updateConfig, isPremiumUpdated: isPremiumUpdated)
|
||||
return AccountReplayedFinalState(state: finalState, addedIncomingMessageIds: addedIncomingMessageIds, addedReactionEvents: addedReactionEvents, wasScheduledMessageIds: wasScheduledMessageIds, addedSecretMessageIds: addedSecretMessageIds, deletedMessageIds: deletedMessageIds, updatedTypingActivities: updatedTypingActivities, updatedWebpages: updatedWebpages, updatedCalls: updatedCalls, addedCallSignalingData: addedCallSignalingData, updatedGroupCallParticipants: updatedGroupCallParticipants, storyUpdates: storyUpdates, updatedPeersNearby: updatedPeersNearby, isContactUpdates: isContactUpdates, delayNotificatonsUntil: delayNotificatonsUntil, updatedIncomingThreadReadStates: updatedIncomingThreadReadStates, updatedOutgoingThreadReadStates: updatedOutgoingThreadReadStates, updateConfig: updateConfig, isPremiumUpdated: isPremiumUpdated, updatedRevenueBalances: updatedRevenueBalances)
|
||||
}
|
||||
|
@ -44,6 +44,10 @@ private final class UpdatedPeersNearbySubscriberContext {
|
||||
let subscribers = Bag<([PeerNearby]) -> Void>()
|
||||
}
|
||||
|
||||
private final class UpdatedRevenueBalancesSubscriberContext {
|
||||
let subscribers = Bag<(RevenueStats.Balances) -> Void>()
|
||||
}
|
||||
|
||||
public enum DeletedMessageId: Hashable {
|
||||
case global(Int32)
|
||||
case messageId(MessageId)
|
||||
@ -277,6 +281,7 @@ public final class AccountStateManager {
|
||||
|
||||
private var updatedWebpageContexts: [MediaId: UpdatedWebpageSubscriberContext] = [:]
|
||||
private var updatedPeersNearbyContext = UpdatedPeersNearbySubscriberContext()
|
||||
private var updatedRevenueBalancesContext = UpdatedRevenueBalancesSubscriberContext()
|
||||
|
||||
private let delayNotificatonsUntil = Atomic<Int32?>(value: nil)
|
||||
private let appliedMaxMessageIdPromise = Promise<Int32?>(nil)
|
||||
@ -1022,6 +1027,9 @@ public final class AccountStateManager {
|
||||
if let updatedPeersNearby = events.updatedPeersNearby {
|
||||
strongSelf.notifyUpdatedPeersNearby(updatedPeersNearby)
|
||||
}
|
||||
if let updatedRevenueBalances = events.updatedRevenueBalances {
|
||||
strongSelf.notifyUpdatedRevenueBalances(updatedRevenueBalances)
|
||||
}
|
||||
if !events.updatedCalls.isEmpty {
|
||||
for call in events.updatedCalls {
|
||||
strongSelf.callSessionManager?.updateSession(call, completion: { _ in })
|
||||
@ -1594,6 +1602,33 @@ public final class AccountStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
public func updatedRevenueBalances() -> Signal<RevenueStats.Balances, NoError> {
|
||||
let queue = self.queue
|
||||
return Signal { [weak self] subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
queue.async {
|
||||
if let strongSelf = self {
|
||||
let index = strongSelf.updatedRevenueBalancesContext.subscribers.add({ revenueBalances in
|
||||
subscriber.putNext(revenueBalances)
|
||||
})
|
||||
|
||||
disposable.set(ActionDisposable {
|
||||
if let strongSelf = self {
|
||||
strongSelf.updatedRevenueBalancesContext.subscribers.remove(index)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
return disposable
|
||||
}
|
||||
}
|
||||
|
||||
private func notifyUpdatedRevenueBalances(_ updatedRevenueBalances: RevenueStats.Balances) {
|
||||
for subscriber in self.updatedRevenueBalancesContext.subscribers.copyItems() {
|
||||
subscriber(updatedRevenueBalances)
|
||||
}
|
||||
}
|
||||
|
||||
func notifyDeletedMessages(messageIds: [MessageId]) {
|
||||
self.deletedMessagesPipe.putNext(messageIds.map { .messageId($0) })
|
||||
}
|
||||
@ -1881,6 +1916,12 @@ public final class AccountStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
public func updatedRevenueBalances() -> Signal<RevenueStats.Balances, NoError> {
|
||||
return self.impl.signalWith { impl, subscriber in
|
||||
return impl.updatedRevenueBalances().start(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion)
|
||||
}
|
||||
}
|
||||
|
||||
func addCustomOperation<T, E>(_ f: Signal<T, E>) -> Signal<T, E> {
|
||||
return self.impl.signalWith { impl, subscriber in
|
||||
return impl.addCustomOperation(f).start(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion)
|
||||
|
@ -162,7 +162,7 @@ func managedSynchronizeEmojiSearchCategories(postbox: Postbox, network: Network,
|
||||
case let .emojiGroups(hash, groups):
|
||||
let categories = EmojiSearchCategories(
|
||||
hash: hash,
|
||||
groups: groups.map { item -> EmojiSearchCategories.Group in
|
||||
groups: groups.compactMap { item -> EmojiSearchCategories.Group? in
|
||||
switch item {
|
||||
case let .emojiGroup(title, iconEmojiId, emoticons):
|
||||
return EmojiSearchCategories.Group(
|
||||
|
@ -5,19 +5,21 @@ import TelegramApi
|
||||
import MtProtoKit
|
||||
|
||||
public struct RevenueStats: Equatable {
|
||||
public struct Balances: Equatable {
|
||||
public let currentBalance: Int64
|
||||
public let availableBalance: Int64
|
||||
public let overallRevenue: Int64
|
||||
}
|
||||
|
||||
public let topHoursGraph: StatsGraph
|
||||
public let revenueGraph: StatsGraph
|
||||
public let currentBalance: Int64
|
||||
public let availableBalance: Int64
|
||||
public let overallRevenue: Int64
|
||||
public let balances: Balances
|
||||
public let usdRate: Double
|
||||
|
||||
init(topHoursGraph: StatsGraph, revenueGraph: StatsGraph, currentBalance: Int64, availableBalance: Int64, overallRevenue: Int64, usdRate: Double) {
|
||||
init(topHoursGraph: StatsGraph, revenueGraph: StatsGraph, balances: Balances, usdRate: Double) {
|
||||
self.topHoursGraph = topHoursGraph
|
||||
self.revenueGraph = revenueGraph
|
||||
self.currentBalance = currentBalance
|
||||
self.availableBalance = availableBalance
|
||||
self.overallRevenue = overallRevenue
|
||||
self.balances = balances
|
||||
self.usdRate = usdRate
|
||||
}
|
||||
|
||||
@ -28,13 +30,7 @@ public struct RevenueStats: Equatable {
|
||||
if lhs.revenueGraph != rhs.revenueGraph {
|
||||
return false
|
||||
}
|
||||
if lhs.currentBalance != rhs.currentBalance {
|
||||
return false
|
||||
}
|
||||
if lhs.availableBalance != rhs.availableBalance {
|
||||
return false
|
||||
}
|
||||
if lhs.overallRevenue != rhs.overallRevenue {
|
||||
if lhs.balances != rhs.balances {
|
||||
return false
|
||||
}
|
||||
if lhs.usdRate != rhs.usdRate {
|
||||
@ -44,14 +40,31 @@ public struct RevenueStats: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
public extension RevenueStats {
|
||||
func withUpdated(balances: RevenueStats.Balances) -> RevenueStats {
|
||||
return RevenueStats(
|
||||
topHoursGraph: self.topHoursGraph,
|
||||
revenueGraph: self.revenueGraph,
|
||||
balances: balances,
|
||||
usdRate: self.usdRate
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension RevenueStats {
|
||||
init(apiRevenueStats: Api.stats.BroadcastRevenueStats, peerId: PeerId) {
|
||||
switch apiRevenueStats {
|
||||
case let .broadcastRevenueStats(topHoursGraph, revenueGraph, balances, usdRate):
|
||||
switch balances {
|
||||
case let .broadcastRevenueBalances(currentBalance, availableBalance, overallRevenue):
|
||||
self.init(topHoursGraph: StatsGraph(apiStatsGraph: topHoursGraph), revenueGraph: StatsGraph(apiStatsGraph: revenueGraph), currentBalance: currentBalance, availableBalance: availableBalance, overallRevenue: overallRevenue, usdRate: usdRate)
|
||||
}
|
||||
self.init(topHoursGraph: StatsGraph(apiStatsGraph: topHoursGraph), revenueGraph: StatsGraph(apiStatsGraph: revenueGraph), balances: RevenueStats.Balances(apiRevenueBalances: balances), usdRate: usdRate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension RevenueStats.Balances {
|
||||
init(apiRevenueBalances: Api.BroadcastRevenueBalances) {
|
||||
switch apiRevenueBalances {
|
||||
case let .broadcastRevenueBalances(currentBalance, availableBalance, overallRevenue):
|
||||
self.init(currentBalance: currentBalance, availableBalance: availableBalance, overallRevenue: overallRevenue)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -85,8 +98,7 @@ private func requestRevenueStats(postbox: Postbox, network: Network, peerId: Pee
|
||||
}
|
||||
|
||||
private final class RevenueStatsContextImpl {
|
||||
private let postbox: Postbox
|
||||
private let network: Network
|
||||
private let account: Account
|
||||
private let peerId: PeerId
|
||||
|
||||
private var _state: RevenueStatsContextState {
|
||||
@ -103,11 +115,10 @@ private final class RevenueStatsContextImpl {
|
||||
|
||||
private let disposable = MetaDisposable()
|
||||
|
||||
init(postbox: Postbox, network: Network, peerId: PeerId) {
|
||||
init(account: Account, peerId: PeerId) {
|
||||
assert(Queue.mainQueue().isCurrent())
|
||||
|
||||
self.postbox = postbox
|
||||
self.network = network
|
||||
self.account = account
|
||||
self.peerId = peerId
|
||||
self._state = RevenueStatsContextState(stats: nil)
|
||||
self._statePromise.set(.single(self._state))
|
||||
@ -123,7 +134,22 @@ private final class RevenueStatsContextImpl {
|
||||
fileprivate func load() {
|
||||
assert(Queue.mainQueue().isCurrent())
|
||||
|
||||
self.disposable.set((requestRevenueStats(postbox: self.postbox, network: self.network, peerId: self.peerId)
|
||||
let account = self.account
|
||||
let signal = requestRevenueStats(postbox: self.account.postbox, network: self.account.network, peerId: self.peerId)
|
||||
|> mapToSignal { initial -> Signal<RevenueStats?, NoError> in
|
||||
guard let initial else {
|
||||
return .single(nil)
|
||||
}
|
||||
return .single(initial)
|
||||
|> then(
|
||||
account.stateManager.updatedRevenueBalances()
|
||||
|> map { balances in
|
||||
return initial.withUpdated(balances: balances)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
self.disposable.set((signal
|
||||
|> deliverOnMainQueue).start(next: { [weak self] stats in
|
||||
if let strongSelf = self {
|
||||
strongSelf._state = RevenueStatsContextState(stats: stats)
|
||||
@ -134,7 +160,7 @@ private final class RevenueStatsContextImpl {
|
||||
|
||||
func loadDetailedGraph(_ graph: StatsGraph, x: Int64) -> Signal<StatsGraph?, NoError> {
|
||||
if let token = graph.token {
|
||||
return requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token, x: x)
|
||||
return requestGraph(postbox: self.account.postbox, network: self.account.network, peerId: self.peerId, token: token, x: x)
|
||||
} else {
|
||||
return .single(nil)
|
||||
}
|
||||
@ -156,9 +182,9 @@ public final class RevenueStatsContext {
|
||||
}
|
||||
}
|
||||
|
||||
public init(postbox: Postbox, network: Network, peerId: PeerId) {
|
||||
public init(account: Account, peerId: PeerId) {
|
||||
self.impl = QueueLocalObject(queue: Queue.mainQueue(), generate: {
|
||||
return RevenueStatsContextImpl(postbox: postbox, network: network, peerId: peerId)
|
||||
return RevenueStatsContextImpl(account: account, peerId: peerId)
|
||||
})
|
||||
}
|
||||
|
||||
@ -187,6 +213,7 @@ private final class RevenueStatsTransactionsContextImpl {
|
||||
private let account: Account
|
||||
private let peerId: EnginePeer.Id
|
||||
private let disposable = MetaDisposable()
|
||||
private var updateDisposable: Disposable?
|
||||
private var isLoadingMore: Bool = false
|
||||
private var hasLoadedOnce: Bool = false
|
||||
private var canLoadMore: Bool = true
|
||||
@ -204,13 +231,21 @@ private final class RevenueStatsTransactionsContextImpl {
|
||||
self.count = 0
|
||||
|
||||
self.loadMore()
|
||||
|
||||
self.updateDisposable = (account.stateManager.updatedRevenueBalances()
|
||||
|> deliverOn(self.queue)).startStrict(next: { [weak self] _ in
|
||||
self?.reload()
|
||||
})
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.disposable.dispose()
|
||||
self.updateDisposable?.dispose()
|
||||
}
|
||||
|
||||
func reload() {
|
||||
self.lastOffset = nil
|
||||
|
||||
self.loadMore()
|
||||
}
|
||||
|
||||
|
@ -31,16 +31,16 @@ private enum MembersActionType: Hashable, CaseIterable {
|
||||
case newMembers
|
||||
case leftMembers
|
||||
|
||||
func title(strings: PresentationStrings) -> String {
|
||||
func title(isGroup: Bool, strings: PresentationStrings) -> String {
|
||||
switch self {
|
||||
case .newAdminRights:
|
||||
return "New Admin Rights"
|
||||
return strings.Channel_AdminLogFilter_EventsAdminRights
|
||||
case .newExceptions:
|
||||
return "New Exceptions"
|
||||
return strings.Channel_AdminLogFilter_EventsExceptions
|
||||
case .newMembers:
|
||||
return "New Members"
|
||||
return isGroup ? strings.Channel_AdminLogFilter_EventsNewMembers : strings.Channel_AdminLogFilter_EventsNewSubscribers
|
||||
case .leftMembers:
|
||||
return "Members left the Group"
|
||||
return isGroup ? strings.Channel_AdminLogFilter_EventsLeavingGroup : strings.Channel_AdminLogFilter_EventsLeavingChannel
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,7 +152,7 @@ private enum ActionType: Hashable {
|
||||
func title(isGroup: Bool, strings: PresentationStrings) -> String {
|
||||
switch self {
|
||||
case let .members(value):
|
||||
return value.title(strings: strings)
|
||||
return value.title(isGroup: isGroup, strings: strings)
|
||||
case let .settings(value):
|
||||
return value.title(isGroup: isGroup, strings: strings)
|
||||
case let .messages(value):
|
||||
@ -515,15 +515,15 @@ private final class RecentActionsSettingsSheetComponent: Component {
|
||||
case .members:
|
||||
totalCount = MembersActionType.allCases.count
|
||||
selectedCount = self.selectedMembersActions.count
|
||||
title = isGroup ? "Members and Admins" : "Subscribers and Admins"
|
||||
title = isGroup ? environment.strings.Channel_AdminLogFilter_Section_MembersGroup : environment.strings.Channel_AdminLogFilter_Section_MembersChannel
|
||||
case .settings:
|
||||
totalCount = SettingsActionType.allCases.count
|
||||
selectedCount = self.selectedSettingsActions.count
|
||||
title = isGroup ? "Group Settings" : "Channel Settings"
|
||||
title = isGroup ? environment.strings.Channel_AdminLogFilter_Section_SettingsGroup : environment.strings.Channel_AdminLogFilter_Section_SettingsChannel
|
||||
case .messages:
|
||||
totalCount = MessagesActionType.allCases.count
|
||||
selectedCount = self.selectedMessagesActions.count
|
||||
title = "Messages"
|
||||
title = environment.strings.Channel_AdminLogFilter_Section_Messages
|
||||
}
|
||||
|
||||
let itemTitle: AnyComponent<Empty> = AnyComponent(HStack([
|
||||
@ -575,7 +575,7 @@ private final class RecentActionsSettingsSheetComponent: Component {
|
||||
theme: environment.theme,
|
||||
title: itemTitle,
|
||||
leftIcon: .check(ListActionItemComponent.LeftIcon.Check(
|
||||
isSelected: selectedCount != 0,
|
||||
isSelected: selectedCount == totalCount,
|
||||
toggle: {
|
||||
toggleAction()
|
||||
}
|
||||
@ -684,8 +684,7 @@ private final class RecentActionsSettingsSheetComponent: Component {
|
||||
)))
|
||||
}
|
||||
|
||||
//TODO:localize
|
||||
let titleString: String = "Recent Actions"
|
||||
let titleString: String = environment.strings.Channel_AdminLogFilter_RecentActionsTitle
|
||||
let titleSize = self.title.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(MultilineTextComponent(
|
||||
@ -722,7 +721,7 @@ private final class RecentActionsSettingsSheetComponent: Component {
|
||||
theme: environment.theme,
|
||||
header: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: "FILTER ACTIONS BY TYPE",
|
||||
string: environment.strings.Channel_AdminLogFilter_FilterActionsTypeTitle,
|
||||
font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize),
|
||||
textColor: environment.theme.list.freeTextColor
|
||||
)),
|
||||
@ -790,7 +789,7 @@ private final class RecentActionsSettingsSheetComponent: Component {
|
||||
title: AnyComponent(VStack([
|
||||
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: "Show Actions by All Admins",
|
||||
string: environment.strings.Channel_AdminLogFilter_ShowAllAdminsActions,
|
||||
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
|
||||
textColor: environment.theme.list.itemPrimaryTextColor
|
||||
)),
|
||||
@ -798,7 +797,7 @@ private final class RecentActionsSettingsSheetComponent: Component {
|
||||
))),
|
||||
], alignment: .left, spacing: 2.0)),
|
||||
leftIcon: .check(ListActionItemComponent.LeftIcon.Check(
|
||||
isSelected: !self.selectedAdmins.isEmpty,
|
||||
isSelected: self.selectedAdmins.count == component.adminPeers.count,
|
||||
toggle: {
|
||||
allAdminsToggleAction()
|
||||
}
|
||||
@ -821,7 +820,7 @@ private final class RecentActionsSettingsSheetComponent: Component {
|
||||
theme: environment.theme,
|
||||
header: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: "FILTER ACTIONS BY ADMINS",
|
||||
string: environment.strings.Channel_AdminLogFilter_FilterActionsAdminsTitle,
|
||||
font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize),
|
||||
textColor: environment.theme.list.freeTextColor
|
||||
)),
|
||||
@ -856,7 +855,7 @@ private final class RecentActionsSettingsSheetComponent: Component {
|
||||
content: AnyComponentWithIdentity(
|
||||
id: AnyHashable(0),
|
||||
component: AnyComponent(ButtonTextContentComponent(
|
||||
text: "Apply Filter",
|
||||
text: environment.strings.Channel_AdminLogFilter_ApplyFilter,
|
||||
badge: 0,
|
||||
textColor: environment.theme.list.itemCheckColors.foregroundColor,
|
||||
badgeBackground: environment.theme.list.itemCheckColors.foregroundColor,
|
||||
|
@ -2244,13 +2244,15 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
|
||||
private let deletedMessagesDisplayedLimit = 5
|
||||
|
||||
func chatRecentActionsEntries(entries: [ChannelAdminEventLogEntry], presentationData: ChatPresentationData, expandedDeletedMessages: Set<EngineMessage.Id>) -> [ChatRecentActionsEntry] {
|
||||
var result: [ChatRecentActionsEntry] = []
|
||||
var deleteMessageEntries: [ChannelAdminEventLogEntry] = []
|
||||
|
||||
func appendCurrentDeleteEntries() {
|
||||
if !deleteMessageEntries.isEmpty, let lastEntry = deleteMessageEntries.last, let lastMessageId = lastEntry.event.action.messageId {
|
||||
let isExpandable = deleteMessageEntries.count > 10
|
||||
let isExpandable = deleteMessageEntries.count > deletedMessagesDisplayedLimit
|
||||
let isExpanded = expandedDeletedMessages.contains(lastMessageId) || !isExpandable
|
||||
let isGroup = deleteMessageEntries.count > 1
|
||||
|
||||
|
@ -13097,7 +13097,7 @@ public func presentAddMembersImpl(context: AccountContext, updatedPresentationDa
|
||||
}, clearHighlightAutomatically: true))
|
||||
}
|
||||
|
||||
let contactsController = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, updatedPresentationData: updatedPresentationData, mode: .peerSelection(searchChatList: false, searchGroups: false, searchChannels: false), options: options, filters: [.excludeSelf, .disable(recentIds)], onlyWriteable: true, isGroupInvitation: true))
|
||||
let contactsController = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, updatedPresentationData: updatedPresentationData, mode: .peerSelection(searchChatList: false, searchGroups: false, searchChannels: false), options: .single(options), filters: [.excludeSelf, .disable(recentIds)], onlyWriteable: true, isGroupInvitation: true))
|
||||
contactsController.navigationPresentation = .modal
|
||||
|
||||
confirmationImpl = { [weak contactsController] peerId in
|
||||
|
@ -384,7 +384,7 @@ final class AutomaticBusinessMessageSetupScreenComponent: Component {
|
||||
additionalCategories: ContactMultiselectionControllerAdditionalCategories(categories: additionalCategories, selectedCategories: selectedCategories),
|
||||
chatListFilters: nil,
|
||||
onlyUsers: true
|
||||
)), options: [], filters: [], alwaysEnabled: true, limit: 100, reachedLimit: { _ in
|
||||
)), filters: [], alwaysEnabled: true, limit: 100, reachedLimit: { _ in
|
||||
}))
|
||||
controller.navigationPresentation = .modal
|
||||
|
||||
|
@ -242,7 +242,7 @@ final class BusinessRecipientListScreenComponent: Component {
|
||||
additionalCategories: ContactMultiselectionControllerAdditionalCategories(categories: additionalCategories, selectedCategories: selectedCategories),
|
||||
chatListFilters: nil,
|
||||
onlyUsers: true
|
||||
)), options: [], filters: [], alwaysEnabled: true, limit: 100, reachedLimit: { _ in
|
||||
)), filters: [], alwaysEnabled: true, limit: 100, reachedLimit: { _ in
|
||||
}))
|
||||
controller.navigationPresentation = .modal
|
||||
|
||||
|
@ -4156,7 +4156,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if case .user = peerType, maxQuantity > 1 {
|
||||
let presentationData = self.presentationData
|
||||
var reachedLimitImpl: ((Int32) -> Void)?
|
||||
let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .requestedUsersSelection, options: [], isPeerEnabled: { peer in
|
||||
let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .requestedUsersSelection, isPeerEnabled: { peer in
|
||||
if case let .user(user) = peer, user.botInfo == nil {
|
||||
return true
|
||||
} else {
|
||||
|
@ -124,7 +124,7 @@ public class ComposeControllerImpl: ViewController, ComposeController {
|
||||
|
||||
self.contactsNode.openCreateNewGroup = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
let controller = strongSelf.context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: strongSelf.context, mode: .groupCreation, options: [], onlyWriteable: true))
|
||||
let controller = strongSelf.context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: strongSelf.context, mode: .groupCreation, onlyWriteable: true))
|
||||
(strongSelf.navigationController as? NavigationController)?.pushViewController(controller, completion: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.contactsNode.contactListNode.listNode.clearHighlightAnimated(true)
|
||||
|
@ -81,7 +81,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
|
||||
private var limitsConfiguration: LimitsConfiguration?
|
||||
private var limitsConfigurationDisposable: Disposable?
|
||||
private var initialPeersDisposable: Disposable?
|
||||
private let options: [ContactListAdditionalOption]
|
||||
private let options: Signal<[ContactListAdditionalOption], NoError>
|
||||
private let filters: [ContactListFilter]
|
||||
private let onlyWriteable: Bool
|
||||
private let isGroupInvitation: Bool
|
||||
|
@ -82,7 +82,7 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
||||
private let onlyWriteable: Bool
|
||||
private let isGroupInvitation: Bool
|
||||
|
||||
init(navigationBar: NavigationBar?, context: AccountContext, presentationData: PresentationData, mode: ContactMultiselectionControllerMode, isPeerEnabled: ((EnginePeer) -> Bool)?, attemptDisabledItemSelection: ((EnginePeer, ChatListDisabledPeerReason) -> Void)?, options: [ContactListAdditionalOption], filters: [ContactListFilter], onlyWriteable: Bool, isGroupInvitation: Bool, limit: Int32?, reachedSelectionLimit: ((Int32) -> Void)?, present: @escaping (ViewController, Any?) -> Void) {
|
||||
init(navigationBar: NavigationBar?, context: AccountContext, presentationData: PresentationData, mode: ContactMultiselectionControllerMode, isPeerEnabled: ((EnginePeer) -> Bool)?, attemptDisabledItemSelection: ((EnginePeer, ChatListDisabledPeerReason) -> Void)?, options: Signal<[ContactListAdditionalOption], NoError>, filters: [ContactListFilter], onlyWriteable: Bool, isGroupInvitation: Bool, limit: Int32?, reachedSelectionLimit: ((Int32) -> Void)?, present: @escaping (ViewController, Any?) -> Void) {
|
||||
self.navigationBar = navigationBar
|
||||
|
||||
self.context = context
|
||||
@ -235,7 +235,13 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
||||
} else {
|
||||
displayTopPeers = .none
|
||||
}
|
||||
let contactListNode = ContactListNode(context: context, presentation: .single(.natural(options: options, includeChatList: includeChatList, topPeers: displayTopPeers)), filters: filters, onlyWriteable: onlyWriteable, isGroupInvitation: isGroupInvitation, selectionState: ContactListNodeGroupSelectionState())
|
||||
|
||||
let presentation: Signal<ContactListPresentation, NoError> = options
|
||||
|> map { options in
|
||||
return .natural(options: options, includeChatList: includeChatList, topPeers: displayTopPeers)
|
||||
}
|
||||
|
||||
let contactListNode = ContactListNode(context: context, presentation: presentation, filters: filters, onlyWriteable: onlyWriteable, isGroupInvitation: isGroupInvitation, selectionState: ContactListNodeGroupSelectionState())
|
||||
self.contentNode = .contacts(contactListNode)
|
||||
|
||||
if !selectedPeers.isEmpty {
|
||||
|
@ -2165,16 +2165,26 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
mode = .premiumGifting(birthdays: nil, selectToday: false)
|
||||
}
|
||||
|
||||
var contactOptions: [ContactListAdditionalOption] = []
|
||||
let contactOptions: Signal<[ContactListAdditionalOption], NoError>
|
||||
if currentBirthdays != nil || "".isEmpty {
|
||||
contactOptions = [ContactListAdditionalOption(
|
||||
title: "Add Your Birthday",
|
||||
icon: .generic(UIImage(bundleImageName: "Contact List/AddBirthdayIcon")!),
|
||||
action: {
|
||||
presentBirthdayPickerImpl?()
|
||||
},
|
||||
clearHighlightAutomatically: true
|
||||
)]
|
||||
contactOptions = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Birthday(id: context.account.peerId))
|
||||
|> map { birthday in
|
||||
if birthday == nil {
|
||||
return [ContactListAdditionalOption(
|
||||
title: presentationData.strings.Premium_Gift_ContactSelection_AddBirthday,
|
||||
icon: .generic(UIImage(bundleImageName: "Contact List/AddBirthdayIcon")!),
|
||||
action: {
|
||||
presentBirthdayPickerImpl?()
|
||||
},
|
||||
clearHighlightAutomatically: true
|
||||
)]
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|> deliverOnMainQueue
|
||||
} else {
|
||||
contactOptions = .single([])
|
||||
}
|
||||
|
||||
var openProfileImpl: ((EnginePeer) -> Void)?
|
||||
|
Loading…
x
Reference in New Issue
Block a user