[WIP] Topics

This commit is contained in:
Ali 2022-10-23 19:34:10 +04:00
parent 8001d6b5f0
commit 79215dc012
15 changed files with 202 additions and 115 deletions

View File

@ -8175,3 +8175,56 @@ Sorry for the inconvenience.";
"CreateTopic.EnterTopicTitle" = "ENTER TOPIC TITLE";
"CreateTopic.EnterTopicTitlePlaceholder" = "What do you want to discuss?";
"CreateTopic.SelectTopicIcon" = "SELECT TOPIC ICON";
"ChatList.Context.CloseTopic" = "Close";
"ChatList.Context.ReopenTopic" = "Reopen";
"Chat.ContextViewAsTopics" = "View as Topics";
"Chat.ContextViewAsMessages" = "View as Messages";
"Chat.CreateTopic" = "New Topic";
"ChatList.DeleteTopicConfirmationText" = "This will delete the topic with all its messages";
"ChatList.DeleteTopicConfirmationAction" = "Delete Topic";
"Notification.TopicCreated" = "Topic created";
"Notification.TopicClosed" = "Topic closed";
"Notification.TopicReopened" = "Topic reopened";
"Notification.TopicRenamed" = "Topic renamed to \"%1$@\"";
"Notification.TopicIconChanged" = "Topic icon changed to %1$@";
"Notification.TopicIconRemoved" = "Topic icon changed";
"Chat.EmptyTopicPlaceholder.Title" = "Almost done!";
"Chat.EmptyTopicPlaceholder.Text" = "Send the first message to\nstart this topic.";
"Chat.Message.TopicAuthorBadge" = "Topic Author";
"Chat.PanelRestartTopic" = "Restart Topic";
"Chat.PanelTopicClosedText" = "The topic is closed by admin";
"Chat.PanelForumModeReplyText" = "Swipe left on a message to reply";
"PeerInfo.TopicHeaderLocation" = "in %1$@";
"PeerInfo.OptionTopics" = "Topics";
"PeerInfo.OptionTopicsText" = "The group chat will be divided into topics created by admins or users.";
"PeerInfo.TopicsLimitedParticipantCountText_1" = "Only groups with more than **%d member** can have topics enabled.";
"PeerInfo.TopicsLimitedParticipantCountText_any" = "Only groups with more than **%d members** can have topics enabled.";
"PeerInfo.TopicsLimitedDiscussionGroups" = "Topics are currently unavailable in groups connected to channels.";
"PeerInfo.TopicNotificationExceptions_1" = "There is [1 topic]() that is listed as exception.";
"PeerInfo.TopicNotificationExceptions_any" = "There are [%d topics]() that are listed as exceptions.";
"PeerInfo.NotificationMemberAdded" = "**%1$@** added to the group.";
"PeerInfo.NotificationMultipleMembersAdded_1" = "**%d** member added to the group.";
"PeerInfo.NotificationMultipleMembersAdded_any" = "**%d** members added to the group.";
"Channel.AdminLog.TopicCreated" = "%1$@ created topic %2$@";
"Channel.AdminLog.TopicDeleted" = "%1$@ deleted topic %2$@";
"Channel.AdminLog.TopicPinned" = "%1$@ pinned topic %2$@";
"Channel.AdminLog.TopicUnpinned" = "%1$@ pinned topic %2$@";
"Channel.AdminLog.TopicsEnabled" = "%1$@ enabled topics";
"Channel.AdminLog.TopicsDisabled" = "%1$@ disabled topics";
"Channel.AdminLog.TopicReopened" = "%1$@ reopened topic %2$@";
"Channel.AdminLog.TopicClosed" = "%1$@ closed topic %2$@";
"Channel.AdminLog.TopicRenamed" = "%1$@ renamed topic %2$@ to %3$@";
"Channel.AdminLog.TopicRenamedWithIcon" = "%1$@ renamed topic %2$@ to %3$@ and changed icon to %4$@";
"Channel.AdminLog.TopicRenamedWithRemovedIcon" = "%1$@ renamed topic %2$@ to %3$@ and removed icon";
"Channel.AdminLog.TopicChangedIcon" = "%1$@ changed topic %2$@ icon to %3$@";
"Channel.AdminLog.TopicRemovedIcon" = "%1$@ removed topic %2$@ icon";

