Update API

This commit is contained in:
Ilya Laktyushin 2024-03-19 01:53:18 +04:00
parent 8279db283c
commit 562d4e6598
16 changed files with 216 additions and 123 deletions

View File

@ -11619,3 +11619,9 @@ Sorry for the inconvenience.";
"WebApp.TermsOfUse" = "Terms of Use"; "WebApp.TermsOfUse" = "Terms of Use";
"WebApp.TermsOfUse_URL" = "https://telegram.org/tos/mini-apps"; "WebApp.TermsOfUse_URL" = "https://telegram.org/tos/mini-apps";
"Privacy.Birthday" = "Date of Birth";
"Privacy.Birthday.WhoCanSeeMyBio" = "WHO CAN SEE MY DATE OF BIRTH";
"Privacy.Birthday.CustomHelp" = "You can restrict who can see your date of birth with granular precision.";
"Privacy.Birthday.AlwaysShareWith.Title" = "Always Share With";
"Privacy.Birthday.NeverShareWith.Title" = "Never Share With";

View File

@ -2314,7 +2314,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
} }
})) }))
self.suggestAutoarchiveDisposable.set((getServerProvidedSuggestions(account: self.context.account) self.suggestAutoarchiveDisposable.set((self.context.engine.notices.getServerProvidedSuggestions()
|> deliverOnMainQueue).startStrict(next: { [weak self] values in |> deliverOnMainQueue).startStrict(next: { [weak self] values in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
@ -2331,13 +2331,13 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
strongSelf.dismissAutoarchiveDisposable.set(dismissServerProvidedSuggestion(account: strongSelf.context.account, suggestion: .autoarchivePopular).startStrict()) strongSelf.dismissAutoarchiveDisposable.set(strongSelf.context.engine.notices.dismissServerProvidedSuggestion(suggestion: .autoarchivePopular).startStrict())
}), }),
TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.ChatList_AutoarchiveSuggestion_OpenSettings, action: { TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.ChatList_AutoarchiveSuggestion_OpenSettings, action: {
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
strongSelf.dismissAutoarchiveDisposable.set(dismissServerProvidedSuggestion(account: strongSelf.context.account, suggestion: .autoarchivePopular).startStrict()) strongSelf.dismissAutoarchiveDisposable.set(strongSelf.context.engine.notices.dismissServerProvidedSuggestion(suggestion: .autoarchivePopular).startStrict())
strongSelf.push(strongSelf.context.sharedContext.makePrivacyAndSecurityController(context: strongSelf.context)) strongSelf.push(strongSelf.context.sharedContext.makePrivacyAndSecurityController(context: strongSelf.context))
}) })
], actionLayout: .vertical, parseMarkdown: true), in: .window(.root)) ], actionLayout: .vertical, parseMarkdown: true), in: .window(.root))

View File

@ -738,7 +738,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
nodeInteraction?.openPremiumGift([]) nodeInteraction?.openPremiumGift([])
case .setupBirthday: case .setupBirthday:
nodeInteraction?.openBirthdaySetup() nodeInteraction?.openBirthdaySetup()
case let .birthdayPremiumGift(peers): case let .birthdayPremiumGift(peers, _):
nodeInteraction?.openPremiumGift(peers.map { $0.id }) nodeInteraction?.openPremiumGift(peers.map { $0.id })
case .reviewLogin: case .reviewLogin:
break break
@ -1074,7 +1074,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
nodeInteraction?.openPremiumGift([]) nodeInteraction?.openPremiumGift([])
case .setupBirthday: case .setupBirthday:
nodeInteraction?.openBirthdaySetup() nodeInteraction?.openBirthdaySetup()
case let .birthdayPremiumGift(peers): case let .birthdayPremiumGift(peers, _):
nodeInteraction?.openPremiumGift(peers.map { $0.id }) nodeInteraction?.openPremiumGift(peers.map { $0.id })
case .reviewLogin: case .reviewLogin:
break break
@ -1675,7 +1675,7 @@ public final class ChatListNode: ListView {
} }
Queue.mainQueue().after(0.6) { [weak self] in Queue.mainQueue().after(0.6) { [weak self] in
if let self { if let self {
let _ = dismissServerProvidedSuggestion(account: self.context.account, suggestion: .setupPassword).startStandalone() let _ = self.context.engine.notices.dismissServerProvidedSuggestion(suggestion: .setupPassword).startStandalone()
} }
} }
let controller = self.context.sharedContext.makeSetupTwoFactorAuthController(context: self.context) let controller = self.context.sharedContext.makeSetupTwoFactorAuthController(context: self.context)
@ -1686,9 +1686,9 @@ public final class ChatListNode: ListView {
} }
Queue.mainQueue().after(0.6) { [weak self] in Queue.mainQueue().after(0.6) { [weak self] in
if let self { if let self {
let _ = dismissServerProvidedSuggestion(account: self.context.account, suggestion: .annualPremium).startStandalone() let _ = self.context.engine.notices.dismissServerProvidedSuggestion(suggestion: .annualPremium).startStandalone()
let _ = dismissServerProvidedSuggestion(account: self.context.account, suggestion: .upgradePremium).startStandalone() let _ = self.context.engine.notices.dismissServerProvidedSuggestion(suggestion: .upgradePremium).startStandalone()
let _ = dismissServerProvidedSuggestion(account: self.context.account, suggestion: .restorePremium).startStandalone() let _ = self.context.engine.notices.dismissServerProvidedSuggestion(suggestion: .restorePremium).startStandalone()
} }
} }
let controller = self.context.sharedContext.makePremiumIntroController(context: self.context, source: .ads, forceDark: false, dismissed: nil) let controller = self.context.sharedContext.makePremiumIntroController(context: self.context, source: .ads, forceDark: false, dismissed: nil)
@ -1794,13 +1794,13 @@ public final class ChatListNode: ListView {
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 } let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
switch notice { switch notice {
case .xmasPremiumGift: case .xmasPremiumGift:
let _ = dismissServerProvidedSuggestion(account: self.context.account, suggestion: .xmasPremiumGift).startStandalone() let _ = self.context.engine.notices.dismissServerProvidedSuggestion(suggestion: .xmasPremiumGift).startStandalone()
self.present?(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: presentationData.strings.ChatList_PremiumGiftInSettingsInfo, timeout: 5.0, customUndoText: nil), elevatedLayout: false, action: { _ in self.present?(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: presentationData.strings.ChatList_PremiumGiftInSettingsInfo, timeout: 5.0, customUndoText: nil), elevatedLayout: false, action: { _ in
return true return true
})) }))
case .setupBirthday: case .setupBirthday:
//TODO:localize //TODO:localize
let _ = dismissServerProvidedSuggestion(account: self.context.account, suggestion: .setupBirthday).startStandalone() let _ = self.context.engine.notices.dismissServerProvidedSuggestion(suggestion: .setupBirthday).startStandalone()
self.present?(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: presentationData.strings.ChatList_PremiumGiftInSettingsInfo, timeout: 5.0, customUndoText: nil), elevatedLayout: false, action: { _ in self.present?(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: presentationData.strings.ChatList_PremiumGiftInSettingsInfo, timeout: 5.0, customUndoText: nil), elevatedLayout: false, action: { _ in
return true return true
})) }))
@ -1896,11 +1896,12 @@ public final class ChatListNode: ListView {
let twoStepData: Signal<TwoStepVerificationConfiguration?, NoError> = .single(nil) |> then(context.engine.auth.twoStepVerificationConfiguration() |> map(Optional.init)) let twoStepData: Signal<TwoStepVerificationConfiguration?, NoError> = .single(nil) |> then(context.engine.auth.twoStepVerificationConfiguration() |> map(Optional.init))
let suggestedChatListNoticeSignal: Signal<ChatListNotice?, NoError> = combineLatest( let suggestedChatListNoticeSignal: Signal<ChatListNotice?, NoError> = combineLatest(
getServerProvidedSuggestions(account: context.account), context.engine.notices.getServerProvidedSuggestions(),
twoStepData, twoStepData,
newSessionReviews(postbox: context.account.postbox) newSessionReviews(postbox: context.account.postbox),
context.account.stateManager.contactBirthdays
) )
|> mapToSignal { suggestions, configuration, newSessionReviews -> Signal<ChatListNotice?, NoError> in |> mapToSignal { suggestions, configuration, newSessionReviews, birthdays -> Signal<ChatListNotice?, NoError> in
if let newSessionReview = newSessionReviews.first { if let newSessionReview = newSessionReviews.first {
return .single(.reviewLogin(newSessionReview: newSessionReview, totalCount: newSessionReviews.count)) return .single(.reviewLogin(newSessionReview: newSessionReview, totalCount: newSessionReviews.count))
} }
@ -1919,15 +1920,20 @@ public final class ChatListNode: ListView {
} }
} }
if suggestions.contains(.setupBirthday) { if suggestions.contains(.setupBirthday) {
return context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId)) return .single(.setupBirthday)
|> map { peer in } else if !birthdays.isEmpty {
if let peer { return context.engine.data.get(
return .birthdayPremiumGift(peers: [peer]) EngineDataMap(birthdays.keys.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:)))
} else { )
return .setupBirthday |> map { result -> ChatListNotice? in
var peers: [EnginePeer] = []
for (peerId, _) in birthdays {
if let maybePeer = result[peerId], let peer = maybePeer {
peers.append(peer)
}
} }
return .birthdayPremiumGift(peers: peers, birthdays: birthdays)
} }
//return .single(.setupBirthday)
} else if suggestions.contains(.xmasPremiumGift) { } else if suggestions.contains(.xmasPremiumGift) {
return .single(.xmasPremiumGift) return .single(.xmasPremiumGift)
} else if suggestions.contains(.annualPremium) || suggestions.contains(.upgradePremium) || suggestions.contains(.restorePremium), let inAppPurchaseManager = context.inAppPurchaseManager { } else if suggestions.contains(.annualPremium) || suggestions.contains(.upgradePremium) || suggestions.contains(.restorePremium), let inAppPurchaseManager = context.inAppPurchaseManager {

View File

@ -87,7 +87,7 @@ public enum ChatListNotice: Equatable {
case premiumRestore(discount: Int32) case premiumRestore(discount: Int32)
case xmasPremiumGift case xmasPremiumGift
case setupBirthday case setupBirthday
case birthdayPremiumGift(peers: [EnginePeer]) case birthdayPremiumGift(peers: [EnginePeer], birthdays: [EnginePeer.Id: TelegramBirthday])
case reviewLogin(newSessionReview: NewSessionReview, totalCount: Int) case reviewLogin(newSessionReview: NewSessionReview, totalCount: Int)
} }

