Various improvements

This commit is contained in:
Ilya Laktyushin 2025-03-18 20:12:41 +04:00
parent 730f03dcd8
commit d6eecb7844
18 changed files with 191 additions and 110 deletions

View File

@ -14059,3 +14059,33 @@ Sorry for the inconvenience.";
"ChatbotSetup.Rights.ManageStories" = "Manage Stories";
"Gift.Send.Upgrade.ForcedInfo" = "%1$@ accepts only unique gifts. [Learn More >]()";
"Privacy.Gifts.ShowGiftButton" = "Show Gift Icon in Chats";
"Privacy.Gifts.ShowGiftButtonInfo" = "Display the #Gift icon in the message input field for both participants in all chats.";
"Privacy.Gifts.AcceptedTypes" = "ACCEPTED GIFT TYPES";
"Privacy.Gifts.AcceptedTypes.Unlimited" = "Unlimited";
"Privacy.Gifts.AcceptedTypes.Limited" = "Limited-Edition";
"Privacy.Gifts.AcceptedTypes.Unique" = "Unique";
"Privacy.Gifts.AcceptedTypes.Premium" = "Premium Subscriptions";
"Privacy.Gifts.AcceptedTypes.Info" = "Choose the types of gifts that you allow others to send you.";
"Chat.PanelFrozenAccount.Title" = "You account is frozen";
"Chat.PanelFrozenAccount.Text" = "Tap to view details";
"FrozenAccount.Title" = "Your Account is Frozen";
"FrozenAccount.Violation.Title" = "Violation of Terms";
"FrozenAccount.Violation.Text" = "Your account was frozen for breaking Telegram's Terms and Conditions.";
"FrozenAccount.ReadOnly.Title" = "Read-Only Mode";
"FrozenAccount.ReadOnly.Text" = "You can access your account but can't send messages or take actions.";
"FrozenAccount.Appeal.Title" = "Appeal Before Deactivation";
"FrozenAccount.Appeal.Text" = "Appeal via [@SpamBot]() before %@, or your account will be deleted.";
"FrozenAccount.SubmitAppeal" = "Submit an Appeal";
"FrozenAccount.Understood" = "Understood";
"AdsInfo.Search.Respect.Text" = "Ads like this do not use your personal information and are based on the search query you entered.";
"AdsInfo.Search.Ads.Text" = "You can turn off ads by subscribing to [Telegram Premium]().";
"AdsInfo.Search.Launch.Text" = "Anyone can create an ad to display in search results for any query. Check out the Telegram Ad Platform for details. [Learn More >]()";
"ChatList.FrozenAccount.Title" = "Your account is frozen";
"ChatList.FrozenAccount.Text" = "Tap to view details and submit an appeal.";

View File