View File

@ -516,8 +516,7 @@ func chatForumTopicMenuItems(context: AccountContext, peerId: PeerId, threadId:
var items: [ContextMenuItem] = []
if channel.hasPermission(.manageTopics) {
//TODO:localize
items.append(.action(ContextMenuActionItem(text: isPinned ? "Unpin" : "Pin", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isPinned ? "Chat/Context Menu/Unpin": "Chat/Context Menu/Pin"), color: theme.contextMenu.primaryColor) }, action: { _, f in
items.append(.action(ContextMenuActionItem(text: isPinned ? presentationData.strings.ChatList_Context_Unpin : presentationData.strings.ChatList_Context_Pin, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isPinned ? "Chat/Context Menu/Unpin": "Chat/Context Menu/Pin"), color: theme.contextMenu.primaryColor) }, action: { _, f in
f(.default)
let _ = context.engine.peers.setForumChannelTopicPinned(id: peerId, threadId: threadId, isPinned: !isPinned).start()
@ -724,8 +723,7 @@ func chatForumTopicMenuItems(context: AccountContext, peerId: PeerId, threadId:
canOpenClose = true
}
if canOpenClose {
//TODO:localize
items.append(.action(ContextMenuActionItem(text: threadData.isClosed ? "Restart" : "Close", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: threadData.isClosed ? "Chat/Context Menu/Play": "Chat/Context Menu/Pause"), color: theme.contextMenu.primaryColor) }, action: { _, f in
items.append(.action(ContextMenuActionItem(text: threadData.isClosed ? presentationData.strings.ChatList_Context_ReopenTopic : presentationData.strings.ChatList_Context_CloseTopic, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: threadData.isClosed ? "Chat/Context Menu/Play": "Chat/Context Menu/Pause"), color: theme.contextMenu.primaryColor) }, action: { _, f in
f(.default)
let _ = context.engine.peers.setForumChannelTopicClosed(id: peerId, threadId: threadId, isClosed: !threadData.isClosed).start()

View File

@ -406,9 +406,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
title = self.presentationData.strings.ChatList_ArchivedChatsTitle
}
case let .forum(peerId):
//TODO:localize
title = "Forum"
title = ""
self.forumChannelTracker = ForumChannelTopics(account: self.context.account, peerId: peerId)
self.moreBarButton.contextAction = { [weak self] sourceNode, gesture in
@ -518,8 +516,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
case .member:
strongSelf.setToolbar(nil, transition: .animated(duration: 0.4, curve: .spring))
default:
//TODO:localize
strongSelf.setToolbar(Toolbar(leftAction: nil, rightAction: nil, middleAction: ToolbarAction(title: "Join", isEnabled: true)), transition: .animated(duration: 0.4, curve: .spring))
strongSelf.setToolbar(Toolbar(leftAction: nil, rightAction: nil, middleAction: ToolbarAction(title: strongSelf.presentationData.strings.Channel_JoinChannel, isEnabled: true)), transition: .animated(duration: 0.4, curve: .spring))
}
}
})
@ -678,8 +675,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
defaultTitle = strongSelf.presentationData.strings.ChatList_ArchivedChatsTitle
}
case .forum:
//TODO:localize
defaultTitle = "Forum"
defaultTitle = ""
}
let previousEditingAndNetworkState = previousEditingAndNetworkStateValue.swap((stateAndFilterId.state.editing, networkState))
if stateAndFilterId.state.editing {
@ -2575,7 +2571,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
var items: [ContextMenuItem] = []
items.append(.action(ContextMenuActionItem(text: "View as Topics", icon: { theme in
items.append(.action(ContextMenuActionItem(text: strings.Chat_ContextViewAsTopics, icon: { theme in
if !isViewingAsTopics {
return nil
}
@ -2590,7 +2586,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
let chatController = context.sharedContext.makeChatListController(context: context, location: .forum(peerId: peerId), controlsHistoryPreload: false, hideNetworkActivityStatus: false, previewing: false, enableDebugActions: false)
navigationController.replaceController(sourceController, with: chatController, animated: false)
})))
items.append(.action(ContextMenuActionItem(text: "View as Messages", icon: { theme in
items.append(.action(ContextMenuActionItem(text: strings.Chat_ContextViewAsMessages, icon: { theme in
if isViewingAsTopics {
return nil
}
@ -2607,8 +2603,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
})))
items.append(.separator)
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Group Info", icon: { theme in
items.append(.action(ContextMenuActionItem(text: strings.GroupInfo_Title, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Contact List/CreateGroupActionIcon"), color: theme.contextMenu.primaryColor)
}, action: { [weak sourceController] _, f in
f(.default)
@ -2625,8 +2620,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
})))
if channel.hasPermission(.inviteMembers) {
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Add Member", icon: { theme in
items.append(.action(ContextMenuActionItem(text: strings.GroupInfo_AddParticipant, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.contextMenu.primaryColor)
}, action: { [weak sourceController] _, f in
f(.default)
@ -2655,8 +2649,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
} else if channel.hasPermission(.createTopics) {
items.append(.separator)
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "New Topic", icon: { theme in
items.append(.action(ContextMenuActionItem(text: strings.Chat_CreateTopic, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor)
}, action: { action in
action.dismissWithResult(.default)
@ -3745,9 +3738,8 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
let actionSheet = ActionSheetController(presentationData: self.presentationData)
var items: [ActionSheetItem] = []
//TODO:localize
items.append(ActionSheetTextItem(title: "This will delete the topic with all its messages", parseMarkdown: true))
items.append(ActionSheetButtonItem(title: "Delete", color: .destructive, action: { [weak self, weak actionSheet] in
items.append(ActionSheetTextItem(title: self.presentationData.strings.ChatList_DeleteTopicConfirmationText, parseMarkdown: true))
items.append(ActionSheetButtonItem(title: self.presentationData.strings.ChatList_DeleteTopicConfirmationAction, color: .destructive, action: { [weak self, weak actionSheet] in
actionSheet?.dismissAnimated()
self?.commitDeletePeerThread(peerId: peerId, threadId: threadId)
}))

View File

@ -59,7 +59,6 @@ private final class AddPaymentMethodSheetContent: CombinedComponent {
transition: context.transition
)
//TODO:localize
let title = title.update(
component: MultilineTextComponent(
text: .plain(NSAttributedString(string: "Payment Method", font: UIFont.boldSystemFont(ofSize: 17.0), textColor: .black)),
@ -71,7 +70,6 @@ private final class AddPaymentMethodSheetContent: CombinedComponent {
transition: context.transition
)
//TODO:localize
let text = text.update(
component: MultilineTextComponent(
text: .plain(NSAttributedString(string: "Add your debit or credit card to buy goods and services on Telegram.", font: UIFont.systemFont(ofSize: 15.0), textColor: .gray)),
@ -83,7 +81,6 @@ private final class AddPaymentMethodSheetContent: CombinedComponent {
transition: context.transition
)
//TODO:localize
let actionButton = actionButton.update(
component: SolidRoundedButtonComponent(
title: "Add Payment Method",
@ -102,7 +99,6 @@ private final class AddPaymentMethodSheetContent: CombinedComponent {
transition: context.transition
)
//TODO:localize
let cancelButton = cancelButton.update(
component: Button(
content: AnyComponent(

View File

@ -406,10 +406,8 @@ public final class PaymentCardEntryScreen: ViewControllerComponentContainer {
updateModelKeyImpl?(key, value)
}), navigationBarAppearance: .transparent)
//TODO:localize
self.title = "Add Payment Method"
//TODO:localize
self.doneItem = UIBarButtonItem(title: "Add", style: .done, target: self, action: #selector(self.donePressed))
self.navigationItem.setRightBarButton(self.doneItem, animated: false)
self.doneItem?.isEnabled = false

View File

@ -32,6 +32,16 @@ public struct AdminLogEventsResult {
}
public enum AdminLogEventAction {
public struct ForumTopicInfo {
public var info: EngineMessageHistoryThread.Info
public var isClosed: Bool
public init(info: EngineMessageHistoryThread.Info, isClosed: Bool) {
self.info = info
self.isClosed = isClosed
}
}
case changeTitle(prev: String, new: String)
case changeAbout(prev: String, new: String)
case changeUsername(prev: String, new: String)
@ -71,7 +81,7 @@ public enum AdminLogEventAction {
case changeUsernames(prev: [String], new: [String])
case createTopic(info: EngineMessageHistoryThread.Info)
case deleteTopic(info: EngineMessageHistoryThread.Info)
case editTopic(prevInfo: EngineMessageHistoryThread.Info, newInfo: EngineMessageHistoryThread.Info)
case editTopic(prevInfo: ForumTopicInfo, newInfo: ForumTopicInfo)
case pinTopic(prevInfo: EngineMessageHistoryThread.Info?, newInfo: EngineMessageHistoryThread.Info?)
case toggleForum(isForum: Bool)
}
@ -289,20 +299,20 @@ func channelAdminLogEvents(postbox: Postbox, network: Network, peerId: PeerId, m
action = .deleteTopic(info: EngineMessageHistoryThread.Info(title: "", icon: nil, iconColor: 0))
}
case let .channelAdminLogEventActionEditTopic(prevTopic, newTopic):
let prevInfo: EngineMessageHistoryThread.Info
let prevInfo: AdminLogEventAction.ForumTopicInfo
switch prevTopic {
case let .forumTopic(_, _, _, title, iconColor, iconEmojiId, _, _, _, _, _, _, _, _, _):
prevInfo = EngineMessageHistoryThread.Info(title: title, icon: iconEmojiId, iconColor: iconColor)
case let .forumTopic(flags, _, _, title, iconColor, iconEmojiId, _, _, _, _, _, _, _, _, _):
prevInfo = AdminLogEventAction.ForumTopicInfo(info: EngineMessageHistoryThread.Info(title: title, icon: iconEmojiId, iconColor: iconColor), isClosed: (flags & (1 << 2)) != 0)
case .forumTopicDeleted:
prevInfo = EngineMessageHistoryThread.Info(title: "", icon: nil, iconColor: 0)
prevInfo = AdminLogEventAction.ForumTopicInfo(info: EngineMessageHistoryThread.Info(title: "", icon: nil, iconColor: 0), isClosed: false)
}
let newInfo: EngineMessageHistoryThread.Info
let newInfo: AdminLogEventAction.ForumTopicInfo
switch newTopic {
case let .forumTopic(_, _, _, title, iconColor, iconEmojiId, _, _, _, _, _, _, _, _, _):
newInfo = EngineMessageHistoryThread.Info(title: title, icon: iconEmojiId, iconColor: iconColor)
case let .forumTopic(flags, _, _, title, iconColor, iconEmojiId, _, _, _, _, _, _, _, _, _):
newInfo = AdminLogEventAction.ForumTopicInfo(info: EngineMessageHistoryThread.Info(title: title, icon: iconEmojiId, iconColor: iconColor), isClosed: (flags & (1 << 2)) != 0)
case .forumTopicDeleted:
newInfo = EngineMessageHistoryThread.Info(title: "", icon: nil, iconColor: 0)
newInfo = AdminLogEventAction.ForumTopicInfo(info: EngineMessageHistoryThread.Info(title: "", icon: nil, iconColor: 0), isClosed: false)
}
action = .editTopic(prevInfo: prevInfo, newInfo: newInfo)

View File

@ -680,10 +680,8 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
attributedString = addAttributesToStringWithRanges(strings.Notification_PremiumGift_Sent(authorName, price)._tuple, body: bodyAttributes, argumentAttributes: attributes)
}
case .topicCreated:
//TODO:localize
attributedString = NSAttributedString(string: "Topic created", font: titleFont, textColor: primaryTextColor)
attributedString = NSAttributedString(string: strings.Notification_TopicCreated, font: titleFont, textColor: primaryTextColor)
case let .topicEdited(components):
//TODO:localize
if let isClosed = components.compactMap({ item -> Bool? in
switch item {
case let .isClosed(isClosed):
@ -693,9 +691,9 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
}
}).first {
if isClosed {
attributedString = NSAttributedString(string: "Topic closed", font: titleFont, textColor: primaryTextColor)
attributedString = NSAttributedString(string: strings.Notification_TopicClosed, font: titleFont, textColor: primaryTextColor)
} else {
attributedString = NSAttributedString(string: "Topic restarted", font: titleFont, textColor: primaryTextColor)
attributedString = NSAttributedString(string: strings.Notification_TopicReopened, font: titleFont, textColor: primaryTextColor)
}
} else if let title = components.compactMap({ item -> String? in
switch item {
@ -705,7 +703,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
return nil
}
}).first {
attributedString = NSAttributedString(string: "Topic renamed to \"\(title)\"", font: titleFont, textColor: primaryTextColor)
attributedString = NSAttributedString(string: strings.Notification_TopicRenamed(title).string, font: titleFont, textColor: primaryTextColor)
} else if let maybeFileId = components.compactMap({ item -> Int64? in
switch item {
case let .iconFileId(id):
@ -714,9 +712,12 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
return nil
}
}).first {
let _ = maybeFileId
//TODO:localize
attributedString = NSAttributedString(string: "Topic icon changed", font: titleFont, textColor: primaryTextColor)
if maybeFileId != 0 {
let bodyAttributes = MarkdownAttributeSet(font: titleFont, textColor: primaryTextColor, additionalAttributes: [:])
attributedString = addAttributesToStringWithRanges(strings.Notification_TopicIconChanged(".")._tuple, body: bodyAttributes, argumentAttributes: [0: MarkdownAttributeSet(font: titleFont, textColor: primaryTextColor, additionalAttributes: [ChatTextInputAttributes.customEmoji.rawValue: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: maybeFileId, file: nil)])])
} else {
attributedString = NSAttributedString(string: strings.Notification_TopicIconRemoved, font: titleFont, textColor: primaryTextColor)
}
}
case .unknown:
attributedString = nil

View File

@ -807,7 +807,6 @@ public class ForumCreateTopicScreen: ViewControllerComponentContainer {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: presentationData.theme.rootController.navigationBar.accentTextColor))
} else {
//TODO:localize
self.navigationItem.rightBarButtonItem = self.doneBarItem
}
}

View File

@ -819,10 +819,8 @@ final class ChatEmptyNodeTopicChatContent: ASDisplayNode, ChatEmptyNodeContent,
self.currentTheme = interfaceState.theme
self.currentStrings = interfaceState.strings
//TODO:localize
self.titleNode.attributedText = NSAttributedString(string: "Almost done!", font: titleFont, textColor: serviceColor.primaryText)
self.textNode.attributedText = NSAttributedString(string: "Send the first message to\nstart this topic.", font: messageFont, textColor: serviceColor.primaryText)
self.titleNode.attributedText = NSAttributedString(string: interfaceState.strings.Chat_EmptyTopicPlaceholder_Title, font: titleFont, textColor: serviceColor.primaryText)
self.textNode.attributedText = NSAttributedString(string: interfaceState.strings.Chat_EmptyTopicPlaceholder_Text, font: messageFont, textColor: serviceColor.primaryText)
}
let inset: CGFloat

View File

@ -1399,8 +1399,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
if authorRank == nil {
if let topicAuthorId = item.associatedData.topicAuthorId, topicAuthorId == message.author?.id {
//TODO:localize
authorRank = .custom("Topic Author")
authorRank = .custom(item.presentationData.strings.Chat_Message_TopicAuthorBadge)
}
}
case .group:

View File

@ -1655,7 +1655,6 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
}
case let .createTopic(info):
//TODO:localize
var peers = SimpleDictionary<PeerId, Peer>()
var author: Peer?
if let peer = self.entry.peers[self.entry.event.peerId] {
@ -1665,9 +1664,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
var text: String = ""
var entities: [MessageTextEntity] = []
let tempString = PresentationStrings.FormattedString(string: "Topic \"\(info.title)\" created", ranges: [])
appendAttributedText(text: tempString, generateEntities: { index in
appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_TopicCreated(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", info.title), generateEntities: { index in
if index == 0, let author = author {
return [.TextMention(peerId: author.id)]
}
@ -1677,7 +1674,6 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
case let .deleteTopic(info):
//TODO:localize
var peers = SimpleDictionary<PeerId, Peer>()
var author: Peer?
if let peer = self.entry.peers[self.entry.event.peerId] {
@ -1686,20 +1682,19 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
}
var text: String = ""
var entities: [MessageTextEntity] = []
let tempString = PresentationStrings.FormattedString(string: "Topic \"\(info.title)\" deleted", ranges: [])
appendAttributedText(text: tempString, generateEntities: { index in
let authorTitle: String = author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""
appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_TopicDeleted(authorTitle, info.title), generateEntities: { index in
if index == 0, let author = author {
return [.TextMention(peerId: author.id)]
}
return []
}, to: &text, entities: &entities)
let action = TelegramMediaActionType.customText(text: text, entities: entities)
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
case let .editTopic(_, newInfo):
//TODO:localize
case let .editTopic(prevInfo, newInfo):
var peers = SimpleDictionary<PeerId, Peer>()
var author: Peer?
if let peer = self.entry.peers[self.entry.event.peerId] {
@ -1708,20 +1703,70 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
}
var text: String = ""
var entities: [MessageTextEntity] = []
let tempString = PresentationStrings.FormattedString(string: "Topic \"\(newInfo.title)\" edited", ranges: [])
appendAttributedText(text: tempString, generateEntities: { index in
if index == 0, let author = author {
return [.TextMention(peerId: author.id)]
/*
"Channel.AdminLog.TopicRenamed" = "%1$@ renamed topic %2$@ to %3$@";
"Channel.AdminLog.TopicRenamedWithIcon" = "%1$@ renamed topic %2$@ to %3$@ and changed icon to %4$@";
"Channel.AdminLog.TopicRenamedWithRemovedIcon" = "%1$@ renamed topic %2$@ to %3$@ and removed icon";
"Channel.AdminLog.TopicChangedIcon" = "%1$@ changed topic %2$@ icon to %3$@";
"Channel.AdminLog.TopicRemovedIcon" = "%1$@ removed topic %2$@ icon";*/
let authorTitle: String = author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""
if prevInfo.isClosed != newInfo.isClosed {
appendAttributedText(text: newInfo.isClosed ? self.presentationData.strings.Channel_AdminLog_TopicClosed(authorTitle, newInfo.info.title) : self.presentationData.strings.Channel_AdminLog_TopicReopened(authorTitle, newInfo.info.title), generateEntities: { index in
if index == 0, let author = author {
return [.TextMention(peerId: author.id)]
}
return []
}, to: &text, entities: &entities)
} else if prevInfo.info.title != newInfo.info.title && prevInfo.info.icon != newInfo.info.icon {
if let fileId = newInfo.info.icon {
appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_TopicRenamedWithIcon(authorTitle, prevInfo.info.title, newInfo.info.title, "."), generateEntities: { index in
if index == 0, let author = author {
return [.TextMention(peerId: author.id)]
} else if index == 3 {
return [.CustomEmoji(stickerPack: nil, fileId: fileId)]
}
return []
}, to: &text, entities: &entities)
} else {
appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_TopicRenamedWithRemovedIcon(authorTitle, prevInfo.info.title, newInfo.info.title), generateEntities: { index in
if index == 0, let author = author {
return [.TextMention(peerId: author.id)]
}
return []
}, to: &text, entities: &entities)
}
return []
}, to: &text, entities: &entities)
} else if prevInfo.info.icon != newInfo.info.icon {
if let fileId = newInfo.info.icon {
appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_TopicChangedIcon(authorTitle, newInfo.info.title, "."), generateEntities: { index in
if index == 0, let author = author {
return [.TextMention(peerId: author.id)]
} else if index == 2 {
return [.CustomEmoji(stickerPack: nil, fileId: fileId)]
}
return []
}, to: &text, entities: &entities)
} else {
appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_TopicRemovedIcon(authorTitle, newInfo.info.title), generateEntities: { index in
if index == 0, let author = author {
return [.TextMention(peerId: author.id)]
}
return []
}, to: &text, entities: &entities)
}
} else {
appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_TopicRenamed(authorTitle, prevInfo.info.title, newInfo.info.title), generateEntities: { index in
if index == 0, let author = author {
return [.TextMention(peerId: author.id)]
}
return []
}, to: &text, entities: &entities)
}
let action = TelegramMediaActionType.customText(text: text, entities: entities)
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
case let .pinTopic(prevInfo, newInfo):
//TODO:localize
var peers = SimpleDictionary<PeerId, Peer>()
var author: Peer?
if let peer = self.entry.peers[self.entry.event.peerId] {
@ -1730,27 +1775,36 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
}
var text: String = ""
var entities: [MessageTextEntity] = []
let tempString: PresentationStrings.FormattedString
let authorTitle: String = author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""
if let newInfo = newInfo {
tempString = PresentationStrings.FormattedString(string: "Topic \"\(newInfo.title)\" pinned", ranges: [])
appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_TopicPinned(authorTitle, newInfo.title), generateEntities: { index in
if index == 0, let author = author {
return [.TextMention(peerId: author.id)]
}
return []
}, to: &text, entities: &entities)
} else if let prevInfo = prevInfo {
tempString = PresentationStrings.FormattedString(string: "Topic \"\(prevInfo.title)\" unpinned", ranges: [])
appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_TopicUnpinned(authorTitle, prevInfo.title), generateEntities: { index in
if index == 0, let author = author {
return [.TextMention(peerId: author.id)]
}
return []
}, to: &text, entities: &entities)
} else {
tempString = PresentationStrings.FormattedString(string: "Topic unpinned", ranges: [])
appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_TopicUnpinned(authorTitle, ""), generateEntities: { index in
if index == 0, let author = author {
return [.TextMention(peerId: author.id)]
}
return []
}, to: &text, entities: &entities)
}
appendAttributedText(text: tempString, generateEntities: { index in
if index == 0, let author = author {
return [.TextMention(peerId: author.id)]
}
return []
}, to: &text, entities: &entities)
let action = TelegramMediaActionType.customText(text: text, entities: entities)
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
case let .toggleForum(isForum):
//TODO:localize
var peers = SimpleDictionary<PeerId, Peer>()
var author: Peer?
if let peer = self.entry.peers[self.entry.event.peerId] {
@ -1760,14 +1814,14 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
var text: String = ""
var entities: [MessageTextEntity] = []
let tempString = PresentationStrings.FormattedString(string: "Forum \(isForum ? "enabled" : "disabled")", ranges: [])
appendAttributedText(text: tempString, generateEntities: { index in
let authorTitle: String = author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""
appendAttributedText(text: isForum ? self.presentationData.strings.Channel_AdminLog_TopicsEnabled(authorTitle) : self.presentationData.strings.Channel_AdminLog_TopicsDisabled(authorTitle), generateEntities: { index in
if index == 0, let author = author {
return [.TextMention(peerId: author.id)]
}
return []
}, to: &text, entities: &entities)
let action = TelegramMediaActionType.customText(text: text, entities: entities)
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))

View File

@ -49,8 +49,7 @@ private enum ChatReportPeerTitleButton: Equatable {
case .addMembers:
return strings.Conversation_AddMembers
case .restartTopic:
//TODO:localize
return "Restart Topic"
return strings.Chat_PanelRestartTopic
}
}
}

View File

@ -46,11 +46,10 @@ final class ChatRestrictedInputPanelNode: ChatInputPanelNode {
var iconImage: UIImage?
if let threadData = interfaceState.threadData, threadData.isClosed {
//TODO:localize
iconImage = PresentationResourcesChat.chatPanelLockIcon(interfaceState.theme)
self.textNode.attributedText = NSAttributedString(string: "The topic is closed by admin", font: Font.regular(15.0), textColor: interfaceState.theme.chat.inputPanel.secondaryTextColor)
self.textNode.attributedText = NSAttributedString(string: interfaceState.strings.Chat_PanelTopicClosedText, font: Font.regular(15.0), textColor: interfaceState.theme.chat.inputPanel.secondaryTextColor)
} else if let channel = interfaceState.renderedPeer?.peer as? TelegramChannel, channel.flags.contains(.isForum), case .peer = interfaceState.chatLocation {
self.textNode.attributedText = NSAttributedString(string: "Swipe left on a message to reply", font: Font.regular(15.0), textColor: interfaceState.theme.chat.inputPanel.secondaryTextColor)
self.textNode.attributedText = NSAttributedString(string: interfaceState.strings.Chat_PanelForumModeReplyText, font: Font.regular(15.0), textColor: interfaceState.theme.chat.inputPanel.secondaryTextColor)
} else if let (untilDate, personal) = bannedPermission {
if personal && untilDate != 0 && untilDate != Int32.max {
self.textNode.attributedText = NSAttributedString(string: interfaceState.strings.Conversation_RestrictedTextTimed(stringForFullDate(timestamp: untilDate, strings: interfaceState.strings, dateTimeFormat: interfaceState.dateTimeFormat)).string, font: Font.regular(13.0), textColor: interfaceState.theme.chat.inputPanel.secondaryTextColor)

View File

@ -2646,12 +2646,11 @@ final class PeerInfoHeaderNode: ASDisplayNode {
} else if let _ = threadData {
let subtitleColor: UIColor = presentationData.theme.list.itemSecondaryTextColor
//TODO:localize
var statusText = "in "
let statusText: String
if let addressName = peer.addressName {
statusText += "@\(addressName)"
statusText = presentationData.strings.PeerInfo_TopicHeaderLocation("@\(addressName)").string
} else {
statusText += peer.debugDisplayTitle
statusText = presentationData.strings.PeerInfo_TopicHeaderLocation(peer.debugDisplayTitle).string
}
smallSubtitleString = NSAttributedString(string: statusText, font: Font.regular(15.0), textColor: UIColor(rgb: 0xffffff, alpha: 0.7))

View File

@ -1627,8 +1627,8 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
if isCreator, let appConfiguration = data.appConfiguration {
var minParticipants = 200
if let data = appConfiguration.data, let value = data["forum_upgrade_participants_min"] as? Int {
minParticipants = value
if let data = appConfiguration.data, let value = data["forum_upgrade_participants_min"] as? Double {
minParticipants = Int(value)
}
var canSetupTopics = false
@ -1646,15 +1646,15 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
}
if canSetupTopics {
//TODO:localize
items[.peerDataSettings]!.append(PeerInfoScreenSwitchItem(id: ItemTopics, text: "Topics", value: channel.flags.contains(.isForum), icon: UIImage(bundleImageName: "Settings/Menu/Topics"), isLocked: topicsLimitedReason != nil, toggled: { value in
items[.peerDataSettings]!.append(PeerInfoScreenSwitchItem(id: ItemTopics, text: presentationData.strings.PeerInfo_OptionTopics, value: channel.flags.contains(.isForum), icon: UIImage(bundleImageName: "Settings/Menu/Topics"), isLocked: topicsLimitedReason != nil, toggled: { value in
if let topicsLimitedReason = topicsLimitedReason {
interaction.displayTopicsLimited(topicsLimitedReason)
} else {
interaction.toggleForumTopics(value)
}
}))
items[.peerDataSettings]!.append(PeerInfoScreenCommentItem(id: ItemTopicsText, text: "The group chat will be divided into topics created by admins or users."))
items[.peerDataSettings]!.append(PeerInfoScreenCommentItem(id: ItemTopicsText, text: presentationData.strings.PeerInfo_OptionTopicsText))
}
}
@ -2095,14 +2095,13 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
return
}
//TODO:localize
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
let text: String
switch reason {
case let .participants(minCount):
text = "Only groups with more than **\(minCount) members** can have topics enabled."
text = self.presentationData.strings.PeerInfo_TopicsLimitedParticipantCountText(Int32(minCount))
case .discussion:
text = "Topics are currently unavailable in groups connected to channels."
text = self.presentationData.strings.PeerInfo_TopicsLimitedDiscussionGroups
}
self.controller?.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_topics", scale: 0.066, colors: [:], title: nil, text: text, customUndoText: nil), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
}
@ -4257,13 +4256,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
if !self.forumTopicNotificationExceptions.isEmpty {
items.append(.separator)
//TODO:localize
let text: String
if self.forumTopicNotificationExceptions.count == 1 {
text = "There is [1 topic]() that is listed as exception."
} else {
text = "There are [\(self.forumTopicNotificationExceptions.count) topics]() that are listed as exceptions."
}
let text: String = self.presentationData.strings.PeerInfo_TopicNotificationExceptions(Int32(self.forumTopicNotificationExceptions.count))
items.append(.action(ContextMenuActionItem(
text: text,
@ -9707,12 +9700,11 @@ func presentAddMembersImpl(context: AccountContext, updatedPresentationData: (in
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let peers = maybePeers.compactMap { $0.value }
//TODO:localize
let text: String
if peers.count == 1 {
text = "**\(peers[0].displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder))** added to the group."
text = presentationData.strings.PeerInfo_NotificationMemberAdded(peers[0].displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string
} else {
text = "**\(peers.count)** members added to the group."
text = presentationData.strings.PeerInfo_NotificationMultipleMembersAdded(Int32(peers.count))
}
parentController?.present(UndoOverlayController(presentationData: presentationData, content: .peers(context: context, peers: peers, title: nil, text: text, customUndoText: nil), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
})