View File

@ -228,7 +228,7 @@ class ChatListStorageInfoItemNode: ItemListRevealOptionsItemNode {
//TODO:localize //TODO:localize
titleString = NSAttributedString(string: "Add your birthday! 🎂", font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor) titleString = NSAttributedString(string: "Add your birthday! 🎂", font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor)
textString = NSAttributedString(string: "Let your contacts know when you're celebrating.", font: textFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor) textString = NSAttributedString(string: "Let your contacts know when you're celebrating.", font: textFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
case let .birthdayPremiumGift(peers): case let .birthdayPremiumGift(peers, _):
//TODO:localize //TODO:localize
let title: String let title: String
let text: String let text: String

View File

@ -277,7 +277,7 @@ func changePhoneNumberCodeController(context: AccountContext, phoneNumber: Strin
let presentationData = context.sharedContext.currentPresentationData.with { $0 } let presentationData = context.sharedContext.currentPresentationData.with { $0 }
presentControllerImpl?(OverlayStatusController(theme: presentationData.theme, type: .success), nil) presentControllerImpl?(OverlayStatusController(theme: presentationData.theme, type: .success), nil)
let _ = dismissServerProvidedSuggestion(account: context.account, suggestion: .validatePhoneNumber).start() let _ = context.engine.notices.dismissServerProvidedSuggestion(suggestion: .validatePhoneNumber).start()
dismissImpl?() dismissImpl?()
})) }))

View File

