diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 1ad149bc9c..1249fbcf45 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -11619,3 +11619,9 @@ Sorry for the inconvenience."; "WebApp.TermsOfUse" = "Terms of Use"; "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"; diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 846bc2613e..bdfa10c597 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -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 guard let strongSelf = self else { return @@ -2331,13 +2331,13 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController guard let strongSelf = self else { 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: { guard let strongSelf = self else { 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)) }) ], actionLayout: .vertical, parseMarkdown: true), in: .window(.root)) diff --git a/submodules/ChatListUI/Sources/Node/ChatListNode.swift b/submodules/ChatListUI/Sources/Node/ChatListNode.swift index df0d87512c..fb089b4510 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNode.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNode.swift @@ -738,7 +738,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL nodeInteraction?.openPremiumGift([]) case .setupBirthday: nodeInteraction?.openBirthdaySetup() - case let .birthdayPremiumGift(peers): + case let .birthdayPremiumGift(peers, _): nodeInteraction?.openPremiumGift(peers.map { $0.id }) case .reviewLogin: break @@ -1074,7 +1074,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL nodeInteraction?.openPremiumGift([]) case .setupBirthday: nodeInteraction?.openBirthdaySetup() - case let .birthdayPremiumGift(peers): + case let .birthdayPremiumGift(peers, _): nodeInteraction?.openPremiumGift(peers.map { $0.id }) case .reviewLogin: break @@ -1675,7 +1675,7 @@ public final class ChatListNode: ListView { } Queue.mainQueue().after(0.6) { [weak self] in 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) @@ -1686,9 +1686,9 @@ public final class ChatListNode: ListView { } Queue.mainQueue().after(0.6) { [weak self] in if let self { - let _ = dismissServerProvidedSuggestion(account: self.context.account, suggestion: .annualPremium).startStandalone() - let _ = dismissServerProvidedSuggestion(account: self.context.account, suggestion: .upgradePremium).startStandalone() - let _ = dismissServerProvidedSuggestion(account: self.context.account, suggestion: .restorePremium).startStandalone() + let _ = self.context.engine.notices.dismissServerProvidedSuggestion(suggestion: .annualPremium).startStandalone() + let _ = self.context.engine.notices.dismissServerProvidedSuggestion(suggestion: .upgradePremium).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) @@ -1794,13 +1794,13 @@ public final class ChatListNode: ListView { let presentationData = self.context.sharedContext.currentPresentationData.with { $0 } switch notice { 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 return true })) case .setupBirthday: //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 return true })) @@ -1896,11 +1896,12 @@ public final class ChatListNode: ListView { let twoStepData: Signal = .single(nil) |> then(context.engine.auth.twoStepVerificationConfiguration() |> map(Optional.init)) let suggestedChatListNoticeSignal: Signal = combineLatest( - getServerProvidedSuggestions(account: context.account), + context.engine.notices.getServerProvidedSuggestions(), twoStepData, - newSessionReviews(postbox: context.account.postbox) + newSessionReviews(postbox: context.account.postbox), + context.account.stateManager.contactBirthdays ) - |> mapToSignal { suggestions, configuration, newSessionReviews -> Signal in + |> mapToSignal { suggestions, configuration, newSessionReviews, birthdays -> Signal in if let newSessionReview = newSessionReviews.first { return .single(.reviewLogin(newSessionReview: newSessionReview, totalCount: newSessionReviews.count)) } @@ -1919,15 +1920,20 @@ public final class ChatListNode: ListView { } } if suggestions.contains(.setupBirthday) { - return context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId)) - |> map { peer in - if let peer { - return .birthdayPremiumGift(peers: [peer]) - } else { - return .setupBirthday + return .single(.setupBirthday) + } else if !birthdays.isEmpty { + return context.engine.data.get( + EngineDataMap(birthdays.keys.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:))) + ) + |> 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) { return .single(.xmasPremiumGift) } else if suggestions.contains(.annualPremium) || suggestions.contains(.upgradePremium) || suggestions.contains(.restorePremium), let inAppPurchaseManager = context.inAppPurchaseManager { diff --git a/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift b/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift index ff79f1ef78..8321ea2e67 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift @@ -87,7 +87,7 @@ public enum ChatListNotice: Equatable { case premiumRestore(discount: Int32) case xmasPremiumGift case setupBirthday - case birthdayPremiumGift(peers: [EnginePeer]) + case birthdayPremiumGift(peers: [EnginePeer], birthdays: [EnginePeer.Id: TelegramBirthday]) case reviewLogin(newSessionReview: NewSessionReview, totalCount: Int) } diff --git a/submodules/ChatListUI/Sources/Node/ChatListStorageInfoItem.swift b/submodules/ChatListUI/Sources/Node/ChatListStorageInfoItem.swift index 7d8bd0f2f2..568ae0aab1 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListStorageInfoItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListStorageInfoItem.swift @@ -228,7 +228,7 @@ class ChatListStorageInfoItemNode: ItemListRevealOptionsItemNode { //TODO:localize 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) - case let .birthdayPremiumGift(peers): + case let .birthdayPremiumGift(peers, _): //TODO:localize let title: String let text: String diff --git a/submodules/SettingsUI/Sources/ChangePhoneNumberCodeController.swift b/submodules/SettingsUI/Sources/ChangePhoneNumberCodeController.swift index 203a896bf7..f829177087 100644 --- a/submodules/SettingsUI/Sources/ChangePhoneNumberCodeController.swift +++ b/submodules/SettingsUI/Sources/ChangePhoneNumberCodeController.swift @@ -277,7 +277,7 @@ func changePhoneNumberCodeController(context: AccountContext, phoneNumber: Strin let presentationData = context.sharedContext.currentPresentationData.with { $0 } 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?() })) diff --git a/submodules/SettingsUI/Sources/ChangePhoneNumberController.swift b/submodules/SettingsUI/Sources/ChangePhoneNumberController.swift index 17a5ce1a2a..321e6b4d2d 100644 --- a/submodules/SettingsUI/Sources/ChangePhoneNumberController.swift +++ b/submodules/SettingsUI/Sources/ChangePhoneNumberController.swift @@ -78,7 +78,7 @@ public func ChangePhoneNumberController(context: AccountContext) -> ViewControll }, completed: { [weak codeController] in 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 { var viewControllers = navigationController.viewControllers diff --git a/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift b/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift index b3359bc6bc..8a0c99be66 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift @@ -31,6 +31,7 @@ private final class PrivacyAndSecurityControllerArguments { let openPhoneNumberPrivacy: () -> Void let openVoiceMessagePrivacy: () -> Void let openBioPrivacy: () -> Void + let openBirthdayPrivacy: () -> Void let openPasscode: () -> Void let openTwoStepVerification: (TwoStepVerificationAccessConfiguration?) -> Void let openActiveSessions: () -> Void @@ -41,7 +42,7 @@ private final class PrivacyAndSecurityControllerArguments { let openEmailSettings: (String?) -> 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.openBlockedUsers = openBlockedUsers self.openLastSeenPrivacy = openLastSeenPrivacy @@ -52,6 +53,7 @@ private final class PrivacyAndSecurityControllerArguments { self.openPhoneNumberPrivacy = openPhoneNumberPrivacy self.openVoiceMessagePrivacy = openVoiceMessagePrivacy self.openBioPrivacy = openBioPrivacy + self.openBirthdayPrivacy = openBirthdayPrivacy self.openPasscode = openPasscode self.openTwoStepVerification = openTwoStepVerification self.openActiveSessions = openActiveSessions @@ -99,6 +101,7 @@ private enum PrivacyAndSecurityEntry: ItemListNodeEntry { case voiceMessagePrivacy(PresentationTheme, String, String, Bool) case messagePrivacy(PresentationTheme, Bool, Bool) case bioPrivacy(PresentationTheme, String, String) + case birthdayPrivacy(PresentationTheme, String, String) case selectivePrivacyInfo(PresentationTheme, String) case passcode(PresentationTheme, String, Bool, String) case twoStepVerification(PresentationTheme, String, String, TwoStepVerificationAccessConfiguration?) @@ -120,7 +123,7 @@ private enum PrivacyAndSecurityEntry: ItemListNodeEntry { switch self { case .blockedPeers, .activeSessions, .passcode, .twoStepVerification, .loginEmail, .loginEmailInfo, .messageAutoremoveTimeout, .messageAutoremoveInfo: 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 case .autoArchiveHeader, .autoArchive, .autoArchiveInfo: return PrivacyAndSecuritySection.autoArchive.rawValue @@ -159,34 +162,36 @@ private enum PrivacyAndSecurityEntry: ItemListNodeEntry { return 12 case .bioPrivacy: return 13 - case .forwardPrivacy: + case .birthdayPrivacy: return 14 - case .voiceCallPrivacy: + case .forwardPrivacy: return 15 - case .groupPrivacy: + case .voiceCallPrivacy: return 16 - case .voiceMessagePrivacy: + case .groupPrivacy: return 17 - case .messagePrivacy: + case .voiceMessagePrivacy: return 18 - case .selectivePrivacyInfo: + case .messagePrivacy: return 19 - case .autoArchiveHeader: + case .selectivePrivacyInfo: return 20 - case .autoArchive: + case .autoArchiveHeader: return 21 - case .autoArchiveInfo: + case .autoArchive: return 22 + case .autoArchiveInfo: + return 23 case .accountHeader: - return 25 + return 24 case .accountTimeout: - return 26 + return 25 case .accountInfo: - return 27 + return 26 case .dataSettings: - return 28 + return 27 case .dataSettingsInfo: - return 29 + return 28 } } @@ -258,6 +263,12 @@ private enum PrivacyAndSecurityEntry: ItemListNodeEntry { } else { 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): if case let .selectivePrivacyInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { return true @@ -402,6 +413,10 @@ private enum PrivacyAndSecurityEntry: ItemListNodeEntry { return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, action: { 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): return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section) 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(.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(.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(.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))) @@ -624,6 +640,7 @@ private func privacyAndSecurityControllerEntries( 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(.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(.voiceCallPrivacy(presentationData.theme, presentationData.strings.Privacy_Calls, 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) } })) + }, 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 = privacySettingsPromise.get() + |> filter { $0 != nil } + |> take(1) + |> deliverOnMainQueue + |> mapToSignal { value -> Signal 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: { let _ = passcodeOptionsAccessController(context: context, pushController: { controller in replaceTopControllerImpl?(controller) diff --git a/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsController.swift b/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsController.swift index a0ea26298c..5977b87d89 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsController.swift @@ -21,6 +21,7 @@ enum SelectivePrivacySettingsKind { case phoneNumber case voiceMessages case bio + case birthday } private enum SelectivePrivacySettingType { @@ -789,6 +790,11 @@ private func selectivePrivacySettingsControllerEntries(presentationData: Present settingInfoText = presentationData.strings.Privacy_Bio_CustomHelp disableForText = presentationData.strings.PrivacyLastSeenSettings_NeverShareWith 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 { @@ -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 statePromise = ValuePromise(initialState, ignoreRepeated: true) @@ -1038,6 +1043,8 @@ func selectivePrivacySettingsController( title = strings.Privacy_VoiceMessages_AlwaysAllow_Title case .bio: title = strings.Privacy_Bio_AlwaysShareWith_Title + case .birthday: + title = strings.Privacy_Birthday_AlwaysShareWith_Title } } else { switch kind { @@ -1057,6 +1064,8 @@ func selectivePrivacySettingsController( title = strings.Privacy_VoiceMessages_NeverAllow_Title case .bio: title = strings.Privacy_Bio_NeverShareWith_Title + case .birthday: + title = strings.Privacy_Birthday_NeverShareWith_Title } } var peerIds: [EnginePeer.Id: SelectivePrivacyPeer] = [:] @@ -1366,6 +1375,8 @@ func selectivePrivacySettingsController( title = presentationData.strings.Privacy_VoiceMessages case .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 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 case .bio: type = .bio + case .birthday: + type = .birthday } let updateSettingsSignal = context.engine.privacy.updateSelectiveAccountPrivacySettings(type: type, settings: settings) diff --git a/submodules/SettingsUI/Sources/Search/SettingsSearchableItems.swift b/submodules/SettingsUI/Sources/Search/SettingsSearchableItems.swift index 1d0507719d..61a47a2228 100644 --- a/submodules/SettingsUI/Sources/Search/SettingsSearchableItems.swift +++ b/submodules/SettingsUI/Sources/Search/SettingsSearchableItems.swift @@ -595,6 +595,8 @@ private func privacySearchableItems(context: AccountContext, privacySettings: Ac current = info.voiceMessages case .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 diff --git a/submodules/TelegramCore/Sources/Suggestions.swift b/submodules/TelegramCore/Sources/Suggestions.swift index 041033480c..c56b413d4b 100644 --- a/submodules/TelegramCore/Sources/Suggestions.swift +++ b/submodules/TelegramCore/Sources/Suggestions.swift @@ -23,7 +23,7 @@ private var dismissedSuggestions: [AccountRecordId: Set Signal<[ServerProvidedSuggestion], NoError> { +func _internal_getServerProvidedSuggestions(account: Account) -> Signal<[ServerProvidedSuggestion], NoError> { let key: PostboxViewKey = .preferences(keys: Set([PreferencesKeys.appConfiguration])) return combineLatest(account.postbox.combinedView(keys: [key]), dismissedSuggestionsPromise.get()) |> map { views, dismissedSuggestionsValue -> [ServerProvidedSuggestion] in @@ -45,7 +45,7 @@ public func getServerProvidedSuggestions(account: Account) -> Signal<[ServerProv |> distinctUntilChanged } -public func dismissServerProvidedSuggestion(account: Account, suggestion: ServerProvidedSuggestion) -> Signal { +func _internal_dismissServerProvidedSuggestion(account: Account, suggestion: ServerProvidedSuggestion) -> Signal { if let _ = dismissedSuggestions[account.id] { dismissedSuggestions[account.id]?.insert(suggestion) } else { @@ -63,7 +63,7 @@ public enum PeerSpecificServerProvidedSuggestion: String { 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) |> map { view in if let cachedData = view.cachedData as? CachedChannelData { @@ -76,7 +76,7 @@ public func getPeerSpecificServerProvidedSuggestions(postbox: Postbox, peerId: P |> distinctUntilChanged } -public func dismissPeerSpecificServerProvidedSuggestion(account: Account, peerId: PeerId, suggestion: PeerSpecificServerProvidedSuggestion) -> Signal { +func _internal_dismissPeerSpecificServerProvidedSuggestion(account: Account, peerId: PeerId, suggestion: PeerSpecificServerProvidedSuggestion) -> Signal { return account.postbox.loadedPeerWithId(peerId) |> mapToSignal { peer -> Signal in guard let inputPeer = apiInputPeer(peer) else { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Notices/TelegramEngineNotices.swift b/submodules/TelegramCore/Sources/TelegramEngine/Notices/TelegramEngineNotices.swift index 509a83c056..7771fa30c8 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Notices/TelegramEngineNotices.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Notices/TelegramEngineNotices.swift @@ -20,5 +20,21 @@ public extension TelegramEngine { } |> ignoreValues } + + public func getServerProvidedSuggestions() -> Signal<[ServerProvidedSuggestion], NoError> { + return _internal_getServerProvidedSuggestions(account: self.account) + } + + public func dismissServerProvidedSuggestion(suggestion: ServerProvidedSuggestion) -> Signal { + 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 { + return _internal_dismissPeerSpecificServerProvidedSuggestion(account: self.account, peerId: peerId, suggestion: suggestion) + } } } diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenBirthdatePickerItem.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenBirthdatePickerItem.swift index 9b8cb6850a..3f201ab857 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenBirthdatePickerItem.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenBirthdatePickerItem.swift @@ -9,13 +9,13 @@ import ComponentFlow final class PeerInfoScreenBirthdatePickerItem: PeerInfoScreenItem { let id: AnyHashable - let value: BirthdayPickerComponent.BirthDate - let valueUpdated: (BirthdayPickerComponent.BirthDate) -> Void + let value: TelegramBirthday + let valueUpdated: (TelegramBirthday) -> Void init( id: AnyHashable, - value: BirthdayPickerComponent.BirthDate, - valueUpdated: @escaping (BirthdayPickerComponent.BirthDate) -> Void + value: TelegramBirthday, + valueUpdated: @escaping (TelegramBirthday) -> Void ) { self.id = id self.value = value @@ -111,41 +111,17 @@ public final class BirthdayPickerComponent: Component { 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 strings: PresentationStrings - public let value: BirthDate - public let valueUpdated: (BirthDate) -> Void + public let value: TelegramBirthday + public let valueUpdated: (TelegramBirthday) -> Void public init( theme: Theme, strings: PresentationStrings, - value: BirthDate, - valueUpdated: @escaping (BirthDate) -> Void + value: TelegramBirthday, + valueUpdated: @escaping (TelegramBirthday) -> Void ) { self.theme = theme self.strings = strings @@ -176,12 +152,12 @@ public final class BirthdayPickerComponent: Component { } private let calendar = Calendar(identifier: .gregorian) - private var value = BirthdayPickerComponent.BirthDate(year: nil, month: 1, day: 1) - private let minYear = 1900 - private let maxYear: Int + private var value = TelegramBirthday(day: 1, month: 1, year: nil) + private let minYear: Int32 = 1900 + private let maxYear: Int32 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) @@ -207,12 +183,12 @@ public final class BirthdayPickerComponent: Component { self.pickerView.reloadAllComponents() 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 { - 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(component.value.day - 1, inComponent: PickerComponent.day.rawValue, animated: false) + self.pickerView.selectRow(Int(component.value.month) - 1, inComponent: PickerComponent.month.rawValue, animated: false) + self.pickerView.selectRow(Int(component.value.day) - 1, inComponent: PickerComponent.day.rawValue, animated: false) } return availableSize @@ -227,12 +203,12 @@ public final class BirthdayPickerComponent: Component { case PickerComponent.day.rawValue: let year = self.value.year ?? 2024 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 case PickerComponent.month.rawValue: return 12 case PickerComponent.year.rawValue: - return self.maxYear - self.minYear + 2 + return Int(self.maxYear - self.minYear + 2) default: return 0 } @@ -279,7 +255,7 @@ public final class BirthdayPickerComponent: Component { if row == self.maxYear - self.minYear + 1 { string = "⎯" } else { - string = "\(self.minYear + row)" + string = "\(self.minYear + Int32(row))" } default: break @@ -291,14 +267,14 @@ public final class BirthdayPickerComponent: Component { public func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { switch component { 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: - self.value = self.value.withUpdated(month: row + 1) + self.value = self.value.withUpdated(month: Int32(row) + 1) case PickerComponent.year.rawValue: if row == self.maxYear - self.minYear + 1 { self.value = self.value.withUpdated(year: nil) } else { - self.value = self.value.withUpdated(year: self.minYear + row) + self.value = self.value.withUpdated(year: self.minYear + Int32(row)) } default: break @@ -336,3 +312,17 @@ public final class BirthdayPickerComponent: Component { 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) + } +} diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift index 905bc9016a..34e2a35e7d 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift @@ -34,7 +34,7 @@ final class PeerInfoState { let avatarUploadProgress: AvatarUploadProgress? let highlightedButton: PeerInfoHeaderButtonKey? let isEditingBirthDate: Bool - let updatingBirthDate: BirthdayPickerComponent.BirthDate? + let updatingBirthDate: TelegramBirthday?? init( isEditing: Bool, @@ -44,7 +44,7 @@ final class PeerInfoState { avatarUploadProgress: AvatarUploadProgress?, highlightedButton: PeerInfoHeaderButtonKey?, isEditingBirthDate: Bool, - updatingBirthDate: BirthdayPickerComponent.BirthDate? + updatingBirthDate: TelegramBirthday?? ) { self.isEditing = isEditing self.selectedMessageIds = selectedMessageIds @@ -147,7 +147,7 @@ final class PeerInfoState { ) } - func withUpdatingBirthDate(_ updatingBirthDate: BirthdayPickerComponent.BirthDate?) -> PeerInfoState { + func withUpdatingBirthDate(_ updatingBirthDate: TelegramBirthday??) -> PeerInfoState { return PeerInfoState( isEditing: self.isEditing, selectedMessageIds: self.selectedMessageIds, @@ -630,7 +630,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id, hasPassport, (context.watchManager?.watchAppInstalled ?? .single(false)), context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration]), - getServerProvidedSuggestions(account: context.account), + context.engine.notices.getServerProvidedSuggestions(), context.engine.data.get( TelegramEngine.EngineData.Item.Configuration.UserLimits(isPremium: false), TelegramEngine.EngineData.Item.Configuration.UserLimits(isPremium: true) diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index 67b15dc80d..a15420d850 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -583,7 +583,7 @@ private final class PeerInfoInteraction { let openPeerMention: (String, ChatControllerInteractionNavigateToPeer) -> Void let openBotApp: (AttachMenuBot) -> Void let openEditing: () -> Void - let updateBirthDate: (BirthdayPickerComponent.BirthDate?) -> Void + let updateBirthDate: (TelegramBirthday??) -> Void let updateIsEditingBirthdate: (Bool) -> Void init( @@ -640,7 +640,7 @@ private final class PeerInfoInteraction { openPeerMention: @escaping (String, ChatControllerInteractionNavigateToPeer) -> Void, openBotApp: @escaping (AttachMenuBot) -> Void, openEditing: @escaping () -> Void, - updateBirthDate: @escaping (BirthdayPickerComponent.BirthDate?) -> Void, + updateBirthDate: @escaping (TelegramBirthday??) -> Void, updateIsEditingBirthdate: @escaping (Bool) -> Void ) { 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: { - 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: { 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(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: { 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)) } + + var birthday: TelegramBirthday? + if let updatingBirthDate = state.updatingBirthDate { + birthday = updatingBirthDate + } else { + birthday = (data.cachedData as? CachedUserData)?.birthday + } + //TODO:localize var birthDateString: String - if let updatingBirthDate = state.updatingBirthDate { + if let birthday { var components: [String] = [] - components.append("\(updatingBirthDate.day)") + components.append("\(birthday.day)") let month: String - switch updatingBirthDate.month { + switch birthday.month { case 1: month = "Jan" case 2: @@ -1058,7 +1066,7 @@ private func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoStat } components.append(month) - if let year = updatingBirthDate.year { + if let year = birthday.year { components.append("\(year)") } @@ -1069,23 +1077,22 @@ private func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoStat 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: { - if !isEditingBirthDate { - interaction.updateBirthDate(BirthdayPickerComponent.BirthDate(year: nil, month: 1, day: 1)) + if !isEditingBirthDate, birthday == nil { + interaction.updateBirthDate(TelegramBirthday(day: 1, month: 1, year: nil)) } interaction.updateIsEditingBirthdate(!isEditingBirthDate) })) - if isEditingBirthDate, let birthDate = state.updatingBirthDate { - items[.birthday]!.append(PeerInfoScreenBirthdatePickerItem(id: ItemBirthdayPicker, value: birthDate, valueUpdated: { value in + if isEditingBirthDate, let birthday { + items[.birthday]!.append(PeerInfoScreenBirthdatePickerItem(id: ItemBirthdayPicker, value: birthday, valueUpdated: { value in interaction.updateBirthDate(value) })) items[.birthday]!.append(PeerInfoScreenActionItem(id: ItemBirthdayRemove, text: "Remove Date of Birth", alignment: .natural, action: { - interaction.updateBirthDate(nil) + interaction.updateBirthDate(.some(nil)) interaction.updateIsEditingBirthdate(false) })) } items[.birthday]!.append(PeerInfoScreenCommentItem(id: ItemBirthdayHelp, text: "Date of birth is only visible to your contacts.")) - 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: { interaction.openSettings(.phoneNumber) @@ -3602,6 +3609,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro let firstName = strongSelf.headerNode.editingContentNode.editingTextForKey(.firstName) ?? "" let lastName = strongSelf.headerNode.editingContentNode.editingTextForKey(.lastName) ?? "" let bio = strongSelf.state.updatingBio + let birthday = strongSelf.state.updatingBirthDate if let bio = bio { if Int32(bio.count) > strongSelf.context.userLimits.maxAboutLength { @@ -3615,21 +3623,29 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro 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 = .complete() 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) hasProgress = true } var updateBioSignal: Signal = .complete() - if let bio = bio, bio != cachedData.about { + if let bio, bio != cachedData.about { updateBioSignal = context.engine.accountData.updateAbout(about: bio) |> `catch` { _ -> Signal in return .complete() } hasProgress = true } + var updatedBirthdaySignal: Signal = .complete() + if let birthday, birthday != cachedData.birthday { + updatedBirthdaySignal = context.engine.accountData.updateBirthday(birthday: birthday) + |> `catch` { _ -> Signal in + return .complete() + } + hasProgress = true + } var dismissStatus: (() -> Void)? let statusController = OverlayStatusController(theme: strongSelf.presentationData.theme, type: .loading(cancelled: { @@ -3642,7 +3658,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro if hasProgress { 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: { dismissStatus?() @@ -3897,7 +3913,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel, nil, nil) } } 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 { strongSelf.scrollNode.view.setContentOffset(CGPoint(), animated: false) strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false) @@ -9021,7 +9037,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro guard let self else { 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) @@ -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))))) } controller.passwordRemembered = { - let _ = dismissServerProvidedSuggestion(account: context.account, suggestion: .validatePassword).startStandalone() + let _ = context.engine.notices.dismissServerProvidedSuggestion(suggestion: .validatePassword).startStandalone() } push(controller) case .emojiStatus: @@ -11108,7 +11124,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc 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 let notificationsWarning = shouldDisplayNotificationsPermissionWarning(status: notificationsAuthorizationStatus, suppressed: notificationsWarningSuppressed) let phoneNumberWarning = suggestions.contains(.validatePhoneNumber) @@ -12020,6 +12036,10 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig previousSecondaryContentNode.alpha = self.previousSecondaryContentNodeAlpha bottomNavigationBar.clippingNode.addSubnode(previousSecondaryContentNode) } + + if let previousTitleView = bottomNavigationBar.titleView as? ChatTitleView, let iconView = previousTitleView.titleCredibilityIconView.componentView { + iconView.frame = iconView.bounds + } } } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 53551f799d..233f0da62d 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -11525,7 +11525,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G strongSelf.displayChecksTooltip() } 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 guard let strongSelf = self, strongSelf.chatLocation.peerId != strongSelf.context.account.peerId else { return @@ -12199,7 +12199,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G })) 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 guard let strongSelf = self else { 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 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 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) |> deliverOnMainQueue).startStandalone(completed: {