Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2023-04-11 22:03:32 +04:00
commit eb7ad97b3a
16 changed files with 318 additions and 243 deletions

View File

@ -30,7 +30,7 @@ Install Xcode (directly from https://developer.apple.com/download/applications o
openssl rand -hex 8
```
2. Create a new Xcode project. Use `Telegram` as the Product Name. Use `org.{identifier from step 1}` as the Organization Identifier.
3. In Signing & Capabilities click on the `i` next to `Xcode Managed Profile` and copy the team ID (`ABCDEFG123`).
3. Open `Keychain Access` and navigate to `Certificates`. Locate `Apple Development: your@email.address (XXXXXXXXXX)` and double tap the certificate. Under `Details`, locate `Organizational Unit`. This is the Team ID.
4. Edit `build-system/template_minimal_development_configuration.json`. Use data from the previous steps.
## Generate an Xcode project

View File

@ -2009,6 +2009,16 @@ xcodeproj(
],
target_environments = ["device", "simulator"],
),
xcode_configurations = {
"Debug": {
"//command_line_option:compilation_mode": "dbg",
},
"Release": {
"//command_line_option:compilation_mode": "opt",
},
},
default_xcode_configuration = "Debug"
)
# Temporary targets used to simplify webrtc build tests

View File

@ -9169,3 +9169,152 @@ Sorry for the inconvenience.";
"PeerInfo.BotBlockedTitle" = "Bot Blocked";
"PeerInfo.BotBlockedText" = "This bot will not be able to message you.";
"ChatList.ContextMuteAll" = "Mute All";
"ChatList.ContextUnmuteAll" = "Unmute All";
"ChatList.ToastFolderMuted" = "All chats in **%@** are now muted";
"ChatList.ToastFolderUnmuted" = "All chats in **%@** are now unmuted";
"ChatList.ContextMenuShare" = "Share";
"ChatList.ContextMenuBadgeNew" = "NEW";
"ChatList.AlertDeleteFolderTitle" = "Delete Folder";
"ChatList.AlertDeleteFolderText" = "Are you sure you want to delete this folder? This will also deactivate all the invite links used to share this folder.";
"ChatList.PanelNewChatsAvailable_1" = "1 New Chat Available";
"ChatList.PanelNewChatsAvailable_any" = "%d New Chats Available";
"ChatListFilter.SectionShare" = "SHARE FOLDER";
"ChatListFilter.CreateLink" = "Create a new Link";
"ChatListFilter.CreateLinkNew" = "Create an Invite Link";
"ChatListFilter.ExcludeChatsAction" = "Add Chats to Exclude";
"ChatListFilter.LinkListInfo" = "Create more links to set up different access levels for different people.";
"ChatListFilter.LinkListInfoNew" = "Share access to some of this folder's groups and channels with others.";
"ChatListFilter.ToastChatsAddedTitle_1" = "Сhat added to folder";
"ChatListFilter.ToastChatsAddedTitle_any" = "%d chats added to folder";
"ChatListFilter.ToastChatsAddedText" = "It will not affect chatlist of the links of this folder";
"ChatListFilter.ToastChatsRemovedTitle_1" = "Сhat removed from folder";
"ChatListFilter.ToastChatsRemovedTitle_any" = "%d chats added to folder";
"ChatListFilter.ToastChatsRemovedText" = "It will not affect chatlist of the links of this folder";
"ChatListFilter.AlertCreateFolderBeforeSharingText" = "Please finish creating this folder to share it.";
"ChatListFilter.ErrorShareInvalidFolder" = "You cant share folders which have chat types or excluded chats.";
"ChatListFilter.SaveAlertActionSave" = "Save";
"ChatListFilter.CreateLinkUnknownError" = "Error creating a share link";
"ChatListFilter.CreateLinkErrorSomeoneHasChannelLimit" = "One of the groups in this folder cant be added because one of its admins has too many groups and channels.";
"ChatListFilterList.CreateFolder" = "Create a Folder";
"FolderLinkScreen.LabelCanInvite" = "you can invite others here";
"FolderLinkScreen.LabelUnavailableBot" = "you can't share chats with bots";
"FolderLinkScreen.AlertTextUnavailableBot" = "You can't share chats with bots";
"FolderLinkScreen.LabelUnavailableUser" = "you can't share private chats";
"FolderLinkScreen.AlertTextUnavailableUser" = "You can't share private chats";
"FolderLinkScreen.LabelUnavailableGeneric" = "you can't invite others here";
"FolderLinkScreen.AlertTextUnavailablePrivateGroup" = "You don't have the admin rights to share invite links to this private group.";
"FolderLinkScreen.AlertTextUnavailablePublicGroup" = "You don't have the admin rights to share invite links to this group chat.";
"FolderLinkScreen.AlertTextUnavailablePrivateChannel" = "You don't have the admin rights to share invite links to this private channel.";
"FolderLinkScreen.AlertTextUnavailablePublicChannel" = "You don't have the admin rights to share invite links to this channel.";
"FolderLinkScreen.TitleDescriptionUnavailable" = "You can only share groups and channels in which you are allowed to create invite links.";
"FolderLinkScreen.ChatCountHeaderUnavailable" = "There are no chats in this folder that you can share with others.";
"FolderLinkScreen.ChatsSectionHeaderUnavailable" = "THESE CHATS CANNOT BE SHARED";
"FolderLinkScreen.TitleDescriptionDeselected" = "Anyone with this link can add **%@** folder and the chats selected below.";
"FolderLinkScreen.ChatsSectionHeader" = "CHATS";
"FolderLinkScreen.ChatsSectionHeaderActionSelectAll" = "SELECT ALL";
"FolderLinkScreen.ChatsSectionHeaderActionDeselectAll" = "DESELECT ALL";
"FolderLinkScreen.TitleDescriptionSelectedCount_1" = "the 1 chat";
"FolderLinkScreen.TitleDescriptionSelectedCount_any" = "the %d chats";
"FolderLinkScreen.TitleDescriptionSelected" = "Anyone with this link can add **%1$@** folder and %2$@ selected below.";
"FolderLinkScreen.ChatsSectionHeaderSelected_1" = "1 CHAT SELECTED";
"FolderLinkScreen.ChatsSectionHeaderSelected_any" = "%d CHATS SELECTED";
"FolderLinkScreen.LinkSectionHeader" = "INVITE LINK";
"FolderLinkScreen.ContextActionNameLink" = "Name Link";
"FolderLinkScreen.NameLink.Title" = "Name This Link";
"FolderLinkScreen.ToastNewChatAdded" = "People who already used the invite link will be able to join newly added chats.";
"FolderLinkScreen.SaveUnknownError" = "An error occurred while updating the link";
"FolderLinkScreen.ToastLinkUpdated" = "Link updated";
"FolderLinkScreen.Title" = "Share Folder";
"FolderLinkScreen.SaveAlertTitle" = "Unsaved Changes";
"FolderLinkScreen.SaveAlertText" = "You have changed the settings of this folder. Apply changes?";
"FolderLinkScreen.SaveAlertActionDiscard" = "Discard";
"FolderLinkScreen.SaveAlertActionApply" = "Apply";
"FolderLinkScreen.SaveAlertActionContinue" = "Cancel";
"FolderLinkScreen.LinkActionCopy" = "Copy";
"FolderLinkScreen.LinkActionShare" = "Share";
"InviteLink.LabelJoinedViaFolder" = "joined via a folder invite link";
"ChatListFilter.LinkLabelChatCount_1" = "includes 1 chat";
"ChatListFilter.LinkLabelChatCount_any" = "includes %d chats";
"ChatListFilter.LinkActionDelete" = "Delete";
"InviteLink.QRCodeFolder.Title" = "Invite by QR Code";
"InviteLink.QRCodeFolder.Text" = "Everyone on Telegram can scan this code to add this folder and join the chats included in this invite link.";
"FolderLinkPreview.IconTabLeft" = "All Chats";
"FolderLinkPreview.IconTabRight" = "Personal";
"FolderLinkPreview.TitleShare" = "Share Folder";
"FolderLinkPreview.TitleRemove" = "Remove Folder";
"FolderLinkPreview.TitleAddFolder" = "Add Folder";
"FolderLinkPreview.TitleAddChats_1" = "Add %d Chat";
"FolderLinkPreview.TitleAddChats_any" = "Add %d Chats";
"FolderLinkPreview.LinkSectionHeader" = "INVITE LINKS";
"FolderLinkPreview.RemoveSectionSelectedHeader_1" = "%d CHAT TO QUIT";
"FolderLinkPreview.RemoveSectionSelectedHeader_any" = "%d CHATS TO QUIT";
"FolderLinkPreview.ChatSectionHeader_1" = "1 CHAT IN THIS FOLDER";
"FolderLinkPreview.ChatSectionHeader_any" = "%d CHATS IN THIS FOLDER";
"FolderLinkPreview.ChatSectionJoinHeader_1" = "1 CHAT IN THIS FOLDER TO JOIN";
"FolderLinkPreview.ChatSectionJoinHeader_any" = "%d CHATS IN THIS FOLDER TO JOIN";
"FolderLinkPreview.ToastChatsAddedTitle" = "Folder %@ Updated";
"FolderLinkPreview.ToastChatsAddedText_1" = "You have joined %d new chat";
"FolderLinkPreview.ToastChatsAddedText_any" = "You have joined %d new chats";
"FolderLinkPreview.ToastFolderAddedTitle" = "Folder %@ Added";
"FolderLinkPreview.ToastFolderAddedText_1" = "You also joined %d chat";
"FolderLinkPreview.ToastFolderAddedText_any" = "You also joined %d chats";
"FolderLinkPreview.TextLinkList" = "Create more links to set up different access\nlevels for different people.";
"FolderLinkPreview.TextRemoveFolder" = "Do you also want to quit the chats included in this folder?";
"FolderLinkPreview.TextAllAdded" = "You have already added this\nfolder and its chats.";
"FolderLinkPreview.TextAddFolder" = "Do you want to add a new chat folder\nand join its groups and channels?";
"FolderLinkPreview.TextAddChatsCount_1" = "%d chat";
"FolderLinkPreview.TextAddChatsCount_any" = "%d chats";
"FolderLinkPreview.TextAddChats" = "Do you want to add **%1$@** to the\nfolder **%2$@**?";
"FolderLinkPreview.LabelPeerSubscriber" = "You are already a subscriber";
"FolderLinkPreview.LabelPeerSubscribers_1" = "%d subscriber";
"FolderLinkPreview.LabelPeerSubscribers_any" = "%d subscribers";
"FolderLinkPreview.LabelPeerMember" = "You are already a member";
"FolderLinkPreview.LabelPeerMembers_1" = "%d member";
"FolderLinkPreview.LabelPeerMembers_any" = "%d members";
"FolderLinkPreview.ToastAlreadyMemberChannel" = "You are already subscribed to this channel.";
"FolderLinkPreview.ToastAlreadyMemberGroup" = "You are already a member of this group.";
"FolderLinkPreview.ButtonRemoveFolder" = "Remove Folder";
"FolderLinkPreview.ButtonRemoveFolderAndChats" = "Remove Folder and Chats";
"FolderLinkPreview.ButtonDoNotJoinChats" = "Do Not Join Any Chats";
"FolderLinkPreview.ButtonJoinChats" = "Join Chats";
"FolderLinkPreview.ButtonAddFolder" = "Add Folder";
"FolderLinkPreview.ToastLeftTitle" = "Folder %@ deleted";
"FolderLinkPreview.ToastLeftChatsText_1" = "You also left **%d** chat";
"FolderLinkPreview.ToastLeftChatsText_any" = "You also left **%d** chats";
"FolderLinkPreview.ListSelectionSelectAllDynamicPartSelect" = "SELECT";
"FolderLinkPreview.ListSelectionSelectAllDynamicPartDeselect" = "DESELECT";
"FolderLinkPreview.ListSelectionSelectAllStaticPartSelect" = "ALL";
"FolderLinkPreview.ListSelectionSelectAllStaticPartDeselect" = "ALL";
"FolderLinkPreview.ListSelectionSelectAllFormat" = "{dynamic}{static}";

View File

@ -1599,12 +1599,10 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
})))
}
//TODO:localize
for filter in filters {
if filter.id == filterId, case let .filter(_, title, _, data) = filter {
if let filterPeersAreMuted {
items.append(.action(ContextMenuActionItem(text: filterPeersAreMuted.areMuted ? "Unmute All" : "Mute All", textColor: .primary, badge: nil, icon: { theme in
items.append(.action(ContextMenuActionItem(text: filterPeersAreMuted.areMuted ? strongSelf.presentationData.strings.ChatList_ContextUnmuteAll : strongSelf.presentationData.strings.ChatList_ContextMuteAll, textColor: .primary, badge: nil, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: filterPeersAreMuted.areMuted ? "Chat/Context Menu/Unmute" : "Chat/Context Menu/Muted"), color: theme.contextMenu.primaryColor)
}, action: { c, f in
c.dismiss(completion: {
@ -1623,21 +1621,23 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
let iconColor: UIColor = .white
let overlayController: UndoOverlayController
if !filterPeersAreMuted.areMuted {
let text = strongSelf.presentationData.strings.ChatList_ToastFolderMuted(title).string
overlayController = UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_profilemute", scale: 0.075, colors: [
"Middle.Group 1.Fill 1": iconColor,
"Top.Group 1.Fill 1": iconColor,
"Bottom.Group 1.Fill 1": iconColor,
"EXAMPLE.Group 1.Fill 1": iconColor,
"Line.Group 1.Stroke 1": iconColor
], title: nil, text: "All chats in **\(title)** are now muted", customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false })
], title: nil, text: text, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false })
} else {
let text = strongSelf.presentationData.strings.ChatList_ToastFolderUnmuted(title).string
overlayController = UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_profileunmute", scale: 0.075, colors: [
"Middle.Group 1.Fill 1": iconColor,
"Top.Group 1.Fill 1": iconColor,
"Bottom.Group 1.Fill 1": iconColor,
"EXAMPLE.Group 1.Fill 1": iconColor,
"Line.Group 1.Stroke 1": iconColor
], title: nil, text: "All chats in **\(title)** are now unmuted", customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false })
], title: nil, text: text, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false })
}
strongSelf.present(overlayController, in: .current)
})
@ -1645,7 +1645,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
}
if !data.includePeers.peers.isEmpty && data.categories.isEmpty && !data.excludeRead && !data.excludeMuted && !data.excludeArchived && data.excludePeers.isEmpty {
items.append(.action(ContextMenuActionItem(text: "Share", textColor: .primary, badge: data.hasSharedLinks ? nil : ContextMenuActionBadge(value: "NEW", color: .accent, style: .label), icon: { theme in
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.ChatList_ContextMenuShare, textColor: .primary, badge: data.hasSharedLinks ? nil : ContextMenuActionBadge(value: strongSelf.presentationData.strings.ChatList_ContextMenuBadgeNew, color: .accent, style: .label), icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Link"), color: theme.contextMenu.primaryColor)
}, action: { c, f in
c.dismiss(completion: {
@ -2997,8 +2997,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
}
if hasLinks {
//TODO:localize
self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: "Delete Folder", text: "Are you sure you want to delete this folder? This will also deactivate all the invite links used to share this folder.", actions: [
self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: presentationData.strings.ChatList_AlertDeleteFolderTitle, text: presentationData.strings.ChatList_AlertDeleteFolderText, actions: [
TextAlertAction(type: .destructiveAction, title: presentationData.strings.Common_Delete, action: {
confirmDeleteFolder()
}),

View File

@ -571,13 +571,7 @@ private final class ChatListContainerItemNode: ASDisplayNode {
self.topPanel = topPanel
}
//TODO:localize
let title: String
if chatFolderUpdates.availableChatsToJoin == 1 {
title = "1 New Chat Available"
} else {
title = "\(chatFolderUpdates.availableChatsToJoin) New Chats Available"
}
let title: String = self.presentationData.strings.ChatList_PanelNewChatsAvailable(Int32(chatFolderUpdates.availableChatsToJoin))
let topPanelHeight: CGFloat = 44.0

View File

@ -547,11 +547,9 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
arguments.expandSection(.exclude)
})
case let .inviteLinkHeader(hasLinks):
//TODO:localize
return ItemListSectionHeaderItem(presentationData: presentationData, text: "SHARE FOLDER", badge: hasLinks ? nil : "NEW", sectionId: self.section)
return ItemListSectionHeaderItem(presentationData: presentationData, text: presentationData.strings.ChatListFilter_SectionShare, badge: hasLinks ? nil : presentationData.strings.ChatList_ContextMenuBadgeNew, sectionId: self.section)
case let .inviteLinkCreate(hasLinks):
//TODO:localize
return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.linkIcon(presentationData.theme), title: hasLinks ? "Create a new Link" : "Create an Invite Link", sectionId: self.section, editing: false, action: {
return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.linkIcon(presentationData.theme), title: hasLinks ? presentationData.strings.ChatListFilter_CreateLink : presentationData.strings.ChatListFilter_CreateLinkNew, sectionId: self.section, editing: false, action: {
arguments.createLink()
})
case let .inviteLink(_, link):
@ -648,8 +646,7 @@ private func chatListFilterPresetControllerEntries(presentationData: Presentatio
if let currentPreset, let data = currentPreset.data, data.isShared {
} else {
entries.append(.excludePeersHeader(presentationData.strings.ChatListFolder_ExcludedSectionHeader))
//TODO:localize
entries.append(.addExcludePeer(title: "Add Chats to Exclude"))
entries.append(.addExcludePeer(title: presentationData.strings.ChatListFilter_ExcludeChatsAction))
var excludeCategoryIndex = 0
for category in ChatListFilterExcludeCategory.allCases {
@ -705,8 +702,7 @@ private func chatListFilterPresetControllerEntries(presentationData: Presentatio
}
}
//TODO:localize
entries.append(.inviteLinkInfo(text: hasLinks ? "Create more links to set up different access levels for different people." : "Share access to some of this folder's groups and channels with others."))
entries.append(.inviteLinkInfo(text: hasLinks ? presentationData.strings.ChatListFilter_LinkListInfo : presentationData.strings.ChatListFilter_LinkListInfoNew))
return entries
}
@ -847,30 +843,13 @@ private func internalChatListFilterAddChatsController(context: AccountContext, f
removedPeers = data.includePeers.peers.filter({ !includePeers.contains($0) })
}
if newPeers.count != 0 {
let title: String
let text: String
//TODO:localize
if newPeers.count == 1 {
title = "Сhat added to folder"
text = "It will not affect chatlist of the links of this folder"
} else {
title = "\(newPeers.count) chats added to folder"
text = "It will not affect chatlist of the links of this folder"
}
let title: String = presentationData.strings.ChatListFilter_ToastChatsAddedTitle(Int32(newPeers.count))
let text: String = presentationData.strings.ChatListFilter_ToastChatsAddedText
presentUndo(.universal(animation: "anim_add_to_folder", scale: 0.1, colors: ["__allcolors__": UIColor.white], title: title, text: text, customUndoText: nil, timeout: nil))
} else if removedPeers.count != 0 {
let title: String
let text: String
if newPeers.count == 1 {
title = "Сhat removed from folder"
text = "It will not affect chatlist of the links of this folder"
} else {
title = "\(newPeers.count) chats removed from folder"
text = "It will not affect chatlist of the links of this folder"
}
let title: String = presentationData.strings.ChatListFilter_ToastChatsRemovedTitle(Int32(newPeers.count))
let text: String = presentationData.strings.ChatListFilter_ToastChatsRemovedText
presentUndo(.universal(animation: "anim_remove_from_folder", scale: 0.1, colors: ["__allcolors__": UIColor.white], title: title, text: text, customUndoText: nil, timeout: nil))
}
@ -1327,14 +1306,13 @@ func chatListFilterPresetController(context: AccountContext, currentPreset initi
let _ = (updatedCurrentPreset |> take(1) |> deliverOnMainQueue).start(next: { currentPreset in
if let currentPreset, let data = currentPreset.data, data.hasSharedLinks {
//TODO:localize
let title: String
let text: String
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
title = "Сhat removed from folder"
text = "It will not affect chatlist of the links of this folder"
title = presentationData.strings.ChatListFilter_ToastChatsRemovedTitle(1)
text = presentationData.strings.ChatListFilter_ToastChatsRemovedText
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_remove_from_folder", scale: 0.1, colors: ["__allcolors__": UIColor.white], title: title, text: text, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
}
@ -1394,17 +1372,15 @@ func chatListFilterPresetController(context: AccountContext, currentPreset initi
},
createLink: {
if initialPreset == nil {
//TODO:localize
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let text = "Please finish creating this folder to share it."
let text = presentationData.strings.ChatListFilter_AlertCreateFolderBeforeSharingText
presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
} else {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let state = stateValue.with({ $0 })
if state.additionallyIncludePeers.isEmpty {
//TODO:localize
let text = "You cant share folders which have chat types or excluded chats."
let text = presentationData.strings.ChatListFilter_ErrorShareInvalidFolder
presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
return
@ -1418,14 +1394,13 @@ func chatListFilterPresetController(context: AccountContext, currentPreset initi
let _ = (updatedCurrentPreset |> take(1) |> deliverOnMainQueue).start(next: { currentPreset in
if let currentPreset, let data = currentPreset.data {
//TODO:localize
var unavailableText: String?
if !data.categories.isEmpty {
unavailableText = "You cant share folders which have chat types or excluded chats."
unavailableText = presentationData.strings.ChatListFilter_ErrorShareInvalidFolder
} else if data.excludeArchived || data.excludeRead || data.excludeMuted {
unavailableText = "You cant share folders which have chat types or excluded chats."
unavailableText = presentationData.strings.ChatListFilter_ErrorShareInvalidFolder
} else if !data.excludePeers.isEmpty {
unavailableText = "You cant share folders which have chat types or excluded chats."
unavailableText = presentationData.strings.ChatListFilter_ErrorShareInvalidFolder
}
if let unavailableText {
statusController?.dismiss()
@ -1602,14 +1577,13 @@ func chatListFilterPresetController(context: AccountContext, currentPreset initi
let _ = (updatedCurrentPreset |> take(1) |> deliverOnMainQueue).start(next: { currentPreset in
if let currentPreset, let data = currentPreset.data, data.hasSharedLinks {
//TODO:localize
let title: String
let text: String
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
title = "Сhat removed from folder"
text = "It will not affect chatlist of the links of this folder"
title = presentationData.strings.ChatListFilter_ToastChatsRemovedTitle(1)
text = presentationData.strings.ChatListFilter_ToastChatsRemovedText
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_remove_from_folder", scale: 0.1, colors: ["__allcolors__": UIColor.white], title: title, text: text, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
}
@ -1790,8 +1764,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset initi
TextAlertAction(type: .genericAction, title: presentationData.strings.ChatListFolder_DiscardDiscard, action: {
dismissImpl?()
}),
//TODO:localize
TextAlertAction(type: .defaultAction, title: "Save", action: {
TextAlertAction(type: .defaultAction, title: presentationData.strings.ChatListFilter_SaveAlertActionSave, action: {
applyImpl?(false, {
dismissImpl?()
})
@ -1932,11 +1905,13 @@ func openCreateChatListFolderLink(context: AccountContext, folderId: Int32, chec
}))
}, error: { error in
completed()
//TODO:localize
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let text: String
switch error {
case .generic:
text = "An error occurred"
text = presentationData.strings.ChatListFilter_CreateLinkUnknownError
case let .sharedFolderLimitExceeded(limit, _):
let limitController = context.sharedContext.makePremiumLimitController(context: context, subject: .membershipInSharedFolders, count: limit, action: {
pushPremiumController(PremiumIntroScreen(context: context, source: .membershipInSharedFolders))
@ -1966,10 +1941,8 @@ func openCreateChatListFolderLink(context: AccountContext, folderId: Int32, chec
return
case .someUserTooManyChannels:
//TODO:localize
text = "One of the groups in this folder cant be added because one of its admins has too many groups and channels."
text = presentationData.strings.ChatListFilter_CreateLinkErrorSomeoneHasChannelLimit
}
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
presentController(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]))
})
}

View File

@ -223,8 +223,7 @@ private func chatListFilterPresetListControllerEntries(presentationData: Present
entries.append(.listHeader(presentationData.strings.ChatListFolderSettings_FoldersSection))
//TODO:localize
entries.append(.addItem(text: "Create a Folder", isEditing: state.isEditing))
entries.append(.addItem(text: presentationData.strings.ChatListFilterList_CreateFolder, isEditing: state.isEditing))
if !filters.isEmpty || suggestedFilters.isEmpty {
var folderCount = 0
@ -450,8 +449,7 @@ public func chatListFilterPresetListController(context: AccountContext, mode: Ch
}
if hasLinks {
//TODO:localize
presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: "Delete Folder", text: "Are you sure you want to delete this folder? This will also deactivate all the invite links used to share this folder.", actions: [
presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: presentationData.strings.ChatList_AlertDeleteFolderTitle, text: presentationData.strings.ChatList_AlertDeleteFolderText, actions: [
TextAlertAction(type: .destructiveAction, title: presentationData.strings.Common_Delete, action: {
confirmDeleteFolder()
}),

View File

@ -221,8 +221,7 @@ class ChatListStorageInfoItemNode: ItemListRevealOptionsItemNode {
switch item.notice {
case .chatFolderUpdates:
//TODO:locallize
strongSelf.setRevealOptions((left: [], right: [ItemListRevealOption(key: 0, title: "Hide", icon: .none, color: item.theme.list.itemDisclosureActions.destructive.fillColor, textColor: item.theme.list.itemDisclosureActions.destructive.foregroundColor)]))
strongSelf.setRevealOptions((left: [], right: [ItemListRevealOption(key: 0, title: item.strings.ChatList_HideAction, icon: .none, color: item.theme.list.itemDisclosureActions.destructive.fillColor, textColor: item.theme.list.itemDisclosureActions.destructive.foregroundColor)]))
default:
strongSelf.setRevealOptions((left: [], right: []))
}

View File

@ -170,7 +170,7 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
case let .mainLinkHeader(text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .mainLink(link, isGenerating):
return ItemListFolderInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: link, count: 0, peers: [], displayButton: true, enableButton: !isGenerating, buttonTitle: link != nil ? "Copy" : "Generate Invite Link", secondaryButtonTitle: link != nil ? "Share" : nil, displayImporters: false, buttonColor: nil, sectionId: self.section, style: .blocks, copyAction: {
return ItemListFolderInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: link, count: 0, peers: [], displayButton: true, enableButton: !isGenerating, buttonTitle: presentationData.strings.FolderLinkScreen_LinkActionCopy, secondaryButtonTitle: link != nil ? presentationData.strings.FolderLinkScreen_LinkActionShare : nil, displayImporters: false, buttonColor: nil, sectionId: self.section, style: .blocks, copyAction: {
if let link {
arguments.copyLink(link.link)
}
@ -196,7 +196,6 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
case let .peersInfo(text):
return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section)
case let .peer(_, peer, isSelected, disabledReasonText):
//TODO:localize
return ItemListPeerItem(
presentationData: presentationData,
dateTimeFormat: PresentationDateTimeFormat(),
@ -204,7 +203,7 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
context: arguments.context,
peer: peer,
presence: nil,
text: .text(disabledReasonText ?? "you can invite others here", .secondary),
text: .text(disabledReasonText ?? presentationData.strings.FolderLinkScreen_LabelCanInvite, .secondary),
label: .none,
editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false),
switchValue: ItemListPeerItemSwitch(value: isSelected, style: .leftCheck, isEnabled: disabledReasonText == nil),
@ -232,8 +231,6 @@ private func folderInviteLinkListControllerEntries(
) -> [InviteLinksListEntry] {
var entries: [InviteLinksListEntry] = []
//TODO:localize
var infoString: String?
let chatCountString: String
let peersHeaderString: String
@ -244,34 +241,26 @@ private func folderInviteLinkListControllerEntries(
var selectAllString: String?
if !canShareChats {
infoString = "You can only share groups and channels in which you are allowed to create invite links."
chatCountString = "There are no chats in this folder that you can share with others."
peersHeaderString = "THESE CHATS CANNOT BE SHARED"
infoString = presentationData.strings.FolderLinkScreen_TitleDescriptionUnavailable
chatCountString = presentationData.strings.FolderLinkScreen_ChatCountHeaderUnavailable
peersHeaderString = presentationData.strings.FolderLinkScreen_ChatsSectionHeaderUnavailable
} else if state.selectedPeerIds.isEmpty {
chatCountString = "Anyone with this link can add **\(title)** folder and the chats selected below."
peersHeaderString = "CHATS"
chatCountString = presentationData.strings.FolderLinkScreen_TitleDescriptionDeselected(title).string
peersHeaderString = presentationData.strings.FolderLinkScreen_ChatsSectionHeader
if allPeers.count > 1 {
selectAllString = allSelected ? "DESELECT ALL" : "SELECT ALL"
}
} else if state.selectedPeerIds.count == 1 {
chatCountString = "Anyone with this link can add **\(title)** folder and the 1 chat selected below."
peersHeaderString = "1 CHAT SELECTED"
if allPeers.count > 1 {
selectAllString = allSelected ? "DESELECT ALL" : "SELECT ALL"
selectAllString = allSelected ? presentationData.strings.FolderLinkScreen_ChatsSectionHeaderActionDeselectAll : presentationData.strings.FolderLinkScreen_ChatsSectionHeaderActionSelectAll
}
} else {
chatCountString = "Anyone with this link can add **\(title)** folder and the \(state.selectedPeerIds.count) chats selected below."
peersHeaderString = "\(state.selectedPeerIds.count) CHATS SELECTED"
chatCountString = presentationData.strings.FolderLinkScreen_TitleDescriptionSelected(title, presentationData.strings.FolderLinkScreen_TitleDescriptionSelectedCount(Int32(state.selectedPeerIds.count))).string
peersHeaderString = presentationData.strings.FolderLinkScreen_ChatsSectionHeaderSelected(Int32(state.selectedPeerIds.count))
if allPeers.count > 1 {
selectAllString = allSelected ? "DESELECT ALL" : "SELECT ALL"
selectAllString = allSelected ? presentationData.strings.FolderLinkScreen_ChatsSectionHeaderActionDeselectAll : presentationData.strings.FolderLinkScreen_ChatsSectionHeaderActionSelectAll
}
}
entries.append(.header(chatCountString))
//TODO:localize
if canShareChats {
entries.append(.mainLinkHeader("INVITE LINK"))
entries.append(.mainLinkHeader(presentationData.strings.FolderLinkScreen_LinkSectionHeader))
entries.append(.mainLink(link: state.currentLink, isGenerating: state.generatingLink))
}
@ -290,12 +279,12 @@ private func folderInviteLinkListControllerEntries(
if !canShareLinkToPeer(peer: peer) {
if case let .user(user) = peer {
if user.botInfo != nil {
disabledReasonText = "you can't share chats with bots"
disabledReasonText = presentationData.strings.FolderLinkScreen_LabelUnavailableBot
} else {
disabledReasonText = "you can't share private chats"
disabledReasonText = presentationData.strings.FolderLinkScreen_LabelUnavailableUser
}
} else {
disabledReasonText = "you can't invite others here"
disabledReasonText = presentationData.strings.FolderLinkScreen_LabelUnavailableGeneric
}
}
entries.append(.peer(index: entries.count, peer: peer, isSelected: state.selectedPeerIds.contains(peer.id), disabledReasonText: disabledReasonText))
@ -420,15 +409,14 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
var items: [ContextMenuItem] = []
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Name Link", icon: { theme in
items.append(.action(ContextMenuActionItem(text: presentationData.strings.FolderLinkScreen_ContextActionNameLink, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Pencil"), color: theme.contextMenu.primaryColor)
}, action: { _, f in
f(.dismissWithoutContent)
let state = stateValue.with({ $0 })
let promptController = promptController(sharedContext: context.sharedContext, updatedPresentationData: updatedPresentationData, text: "Name This Link", titleFont: .bold, value: state.title ?? "", characterLimit: 32, apply: { value in
let promptController = promptController(sharedContext: context.sharedContext, updatedPresentationData: updatedPresentationData, text: presentationData.strings.FolderLinkScreen_NameLink_Title, titleFont: .bold, value: state.title ?? "", characterLimit: 32, apply: { value in
if let value {
updateState { state in
var state = state
@ -481,6 +469,8 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .reference(InviteLinkContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
presentInGlobalOverlayImpl?(contextController)
}, peerAction: { peer, isEnabled in
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
if isEnabled {
var added = false
updateState { state in
@ -503,17 +493,15 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese
didDisplayAddPeerNotice = true
dismissTooltipsImpl?()
//TODO:localize
displayTooltipImpl?(.info(title: nil, text: "People who already used the invite link will be able to join newly added chats.", timeout: 8), true)
displayTooltipImpl?(.info(title: nil, text: presentationData.strings.FolderLinkScreen_ToastNewChatAdded, timeout: 8), true)
}
} else {
//TODO:localize
let text: String
if case let .user(user) = peer {
if user.botInfo != nil {
text = "You can't share chats with bots"
text = presentationData.strings.FolderLinkScreen_AlertTextUnavailableBot
} else {
text = "You can't share private chats"
text = presentationData.strings.FolderLinkScreen_AlertTextUnavailableUser
}
} else {
var isGroup = true
@ -523,15 +511,15 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese
}
if isGroup {
if isPrivate {
text = "You don't have the admin rights to share invite links to this private group."
text = presentationData.strings.FolderLinkScreen_AlertTextUnavailablePrivateGroup
} else {
text = "You don't have the admin rights to share invite links to this group chat."
text = presentationData.strings.FolderLinkScreen_AlertTextUnavailablePublicGroup
}
} else {
if isPrivate {
text = "You don't have the admin rights to share invite links to this private channel."
text = presentationData.strings.FolderLinkScreen_AlertTextUnavailablePrivateChannel
} else {
text = "You don't have the admin rights to share invite links to this channel."
text = presentationData.strings.FolderLinkScreen_AlertTextUnavailablePublicChannel
}
}
}
@ -605,12 +593,11 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese
dismissTooltipsImpl?()
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
//TODO:localize
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: "An error occurred.", timeout: nil), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: presentationData.strings.FolderLinkScreen_SaveUnknownError, timeout: nil), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
}, completed: {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
linkUpdated(ExportedChatFolderLink(title: state.title ?? "", link: currentLink.link, peerIds: Array(state.selectedPeerIds), isRevoked: false))
//TODO:localize
displayTooltipImpl?(.info(title: nil, text: "Link updated", timeout: 3), false)
displayTooltipImpl?(.info(title: nil, text: presentationData.strings.FolderLinkScreen_ToastLinkUpdated, timeout: 3), false)
dismissImpl?()
}))
@ -666,10 +653,9 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese
animateChanges = true
}
//TODO:localize
let title: ItemListControllerTitle
var folderTitle = "Share Folder"
var folderTitle = presentationData.strings.FolderLinkScreen_Title
if let title = state.title, !title.isEmpty {
folderTitle = title
}
@ -742,13 +728,12 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese
if hasChanges {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
//TODO:localize
presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: "Unsaved Changes", text: "You have changed the settings of this folder. Apply changes?", actions: [
TextAlertAction(type: .genericAction, title: "Discard", action: {
presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: presentationData.strings.FolderLinkScreen_SaveAlertTitle, text: presentationData.strings.FolderLinkScreen_SaveAlertText, actions: [
TextAlertAction(type: .genericAction, title: presentationData.strings.FolderLinkScreen_SaveAlertActionDiscard, action: {
f()
dismissImpl?()
}),
TextAlertAction(type: .defaultAction, title: state.selectedPeerIds.isEmpty ? "Continue" : "Apply", action: {
TextAlertAction(type: .defaultAction, title: state.selectedPeerIds.isEmpty ? presentationData.strings.FolderLinkScreen_SaveAlertActionApply : presentationData.strings.FolderLinkScreen_SaveAlertActionContinue, action: {
applyChangesImpl?()
})
]), nil)

View File

@ -227,8 +227,7 @@ private enum InviteLinkViewEntry: Comparable, Identifiable {
case let .importer(_, _, dateTimeFormat, peer, date, joinedViaFolderLink, loading):
let dateString: String
if joinedViaFolderLink {
//TODO:localize
dateString = "joined via a folder invite link"
dateString = presentationData.strings.InviteLink_LabelJoinedViaFolder
} else {
dateString = stringForFullDate(timestamp: date, strings: presentationData.strings, dateTimeFormat: dateTimeFormat)
}

View File

@ -308,12 +308,7 @@ public class ItemListFolderInviteLinkListItemNode: ItemListRevealOptionsItemNode
titleText = invite.title
}
//TODO:localize
if invite.peerIds.count == 1 {
subtitleText = "includes 1 chat"
} else {
subtitleText = "includes \(invite.peerIds.count) chats"
}
subtitleText = item.presentationData.strings.ChatListFilter_LinkLabelChatCount(Int32(invite.peerIds.count))
} else {
titleText = " "
subtitleText = " "
@ -519,8 +514,7 @@ public class ItemListFolderInviteLinkListItemNode: ItemListRevealOptionsItemNode
strongSelf.updateLayout(size: layout.contentSize, leftInset: params.leftInset, rightInset: params.rightInset)
if item.removeAction != nil {
//TODO:localize
strongSelf.setRevealOptions((left: [], right: [ItemListRevealOption(key: 0, title: "Delete", icon: .none, color: item.presentationData.theme.list.itemDisclosureActions.destructive.fillColor, textColor: item.presentationData.theme.list.itemDisclosureActions.destructive.foregroundColor)]))
strongSelf.setRevealOptions((left: [], right: [ItemListRevealOption(key: 0, title: item.presentationData.strings.ChatListFilter_LinkActionDelete, icon: .none, color: item.presentationData.theme.list.itemDisclosureActions.destructive.fillColor, textColor: item.presentationData.theme.list.itemDisclosureActions.destructive.foregroundColor)]))
} else {
strongSelf.setRevealOptions((left: [], right: []))
}

View File

@ -239,9 +239,8 @@ public final class QrCodeScreen: ViewController {
title = self.presentationData.strings.InviteLink_QRCode_Title
text = isGroup ? self.presentationData.strings.InviteLink_QRCode_Info : self.presentationData.strings.InviteLink_QRCode_InfoChannel
case .chatFolder:
//TODO:localize
title = "Invite by QR Code"
text = "Everyone on Telegram can scan this code to add this folder and join the chats included in this invite link."
title = self.presentationData.strings.InviteLink_QRCodeFolder_Title
text = self.presentationData.strings.InviteLink_QRCodeFolder_Text
default:
title = ""
text = ""

View File

@ -693,9 +693,9 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
buttons.append(button)
} else if case .urlAuth = button.action {
buttons.append(button)
} else if case let .switchInline(samePeer, query) = button.action, sourceSentViaBot {
} else if case let .switchInline(samePeer, query, peerTypes) = button.action, sourceSentViaBot {
let samePeer = samePeer && peerId == sourceMessage.id.peerId
let updatedButton = ReplyMarkupButton(title: button.titleWhenForwarded ?? button.title, titleWhenForwarded: button.titleWhenForwarded, action: .switchInline(samePeer: samePeer, query: query))
let updatedButton = ReplyMarkupButton(title: button.titleWhenForwarded ?? button.title, titleWhenForwarded: button.titleWhenForwarded, action: .switchInline(samePeer: samePeer, query: query, peerTypes: peerTypes))
buttons.append(updatedButton)
} else {
rows.removeAll()

View File

@ -151,9 +151,8 @@ final class ChatFolderLinkHeaderComponent: Component {
let badgeSpacing: CGFloat = 6.0
if themeUpdated {
//TODO:localize
let leftString = NSAttributedString(string: "All Chats", font: Font.semibold(14.0), textColor: component.theme.list.freeTextColor)
let rightString = NSAttributedString(string: "Personal", font: Font.semibold(14.0), textColor: component.theme.list.freeTextColor)
let leftString = NSAttributedString(string: component.strings.FolderLinkPreview_IconTabLeft, font: Font.semibold(14.0), textColor: component.theme.list.freeTextColor)
let rightString = NSAttributedString(string: component.strings.FolderLinkPreview_IconTabRight, font: Font.semibold(14.0), textColor: component.theme.list.freeTextColor)
let leftStringBounds = leftString.boundingRect(with: CGSize(width: 200.0, height: 100.0), options: .usesLineFragmentOrigin, context: nil)
let rightStringBounds = rightString.boundingRect(with: CGSize(width: 200.0, height: 100.0), options: .usesLineFragmentOrigin, context: nil)

View File

@ -388,12 +388,10 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
var allChatsAdded = false
var canAddChatCount = 0
if case .linkList = component.subject {
//TODO:localize
titleString = "Share Folder"
titleString = environment.strings.FolderLinkPreview_TitleShare
} else if let linkContents = component.linkContents {
//TODO:localize
if case .remove = component.subject {
titleString = "Remove Folder"
titleString = environment.strings.FolderLinkPreview_TitleRemove
} else if linkContents.localFilterId != nil {
if linkContents.alreadyMemberPeerIds == Set(linkContents.peers.map(\.id)) {
allChatsAdded = true
@ -401,14 +399,12 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
canAddChatCount = linkContents.peers.map(\.id).count - linkContents.alreadyMemberPeerIds.count
if allChatsAdded {
titleString = "Add Folder"
} else if canAddChatCount == 1 {
titleString = "Add \(canAddChatCount) chat"
titleString = environment.strings.FolderLinkPreview_TitleAddFolder
} else {
titleString = "Add \(canAddChatCount) chats"
titleString = environment.strings.FolderLinkPreview_TitleAddChats(Int32(canAddChatCount))
}
} else {
titleString = "Add Folder"
titleString = environment.strings.FolderLinkPreview_TitleAddFolder
}
} else {
titleString = " "
@ -464,26 +460,17 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
let text: String
if case .linkList = component.subject {
text = "Create more links to set up different access\nlevels for different people."
text = environment.strings.FolderLinkPreview_TextLinkList
} else if let linkContents = component.linkContents {
if case .remove = component.subject {
text = "Do you also want to quit the chats included in this folder?"
text = environment.strings.FolderLinkPreview_TextRemoveFolder
} else if allChatsAdded {
text = "You have already added this\nfolder and its chats."
text = environment.strings.FolderLinkPreview_TextAllAdded
} else if linkContents.localFilterId == nil {
text = "Do you want to add a new chat folder\nand join its groups and channels?"
text = environment.strings.FolderLinkPreview_TextAddFolder
} else {
let chatCountString: String
if canAddChatCount == 1 {
chatCountString = "1 chat"
} else {
chatCountString = "\(canAddChatCount) chats"
}
if let title = linkContents.title {
text = "Do you want to add **\(chatCountString)** to the\nfolder **\(title)**?"
} else {
text = "Do you want to add **\(chatCountString)** chats to the\nfolder?"
}
let chatCountString: String = environment.strings.FolderLinkPreview_TextAddChatsCount(Int32(canAddChatCount))
text = environment.strings.FolderLinkPreview_TextAddChats(chatCountString, linkContents.title ?? "").string
}
} else {
text = " "
@ -544,7 +531,7 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
theme: environment.theme,
sideInset: 0.0,
iconName: "Contact List/LinkActionIcon",
title: "Create a New Link",
title: environment.strings.InviteLink_Create,
hasNext: !self.linkListItems.isEmpty,
action: { [weak self] in
self?.openCreateLink()
@ -582,12 +569,7 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
self.items[id] = item
}
let subtitle: String
if link.peerIds.count == 1 {
subtitle = "includes 1 chat"
} else {
subtitle = "includes \(link.peerIds.count) chats"
}
let subtitle: String = environment.strings.ChatListFilter_LinkLabelChatCount(Int32(link.peerIds.count))
let itemComponent = LinkListItemComponent(
theme: environment.theme,
@ -713,15 +695,15 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
var subtitle: String?
if case let .channel(channel) = peer, case .broadcast = channel.info {
if linkContents.alreadyMemberPeerIds.contains(peer.id) {
subtitle = "You are already a subscriber"
subtitle = environment.strings.FolderLinkPreview_LabelPeerSubscriber
} else if let memberCount = linkContents.memberCounts[peer.id] {
subtitle = "\(memberCount) subscribers"
subtitle = environment.strings.FolderLinkPreview_LabelPeerSubscribers(Int32(memberCount))
}
} else {
if linkContents.alreadyMemberPeerIds.contains(peer.id) {
subtitle = "You are already a member"
subtitle = environment.strings.FolderLinkPreview_LabelPeerMember
} else if let memberCount = linkContents.memberCounts[peer.id] {
subtitle = "\(memberCount) participants"
subtitle = environment.strings.FolderLinkPreview_LabelPeerMembers(Int32(memberCount))
}
}
@ -753,9 +735,9 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
let text: String
if case let .channel(channel) = peer, case .broadcast = channel.info {
text = "You are already a member of this channel."
text = presentationData.strings.FolderLinkPreview_ToastAlreadyMemberChannel
} else {
text = "You are already a member of this group."
text = presentationData.strings.FolderLinkPreview_ToastAlreadyMemberGroup
}
controller.present(UndoOverlayController(presentationData: presentationData, content: .peers(context: component.context, peers: [peer], title: nil, text: text, customUndoText: nil), elevatedLayout: false, action: { _ in true }), in: .current)
} else {
@ -798,43 +780,59 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
let listHeaderTitle: String
if case .linkList = component.subject {
listHeaderTitle = "INVITE LINKS"
listHeaderTitle = environment.strings.FolderLinkPreview_LinkSectionHeader
} else if let linkContents = component.linkContents {
if case .remove = component.subject {
if linkContents.peers.count == 1 {
listHeaderTitle = "1 CHAT TO QUIT"
} else {
listHeaderTitle = "\(linkContents.peers.count) CHATS TO QUIT"
}
listHeaderTitle = environment.strings.FolderLinkPreview_RemoveSectionSelectedHeader(Int32(linkContents.peers.count))
} else if allChatsAdded {
if linkContents.peers.count == 1 {
listHeaderTitle = "1 CHAT IN THIS FOLDER"
} else {
listHeaderTitle = "\(linkContents.peers.count) CHATS IN THIS FOLDER"
}
listHeaderTitle = environment.strings.FolderLinkPreview_ChatSectionHeader(Int32(linkContents.peers.count))
} else {
if linkContents.peers.count == 1 {
listHeaderTitle = "1 CHAT IN FOLDER TO JOIN"
} else {
listHeaderTitle = "\(linkContents.peers.count) CHATS IN FOLDER TO JOIN"
}
listHeaderTitle = environment.strings.FolderLinkPreview_ChatSectionJoinHeader(Int32(linkContents.peers.count))
}
} else {
listHeaderTitle = " "
}
//TODO:localize
let listHeaderActionItems: [AnimatedCounterComponent.Item]
var listHeaderActionItems: [AnimatedCounterComponent.Item] = []
let dynamicIndex = environment.strings.FolderLinkPreview_ListSelectionSelectAllFormat.range(of: "{dynamic}")
let staticIndex = environment.strings.FolderLinkPreview_ListSelectionSelectAllFormat.range(of: "{static}")
var headerActionItemIndices: [Int: Int] = [:]
if let dynamicIndex, let staticIndex {
if dynamicIndex.lowerBound < staticIndex.lowerBound {
headerActionItemIndices[0] = 0
headerActionItemIndices[1] = 1
} else {
headerActionItemIndices[0] = 1
headerActionItemIndices[1] = 0
}
} else if dynamicIndex != nil {
headerActionItemIndices[0] = 0
} else if staticIndex != nil {
headerActionItemIndices[1] = 0
}
let dynamicItem: AnimatedCounterComponent.Item
let staticItem: AnimatedCounterComponent.Item
if self.selectedItems.count == self.items.count {
listHeaderActionItems = [
AnimatedCounterComponent.Item(id: AnyHashable(0), text: "DESELECT", numericValue: 0),
AnimatedCounterComponent.Item(id: AnyHashable(1), text: "ALL", numericValue: 1)
]
dynamicItem = AnimatedCounterComponent.Item(id: AnyHashable(0), text: environment.strings.FolderLinkPreview_ListSelectionSelectAllDynamicPartDeselect, numericValue: 0)
staticItem = AnimatedCounterComponent.Item(id: AnyHashable(1), text: environment.strings.FolderLinkPreview_ListSelectionSelectAllStaticPartDeselect, numericValue: 1)
} else {
listHeaderActionItems = [
AnimatedCounterComponent.Item(id: AnyHashable(0), text: "SELECT", numericValue: 1),
AnimatedCounterComponent.Item(id: AnyHashable(1), text: "ALL", numericValue: 1)
]
dynamicItem = AnimatedCounterComponent.Item(id: AnyHashable(0), text: environment.strings.FolderLinkPreview_ListSelectionSelectAllDynamicPartSelect, numericValue: 1)
staticItem = AnimatedCounterComponent.Item(id: AnyHashable(1), text: environment.strings.FolderLinkPreview_ListSelectionSelectAllStaticPartSelect, numericValue: 1)
}
if let dynamicIndex = headerActionItemIndices[0], let staticIndex = headerActionItemIndices[1] {
if dynamicIndex < staticIndex {
listHeaderActionItems = [dynamicItem, staticItem]
} else {
listHeaderActionItems = [staticItem, dynamicItem]
}
} else if headerActionItemIndices[0] != nil {
listHeaderActionItems = [dynamicItem]
} else if headerActionItemIndices[1] != nil {
listHeaderActionItems = [staticItem]
}
let listHeaderBody = MarkdownAttributeSet(font: Font.with(size: 13.0, design: .regular, traits: [.monospacedNumbers]), textColor: environment.theme.list.freeTextColor)
@ -928,23 +926,23 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
if case .remove = component.subject {
actionButtonBadge = self.selectedItems.count
if self.selectedItems.isEmpty {
actionButtonTitle = "Remove Folder"
actionButtonTitle = environment.strings.FolderLinkPreview_ButtonRemoveFolder
} else {
actionButtonTitle = "Remove Folder and Chats"
actionButtonTitle = environment.strings.FolderLinkPreview_ButtonRemoveFolderAndChats
}
} else if allChatsAdded {
actionButtonBadge = 0
actionButtonTitle = "OK"
actionButtonTitle = environment.strings.Common_OK
} else if let linkContents = component.linkContents {
actionButtonBadge = max(0, self.selectedItems.count - (linkContents.peers.count - canAddChatCount))
if linkContents.localFilterId != nil {
if self.selectedItems.isEmpty {
actionButtonTitle = "Do Not Join Any Chats"
actionButtonTitle = environment.strings.FolderLinkPreview_ButtonDoNotJoinChats
} else {
actionButtonTitle = "Join Chats"
actionButtonTitle = environment.strings.FolderLinkPreview_ButtonJoinChats
}
} else {
actionButtonTitle = "Add Folder"
actionButtonTitle = environment.strings.FolderLinkPreview_ButtonAddFolder
}
} else {
actionButtonTitle = " "
@ -987,17 +985,13 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
let folderTitle = linkContents.title ?? ""
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 })
var additionalText: String?
if !self.selectedItems.isEmpty {
if self.selectedItems.count == 1 {
additionalText = "You also left **1** chat"
} else {
additionalText = "You also left **\(self.selectedItems.count)** chats"
}
additionalText = presentationData.strings.FolderLinkPreview_ToastLeftChatsText(Int32(self.selectedItems.count))
}
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 })
var chatListController: ChatListController?
if let navigationController = controller.navigationController as? NavigationController {
for viewController in navigationController.viewControllers.reversed() {
@ -1025,7 +1019,7 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
let selectedItems = self.selectedItems
let undoOverlayController = UndoOverlayController(
presentationData: presentationData,
content: .removedChat(title: "Folder \(folderTitle) deleted", text: additionalText),
content: .removedChat(title: presentationData.strings.FolderLinkPreview_ToastLeftTitle(folderTitle).string, text: additionalText),
elevatedLayout: false,
action: { value in
if case .commit = value {
@ -1106,7 +1100,6 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
return
}
//TODO:localize
let presentationData = context.sharedContext.currentPresentationData.with({ $0 })
var isUpdates = false
@ -1119,29 +1112,15 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
}
if isUpdates {
let chatCountString: String
if result.newChatCount == 1 {
chatCountString = "1 new chat"
} else {
chatCountString = "\(result.newChatCount) new chats"
}
chatListController.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_add_to_folder", scale: 0.1, colors: ["__allcolors__": UIColor.white], title: "Folder \(result.title) Updated", text: "You have joined \(chatCountString)", customUndoText: nil, timeout: 5), elevatedLayout: false, action: { _ in true }), in: .current)
chatListController.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_add_to_folder", scale: 0.1, colors: ["__allcolors__": UIColor.white], title: presentationData.strings.FolderLinkPreview_ToastChatsAddedTitle(result.title).string, text: presentationData.strings.FolderLinkPreview_ToastChatsAddedText(Int32(result.newChatCount)), customUndoText: nil, timeout: 5), elevatedLayout: false, action: { _ in true }), in: .current)
} else if result.newChatCount != 0 {
let chatCountString: String
if result.newChatCount == 1 {
chatCountString = "1 chat"
} else {
chatCountString = "\(result.newChatCount) chats"
}
let animationBackgroundColor: UIColor
if presentationData.theme.overallDarkAppearance {
animationBackgroundColor = presentationData.theme.rootController.tabBar.backgroundColor
} else {
animationBackgroundColor = UIColor(rgb: 0x474747)
}
chatListController.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_success", scale: 1.0, colors: ["info1.info1.stroke": animationBackgroundColor, "info2.info2.Fill": animationBackgroundColor], title: "Folder \(result.title) Added", text: "You also joined \(chatCountString)", customUndoText: nil, timeout: 5), elevatedLayout: false, action: { _ in true }), in: .current)
chatListController.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_success", scale: 1.0, colors: ["info1.info1.stroke": animationBackgroundColor, "info2.info2.Fill": animationBackgroundColor], title: presentationData.strings.FolderLinkPreview_ToastFolderAddedTitle(result.title).string, text: presentationData.strings.FolderLinkPreview_ToastFolderAddedText(Int32(result.newChatCount)), customUndoText: nil, timeout: 5), elevatedLayout: false, action: { _ in true }), in: .current)
} else {
let animationBackgroundColor: UIColor
if presentationData.theme.overallDarkAppearance {
@ -1149,7 +1128,7 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
} else {
animationBackgroundColor = UIColor(rgb: 0x474747)
}
chatListController.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_success", scale: 1.0, colors: ["info1.info1.stroke": animationBackgroundColor, "info2.info2.Fill": animationBackgroundColor], title: "Folder \(result.title) Added", text: "", customUndoText: nil, timeout: 5), elevatedLayout: false, action: { _ in true }), in: .current)
chatListController.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_success", scale: 1.0, colors: ["info1.info1.stroke": animationBackgroundColor, "info2.info2.Fill": animationBackgroundColor], title: presentationData.strings.FolderLinkPreview_ToastFolderAddedTitle(result.title).string, text: "", customUndoText: nil, timeout: 5), elevatedLayout: false, action: { _ in true }), in: .current)
}
})
}
@ -1423,11 +1402,12 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
let context = component.context
let navigationController = controller.navigationController as? NavigationController
//TODO:localize
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
let text: String
switch error {
case .generic:
text = "An error occurred"
text = presentationData.strings.ChatListFilter_CreateLinkUnknownError
case let .sharedFolderLimitExceeded(limit, _):
let limitController = component.context.sharedContext.makePremiumLimitController(context: component.context, subject: .membershipInSharedFolders, count: limit, action: { [weak navigationController] in
guard let navigationController else {
@ -1472,10 +1452,8 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
return
case .someUserTooManyChannels:
//TODO:localize
text = "One of the groups in this folder cant be added because one of its admins has too many groups and channels."
text = presentationData.strings.ChatListFilter_CreateLinkErrorSomeoneHasChannelLimit
}
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
controller.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
})
}

View File

@ -218,20 +218,19 @@ final class PeerListItemComponent: Component {
}
}
//TODO:localize
let labelData: (String, Bool)
if let subtitle = component.subtitle {
labelData = (subtitle, false)
} else if case .legacyGroup = component.peer {
labelData = ("group", false)
labelData = (component.strings.Group_Status, false)
} else if case let .channel(channel) = component.peer {
if case .group = channel.info {
labelData = ("group", false)
labelData = (component.strings.Group_Status, false)
} else {
labelData = ("channel", false)
labelData = (component.strings.Channel_Status, false)
}
} else {
labelData = ("group", false)
labelData = (component.strings.Group_Status, false)
}
let labelSize = self.label.update(