@ -78,7 +78,7 @@ public func ChangePhoneNumberController(context: AccountContext) -> ViewControll
}, completed: { [weak codeController] in }, completed: { [weak codeController] in
codeController?.present(OverlayStatusController(theme: presentationData.theme, type: .success), in: .window(.root)) codeController?.present(OverlayStatusController(theme: presentationData.theme, type: .success), in: .window(.root))
let _ = dismissServerProvidedSuggestion(account: context.account, suggestion: .validatePhoneNumber).start() let _ = context.engine.notices.dismissServerProvidedSuggestion(suggestion: .validatePhoneNumber).start()
if let navigationController = codeController?.navigationController as? NavigationController { if let navigationController = codeController?.navigationController as? NavigationController {
var viewControllers = navigationController.viewControllers var viewControllers = navigationController.viewControllers

View File

@ -31,6 +31,7 @@ private final class PrivacyAndSecurityControllerArguments {
let openPhoneNumberPrivacy: () -> Void let openPhoneNumberPrivacy: () -> Void
let openVoiceMessagePrivacy: () -> Void let openVoiceMessagePrivacy: () -> Void
let openBioPrivacy: () -> Void let openBioPrivacy: () -> Void
let openBirthdayPrivacy: () -> Void
let openPasscode: () -> Void let openPasscode: () -> Void
let openTwoStepVerification: (TwoStepVerificationAccessConfiguration?) -> Void let openTwoStepVerification: (TwoStepVerificationAccessConfiguration?) -> Void
let openActiveSessions: () -> Void let openActiveSessions: () -> Void
@ -41,7 +42,7 @@ private final class PrivacyAndSecurityControllerArguments {
let openEmailSettings: (String?) -> Void let openEmailSettings: (String?) -> Void
let openMessagePrivacy: () -> Void let openMessagePrivacy: () -> Void
init(account: Account, openBlockedUsers: @escaping () -> Void, openLastSeenPrivacy: @escaping () -> Void, openGroupsPrivacy: @escaping () -> Void, openVoiceCallPrivacy: @escaping () -> Void, openProfilePhotoPrivacy: @escaping () -> Void, openForwardPrivacy: @escaping () -> Void, openPhoneNumberPrivacy: @escaping () -> Void, openVoiceMessagePrivacy: @escaping () -> Void, openBioPrivacy: @escaping () -> Void, openPasscode: @escaping () -> Void, openTwoStepVerification: @escaping (TwoStepVerificationAccessConfiguration?) -> Void, openActiveSessions: @escaping () -> Void, toggleArchiveAndMuteNonContacts: @escaping (Bool) -> Void, setupAccountAutoremove: @escaping () -> Void, setupMessageAutoremove: @escaping () -> Void, openDataSettings: @escaping () -> Void, openEmailSettings: @escaping (String?) -> Void, openMessagePrivacy: @escaping () -> Void) { init(account: Account, openBlockedUsers: @escaping () -> Void, openLastSeenPrivacy: @escaping () -> Void, openGroupsPrivacy: @escaping () -> Void, openVoiceCallPrivacy: @escaping () -> Void, openProfilePhotoPrivacy: @escaping () -> Void, openForwardPrivacy: @escaping () -> Void, openPhoneNumberPrivacy: @escaping () -> Void, openVoiceMessagePrivacy: @escaping () -> Void, openBioPrivacy: @escaping () -> Void, openBirthdayPrivacy: @escaping () -> Void, openPasscode: @escaping () -> Void, openTwoStepVerification: @escaping (TwoStepVerificationAccessConfiguration?) -> Void, openActiveSessions: @escaping () -> Void, toggleArchiveAndMuteNonContacts: @escaping (Bool) -> Void, setupAccountAutoremove: @escaping () -> Void, setupMessageAutoremove: @escaping () -> Void, openDataSettings: @escaping () -> Void, openEmailSettings: @escaping (String?) -> Void, openMessagePrivacy: @escaping () -> Void) {
self.account = account self.account = account
self.openBlockedUsers = openBlockedUsers self.openBlockedUsers = openBlockedUsers
self.openLastSeenPrivacy = openLastSeenPrivacy self.openLastSeenPrivacy = openLastSeenPrivacy
@ -52,6 +53,7 @@ private final class PrivacyAndSecurityControllerArguments {
self.openPhoneNumberPrivacy = openPhoneNumberPrivacy self.openPhoneNumberPrivacy = openPhoneNumberPrivacy
self.openVoiceMessagePrivacy = openVoiceMessagePrivacy self.openVoiceMessagePrivacy = openVoiceMessagePrivacy
self.openBioPrivacy = openBioPrivacy self.openBioPrivacy = openBioPrivacy
self.openBirthdayPrivacy = openBirthdayPrivacy
self.openPasscode = openPasscode self.openPasscode = openPasscode
self.openTwoStepVerification = openTwoStepVerification self.openTwoStepVerification = openTwoStepVerification
self.openActiveSessions = openActiveSessions self.openActiveSessions = openActiveSessions
@ -99,6 +101,7 @@ private enum PrivacyAndSecurityEntry: ItemListNodeEntry {
case voiceMessagePrivacy(PresentationTheme, String, String, Bool) case voiceMessagePrivacy(PresentationTheme, String, String, Bool)
case messagePrivacy(PresentationTheme, Bool, Bool) case messagePrivacy(PresentationTheme, Bool, Bool)
case bioPrivacy(PresentationTheme, String, String) case bioPrivacy(PresentationTheme, String, String)
case birthdayPrivacy(PresentationTheme, String, String)
case selectivePrivacyInfo(PresentationTheme, String) case selectivePrivacyInfo(PresentationTheme, String)
case passcode(PresentationTheme, String, Bool, String) case passcode(PresentationTheme, String, Bool, String)
case twoStepVerification(PresentationTheme, String, String, TwoStepVerificationAccessConfiguration?) case twoStepVerification(PresentationTheme, String, String, TwoStepVerificationAccessConfiguration?)
@ -120,7 +123,7 @@ private enum PrivacyAndSecurityEntry: ItemListNodeEntry {
switch self { switch self {
case .blockedPeers, .activeSessions, .passcode, .twoStepVerification, .loginEmail, .loginEmailInfo, .messageAutoremoveTimeout, .messageAutoremoveInfo: case .blockedPeers, .activeSessions, .passcode, .twoStepVerification, .loginEmail, .loginEmailInfo, .messageAutoremoveTimeout, .messageAutoremoveInfo:
return PrivacyAndSecuritySection.general.rawValue return PrivacyAndSecuritySection.general.rawValue
case .privacyHeader, .phoneNumberPrivacy, .lastSeenPrivacy, .profilePhotoPrivacy, .forwardPrivacy, .groupPrivacy, .voiceCallPrivacy, .voiceMessagePrivacy, .messagePrivacy, .bioPrivacy, .selectivePrivacyInfo: case .privacyHeader, .phoneNumberPrivacy, .lastSeenPrivacy, .profilePhotoPrivacy, .forwardPrivacy, .groupPrivacy, .voiceCallPrivacy, .voiceMessagePrivacy, .messagePrivacy, .bioPrivacy, .birthdayPrivacy, .selectivePrivacyInfo:
return PrivacyAndSecuritySection.privacy.rawValue return PrivacyAndSecuritySection.privacy.rawValue
case .autoArchiveHeader, .autoArchive, .autoArchiveInfo: case .autoArchiveHeader, .autoArchive, .autoArchiveInfo:
return PrivacyAndSecuritySection.autoArchive.rawValue return PrivacyAndSecuritySection.autoArchive.rawValue
@ -159,34 +162,36 @@ private enum PrivacyAndSecurityEntry: ItemListNodeEntry {
return 12 return 12
case .bioPrivacy: case .bioPrivacy:
return 13 return 13
case .forwardPrivacy: case .birthdayPrivacy:
return 14 return 14
case .voiceCallPrivacy: case .forwardPrivacy:
return 15 return 15
case .groupPrivacy: case .voiceCallPrivacy:
return 16 return 16
case .voiceMessagePrivacy: case .groupPrivacy:
return 17 return 17
case .messagePrivacy: case .voiceMessagePrivacy:
return 18 return 18
case .selectivePrivacyInfo: case .messagePrivacy:
return 19 return 19
case .autoArchiveHeader: case .selectivePrivacyInfo:
return 20 return 20
case .autoArchive: case .autoArchiveHeader:
return 21 return 21
case .autoArchiveInfo: case .autoArchive:
return 22 return 22
case .autoArchiveInfo:
return 23
case .accountHeader: case .accountHeader:
return 25 return 24
case .accountTimeout: case .accountTimeout:
return 26 return 25
case .accountInfo: case .accountInfo:
return 27 return 26
case .dataSettings: case .dataSettings:
return 28 return 27
case .dataSettingsInfo: case .dataSettingsInfo:
return 29 return 28
} }
} }
@ -258,6 +263,12 @@ private enum PrivacyAndSecurityEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .birthdayPrivacy(lhsTheme, lhsText, lhsValue):
if case let .birthdayPrivacy(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .selectivePrivacyInfo(lhsTheme, lhsText): case let .selectivePrivacyInfo(lhsTheme, lhsText):
if case let .selectivePrivacyInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { if case let .selectivePrivacyInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true return true
@ -402,6 +413,10 @@ private enum PrivacyAndSecurityEntry: ItemListNodeEntry {
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, action: { return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, action: {
arguments.openBioPrivacy() arguments.openBioPrivacy()
}) })
case let .birthdayPrivacy(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, action: {
arguments.openBirthdayPrivacy()
})
case let .selectivePrivacyInfo(_, text): case let .selectivePrivacyInfo(_, text):
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section) return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
case let .voiceCallPrivacy(_, text, value): case let .voiceCallPrivacy(_, text, value):
@ -612,6 +627,7 @@ private func privacyAndSecurityControllerEntries(
entries.append(.lastSeenPrivacy(presentationData.theme, presentationData.strings.PrivacySettings_LastSeen, stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.presence))) entries.append(.lastSeenPrivacy(presentationData.theme, presentationData.strings.PrivacySettings_LastSeen, stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.presence)))
entries.append(.profilePhotoPrivacy(presentationData.theme, presentationData.strings.Privacy_ProfilePhoto, stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.profilePhoto))) entries.append(.profilePhotoPrivacy(presentationData.theme, presentationData.strings.Privacy_ProfilePhoto, stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.profilePhoto)))
entries.append(.bioPrivacy(presentationData.theme, presentationData.strings.Privacy_Bio, stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.bio))) entries.append(.bioPrivacy(presentationData.theme, presentationData.strings.Privacy_Bio, stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.bio)))
entries.append(.birthdayPrivacy(presentationData.theme, presentationData.strings.Privacy_Birthday, stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.birthday)))
entries.append(.forwardPrivacy(presentationData.theme, presentationData.strings.Privacy_Forwards, stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.forwards))) entries.append(.forwardPrivacy(presentationData.theme, presentationData.strings.Privacy_Forwards, stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.forwards)))
entries.append(.voiceCallPrivacy(presentationData.theme, presentationData.strings.Privacy_Calls, stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.voiceCalls))) entries.append(.voiceCallPrivacy(presentationData.theme, presentationData.strings.Privacy_Calls, stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.voiceCalls)))
entries.append(.groupPrivacy(presentationData.theme, presentationData.strings.Privacy_GroupsAndChannels, stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.groupInvitations))) entries.append(.groupPrivacy(presentationData.theme, presentationData.strings.Privacy_GroupsAndChannels, stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.groupInvitations)))
@ -624,6 +640,7 @@ private func privacyAndSecurityControllerEntries(
entries.append(.lastSeenPrivacy(presentationData.theme, presentationData.strings.PrivacySettings_LastSeen, presentationData.strings.Channel_NotificationLoading)) entries.append(.lastSeenPrivacy(presentationData.theme, presentationData.strings.PrivacySettings_LastSeen, presentationData.strings.Channel_NotificationLoading))
entries.append(.profilePhotoPrivacy(presentationData.theme, presentationData.strings.Privacy_ProfilePhoto, presentationData.strings.Channel_NotificationLoading)) entries.append(.profilePhotoPrivacy(presentationData.theme, presentationData.strings.Privacy_ProfilePhoto, presentationData.strings.Channel_NotificationLoading))
entries.append(.bioPrivacy(presentationData.theme, presentationData.strings.Privacy_GroupsAndChannels, presentationData.strings.Channel_NotificationLoading)) entries.append(.bioPrivacy(presentationData.theme, presentationData.strings.Privacy_GroupsAndChannels, presentationData.strings.Channel_NotificationLoading))
entries.append(.birthdayPrivacy(presentationData.theme, presentationData.strings.Privacy_Birthday, presentationData.strings.Channel_NotificationLoading))
entries.append(.forwardPrivacy(presentationData.theme, presentationData.strings.Privacy_Forwards, presentationData.strings.Channel_NotificationLoading)) entries.append(.forwardPrivacy(presentationData.theme, presentationData.strings.Privacy_Forwards, presentationData.strings.Channel_NotificationLoading))
entries.append(.voiceCallPrivacy(presentationData.theme, presentationData.strings.Privacy_Calls, presentationData.strings.Channel_NotificationLoading)) entries.append(.voiceCallPrivacy(presentationData.theme, presentationData.strings.Privacy_Calls, presentationData.strings.Channel_NotificationLoading))
entries.append(.groupPrivacy(presentationData.theme, presentationData.strings.Privacy_GroupsAndChannels, presentationData.strings.Channel_NotificationLoading)) entries.append(.groupPrivacy(presentationData.theme, presentationData.strings.Privacy_GroupsAndChannels, presentationData.strings.Channel_NotificationLoading))
@ -1011,6 +1028,29 @@ public func privacyAndSecurityController(
}), true) }), true)
} }
})) }))
}, openBirthdayPrivacy: {
let signal = privacySettingsPromise.get()
|> take(1)
|> deliverOnMainQueue
currentInfoDisposable.set(signal.start(next: { [weak currentInfoDisposable] info in
if let info = info {
pushControllerImpl?(selectivePrivacySettingsController(context: context, kind: .birthday, current: info.birthday, updated: { updated, _, updatedDiscoveryEnabled, _ in
if let currentInfoDisposable = currentInfoDisposable {
let applySetting: Signal<Void, NoError> = privacySettingsPromise.get()
|> filter { $0 != nil }
|> take(1)
|> deliverOnMainQueue
|> mapToSignal { value -> Signal<Void, NoError> in
if let value = value {
privacySettingsPromise.set(.single(AccountPrivacySettings(presence: value.presence, groupInvitations: value.groupInvitations, voiceCalls: value.voiceCalls, voiceCallsP2P: value.voiceCallsP2P, profilePhoto: value.profilePhoto, forwards: value.forwards, phoneNumber: value.phoneNumber, phoneDiscoveryEnabled: value.phoneDiscoveryEnabled, voiceMessages: value.voiceMessages, bio: value.bio, birthday: updated, globalSettings: value.globalSettings, accountRemovalTimeout: value.accountRemovalTimeout, messageAutoremoveTimeout: value.messageAutoremoveTimeout)))
}
return .complete()
}
currentInfoDisposable.set(applySetting.start())
}
}), true)
}
}))
}, openPasscode: { }, openPasscode: {
let _ = passcodeOptionsAccessController(context: context, pushController: { controller in let _ = passcodeOptionsAccessController(context: context, pushController: { controller in
replaceTopControllerImpl?(controller) replaceTopControllerImpl?(controller)

View File

@ -21,6 +21,7 @@ enum SelectivePrivacySettingsKind {
case phoneNumber case phoneNumber
case voiceMessages case voiceMessages
case bio case bio
case birthday
} }
private enum SelectivePrivacySettingType { private enum SelectivePrivacySettingType {
@ -789,6 +790,11 @@ private func selectivePrivacySettingsControllerEntries(presentationData: Present
settingInfoText = presentationData.strings.Privacy_Bio_CustomHelp settingInfoText = presentationData.strings.Privacy_Bio_CustomHelp
disableForText = presentationData.strings.PrivacyLastSeenSettings_NeverShareWith disableForText = presentationData.strings.PrivacyLastSeenSettings_NeverShareWith
enableForText = presentationData.strings.PrivacyLastSeenSettings_AlwaysShareWith enableForText = presentationData.strings.PrivacyLastSeenSettings_AlwaysShareWith
case .birthday:
settingTitle = presentationData.strings.Privacy_Birthday_WhoCanSeeMyBio
settingInfoText = presentationData.strings.Privacy_Birthday_CustomHelp
disableForText = presentationData.strings.PrivacyLastSeenSettings_NeverShareWith
enableForText = presentationData.strings.PrivacyLastSeenSettings_AlwaysShareWith
} }
if case .forwards = kind { if case .forwards = kind {
@ -997,7 +1003,6 @@ func selectivePrivacySettingsController(
} }
} }
//TODO:replace hideReadTimeEnabled with actual value
let initialState = SelectivePrivacySettingsControllerState(setting: SelectivePrivacySettingType(current), enableFor: initialEnableFor, enableForPremium: initialEnableForPremium, disableFor: initialDisableFor, enableForCloseFriends: initialEnableForCloseFriends, saving: false, callDataSaving: callSettings?.1.dataSaving, callP2PMode: callSettings != nil ? SelectivePrivacySettingType(callSettings!.0) : nil, callP2PEnableFor: initialCallP2PEnableFor, callP2PDisableFor: initialCallP2PDisableFor, callP2PEnableForCloseFriends: initialCallEnableForCloseFriends, callIntegrationAvailable: callIntegrationAvailable, callIntegrationEnabled: callSettings?.1.enableSystemIntegration, phoneDiscoveryEnabled: phoneDiscoveryEnabled, hideReadTimeEnabled: globalSettings?.hideReadTime, uploadedPhoto: nil) let initialState = SelectivePrivacySettingsControllerState(setting: SelectivePrivacySettingType(current), enableFor: initialEnableFor, enableForPremium: initialEnableForPremium, disableFor: initialDisableFor, enableForCloseFriends: initialEnableForCloseFriends, saving: false, callDataSaving: callSettings?.1.dataSaving, callP2PMode: callSettings != nil ? SelectivePrivacySettingType(callSettings!.0) : nil, callP2PEnableFor: initialCallP2PEnableFor, callP2PDisableFor: initialCallP2PDisableFor, callP2PEnableForCloseFriends: initialCallEnableForCloseFriends, callIntegrationAvailable: callIntegrationAvailable, callIntegrationEnabled: callSettings?.1.enableSystemIntegration, phoneDiscoveryEnabled: phoneDiscoveryEnabled, hideReadTimeEnabled: globalSettings?.hideReadTime, uploadedPhoto: nil)
let statePromise = ValuePromise(initialState, ignoreRepeated: true) let statePromise = ValuePromise(initialState, ignoreRepeated: true)
@ -1038,6 +1043,8 @@ func selectivePrivacySettingsController(
title = strings.Privacy_VoiceMessages_AlwaysAllow_Title title = strings.Privacy_VoiceMessages_AlwaysAllow_Title
case .bio: case .bio:
title = strings.Privacy_Bio_AlwaysShareWith_Title title = strings.Privacy_Bio_AlwaysShareWith_Title
case .birthday:
title = strings.Privacy_Birthday_AlwaysShareWith_Title
} }
} else { } else {
switch kind { switch kind {
@ -1057,6 +1064,8 @@ func selectivePrivacySettingsController(
title = strings.Privacy_VoiceMessages_NeverAllow_Title title = strings.Privacy_VoiceMessages_NeverAllow_Title
case .bio: case .bio:
title = strings.Privacy_Bio_NeverShareWith_Title title = strings.Privacy_Bio_NeverShareWith_Title
case .birthday:
title = strings.Privacy_Birthday_NeverShareWith_Title
} }
} }
var peerIds: [EnginePeer.Id: SelectivePrivacyPeer] = [:] var peerIds: [EnginePeer.Id: SelectivePrivacyPeer] = [:]
@ -1366,6 +1375,8 @@ func selectivePrivacySettingsController(
title = presentationData.strings.Privacy_VoiceMessages title = presentationData.strings.Privacy_VoiceMessages
case .bio: case .bio:
title = presentationData.strings.Privacy_Bio title = presentationData.strings.Privacy_Bio
case .birthday:
title = presentationData.strings.Privacy_Birthday
} }
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false) let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: selectivePrivacySettingsControllerEntries(presentationData: presentationData, kind: kind, state: state, peerName: peerName ?? "", phoneNumber: phoneNumber, peer: peer, publicPhoto: publicPhoto), style: .blocks, animateChanges: true) let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: selectivePrivacySettingsControllerEntries(presentationData: presentationData, kind: kind, state: state, peerName: peerName ?? "", phoneNumber: phoneNumber, peer: peer, publicPhoto: publicPhoto), style: .blocks, animateChanges: true)
@ -1455,6 +1466,8 @@ func selectivePrivacySettingsController(
type = .voiceMessages type = .voiceMessages
case .bio: case .bio:
type = .bio type = .bio
case .birthday:
type = .birthday
} }
let updateSettingsSignal = context.engine.privacy.updateSelectiveAccountPrivacySettings(type: type, settings: settings) let updateSettingsSignal = context.engine.privacy.updateSelectiveAccountPrivacySettings(type: type, settings: settings)