@ -11,6 +11,7 @@ public final class BotCheckoutController: ViewController {
public final class InputData {
public enum FetchError {
case generic
case disallowedStarGifts
}
public let form: BotPaymentForm
@ -53,8 +54,13 @@ public final class BotCheckoutController: ViewController {
}
return context.engine.payments.fetchBotPaymentForm(source: source, themeParams: themeParams)
|> mapError { _ -> FetchError in
return .generic
|> mapError { error -> FetchError in
switch error {
case .disallowedStarGift:
return .disallowedStarGifts
default:
return .generic
}
}
|> mapToSignal { paymentForm -> Signal<InputData, FetchError> in
let botPeer: Signal<EnginePeer?, FetchError>

View File

@ -6139,7 +6139,6 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
let context = self.context
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
//TODO:localize
var actions: [ContextMenuItem] = []
if adPeer.sponsorInfo != nil || adPeer.additionalInfo != nil {
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.Chat_ContextMenu_AdSponsorInfo, textColor: .primary, icon: { theme in
@ -6191,7 +6190,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
})))
}
actions.append(.action(ContextMenuActionItem(text: "About These Ads", textColor: .primary, textLayout: .twoLinesMax, textFont: .custom(font: Font.regular(presentationData.listsFontSize.baseDisplaySize - 1.0), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.Chat_ContextMenu_AboutAd, textColor: .primary, textLayout: .twoLinesMax, textFont: .custom(font: Font.regular(presentationData.listsFontSize.baseDisplaySize - 1.0), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Info"), color: theme.actionSheet.primaryTextColor)
}, iconSource: nil, action: { [weak self] _, f in
f(.default)

View File

@ -855,6 +855,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .generalSearch(isSavedMessages: false), peer: .peer(peer: peer.peer, chatPeer: peer.peer), status: .addressName(suffixString), badge: nil, requiresPremiumForMessaging: false, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, searchQuery: nil, isAd: true, action: { _ in
interaction.peerSelected(peer.peer, nil, nil, nil, false)
context.engine.messages.markAdAction(opaqueId: peer.opaqueId, media: false, fullscreen: false)
}, disabledAction: { _ in
interaction.disabledPeerSelected(peer.peer, nil, .generic)
}, contextAction: peerContextAction.flatMap { peerContextAction in

View File

@ -289,9 +289,8 @@ final class ChatListNoticeItemNode: ItemListRevealOptionsItemNode {
textString = NSAttributedString(string: item.strings.ChatList_AddPhoto_Text, font: smallTextFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
avatarPeer = accountPeer
case .accountFreeze:
//TODO:localize
titleString = NSAttributedString(string: "Your account is frozen", font: titleFont, textColor: item.theme.list.itemDestructiveColor)
textString = NSAttributedString(string: "Tap to view details and submit an appeal.", font: smallTextFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
titleString = NSAttributedString(string: item.strings.ChatList_FrozenAccount_Title, font: titleFont, textColor: item.theme.list.itemDestructiveColor)
textString = NSAttributedString(string: item.strings.ChatList_FrozenAccount_Text, font: smallTextFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
}
var leftInset: CGFloat = sideInset

View File

@ -36,12 +36,13 @@ public class ItemListCheckboxItem: ListViewItem, ItemListItem {
let color: ItemListCheckboxItemColor
let textColor: TextColor
let checked: Bool
let enabled: Bool
let zeroSeparatorInsets: Bool
public let sectionId: ItemListSectionId
let action: () -> Void
let deleteAction: (() -> Void)?
public init(presentationData: ItemListPresentationData, icon: UIImage? = nil, iconSize: CGSize? = nil, iconPlacement: IconPlacement = .default, title: String, subtitle: String? = nil, style: ItemListCheckboxItemStyle, color: ItemListCheckboxItemColor = .accent, textColor: TextColor = .primary, checked: Bool, zeroSeparatorInsets: Bool, sectionId: ItemListSectionId, action: @escaping () -> Void, deleteAction: (() -> Void)? = nil) {
public init(presentationData: ItemListPresentationData, icon: UIImage? = nil, iconSize: CGSize? = nil, iconPlacement: IconPlacement = .default, title: String, subtitle: String? = nil, style: ItemListCheckboxItemStyle, color: ItemListCheckboxItemColor = .accent, textColor: TextColor = .primary, checked: Bool, enabled: Bool = true, zeroSeparatorInsets: Bool, sectionId: ItemListSectionId, action: @escaping () -> Void, deleteAction: (() -> Void)? = nil) {
self.presentationData = presentationData
self.icon = icon
self.iconSize = iconSize
@ -52,6 +53,7 @@ public class ItemListCheckboxItem: ListViewItem, ItemListItem {
self.color = color
self.textColor = textColor
self.checked = checked
self.enabled = enabled
self.zeroSeparatorInsets = zeroSeparatorInsets
self.sectionId = sectionId
self.action = action
@ -95,7 +97,9 @@ public class ItemListCheckboxItem: ListViewItem, ItemListItem {
public func selected(listView: ListView){
listView.clearHighlightAnimated(true)
self.action()
if self.enabled {
self.action()
}
}
}
@ -209,7 +213,7 @@ public class ItemListCheckboxItemNode: ItemListRevealOptionsItemNode {
let titleFont = Font.regular(item.presentationData.fontSize.itemListBaseFontSize)
let subtitleFont = Font.regular(floor(item.presentationData.fontSize.itemListBaseFontSize * 15.0 / 17.0))
let titleColor: UIColor
var titleColor: UIColor
let subtitleColor: UIColor = item.presentationData.theme.list.itemSecondaryTextColor
switch item.textColor {
case .primary:
@ -217,6 +221,9 @@ public class ItemListCheckboxItemNode: ItemListRevealOptionsItemNode {
case .accent:
titleColor = item.presentationData.theme.list.itemAccentColor
}
if !item.enabled {
titleColor = item.presentationData.theme.list.itemDisabledTextColor
}
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.title, font: titleFont, textColor: titleColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 28.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
@ -239,12 +246,16 @@ public class ItemListCheckboxItemNode: ItemListRevealOptionsItemNode {
updatedTheme = item.presentationData.theme
}
if currentItem?.presentationData.theme !== item.presentationData.theme || currentItem?.color != item.color {
switch item.color {
case .accent:
updateCheckImage = PresentationResourcesItemList.checkIconImage(item.presentationData.theme)
case .secondary:
updateCheckImage = PresentationResourcesItemList.secondaryCheckIconImage(item.presentationData.theme)
if currentItem?.presentationData.theme !== item.presentationData.theme || currentItem?.color != item.color || currentItem?.enabled != item.enabled {
if !item.enabled {
updateCheckImage = PresentationResourcesItemList.disabledCheckIconImage(item.presentationData.theme)
} else {
switch item.color {
case .accent:
updateCheckImage = PresentationResourcesItemList.checkIconImage(item.presentationData.theme)
case .secondary:
updateCheckImage = PresentationResourcesItemList.secondaryCheckIconImage(item.presentationData.theme)
}
}
}
@ -261,6 +272,11 @@ public class ItemListCheckboxItemNode: ItemListRevealOptionsItemNode {
} else {
strongSelf.activateArea.accessibilityValue = ""
}
if item.enabled {
strongSelf.activateArea.accessibilityTraits = []
} else {
strongSelf.activateArea.accessibilityTraits = [.notEnabled]
}
strongSelf.activateArea.frame = CGRect(origin: CGPoint(x: params.leftInset, y: 0.0), size: CGSize(width: params.width - params.leftInset - params.rightInset, height: layout.contentSize.height))
@ -368,7 +384,7 @@ public class ItemListCheckboxItemNode: ItemListRevealOptionsItemNode {
override public func setHighlighted(_ highlighted: Bool, at point: CGPoint, animated: Bool) {
super.setHighlighted(highlighted, at: point, animated: animated)
if highlighted {
if highlighted && (self.item?.enabled ?? false) {
self.highlightedBackgroundNode.alpha = 1.0
if self.highlightedBackgroundNode.supernode == nil {
var anchorNode: ASDisplayNode?

View File

@ -141,13 +141,13 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
case forwardsPreview(PresentationTheme, TelegramWallpaper, PresentationFontSize, PresentationChatBubbleCorners, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, String, Bool, String)
case birthdayHeader(PresentationTheme, String)
case settingHeader(PresentationTheme, String)
case everybody(PresentationTheme, String, Bool, Bool)
case contacts(PresentationTheme, String, Bool, Bool)
case nobody(PresentationTheme, String, Bool, Bool)
case everybody(PresentationTheme, String, Bool, Bool, Bool)
case contacts(PresentationTheme, String, Bool, Bool, Bool)
case nobody(PresentationTheme, String, Bool, Bool, Bool)
case settingInfo(PresentationTheme, String, String)
case exceptionsHeader(PresentationTheme, String)
case disableFor(PresentationTheme, String, String)
case enableFor(PresentationTheme, String, String)
case disableFor(PresentationTheme, String, String, Bool)
case enableFor(PresentationTheme, String, String, Bool)
case peersInfo(PresentationTheme, String)
case callsP2PHeader(PresentationTheme, String)
case callsP2PAlways(PresentationTheme, String, Bool)
@ -323,20 +323,20 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
} else {
return false
}
case let .everybody(lhsTheme, lhsText, lhsValue, lhsIsLocked):
if case let .everybody(rhsTheme, rhsText, rhsValue, rhsIsLocked) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue, lhsIsLocked == rhsIsLocked {
case let .everybody(lhsTheme, lhsText, lhsValue, lhsIsLocked, lhsEnabled):
if case let .everybody(rhsTheme, rhsText, rhsValue, rhsIsLocked, rhsEnabled) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue, lhsIsLocked == rhsIsLocked, lhsEnabled == rhsEnabled {
return true
} else {
return false
}
case let .contacts(lhsTheme, lhsText, lhsValue, lhsIsLocked):
if case let .contacts(rhsTheme, rhsText, rhsValue, rhsIsLocked) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue, lhsIsLocked == rhsIsLocked {
case let .contacts(lhsTheme, lhsText, lhsValue, lhsIsLocked, lhsEnabled):
if case let .contacts(rhsTheme, rhsText, rhsValue, rhsIsLocked, rhsEnabled) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue, lhsIsLocked == rhsIsLocked, lhsEnabled == rhsEnabled {
return true
} else {
return false
}
case let .nobody(lhsTheme, lhsText, lhsValue, lhsIsLocked):
if case let .nobody(rhsTheme, rhsText, rhsValue, rhsIsLocked) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue, lhsIsLocked == rhsIsLocked {
case let .nobody(lhsTheme, lhsText, lhsValue, lhsIsLocked, lhsEnabled):
if case let .nobody(rhsTheme, rhsText, rhsValue, rhsIsLocked, rhsEnabled) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue, lhsIsLocked == rhsIsLocked, lhsEnabled == rhsEnabled {
return true
} else {
return false
@ -353,14 +353,14 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
} else {
return false
}
case let .disableFor(lhsTheme, lhsText, lhsValue):
if case let .disableFor(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
case let .disableFor(lhsTheme, lhsText, lhsValue, lhsEnabled):
if case let .disableFor(rhsTheme, rhsText, rhsValue, rhsEnabled) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue, lhsEnabled == rhsEnabled {
return true
} else {
return false
}
case let .enableFor(lhsTheme, lhsText, lhsValue):
if case let .enableFor(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
case let .enableFor(lhsTheme, lhsText, lhsValue, lhsEnabled):
if case let .enableFor(rhsTheme, rhsText, rhsValue, rhsEnabled) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue, lhsEnabled == rhsEnabled {
return true
} else {
return false
@ -565,23 +565,23 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
})
case let .settingHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, multiline: true, sectionId: self.section)
case let .everybody(_, text, value, isLocked):
return ItemListCheckboxItem(presentationData: presentationData, icon: !isLocked ? nil : generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/Lock"), color: presentationData.theme.list.itemSecondaryTextColor), iconPlacement: .check, title: text, style: .left, checked: value && !isLocked, zeroSeparatorInsets: false, sectionId: self.section, action: {
case let .everybody(_, text, value, isLocked, isEnabled):
return ItemListCheckboxItem(presentationData: presentationData, icon: !isLocked ? nil : generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/Lock"), color: presentationData.theme.list.itemSecondaryTextColor), iconPlacement: .check, title: text, style: .left, checked: value && !isLocked, enabled: isEnabled, zeroSeparatorInsets: false, sectionId: self.section, action: {
if isLocked {
} else {
arguments.updateType(.everybody)
}
})
case let .contacts(_, text, value, isLocked):
return ItemListCheckboxItem(presentationData: presentationData, icon: !isLocked ? nil : generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/Lock"), color: presentationData.theme.list.itemSecondaryTextColor), iconPlacement: .check, title: text, style: .left, checked: value && !isLocked, zeroSeparatorInsets: false, sectionId: self.section, action: {
case let .contacts(_, text, value, isLocked, isEnabled):
return ItemListCheckboxItem(presentationData: presentationData, icon: !isLocked ? nil : generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/Lock"), color: presentationData.theme.list.itemSecondaryTextColor), iconPlacement: .check, title: text, style: .left, checked: value && !isLocked, enabled: isEnabled, zeroSeparatorInsets: false, sectionId: self.section, action: {
if isLocked {
arguments.displayLockedInfo()
} else {
arguments.updateType(.contacts)
}
})
case let .nobody(_, text, value, isLocked):
return ItemListCheckboxItem(presentationData: presentationData, icon: !isLocked ? nil : generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/Lock"), color: presentationData.theme.list.itemSecondaryTextColor), iconPlacement: .check, title: text, style: .left, checked: value && !isLocked, zeroSeparatorInsets: false, sectionId: self.section, action: {
case let .nobody(_, text, value, isLocked, isEnabled):
return ItemListCheckboxItem(presentationData: presentationData, icon: !isLocked ? nil : generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/Lock"), color: presentationData.theme.list.itemSecondaryTextColor), iconPlacement: .check, title: text, style: .left, checked: value && !isLocked, enabled: isEnabled, zeroSeparatorInsets: false, sectionId: self.section, action: {
if isLocked {
arguments.displayLockedInfo()
} else {
@ -594,12 +594,12 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
})
case let .exceptionsHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .disableFor(_, title, value):
return ItemListDisclosureItem(presentationData: presentationData, title: title, label: value, sectionId: self.section, style: .blocks, action: {
arguments.openSelective(.main, false)
})
case let .enableFor(_, title, value):
return ItemListDisclosureItem(presentationData: presentationData, title: title, label: value, sectionId: self.section, style: .blocks, action: {
case let .disableFor(_, title, value, isEnabled):
return ItemListDisclosureItem(presentationData: presentationData, title: title, enabled: isEnabled, label: value, sectionId: self.section, style: .blocks, action: {
arguments.openSelective(.main, false)
})
case let .enableFor(_, title, value, isEnabled):
return ItemListDisclosureItem(presentationData: presentationData, title: title, enabled: isEnabled, label: value, sectionId: self.section, style: .blocks, action: {
arguments.openSelective(.main, true)
})
case let .peersInfo(_, text):
@ -1000,9 +1000,14 @@ private func selectivePrivacySettingsControllerEntries(presentationData: Present
enableForText = presentationData.strings.Privacy_GroupsAndChannels_AlwaysAllow
}
var permisisonsEnabled = true
if case .giftsAutoSave = kind {
entries.append(.showGiftButton(presentationData.theme, "Show Gift Icon in Chats", !isPremium, state.showGiftButton == true && state.disallowedGifts != TelegramDisallowedGifts.All, state.disallowedGifts != TelegramDisallowedGifts.All))
entries.append(.showGiftButtonInfo(presentationData.theme, "Display the # Gift icon in the message input field for both participants in all chats."))
entries.append(.showGiftButton(presentationData.theme, presentationData.strings.Privacy_Gifts_ShowGiftButton, !isPremium, state.showGiftButton == true, true))
entries.append(.showGiftButtonInfo(presentationData.theme, presentationData.strings.Privacy_Gifts_ShowGiftButtonInfo.replacingOccurrences(of: "#", with: " # ")))
if state.disallowedGifts == TelegramDisallowedGifts.All {
permisisonsEnabled = false
}
}
if case .forwards = kind {
@ -1030,13 +1035,13 @@ private func selectivePrivacySettingsControllerEntries(presentationData: Present
entries.append(.settingHeader(presentationData.theme, settingTitle))
if case .voiceMessages = kind {
entries.append(.everybody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenEverybody, state.setting == .everybody || !isPremium, false))
entries.append(.contacts(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenContacts, state.setting == .contacts && isPremium, !isPremium))
entries.append(.nobody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenNobody, state.setting == .nobody && isPremium, !isPremium))
entries.append(.everybody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenEverybody, state.setting == .everybody || !isPremium, false, permisisonsEnabled))
entries.append(.contacts(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenContacts, state.setting == .contacts && isPremium, !isPremium, permisisonsEnabled))
entries.append(.nobody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenNobody, state.setting == .nobody && isPremium, !isPremium, permisisonsEnabled))
} else {
entries.append(.everybody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenEverybody, state.setting == .everybody, false))
entries.append(.contacts(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenContacts, state.setting == .contacts, false))
entries.append(.nobody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenNobody, state.setting == .nobody, false))
entries.append(.everybody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenEverybody, state.setting == .everybody, false, permisisonsEnabled))
entries.append(.contacts(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenContacts, state.setting == .contacts, false, permisisonsEnabled))
entries.append(.nobody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenNobody, state.setting == .nobody, false, permisisonsEnabled))
}
if let settingInfoText = settingInfoText {
@ -1059,12 +1064,12 @@ private func selectivePrivacySettingsControllerEntries(presentationData: Present
switch state.setting {
case .everybody:
entries.append(.disableFor(presentationData.theme, disableForText, stringForUserCount(state.disableFor, enableForPremium: false, enableForBots: false, strings: presentationData.strings)))
entries.append(.disableFor(presentationData.theme, disableForText, stringForUserCount(state.disableFor, enableForPremium: false, enableForBots: false, strings: presentationData.strings), permisisonsEnabled))
case .contacts:
entries.append(.disableFor(presentationData.theme, disableForText, stringForUserCount(state.disableFor, enableForPremium: false, enableForBots: false, strings: presentationData.strings)))
entries.append(.enableFor(presentationData.theme, enableForText, stringForUserCount(state.enableFor, enableForPremium: state.enableForPremium, enableForBots: state.enableForBots, strings: presentationData.strings)))
entries.append(.disableFor(presentationData.theme, disableForText, stringForUserCount(state.disableFor, enableForPremium: false, enableForBots: false, strings: presentationData.strings), permisisonsEnabled))
entries.append(.enableFor(presentationData.theme, enableForText, stringForUserCount(state.enableFor, enableForPremium: state.enableForPremium, enableForBots: state.enableForBots, strings: presentationData.strings), permisisonsEnabled))
case .nobody:
entries.append(.enableFor(presentationData.theme, enableForText, stringForUserCount(state.enableFor, enableForPremium: state.enableForPremium, enableForBots: state.enableForBots, strings: presentationData.strings)))
entries.append(.enableFor(presentationData.theme, enableForText, stringForUserCount(state.enableFor, enableForPremium: state.enableForPremium, enableForBots: state.enableForBots, strings: presentationData.strings), permisisonsEnabled))
}
let exceptionsInfo: String
if case .profilePhoto = kind {
@ -1146,13 +1151,12 @@ private func selectivePrivacySettingsControllerEntries(presentationData: Present
}
if case .giftsAutoSave = kind {
//TODO:localize
entries.append(.disallowedGiftsHeader(presentationData.theme, "ACCEPTED GIFT TYPES"))
entries.append(.disallowedGiftsUnlimited(presentationData.theme, "Unlimited", !isPremium, !(state.disallowedGifts?.contains(.unlimited) ?? false)))
entries.append(.disallowedGiftsLimited(presentationData.theme, "Limited-Edition", !isPremium, !(state.disallowedGifts?.contains(.limited) ?? false)))
entries.append(.disallowedGiftsUnique(presentationData.theme, "Unique", !isPremium, !(state.disallowedGifts?.contains(.unique) ?? false)))
entries.append(.disallowedGiftsPremium(presentationData.theme, "Premium Subscriptions", !isPremium, !(state.disallowedGifts?.contains(.premium) ?? false)))
entries.append(.disallowedGiftsInfo(presentationData.theme, "Choose the types of gifts that you allow others to send you."))
entries.append(.disallowedGiftsHeader(presentationData.theme, presentationData.strings.Privacy_Gifts_AcceptedTypes.uppercased()))
entries.append(.disallowedGiftsUnlimited(presentationData.theme, presentationData.strings.Privacy_Gifts_AcceptedTypes_Unlimited, !isPremium, !(state.disallowedGifts?.contains(.unlimited) ?? false)))
entries.append(.disallowedGiftsLimited(presentationData.theme, presentationData.strings.Privacy_Gifts_AcceptedTypes_Limited, !isPremium, !(state.disallowedGifts?.contains(.limited) ?? false)))
entries.append(.disallowedGiftsUnique(presentationData.theme, presentationData.strings.Privacy_Gifts_AcceptedTypes_Unique, !isPremium, !(state.disallowedGifts?.contains(.unique) ?? false)))
entries.append(.disallowedGiftsPremium(presentationData.theme, presentationData.strings.Privacy_Gifts_AcceptedTypes_Premium, !isPremium, !(state.disallowedGifts?.contains(.premium) ?? false)))
entries.append(.disallowedGiftsInfo(presentationData.theme, presentationData.strings.Privacy_Gifts_AcceptedTypes_Info))
}
return entries

View File

@ -1000,7 +1000,7 @@ public final class CachedUserData: CachedPeerData {
public let starRefProgram: TelegramStarRefProgram?
public let verification: PeerVerification?
public let sendPaidMessageStars: StarsAmount?
public let disallowedGifts: TelegramDisallowedGifts
public let disallowedGifts: TelegramDisallowedGifts?
public let peerIds: Set<PeerId>
public let messageIds: Set<MessageId>
@ -1042,10 +1042,10 @@ public final class CachedUserData: CachedPeerData {
self.starRefProgram = nil
self.verification = nil
self.sendPaidMessageStars = nil
self.disallowedGifts = []
self.disallowedGifts = nil
}
public init(about: String?, botInfo: BotInfo?, editableBotInfo: EditableBotInfo?, peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, isBlocked: Bool, commonGroupCount: Int32, voiceCallsAvailable: Bool, videoCallsAvailable: Bool, callsPrivate: Bool, canPinMessages: Bool, hasScheduledMessages: Bool, autoremoveTimeout: CachedPeerAutoremoveTimeout, themeEmoticon: String?, photo: CachedPeerProfilePhoto, personalPhoto: CachedPeerProfilePhoto, fallbackPhoto: CachedPeerProfilePhoto, voiceMessagesAvailable: Bool, wallpaper: TelegramWallpaper?, flags: CachedUserFlags, businessHours: TelegramBusinessHours?, businessLocation: TelegramBusinessLocation?, greetingMessage: TelegramBusinessGreetingMessage?, awayMessage: TelegramBusinessAwayMessage?, connectedBot: TelegramAccountConnectedBot?, businessIntro: CachedTelegramBusinessIntro, birthday: TelegramBirthday?, personalChannel: CachedTelegramPersonalChannel, botPreview: BotPreview?, starGiftsCount: Int32?, starRefProgram: TelegramStarRefProgram?, verification: PeerVerification?, sendPaidMessageStars: StarsAmount?, disallowedGifts: TelegramDisallowedGifts) {
public init(about: String?, botInfo: BotInfo?, editableBotInfo: EditableBotInfo?, peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, isBlocked: Bool, commonGroupCount: Int32, voiceCallsAvailable: Bool, videoCallsAvailable: Bool, callsPrivate: Bool, canPinMessages: Bool, hasScheduledMessages: Bool, autoremoveTimeout: CachedPeerAutoremoveTimeout, themeEmoticon: String?, photo: CachedPeerProfilePhoto, personalPhoto: CachedPeerProfilePhoto, fallbackPhoto: CachedPeerProfilePhoto, voiceMessagesAvailable: Bool, wallpaper: TelegramWallpaper?, flags: CachedUserFlags, businessHours: TelegramBusinessHours?, businessLocation: TelegramBusinessLocation?, greetingMessage: TelegramBusinessGreetingMessage?, awayMessage: TelegramBusinessAwayMessage?, connectedBot: TelegramAccountConnectedBot?, businessIntro: CachedTelegramBusinessIntro, birthday: TelegramBirthday?, personalChannel: CachedTelegramPersonalChannel, botPreview: BotPreview?, starGiftsCount: Int32?, starRefProgram: TelegramStarRefProgram?, verification: PeerVerification?, sendPaidMessageStars: StarsAmount?, disallowedGifts: TelegramDisallowedGifts?) {
self.about = about
self.botInfo = botInfo
self.editableBotInfo = editableBotInfo
@ -1153,7 +1153,7 @@ public final class CachedUserData: CachedPeerData {
self.sendPaidMessageStars = decoder.decodeCodable(StarsAmount.self, forKey: "sendPaidMessageStars")
self.disallowedGifts = TelegramDisallowedGifts(rawValue: decoder.decodeInt32ForKey("disallowedGifts", orElse: 0))
self.disallowedGifts = decoder.decodeOptionalInt32ForKey("disallowedGifts").flatMap { TelegramDisallowedGifts(rawValue: $0) }
}
public func encode(_ encoder: PostboxEncoder) {
@ -1283,7 +1283,11 @@ public final class CachedUserData: CachedPeerData {
encoder.encodeNil(forKey: "sendPaidMessageStars")
}
encoder.encodeInt32(self.disallowedGifts.rawValue, forKey: "disallowedGifts")
if let disallowedGifts = self.disallowedGifts {
encoder.encodeInt32(disallowedGifts.rawValue, forKey: "disallowedGifts")
} else {
encoder.encodeNil(forKey: "disallowedGifts")
}
}
public func isEqual(to: CachedPeerData) -> Bool {

View File

@ -617,9 +617,6 @@ func _internal_markAdAction(account: Account, opaqueId: Data, media: Bool, fulls
let _ = signal.start()
}
func _internal_markAsSeen(account: Account, opaqueId: Data) -> Signal<Never, NoError> {
return account.network.request(Api.functions.messages.viewSponsoredMessage(randomId: Buffer(data: opaqueId)))
|> `catch` { _ -> Signal<Api.Bool, NoError> in

View File

@ -43,6 +43,7 @@ public enum PresentationResourceKey: Int32 {
case itemListDisclosureLocked
case itemListCheckIcon
case itemListSecondaryCheckIcon
case itemListDisabledCheckIcon
case itemListPlusIcon
case itemListRoundPlusIcon
case itemListAccentDeleteIcon

View File

@ -57,6 +57,12 @@ public struct PresentationResourcesItemList {
})
}
public static func disabledCheckIconImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListDisabledCheckIcon.rawValue, { theme in
return generateItemListCheckIcon(color: theme.list.itemDisabledTextColor)
})
}
public static func plusIconImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListPlusIcon.rawValue, { theme in
return generateItemListPlusIcon(theme.list.itemAccentColor)

View File

@ -193,10 +193,9 @@ private final class ScrollContent: CombinedComponent {
adsText = strings.AdsInfo_Bot_Ads_Text
infoRawText = strings.AdsInfo_Bot_Launch_Text
case .search:
//TODO:localize
respectText = "Ads like this do not use your personal information and are based on the search query you entered."
adsText = strings.AdsInfo_Bot_Ads_Text
infoRawText = "Anyone can create an ad to display in search results for any query. Check out the Telegram Ad Platform for details. [Learn More >]()"
respectText = strings.AdsInfo_Search_Respect_Text
adsText = strings.AdsInfo_Search_Ads_Text
infoRawText = strings.AdsInfo_Search_Launch_Text
}
var items: [AnyComponentWithIdentity<Empty>] = []

View File

@ -692,6 +692,10 @@ final class GiftOptionsScreenComponent: Component {
}
self.component = component
if let disallowedGifts = self.state?.disallowedGifts, disallowedGifts == .All {
controller()?.dismiss()
}
if (state.starGifts ?? []).isEmpty && !(state.transferStarGifts ?? []).isEmpty {
self.starsFilter = .transfer
}
@ -1344,19 +1348,26 @@ final class GiftOptionsScreenComponent: Component {
self.disposable = combineLatest(
queue: Queue.mainQueue(),
context.engine.data.get(
TelegramEngine.EngineData.Item.Peer.Peer.init(id: peerId),
TelegramEngine.EngineData.Item.Peer.Peer.init(id: peerId)
),
context.engine.data.subscribe(
TelegramEngine.EngineData.Item.Peer.DisallowedGifts(id: peerId)
),
availableProducts,
context.engine.payments.cachedStarGifts(),
self.starGiftsContext.state
).start(next: { [weak self] data, availableProducts, starGifts, profileGiftsState in
).start(next: { [weak self] peer, disallowedGifts, availableProducts, starGifts, profileGiftsState in
guard let self else {
return
}
self.peer = data.0
self.disallowedGifts = data.1 ?? []
if disallowedGifts == nil && self.peer == nil, case .user = peer {
let _ = context.engine.peers.fetchAndUpdateCachedPeerData(peerId: peerId).startStandalone()
}
self.peer = peer
self.disallowedGifts = disallowedGifts ?? []
if peerId != context.account.peerId {
if availableProducts.isEmpty {
var premiumProducts: [PremiumGiftProduct] = []

View File

@ -390,8 +390,13 @@ final class GiftSetupScreenComponent: Component {
let completion = component.completion
let signal = BotCheckoutController.InputData.fetch(context: component.context, source: source)
|> `catch` { _ -> Signal<BotCheckoutController.InputData, SendBotPaymentFormError> in
return .fail(.generic)
|> `catch` { error -> Signal<BotCheckoutController.InputData, SendBotPaymentFormError> in
switch error {
case .disallowedStarGifts:
return .fail(.disallowedStarGift)
default:
return .fail(.generic)
}
}
|> mapToSignal { inputData -> Signal<SendBotPaymentResult, SendBotPaymentFormError> in
return component.context.engine.payments.sendStarsPaymentForm(formId: inputData.form.id, source: source)

View File

@ -14363,7 +14363,7 @@ private final class AccountPeerContextItemNode: ASDisplayNode, ContextMenuCustom
action: nil
)),
environment: {},
containerSize: CGSize(width: 28.0, height: 28.0)
containerSize: CGSize(width: 24.0, height: 24.0)
)
if let view = self.emojiStatusView.view {
if view.superview == nil {

View File

@ -111,7 +111,7 @@ private final class SheetContent: CombinedComponent {
let title = title.update(
component: BalancedTextComponent(
text: .plain(NSAttributedString(string: "Your Account is Frozen", font: titleFont, textColor: textColor)),
text: .plain(NSAttributedString(string: strings.FrozenAccount_Title, font: titleFont, textColor: textColor)),
horizontalAlignment: .center,
maximumNumberOfLines: 0,
lineSpacing: 0.1
@ -125,15 +125,14 @@ private final class SheetContent: CombinedComponent {
contentSize.height += title.size.height
contentSize.height += spacing - 2.0
//TODO:localize
var items: [AnyComponentWithIdentity<Empty>] = []
items.append(
AnyComponentWithIdentity(
id: "ads",
id: "violation",
component: AnyComponent(ParagraphComponent(
title: "Violation of Terms",
title: strings.FrozenAccount_Violation_Title,
titleColor: textColor,
text: "Your account was frozen for breaking Telegram's Terms and Conditions.",
text: strings.FrozenAccount_Violation_Text,
textColor: secondaryTextColor,
iconName: "Account Freeze/Violation",
iconColor: linkColor
@ -142,11 +141,11 @@ private final class SheetContent: CombinedComponent {
)
items.append(
AnyComponentWithIdentity(
id: "split",
id: "readOnly",
component: AnyComponent(ParagraphComponent(
title: "Read-Only Mode",
title: strings.FrozenAccount_ReadOnly_Title,
titleColor: textColor,
text: "You can access your account but can't send messages or take actions.",
text: strings.FrozenAccount_ReadOnly_Text,
textColor: secondaryTextColor,
iconName: "Ads/Privacy",
iconColor: linkColor
@ -156,19 +155,17 @@ private final class SheetContent: CombinedComponent {
let dateString = stringForFullDate(timestamp: component.configuration.freezeUntilDate ?? 0, strings: strings, dateTimeFormat: environment.dateTimeFormat)
items.append(
AnyComponentWithIdentity(
id: "withdrawal",
id: "appeal",
component: AnyComponent(ParagraphComponent(
title: "Appeal Before Deactivation",
title: strings.FrozenAccount_Appeal_Title,
titleColor: textColor,
text: "Appeal via [@SpamBot]() before \(dateString), or your account will be deleted.",
text: strings.FrozenAccount_Appeal_Text(dateString).string,
textColor: secondaryTextColor,
iconName: "Account Freeze/Appeal",
iconColor: linkColor,
action: {
component.submitAppeal()
component.dismiss()
Queue.mainQueue().after(0.5) {
component.submitAppeal()
}
}
))
)
@ -185,7 +182,7 @@ private final class SheetContent: CombinedComponent {
contentSize.height += list.size.height
contentSize.height += spacing + 2.0
let buttonAttributedString = NSMutableAttributedString(string: "Submit an Appeal", font: Font.semibold(17.0), textColor: environment.theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center)
let buttonAttributedString = NSMutableAttributedString(string: strings.FrozenAccount_SubmitAppeal, font: Font.semibold(17.0), textColor: environment.theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center)
let actionButton = actionButton.update(
component: ButtonComponent(
background: ButtonComponent.Background(
@ -201,10 +198,8 @@ private final class SheetContent: CombinedComponent {
isEnabled: true,
displaysProgress: false,
action: {
component.submitAppeal()
component.dismiss()
Queue.mainQueue().after(0.5) {
component.submitAppeal()
}
}
),
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: 50.0),
@ -217,7 +212,7 @@ private final class SheetContent: CombinedComponent {
contentSize.height += actionButton.size.height
contentSize.height += 8.0
let closeAttributedString = NSMutableAttributedString(string: "Understood", font: Font.regular(17.0), textColor: environment.theme.list.itemCheckColors.fillColor, paragraphAlignment: .center)
let closeAttributedString = NSMutableAttributedString(string: strings.FrozenAccount_Understood, font: Font.regular(17.0), textColor: environment.theme.list.itemCheckColors.fillColor, paragraphAlignment: .center)
let closeButton = closeButton.update(
component: ButtonComponent(
background: ButtonComponent.Background(
@ -390,10 +385,12 @@ public final class AccountFreezeInfoScreen: ViewControllerComponentContainer {
self.navigationPresentation = .flatModal
submitAppealImpl = { [weak self] in
guard let self, let url = configuration.freezeAppealUrl else {
guard let self, let navigationController = self.navigationController as? NavigationController, let url = configuration.freezeAppealUrl else {
return
}
context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: url, forceExternal: false, presentationData: context.sharedContext.currentPresentationData.with { $0 }, navigationController: self.navigationController as? NavigationController, dismissInput: {})
Queue.mainQueue().after(0.4) {
context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: url, forceExternal: false, presentationData: context.sharedContext.currentPresentationData.with { $0 }, navigationController: navigationController, dismissInput: {})
}
}
}

View File

@ -1061,11 +1061,16 @@ final class ChatbotSetupScreenComponent: Component {
)
if let subpermissions = permission.subpermissions {
value = false
value = true
var selectedCount = 0
for subpermission in subpermissions {
if subpermission.value == true {
value = true
if let key = subpermission.key {
if self.botRights.contains(key) {
selectedCount += 1
} else {
value = false
}
} else if subpermission.value == true {
selectedCount += 1
}
}
@ -1138,8 +1143,10 @@ final class ChatbotSetupScreenComponent: Component {
if let subpermissions = permission.subpermissions, permission.expanded == true {
for subpermission in subpermissions {
var value = false
if let key = permission.key {
if let key = subpermission.key {
value = self.botRights.contains(key)
} else if subpermission.value == true {
value = true
}
permissionsItems.append(

View File

@ -89,10 +89,9 @@ final class ChatRestrictedInputPanelNode: ChatInputPanelNode {
if let context = self.context {
accountFreezeConfiguration = AccountFreezeConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
}
//TODO:localize
if let _ = accountFreezeConfiguration?.freezeUntilDate {
self.textNode.attributedText = NSAttributedString(string: "You account is frozen", font: Font.semibold(15.0), textColor: interfaceState.theme.list.itemDestructiveColor)
self.subtitleNode.attributedText = NSAttributedString(string: "Tap to view details", font: Font.regular(13.0), textColor: interfaceState.theme.chat.inputPanel.secondaryTextColor)
self.textNode.attributedText = NSAttributedString(string: interfaceState.strings.Chat_PanelFrozenAccount_Title, font: Font.semibold(15.0), textColor: interfaceState.theme.list.itemDestructiveColor)
self.subtitleNode.attributedText = NSAttributedString(string: interfaceState.strings.Chat_PanelFrozenAccount_Text, font: Font.regular(13.0), textColor: interfaceState.theme.chat.inputPanel.secondaryTextColor)
isUserInteractionEnabled = true
} else if case let .replyThread(message) = interfaceState.chatLocation, message.peerId == self.context?.account.peerId {
self.textNode.attributedText = NSAttributedString(string: interfaceState.strings.Chat_PanelStatusAuthorHidden, font: Font.regular(13.0), textColor: interfaceState.theme.chat.inputPanel.secondaryTextColor)