View File

@ -595,6 +595,8 @@ private func privacySearchableItems(context: AccountContext, privacySettings: Ac
current = info.voiceMessages current = info.voiceMessages
case .bio: case .bio:
current = info.bio current = info.bio
case .birthday:
current = info.birthday
} }
present(.push, selectivePrivacySettingsController(context: context, kind: kind, current: current, callSettings: callSettings != nil ? (info.voiceCallsP2P, callSettings!.0) : nil, voipConfiguration: callSettings?.1, callIntegrationAvailable: CallKitIntegration.isAvailable, updated: { updated, updatedCallSettings, _, _ in present(.push, selectivePrivacySettingsController(context: context, kind: kind, current: current, callSettings: callSettings != nil ? (info.voiceCallsP2P, callSettings!.0) : nil, voipConfiguration: callSettings?.1, callIntegrationAvailable: CallKitIntegration.isAvailable, updated: { updated, updatedCallSettings, _, _ in

View File

@ -23,7 +23,7 @@ private var dismissedSuggestions: [AccountRecordId: Set<ServerProvidedSuggestion
} }
} }
public func getServerProvidedSuggestions(account: Account) -> Signal<[ServerProvidedSuggestion], NoError> { func _internal_getServerProvidedSuggestions(account: Account) -> Signal<[ServerProvidedSuggestion], NoError> {
let key: PostboxViewKey = .preferences(keys: Set([PreferencesKeys.appConfiguration])) let key: PostboxViewKey = .preferences(keys: Set([PreferencesKeys.appConfiguration]))
return combineLatest(account.postbox.combinedView(keys: [key]), dismissedSuggestionsPromise.get()) return combineLatest(account.postbox.combinedView(keys: [key]), dismissedSuggestionsPromise.get())
|> map { views, dismissedSuggestionsValue -> [ServerProvidedSuggestion] in |> map { views, dismissedSuggestionsValue -> [ServerProvidedSuggestion] in
@ -45,7 +45,7 @@ public func getServerProvidedSuggestions(account: Account) -> Signal<[ServerProv
|> distinctUntilChanged |> distinctUntilChanged
} }
public func dismissServerProvidedSuggestion(account: Account, suggestion: ServerProvidedSuggestion) -> Signal<Never, NoError> { func _internal_dismissServerProvidedSuggestion(account: Account, suggestion: ServerProvidedSuggestion) -> Signal<Never, NoError> {
if let _ = dismissedSuggestions[account.id] { if let _ = dismissedSuggestions[account.id] {
dismissedSuggestions[account.id]?.insert(suggestion) dismissedSuggestions[account.id]?.insert(suggestion)
} else { } else {
@ -63,7 +63,7 @@ public enum PeerSpecificServerProvidedSuggestion: String {
case convertToGigagroup = "CONVERT_GIGAGROUP" case convertToGigagroup = "CONVERT_GIGAGROUP"
} }
public func getPeerSpecificServerProvidedSuggestions(postbox: Postbox, peerId: PeerId) -> Signal<[PeerSpecificServerProvidedSuggestion], NoError> { func _internal_getPeerSpecificServerProvidedSuggestions(postbox: Postbox, peerId: PeerId) -> Signal<[PeerSpecificServerProvidedSuggestion], NoError> {
return postbox.peerView(id: peerId) return postbox.peerView(id: peerId)
|> map { view in |> map { view in
if let cachedData = view.cachedData as? CachedChannelData { if let cachedData = view.cachedData as? CachedChannelData {
@ -76,7 +76,7 @@ public func getPeerSpecificServerProvidedSuggestions(postbox: Postbox, peerId: P
|> distinctUntilChanged |> distinctUntilChanged
} }
public func dismissPeerSpecificServerProvidedSuggestion(account: Account, peerId: PeerId, suggestion: PeerSpecificServerProvidedSuggestion) -> Signal<Never, NoError> { func _internal_dismissPeerSpecificServerProvidedSuggestion(account: Account, peerId: PeerId, suggestion: PeerSpecificServerProvidedSuggestion) -> Signal<Never, NoError> {
return account.postbox.loadedPeerWithId(peerId) return account.postbox.loadedPeerWithId(peerId)
|> mapToSignal { peer -> Signal<Never, NoError> in |> mapToSignal { peer -> Signal<Never, NoError> in
guard let inputPeer = apiInputPeer(peer) else { guard let inputPeer = apiInputPeer(peer) else {

View File

@ -20,5 +20,21 @@ public extension TelegramEngine {
} }
|> ignoreValues |> ignoreValues
} }
public func getServerProvidedSuggestions() -> Signal<[ServerProvidedSuggestion], NoError> {
return _internal_getServerProvidedSuggestions(account: self.account)
}
public func dismissServerProvidedSuggestion(suggestion: ServerProvidedSuggestion) -> Signal<Never, NoError> {
return _internal_dismissServerProvidedSuggestion(account: self.account, suggestion: suggestion)
}
public func getPeerSpecificServerProvidedSuggestions(peerId: EnginePeer.Id) -> Signal<[PeerSpecificServerProvidedSuggestion], NoError> {
return _internal_getPeerSpecificServerProvidedSuggestions(postbox: self.account.postbox, peerId: peerId)
}
public func dismissPeerSpecificServerProvidedSuggestion(peerId: PeerId, suggestion: PeerSpecificServerProvidedSuggestion) -> Signal<Never, NoError> {
return _internal_dismissPeerSpecificServerProvidedSuggestion(account: self.account, peerId: peerId, suggestion: suggestion)
}
} }
} }

View File

@ -9,13 +9,13 @@ import ComponentFlow
final class PeerInfoScreenBirthdatePickerItem: PeerInfoScreenItem { final class PeerInfoScreenBirthdatePickerItem: PeerInfoScreenItem {
let id: AnyHashable let id: AnyHashable
let value: BirthdayPickerComponent.BirthDate let value: TelegramBirthday
let valueUpdated: (BirthdayPickerComponent.BirthDate) -> Void let valueUpdated: (TelegramBirthday) -> Void
init( init(
id: AnyHashable, id: AnyHashable,
value: BirthdayPickerComponent.BirthDate, value: TelegramBirthday,
valueUpdated: @escaping (BirthdayPickerComponent.BirthDate) -> Void valueUpdated: @escaping (TelegramBirthday) -> Void
) { ) {
self.id = id self.id = id
self.value = value self.value = value
@ -111,41 +111,17 @@ public final class BirthdayPickerComponent: Component {
self.selectionColor = presentationTheme.list.itemHighlightedBackgroundColor self.selectionColor = presentationTheme.list.itemHighlightedBackgroundColor
} }
} }
public struct BirthDate: Equatable {
let year: Int?
let month: Int
let day: Int
init(year: Int?, month: Int, day: Int) {
self.year = year
self.month = month
self.day = day
}
func withUpdated(year: Int?) -> BirthDate {
return BirthDate(year: year, month: self.month, day: self.day)
}
func withUpdated(month: Int) -> BirthDate {
return BirthDate(year: self.year, month: month, day: self.day)
}
func withUpdated(day: Int) -> BirthDate {
return BirthDate(year: self.year, month: self.month, day: day)
}
}
public let theme: Theme public let theme: Theme
public let strings: PresentationStrings public let strings: PresentationStrings
public let value: BirthDate public let value: TelegramBirthday
public let valueUpdated: (BirthDate) -> Void public let valueUpdated: (TelegramBirthday) -> Void
public init( public init(
theme: Theme, theme: Theme,
strings: PresentationStrings, strings: PresentationStrings,
value: BirthDate, value: TelegramBirthday,
valueUpdated: @escaping (BirthDate) -> Void valueUpdated: @escaping (TelegramBirthday) -> Void
) { ) {
self.theme = theme self.theme = theme
self.strings = strings self.strings = strings
@ -176,12 +152,12 @@ public final class BirthdayPickerComponent: Component {
} }
private let calendar = Calendar(identifier: .gregorian) private let calendar = Calendar(identifier: .gregorian)
private var value = BirthdayPickerComponent.BirthDate(year: nil, month: 1, day: 1) private var value = TelegramBirthday(day: 1, month: 1, year: nil)
private let minYear = 1900 private let minYear: Int32 = 1900
private let maxYear: Int private let maxYear: Int32
override init(frame: CGRect) { override init(frame: CGRect) {
self.maxYear = self.calendar.component(.year, from: Date()) self.maxYear = Int32(self.calendar.component(.year, from: Date()))
super.init(frame: frame) super.init(frame: frame)
@ -207,12 +183,12 @@ public final class BirthdayPickerComponent: Component {
self.pickerView.reloadAllComponents() self.pickerView.reloadAllComponents()
if let year = component.value.year { if let year = component.value.year {
self.pickerView.selectRow(year - self.minYear, inComponent: PickerComponent.year.rawValue, animated: false) self.pickerView.selectRow(Int(year - self.minYear), inComponent: PickerComponent.year.rawValue, animated: false)
} else { } else {
self.pickerView.selectRow(self.maxYear - self.minYear + 1, inComponent: PickerComponent.year.rawValue, animated: false) self.pickerView.selectRow(Int(self.maxYear - self.minYear + 1), inComponent: PickerComponent.year.rawValue, animated: false)
} }
self.pickerView.selectRow(component.value.month - 1, inComponent: PickerComponent.month.rawValue, animated: false) self.pickerView.selectRow(Int(component.value.month) - 1, inComponent: PickerComponent.month.rawValue, animated: false)
self.pickerView.selectRow(component.value.day - 1, inComponent: PickerComponent.day.rawValue, animated: false) self.pickerView.selectRow(Int(component.value.day) - 1, inComponent: PickerComponent.day.rawValue, animated: false)
} }
return availableSize return availableSize
@ -227,12 +203,12 @@ public final class BirthdayPickerComponent: Component {
case PickerComponent.day.rawValue: case PickerComponent.day.rawValue:
let year = self.value.year ?? 2024 let year = self.value.year ?? 2024
let month = self.value.month let month = self.value.month
let range = Calendar.current.range(of: .day, in: .month, for: Calendar.current.date(from: DateComponents(year: year, month: month))!)! let range = Calendar.current.range(of: .day, in: .month, for: Calendar.current.date(from: DateComponents(year: Int(year), month: Int(month)))!)!
return range.upperBound - range.lowerBound return range.upperBound - range.lowerBound
case PickerComponent.month.rawValue: case PickerComponent.month.rawValue:
return 12 return 12
case PickerComponent.year.rawValue: case PickerComponent.year.rawValue:
return self.maxYear - self.minYear + 2 return Int(self.maxYear - self.minYear + 2)
default: default:
return 0 return 0
} }
@ -279,7 +255,7 @@ public final class BirthdayPickerComponent: Component {
if row == self.maxYear - self.minYear + 1 { if row == self.maxYear - self.minYear + 1 {
string = "" string = ""
} else { } else {
string = "\(self.minYear + row)" string = "\(self.minYear + Int32(row))"
} }
default: default:
break break
@ -291,14 +267,14 @@ public final class BirthdayPickerComponent: Component {
public func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { public func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
switch component { switch component {
case PickerComponent.day.rawValue: case PickerComponent.day.rawValue:
self.value = self.value.withUpdated(day: row + 1) self.value = self.value.withUpdated(day: Int32(row) + 1)
case PickerComponent.month.rawValue: case PickerComponent.month.rawValue:
self.value = self.value.withUpdated(month: row + 1) self.value = self.value.withUpdated(month: Int32(row) + 1)
case PickerComponent.year.rawValue: case PickerComponent.year.rawValue:
if row == self.maxYear - self.minYear + 1 { if row == self.maxYear - self.minYear + 1 {
self.value = self.value.withUpdated(year: nil) self.value = self.value.withUpdated(year: nil)
} else { } else {
self.value = self.value.withUpdated(year: self.minYear + row) self.value = self.value.withUpdated(year: self.minYear + Int32(row))
} }
default: default:
break break
@ -336,3 +312,17 @@ public final class BirthdayPickerComponent: Component {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition) return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
} }
} }
private extension TelegramBirthday {
func withUpdated(day: Int32) -> TelegramBirthday {
return TelegramBirthday(day: day, month: self.month, year: self.year)
}
func withUpdated(month: Int32) -> TelegramBirthday {
return TelegramBirthday(day: self.day, month: month, year: self.year)
}
func withUpdated(year: Int32?) -> TelegramBirthday {
return TelegramBirthday(day: self.day, month: self.month, year: year)
}
}

View File

@ -34,7 +34,7 @@ final class PeerInfoState {
let avatarUploadProgress: AvatarUploadProgress? let avatarUploadProgress: AvatarUploadProgress?
let highlightedButton: PeerInfoHeaderButtonKey? let highlightedButton: PeerInfoHeaderButtonKey?
let isEditingBirthDate: Bool let isEditingBirthDate: Bool
let updatingBirthDate: BirthdayPickerComponent.BirthDate? let updatingBirthDate: TelegramBirthday??
init( init(
isEditing: Bool, isEditing: Bool,
@ -44,7 +44,7 @@ final class PeerInfoState {
avatarUploadProgress: AvatarUploadProgress?, avatarUploadProgress: AvatarUploadProgress?,
highlightedButton: PeerInfoHeaderButtonKey?, highlightedButton: PeerInfoHeaderButtonKey?,
isEditingBirthDate: Bool, isEditingBirthDate: Bool,
updatingBirthDate: BirthdayPickerComponent.BirthDate? updatingBirthDate: TelegramBirthday??
) { ) {
self.isEditing = isEditing self.isEditing = isEditing
self.selectedMessageIds = selectedMessageIds self.selectedMessageIds = selectedMessageIds
@ -147,7 +147,7 @@ final class PeerInfoState {
) )
} }
func withUpdatingBirthDate(_ updatingBirthDate: BirthdayPickerComponent.BirthDate?) -> PeerInfoState { func withUpdatingBirthDate(_ updatingBirthDate: TelegramBirthday??) -> PeerInfoState {
return PeerInfoState( return PeerInfoState(
isEditing: self.isEditing, isEditing: self.isEditing,
selectedMessageIds: self.selectedMessageIds, selectedMessageIds: self.selectedMessageIds,
@ -630,7 +630,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
hasPassport, hasPassport,
(context.watchManager?.watchAppInstalled ?? .single(false)), (context.watchManager?.watchAppInstalled ?? .single(false)),
context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration]), context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration]),
getServerProvidedSuggestions(account: context.account), context.engine.notices.getServerProvidedSuggestions(),
context.engine.data.get( context.engine.data.get(
TelegramEngine.EngineData.Item.Configuration.UserLimits(isPremium: false), TelegramEngine.EngineData.Item.Configuration.UserLimits(isPremium: false),
TelegramEngine.EngineData.Item.Configuration.UserLimits(isPremium: true) TelegramEngine.EngineData.Item.Configuration.UserLimits(isPremium: true)

View File

@ -583,7 +583,7 @@ private final class PeerInfoInteraction {
let openPeerMention: (String, ChatControllerInteractionNavigateToPeer) -> Void let openPeerMention: (String, ChatControllerInteractionNavigateToPeer) -> Void
let openBotApp: (AttachMenuBot) -> Void let openBotApp: (AttachMenuBot) -> Void
let openEditing: () -> Void let openEditing: () -> Void
let updateBirthDate: (BirthdayPickerComponent.BirthDate?) -> Void let updateBirthDate: (TelegramBirthday??) -> Void
let updateIsEditingBirthdate: (Bool) -> Void let updateIsEditingBirthdate: (Bool) -> Void
init( init(
@ -640,7 +640,7 @@ private final class PeerInfoInteraction {
openPeerMention: @escaping (String, ChatControllerInteractionNavigateToPeer) -> Void, openPeerMention: @escaping (String, ChatControllerInteractionNavigateToPeer) -> Void,
openBotApp: @escaping (AttachMenuBot) -> Void, openBotApp: @escaping (AttachMenuBot) -> Void,
openEditing: @escaping () -> Void, openEditing: @escaping () -> Void,
updateBirthDate: @escaping (BirthdayPickerComponent.BirthDate?) -> Void, updateBirthDate: @escaping (TelegramBirthday??) -> Void,
updateIsEditingBirthdate: @escaping (Bool) -> Void updateIsEditingBirthdate: @escaping (Bool) -> Void
) { ) {
self.openUsername = openUsername self.openUsername = openUsername
@ -778,7 +778,7 @@ private func settingsItems(data: PeerInfoScreenData?, context: AccountContext, p
} }
})) }))
items[.phone]!.append(PeerInfoScreenActionItem(id: 1, text: presentationData.strings.Settings_KeepPhoneNumber(phoneNumber).string, action: { items[.phone]!.append(PeerInfoScreenActionItem(id: 1, text: presentationData.strings.Settings_KeepPhoneNumber(phoneNumber).string, action: {
let _ = dismissServerProvidedSuggestion(account: context.account, suggestion: .validatePhoneNumber).startStandalone() let _ = context.engine.notices.dismissServerProvidedSuggestion(suggestion: .validatePhoneNumber).startStandalone()
})) }))
items[.phone]!.append(PeerInfoScreenActionItem(id: 2, text: presentationData.strings.Settings_ChangePhoneNumber, action: { items[.phone]!.append(PeerInfoScreenActionItem(id: 2, text: presentationData.strings.Settings_ChangePhoneNumber, action: {
interaction.openSettings(.phoneNumber) interaction.openSettings(.phoneNumber)
@ -787,7 +787,7 @@ private func settingsItems(data: PeerInfoScreenData?, context: AccountContext, p
items[.phone]!.append(PeerInfoScreenInfoItem(id: 0, title: presentationData.strings.Settings_CheckPasswordTitle, text: .markdown(presentationData.strings.Settings_CheckPasswordText), linkAction: { _ in items[.phone]!.append(PeerInfoScreenInfoItem(id: 0, title: presentationData.strings.Settings_CheckPasswordTitle, text: .markdown(presentationData.strings.Settings_CheckPasswordText), linkAction: { _ in
})) }))
items[.phone]!.append(PeerInfoScreenActionItem(id: 1, text: presentationData.strings.Settings_KeepPassword, action: { items[.phone]!.append(PeerInfoScreenActionItem(id: 1, text: presentationData.strings.Settings_KeepPassword, action: {
let _ = dismissServerProvidedSuggestion(account: context.account, suggestion: .validatePassword).startStandalone() let _ = context.engine.notices.dismissServerProvidedSuggestion(suggestion: .validatePassword).startStandalone()
})) }))
items[.phone]!.append(PeerInfoScreenActionItem(id: 2, text: presentationData.strings.Settings_TryEnterPassword, action: { items[.phone]!.append(PeerInfoScreenActionItem(id: 2, text: presentationData.strings.Settings_TryEnterPassword, action: {
interaction.openSettings(.rememberPassword) interaction.openSettings(.rememberPassword)
@ -1021,14 +1021,22 @@ private func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoStat
items[.bio]!.append(PeerInfoScreenCommentItem(id: ItemBioHelp, text: presentationData.strings.Settings_About_Help)) items[.bio]!.append(PeerInfoScreenCommentItem(id: ItemBioHelp, text: presentationData.strings.Settings_About_Help))
} }
var birthday: TelegramBirthday?
if let updatingBirthDate = state.updatingBirthDate {
birthday = updatingBirthDate
} else {
birthday = (data.cachedData as? CachedUserData)?.birthday
}
//TODO:localize //TODO:localize
var birthDateString: String var birthDateString: String
if let updatingBirthDate = state.updatingBirthDate { if let birthday {
var components: [String] = [] var components: [String] = []
components.append("\(updatingBirthDate.day)") components.append("\(birthday.day)")
let month: String let month: String
switch updatingBirthDate.month { switch birthday.month {
case 1: case 1:
month = "Jan" month = "Jan"
case 2: case 2:
@ -1058,7 +1066,7 @@ private func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoStat
} }
components.append(month) components.append(month)
if let year = updatingBirthDate.year { if let year = birthday.year {
components.append("\(year)") components.append("\(year)")
} }
@ -1069,23 +1077,22 @@ private func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoStat
let isEditingBirthDate = state.isEditingBirthDate let isEditingBirthDate = state.isEditingBirthDate
items[.birthday]!.append(PeerInfoScreenDisclosureItem(id: ItemBirthday, label: .coloredText(birthDateString, isEditingBirthDate ? .accent : .generic), text: "Date of Birth", icon: nil, hasArrow: false, action: { items[.birthday]!.append(PeerInfoScreenDisclosureItem(id: ItemBirthday, label: .coloredText(birthDateString, isEditingBirthDate ? .accent : .generic), text: "Date of Birth", icon: nil, hasArrow: false, action: {
if !isEditingBirthDate { if !isEditingBirthDate, birthday == nil {
interaction.updateBirthDate(BirthdayPickerComponent.BirthDate(year: nil, month: 1, day: 1)) interaction.updateBirthDate(TelegramBirthday(day: 1, month: 1, year: nil))
} }
interaction.updateIsEditingBirthdate(!isEditingBirthDate) interaction.updateIsEditingBirthdate(!isEditingBirthDate)
})) }))
if isEditingBirthDate, let birthDate = state.updatingBirthDate { if isEditingBirthDate, let birthday {
items[.birthday]!.append(PeerInfoScreenBirthdatePickerItem(id: ItemBirthdayPicker, value: birthDate, valueUpdated: { value in items[.birthday]!.append(PeerInfoScreenBirthdatePickerItem(id: ItemBirthdayPicker, value: birthday, valueUpdated: { value in
interaction.updateBirthDate(value) interaction.updateBirthDate(value)
})) }))
items[.birthday]!.append(PeerInfoScreenActionItem(id: ItemBirthdayRemove, text: "Remove Date of Birth", alignment: .natural, action: { items[.birthday]!.append(PeerInfoScreenActionItem(id: ItemBirthdayRemove, text: "Remove Date of Birth", alignment: .natural, action: {
interaction.updateBirthDate(nil) interaction.updateBirthDate(.some(nil))
interaction.updateIsEditingBirthdate(false) interaction.updateIsEditingBirthdate(false)
})) }))
} }
items[.birthday]!.append(PeerInfoScreenCommentItem(id: ItemBirthdayHelp, text: "Date of birth is only visible to your contacts.")) items[.birthday]!.append(PeerInfoScreenCommentItem(id: ItemBirthdayHelp, text: "Date of birth is only visible to your contacts."))
if let user = data.peer as? TelegramUser { if let user = data.peer as? TelegramUser {
items[.info]!.append(PeerInfoScreenDisclosureItem(id: ItemPhoneNumber, label: .text(user.phone.flatMap({ formatPhoneNumber(context: context, number: $0) }) ?? ""), text: presentationData.strings.Settings_PhoneNumber, action: { items[.info]!.append(PeerInfoScreenDisclosureItem(id: ItemPhoneNumber, label: .text(user.phone.flatMap({ formatPhoneNumber(context: context, number: $0) }) ?? ""), text: presentationData.strings.Settings_PhoneNumber, action: {
interaction.openSettings(.phoneNumber) interaction.openSettings(.phoneNumber)
@ -3602,6 +3609,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
let firstName = strongSelf.headerNode.editingContentNode.editingTextForKey(.firstName) ?? "" let firstName = strongSelf.headerNode.editingContentNode.editingTextForKey(.firstName) ?? ""
let lastName = strongSelf.headerNode.editingContentNode.editingTextForKey(.lastName) ?? "" let lastName = strongSelf.headerNode.editingContentNode.editingTextForKey(.lastName) ?? ""
let bio = strongSelf.state.updatingBio let bio = strongSelf.state.updatingBio
let birthday = strongSelf.state.updatingBirthDate
if let bio = bio { if let bio = bio {
if Int32(bio.count) > strongSelf.context.userLimits.maxAboutLength { if Int32(bio.count) > strongSelf.context.userLimits.maxAboutLength {
@ -3615,21 +3623,29 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
let peerBio = cachedData.about ?? "" let peerBio = cachedData.about ?? ""
if (peer.firstName ?? "") != firstName || (peer.lastName ?? "") != lastName || (bio ?? "") != peerBio { if (peer.firstName ?? "") != firstName || (peer.lastName ?? "") != lastName || (bio ?? "") != peerBio || (cachedData.birthday != birthday) {
var updateNameSignal: Signal<Void, NoError> = .complete() var updateNameSignal: Signal<Void, NoError> = .complete()
var hasProgress = false var hasProgress = false
if peer.firstName != firstName || peer.lastName != lastName { if (peer.firstName ?? "") != firstName || (peer.lastName ?? "") != lastName {
updateNameSignal = context.engine.accountData.updateAccountPeerName(firstName: firstName, lastName: lastName) updateNameSignal = context.engine.accountData.updateAccountPeerName(firstName: firstName, lastName: lastName)
hasProgress = true hasProgress = true
} }
var updateBioSignal: Signal<Void, NoError> = .complete() var updateBioSignal: Signal<Void, NoError> = .complete()
if let bio = bio, bio != cachedData.about { if let bio, bio != cachedData.about {
updateBioSignal = context.engine.accountData.updateAbout(about: bio) updateBioSignal = context.engine.accountData.updateAbout(about: bio)
|> `catch` { _ -> Signal<Void, NoError> in |> `catch` { _ -> Signal<Void, NoError> in
return .complete() return .complete()
} }
hasProgress = true hasProgress = true
} }
var updatedBirthdaySignal: Signal<Never, NoError> = .complete()
if let birthday, birthday != cachedData.birthday {
updatedBirthdaySignal = context.engine.accountData.updateBirthday(birthday: birthday)
|> `catch` { _ -> Signal<Never, NoError> in
return .complete()
}
hasProgress = true
}
var dismissStatus: (() -> Void)? var dismissStatus: (() -> Void)?
let statusController = OverlayStatusController(theme: strongSelf.presentationData.theme, type: .loading(cancelled: { let statusController = OverlayStatusController(theme: strongSelf.presentationData.theme, type: .loading(cancelled: {
@ -3642,7 +3658,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
if hasProgress { if hasProgress {
strongSelf.controller?.present(statusController, in: .window(.root)) strongSelf.controller?.present(statusController, in: .window(.root))
} }
strongSelf.activeActionDisposable.set((combineLatest(updateNameSignal, updateBioSignal) |> deliverOnMainQueue strongSelf.activeActionDisposable.set((combineLatest(updateNameSignal, updateBioSignal, updatedBirthdaySignal) |> deliverOnMainQueue
|> deliverOnMainQueue).startStrict(completed: { |> deliverOnMainQueue).startStrict(completed: {
dismissStatus?() dismissStatus?()
@ -3897,7 +3913,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel, nil, nil) strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel, nil, nil)
} }
} else { } else {
strongSelf.state = strongSelf.state.withIsEditing(false).withUpdatingBio(nil) strongSelf.state = strongSelf.state.withIsEditing(false).withUpdatingBio(nil).withUpdatingBirthDate(nil).withIsEditingBirthDate(false)
if let (layout, navigationHeight) = strongSelf.validLayout { if let (layout, navigationHeight) = strongSelf.validLayout {
strongSelf.scrollNode.view.setContentOffset(CGPoint(), animated: false) strongSelf.scrollNode.view.setContentOffset(CGPoint(), animated: false)
strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false) strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
@ -9021,7 +9037,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
guard let self else { guard let self else {
return return
} }
let _ = dismissServerProvidedSuggestion(account: self.context.account, suggestion: .setupPassword).startStandalone() let _ = self.context.engine.notices.dismissServerProvidedSuggestion(suggestion: .setupPassword).startStandalone()
}) })
let controller = self.context.sharedContext.makeSetupTwoFactorAuthController(context: self.context) let controller = self.context.sharedContext.makeSetupTwoFactorAuthController(context: self.context)
@ -9133,7 +9149,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
return twoStepVerificationUnlockSettingsController(context: context, mode: .access(intro: false, data: .single(TwoStepVerificationUnlockSettingsControllerData.access(configuration: TwoStepVerificationAccessConfiguration(configuration: configuration, password: nil))))) return twoStepVerificationUnlockSettingsController(context: context, mode: .access(intro: false, data: .single(TwoStepVerificationUnlockSettingsControllerData.access(configuration: TwoStepVerificationAccessConfiguration(configuration: configuration, password: nil)))))
} }
controller.passwordRemembered = { controller.passwordRemembered = {
let _ = dismissServerProvidedSuggestion(account: context.account, suggestion: .validatePassword).startStandalone() let _ = context.engine.notices.dismissServerProvidedSuggestion(suggestion: .validatePassword).startStandalone()
} }
push(controller) push(controller)
case .emojiStatus: case .emojiStatus:
@ -11108,7 +11124,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
icon = UIImage(bundleImageName: "Chat List/Tabs/IconSettings") icon = UIImage(bundleImageName: "Chat List/Tabs/IconSettings")
} }
let tabBarItem: Signal<(String, UIImage?, UIImage?, String?, Bool, Bool), NoError> = combineLatest(queue: .mainQueue(), self.context.sharedContext.presentationData, notificationsAuthorizationStatus.get(), notificationsWarningSuppressed.get(), getServerProvidedSuggestions(account: self.context.account), accountTabBarAvatar, accountTabBarAvatarBadge) let tabBarItem: Signal<(String, UIImage?, UIImage?, String?, Bool, Bool), NoError> = combineLatest(queue: .mainQueue(), self.context.sharedContext.presentationData, notificationsAuthorizationStatus.get(), notificationsWarningSuppressed.get(), context.engine.notices.getServerProvidedSuggestions(), accountTabBarAvatar, accountTabBarAvatarBadge)
|> map { presentationData, notificationsAuthorizationStatus, notificationsWarningSuppressed, suggestions, accountTabBarAvatar, accountTabBarAvatarBadge -> (String, UIImage?, UIImage?, String?, Bool, Bool) in |> map { presentationData, notificationsAuthorizationStatus, notificationsWarningSuppressed, suggestions, accountTabBarAvatar, accountTabBarAvatarBadge -> (String, UIImage?, UIImage?, String?, Bool, Bool) in
let notificationsWarning = shouldDisplayNotificationsPermissionWarning(status: notificationsAuthorizationStatus, suppressed: notificationsWarningSuppressed) let notificationsWarning = shouldDisplayNotificationsPermissionWarning(status: notificationsAuthorizationStatus, suppressed: notificationsWarningSuppressed)
let phoneNumberWarning = suggestions.contains(.validatePhoneNumber) let phoneNumberWarning = suggestions.contains(.validatePhoneNumber)
@ -12020,6 +12036,10 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig
previousSecondaryContentNode.alpha = self.previousSecondaryContentNodeAlpha previousSecondaryContentNode.alpha = self.previousSecondaryContentNodeAlpha
bottomNavigationBar.clippingNode.addSubnode(previousSecondaryContentNode) bottomNavigationBar.clippingNode.addSubnode(previousSecondaryContentNode)
} }
if let previousTitleView = bottomNavigationBar.titleView as? ChatTitleView, let iconView = previousTitleView.titleCredibilityIconView.componentView {
iconView.frame = iconView.bounds
}
} }
} }

View File

@ -11525,7 +11525,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.displayChecksTooltip() strongSelf.displayChecksTooltip()
} }
strongSelf.shouldDisplayChecksTooltip = false strongSelf.shouldDisplayChecksTooltip = false
strongSelf.checksTooltipDisposable.set(dismissServerProvidedSuggestion(account: strongSelf.context.account, suggestion: .newcomerTicks).startStrict()) strongSelf.checksTooltipDisposable.set(strongSelf.context.engine.notices.dismissServerProvidedSuggestion(suggestion: .newcomerTicks).startStrict())
} }
} }
})) }))
@ -12187,7 +12187,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
})) }))
} }
self.checksTooltipDisposable.set((getServerProvidedSuggestions(account: self.context.account) self.checksTooltipDisposable.set((self.context.engine.notices.getServerProvidedSuggestions()
|> deliverOnMainQueue).startStrict(next: { [weak self] values in |> deliverOnMainQueue).startStrict(next: { [weak self] values in
guard let strongSelf = self, strongSelf.chatLocation.peerId != strongSelf.context.account.peerId else { guard let strongSelf = self, strongSelf.chatLocation.peerId != strongSelf.context.account.peerId else {
return return
@ -12199,7 +12199,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
})) }))
if case let .peer(peerId) = self.chatLocation { if case let .peer(peerId) = self.chatLocation {
self.peerSuggestionsDisposable.set((getPeerSpecificServerProvidedSuggestions(postbox: self.context.account.postbox, peerId: peerId) self.peerSuggestionsDisposable.set((self.context.engine.notices.getPeerSpecificServerProvidedSuggestions(peerId: peerId)
|> deliverOnMainQueue).startStrict(next: { [weak self] values in |> deliverOnMainQueue).startStrict(next: { [weak self] values in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
@ -12236,11 +12236,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let attributedText = parseMarkdownIntoAttributedString(presentationData.strings.BroadcastGroups_ConfirmationAlert_Text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .center) let attributedText = parseMarkdownIntoAttributedString(presentationData.strings.BroadcastGroups_ConfirmationAlert_Text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .center)
let alertController = richTextAlertController(context: context, title: attributedTitle, text: attributedText, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: { let alertController = richTextAlertController(context: context, title: attributedTitle, text: attributedText, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
let _ = dismissPeerSpecificServerProvidedSuggestion(account: context.account, peerId: peerId, suggestion: .convertToGigagroup).startStandalone() let _ = context.engine.notices.dismissPeerSpecificServerProvidedSuggestion(peerId: peerId, suggestion: .convertToGigagroup).startStandalone()
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.BroadcastGroups_ConfirmationAlert_Convert, action: { [weak controller] in }), TextAlertAction(type: .defaultAction, title: presentationData.strings.BroadcastGroups_ConfirmationAlert_Convert, action: { [weak controller] in
controller?.dismiss() controller?.dismiss()
let _ = dismissPeerSpecificServerProvidedSuggestion(account: context.account, peerId: peerId, suggestion: .convertToGigagroup).startStandalone() let _ = context.engine.notices.dismissPeerSpecificServerProvidedSuggestion(peerId: peerId, suggestion: .convertToGigagroup).startStandalone()
let _ = (convertGroupToGigagroup(account: context.account, peerId: peerId) let _ = (convertGroupToGigagroup(account: context.account, peerId: peerId)
|> deliverOnMainQueue).startStandalone(completed: { |> deliverOnMainQueue).startStandalone(completed: {