Various Improvements

This commit is contained in:
Ilya Laktyushin 2021-08-13 17:50:32 +03:00
parent 6f5c99d208
commit dfc224aab0
18 changed files with 235 additions and 44 deletions

View File

@ -6585,3 +6585,26 @@ Sorry for the inconvenience.";
"Chat.NextChannelArchivedSwipeAction" = "Release to go to archived channels"; "Chat.NextChannelArchivedSwipeAction" = "Release to go to archived channels";
"Chat.NextChannelUnarchivedSwipeProgress" = "Swipe up to go to unarchived channels"; "Chat.NextChannelUnarchivedSwipeProgress" = "Swipe up to go to unarchived channels";
"Chat.NextChannelUnarchivedSwipeAction" = "Release to go to unarchived channels"; "Chat.NextChannelUnarchivedSwipeAction" = "Release to go to unarchived channels";
"Conversation.ForwardOptions.Text" = "What whould you like to do with %1$@ from %2$@?";
"Conversation.ForwardOptions.TextPersonal" = "What whould you like to do with %1$@ from your chat with %2$@?";
"Conversation.ForwardOptions.ForwardToAnotherChat" = "Forward to Another Chat";
"Conversation.ForwardOptions.CancelForwarding" = "Cancel Forwarding";
"Conversation.ForwardOptions.HideSendersNames" = "Hide Senders' Names";
"Conversation.ForwardOptions.ShowSendersNames" = "Show Senders' Names";
"Conversation.ForwardOptions.Title_1" = "%@ Message";
"Conversation.ForwardOptions.Title_2" = "%@ Messages";
"Conversation.ForwardOptions.Title_3_10" = "%@ Messages";
"Conversation.ForwardOptions.Title_any" = "%@ Messages";
"Conversation.ForwardOptions.Title_many" = "%@ Messages";
"Conversation.ForwardOptions.Title_0" = "%@ Messages";
"Conversation.ForwardOptions.Messages_1" = "%@ message";
"Conversation.ForwardOptions.Messages_2" = "%@ messages";
"Conversation.ForwardOptions.Messages_3_10" = "%@ messages";
"Conversation.ForwardOptions.Messages_any" = "%@ messages";
"Conversation.ForwardOptions.Messages_many" = "%@ messages";
"Conversation.ForwardOptions.Messages_0" = "%@ messages";
"Conversation.ForwardOptions.You" = "You (senders' names hidden)";

View File

@ -264,6 +264,7 @@ public final class ChatInterfaceState: Codable, Equatable {
public let composeDisableUrlPreview: String? public let composeDisableUrlPreview: String?
public let replyMessageId: EngineMessage.Id? public let replyMessageId: EngineMessage.Id?
public let forwardMessageIds: [EngineMessage.Id]? public let forwardMessageIds: [EngineMessage.Id]?
public let forwardMessageHideSendersNames: Bool
public let editMessage: ChatEditMessageState? public let editMessage: ChatEditMessageState?
public let selectionState: ChatInterfaceSelectionState? public let selectionState: ChatInterfaceSelectionState?
public let messageActionsState: ChatInterfaceMessageActionsState public let messageActionsState: ChatInterfaceMessageActionsState
@ -306,6 +307,7 @@ public final class ChatInterfaceState: Codable, Equatable {
self.composeDisableUrlPreview = nil self.composeDisableUrlPreview = nil
self.replyMessageId = nil self.replyMessageId = nil
self.forwardMessageIds = nil self.forwardMessageIds = nil
self.forwardMessageHideSendersNames = false
self.editMessage = nil self.editMessage = nil
self.selectionState = nil self.selectionState = nil
self.messageActionsState = ChatInterfaceMessageActionsState() self.messageActionsState = ChatInterfaceMessageActionsState()
@ -315,12 +317,13 @@ public final class ChatInterfaceState: Codable, Equatable {
self.inputLanguage = nil self.inputLanguage = nil
} }
public init(timestamp: Int32, composeInputState: ChatTextInputState, composeDisableUrlPreview: String?, replyMessageId: EngineMessage.Id?, forwardMessageIds: [EngineMessage.Id]?, editMessage: ChatEditMessageState?, selectionState: ChatInterfaceSelectionState?, messageActionsState: ChatInterfaceMessageActionsState, historyScrollState: ChatInterfaceHistoryScrollState?, mediaRecordingMode: ChatTextInputMediaRecordingButtonMode, silentPosting: Bool, inputLanguage: String?) { public init(timestamp: Int32, composeInputState: ChatTextInputState, composeDisableUrlPreview: String?, replyMessageId: EngineMessage.Id?, forwardMessageIds: [EngineMessage.Id]?, forwardMessageHideSendersNames: Bool, editMessage: ChatEditMessageState?, selectionState: ChatInterfaceSelectionState?, messageActionsState: ChatInterfaceMessageActionsState, historyScrollState: ChatInterfaceHistoryScrollState?, mediaRecordingMode: ChatTextInputMediaRecordingButtonMode, silentPosting: Bool, inputLanguage: String?) {
self.timestamp = timestamp self.timestamp = timestamp
self.composeInputState = composeInputState self.composeInputState = composeInputState
self.composeDisableUrlPreview = composeDisableUrlPreview self.composeDisableUrlPreview = composeDisableUrlPreview
self.replyMessageId = replyMessageId self.replyMessageId = replyMessageId
self.forwardMessageIds = forwardMessageIds self.forwardMessageIds = forwardMessageIds
self.forwardMessageHideSendersNames = forwardMessageHideSendersNames
self.editMessage = editMessage self.editMessage = editMessage
self.selectionState = selectionState self.selectionState = selectionState
self.messageActionsState = messageActionsState self.messageActionsState = messageActionsState
@ -357,6 +360,7 @@ public final class ChatInterfaceState: Codable, Equatable {
} else { } else {
self.forwardMessageIds = nil self.forwardMessageIds = nil
} }
self.forwardMessageHideSendersNames = ((try? container.decode(Int32.self, forKey: "fhn")) ?? 0) != 0
if let editMessage = try? container.decodeIfPresent(ChatEditMessageState.self, forKey: "em") { if let editMessage = try? container.decodeIfPresent(ChatEditMessageState.self, forKey: "em") {
self.editMessage = editMessage self.editMessage = editMessage
} else { } else {
@ -406,6 +410,7 @@ public final class ChatInterfaceState: Codable, Equatable {
} else { } else {
try container.encodeNil(forKey: "fm") try container.encodeNil(forKey: "fm")
} }
try container.encode((self.forwardMessageHideSendersNames ? 1 : 0) as Int32, forKey: "fhn")
if let editMessage = self.editMessage { if let editMessage = self.editMessage {
try container.encode(editMessage, forKey: "em") try container.encode(editMessage, forKey: "em")
} else { } else {
@ -446,6 +451,9 @@ public final class ChatInterfaceState: Codable, Equatable {
} else if (lhs.forwardMessageIds != nil) != (rhs.forwardMessageIds != nil) { } else if (lhs.forwardMessageIds != nil) != (rhs.forwardMessageIds != nil) {
return false return false
} }
if lhs.forwardMessageHideSendersNames != rhs.forwardMessageHideSendersNames {
return false
}
if lhs.messageActionsState != rhs.messageActionsState { if lhs.messageActionsState != rhs.messageActionsState {
return false return false
} }
@ -467,11 +475,11 @@ public final class ChatInterfaceState: Codable, Equatable {
public func withUpdatedComposeInputState(_ inputState: ChatTextInputState) -> ChatInterfaceState { public func withUpdatedComposeInputState(_ inputState: ChatTextInputState) -> ChatInterfaceState {
let updatedComposeInputState = inputState let updatedComposeInputState = inputState
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: updatedComposeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) return ChatInterfaceState(timestamp: self.timestamp, composeInputState: updatedComposeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
} }
public func withUpdatedComposeDisableUrlPreview(_ disableUrlPreview: String?) -> ChatInterfaceState { public func withUpdatedComposeDisableUrlPreview(_ disableUrlPreview: String?) -> ChatInterfaceState {
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: disableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: disableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
} }
public func withUpdatedEffectiveInputState(_ inputState: ChatTextInputState) -> ChatInterfaceState { public func withUpdatedEffectiveInputState(_ inputState: ChatTextInputState) -> ChatInterfaceState {
@ -483,15 +491,19 @@ public final class ChatInterfaceState: Codable, Equatable {
updatedComposeInputState = inputState updatedComposeInputState = inputState
} }
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: updatedComposeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: updatedEditMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) return ChatInterfaceState(timestamp: self.timestamp, composeInputState: updatedComposeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: updatedEditMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
} }
public func withUpdatedReplyMessageId(_ replyMessageId: EngineMessage.Id?) -> ChatInterfaceState { public func withUpdatedReplyMessageId(_ replyMessageId: EngineMessage.Id?) -> ChatInterfaceState {
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
} }
public func withUpdatedForwardMessageIds(_ forwardMessageIds: [EngineMessage.Id]?) -> ChatInterfaceState { public func withUpdatedForwardMessageIds(_ forwardMessageIds: [EngineMessage.Id]?) -> ChatInterfaceState {
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
}
public func withUpdatedForwardMessageHideSendersNames(_ forwardMessageHideSendersNames: Bool) -> ChatInterfaceState {
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
} }
public func withUpdatedSelectedMessages(_ messageIds: [EngineMessage.Id]) -> ChatInterfaceState { public func withUpdatedSelectedMessages(_ messageIds: [EngineMessage.Id]) -> ChatInterfaceState {
@ -502,7 +514,7 @@ public final class ChatInterfaceState: Codable, Equatable {
for messageId in messageIds { for messageId in messageIds {
selectedIds.insert(messageId) selectedIds.insert(messageId)
} }
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds), messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds), messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
} }
public func withToggledSelectedMessages(_ messageIds: [EngineMessage.Id], value: Bool) -> ChatInterfaceState { public func withToggledSelectedMessages(_ messageIds: [EngineMessage.Id], value: Bool) -> ChatInterfaceState {
@ -517,39 +529,39 @@ public final class ChatInterfaceState: Codable, Equatable {
selectedIds.remove(messageId) selectedIds.remove(messageId)
} }
} }
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds), messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds), messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
} }
public func withoutSelectionState() -> ChatInterfaceState { public func withoutSelectionState() -> ChatInterfaceState {
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: nil, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: nil, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
} }
public func withUpdatedTimestamp(_ timestamp: Int32) -> ChatInterfaceState { public func withUpdatedTimestamp(_ timestamp: Int32) -> ChatInterfaceState {
return ChatInterfaceState(timestamp: timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) return ChatInterfaceState(timestamp: timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
} }
public func withUpdatedEditMessage(_ editMessage: ChatEditMessageState?) -> ChatInterfaceState { public func withUpdatedEditMessage(_ editMessage: ChatEditMessageState?) -> ChatInterfaceState {
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
} }
public func withUpdatedMessageActionsState(_ f: (ChatInterfaceMessageActionsState) -> ChatInterfaceMessageActionsState) -> ChatInterfaceState { public func withUpdatedMessageActionsState(_ f: (ChatInterfaceMessageActionsState) -> ChatInterfaceMessageActionsState) -> ChatInterfaceState {
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: f(self.messageActionsState), historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: f(self.messageActionsState), historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
} }
public func withUpdatedHistoryScrollState(_ historyScrollState: ChatInterfaceHistoryScrollState?) -> ChatInterfaceState { public func withUpdatedHistoryScrollState(_ historyScrollState: ChatInterfaceHistoryScrollState?) -> ChatInterfaceState {
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
} }
public func withUpdatedMediaRecordingMode(_ mediaRecordingMode: ChatTextInputMediaRecordingButtonMode) -> ChatInterfaceState { public func withUpdatedMediaRecordingMode(_ mediaRecordingMode: ChatTextInputMediaRecordingButtonMode) -> ChatInterfaceState {
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
} }
public func withUpdatedSilentPosting(_ silentPosting: Bool) -> ChatInterfaceState { public func withUpdatedSilentPosting(_ silentPosting: Bool) -> ChatInterfaceState {
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: silentPosting, inputLanguage: self.inputLanguage) return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: silentPosting, inputLanguage: self.inputLanguage)
} }
public func withUpdatedInputLanguage(_ inputLanguage: String?) -> ChatInterfaceState { public func withUpdatedInputLanguage(_ inputLanguage: String?) -> ChatInterfaceState {
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: inputLanguage) return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: inputLanguage)
} }
public static func parse(_ state: OpaqueChatInterfaceState) -> ChatInterfaceState { public static func parse(_ state: OpaqueChatInterfaceState) -> ChatInterfaceState {

View File

@ -327,6 +327,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
private var reorderFeedbackDisposable: MetaDisposable? private var reorderFeedbackDisposable: MetaDisposable?
private var reorderInProgress: Bool = false private var reorderInProgress: Bool = false
private var reorderingItemsCompleted: (() -> Void)? private var reorderingItemsCompleted: (() -> Void)?
private var reorderScrollStartTimestamp: Double?
public var reorderedItemHasShadow = true public var reorderedItemHasShadow = true
private let waitingForNodesDisposable = MetaDisposable() private let waitingForNodesDisposable = MetaDisposable()
@ -3974,20 +3975,38 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
var offsetRanges = OffsetRanges() var offsetRanges = OffsetRanges()
var scrollingForReorder = false
if let reorderOffset = self.reorderNode?.currentOffset(), !self.itemNodes.isEmpty { if let reorderOffset = self.reorderNode?.currentOffset(), !self.itemNodes.isEmpty {
let effectiveInsets = self.visualInsets ?? self.insets let effectiveInsets = self.visualInsets ?? self.insets
var offset: CGFloat = 6.0
if let reorderScrollStartTimestamp = self.reorderScrollStartTimestamp, reorderScrollStartTimestamp + 2.0 < timestamp {
offset *= 2.0
}
if reorderOffset < effectiveInsets.top + 10.0 { if reorderOffset < effectiveInsets.top + 10.0 {
if self.itemNodes[0].apparentFrame.minY < effectiveInsets.top { if self.itemNodes[0].apparentFrame.minY < effectiveInsets.top {
continueAnimations = true continueAnimations = true
offsetRanges.offset(IndexRange(first: 0, last: Int.max), offset: 6.0) offsetRanges.offset(IndexRange(first: 0, last: Int.max), offset: offset)
scrollingForReorder = true
} }
} else if reorderOffset > self.visibleSize.height - effectiveInsets.bottom - 10.0 { } else if reorderOffset > self.visibleSize.height - effectiveInsets.bottom - 10.0 {
if self.itemNodes[self.itemNodes.count - 1].apparentFrame.maxY > self.visibleSize.height - effectiveInsets.bottom { if self.itemNodes[self.itemNodes.count - 1].apparentFrame.maxY > self.visibleSize.height - effectiveInsets.bottom {
continueAnimations = true continueAnimations = true
offsetRanges.offset(IndexRange(first: 0, last: Int.max), offset: -6.0) if self.reorderScrollStartTimestamp == nil {
self.reorderScrollStartTimestamp = timestamp
}
offsetRanges.offset(IndexRange(first: 0, last: Int.max), offset: -offset)
scrollingForReorder = true
} }
} }
} }
if scrollingForReorder {
if self.reorderScrollStartTimestamp == nil {
self.reorderScrollStartTimestamp = timestamp
}
} else {
self.reorderScrollStartTimestamp = nil
}
var requestUpdateVisibleItems = false var requestUpdateVisibleItems = false
var index = 0 var index = 0

View File

@ -19,6 +19,7 @@ import ContextUI
import SaveToCameraRoll import SaveToCameraRoll
import UndoUI import UndoUI
import TelegramUIPreferences import TelegramUIPreferences
import OpenInExternalAppUI
public enum UniversalVideoGalleryItemContentInfo { public enum UniversalVideoGalleryItemContentInfo {
case message(Message) case message(Message)
@ -2088,6 +2089,36 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
c.setItems(strongSelf.contextMenuSpeedItems()) c.setItems(strongSelf.contextMenuSpeedItems())
}))) })))
if let (message, _, _) = strongSelf.contentInfo() {
for media in message.media {
if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content {
let url = content.url
let item = OpenInItem.url(url: url)
let canOpenIn = availableOpenInOptions(context: strongSelf.context, item: item).count > 1
let openText = canOpenIn ? strongSelf.presentationData.strings.Conversation_FileOpenIn : strongSelf.presentationData.strings.Conversation_LinkDialogOpen
items.append(.action(ContextMenuActionItem(text: openText, textColor: .primary, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Share"), color: theme.contextMenu.primaryColor) }, action: { _, f in
f(.default)
if let strongSelf = self, let controller = strongSelf.galleryController() {
var presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
if !presentationData.theme.overallDarkAppearance {
presentationData = presentationData.withUpdated(theme: defaultDarkColorPresentationTheme)
}
let actionSheet = OpenInActionSheetController(context: strongSelf.context, forceTheme: presentationData.theme, item: item, openUrl: { [weak self] url in
if let strongSelf = self {
strongSelf.context.sharedContext.openExternalUrl(context: strongSelf.context, urlContext: .generic, url: url, forceExternal: true, presentationData: presentationData, navigationController: strongSelf.baseNavigationController(), dismissInput: {})
}
})
controller.present(actionSheet, in: .window(.root))
}
})))
break
}
}
}
if let (message, maybeFile, _) = strongSelf.contentInfo(), let file = maybeFile { if let (message, maybeFile, _) = strongSelf.contentInfo(), let file = maybeFile {
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Gallery_SaveVideo, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Download"), color: theme.actionSheet.primaryTextColor) }, action: { _, f in items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Gallery_SaveVideo, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Download"), color: theme.actionSheet.primaryTextColor) }, action: { _, f in
f(.default) f(.default)

View File

@ -62,9 +62,20 @@ private func allOpenInOptions(context: AccountContext, item: OpenInItem) -> [Ope
var options: [OpenInOption] = [] var options: [OpenInOption] = []
switch item { switch item {
case let .url(url): case let .url(url):
options.append(OpenInOption(identifier: "safari", application: .safari, action: { var skipSafari = false
return .openUrl(url: url) if url.contains("youtube.com/") || url.contains("youtu.be/") {
})) let updatedUrl = url.replacingOccurrences(of: "https://", with: "youtube://").replacingOccurrences(of: "http://", with: "youtube://")
options.append(OpenInOption(identifier: "youtube", application: .other(title: "YouTube", identifier: 544007664, scheme: "youtube", store: nil), action: {
return .openUrl(url: updatedUrl)
}))
skipSafari = true
}
if !skipSafari {
options.append(OpenInOption(identifier: "safari", application: .safari, action: {
return .openUrl(url: url)
}))
}
options.append(OpenInOption(identifier: "chrome", application: .other(title: "Chrome", identifier: 535886823, scheme: "googlechrome", store: nil), action: { options.append(OpenInOption(identifier: "chrome", application: .other(title: "Chrome", identifier: 535886823, scheme: "googlechrome", store: nil), action: {
if let url = URL(string: url), var components = URLComponents(url: url, resolvingAgainstBaseURL: true) { if let url = URL(string: url), var components = URLComponents(url: url, resolvingAgainstBaseURL: true) {

View File

@ -175,6 +175,7 @@ private var declaredEncodables: Void = {
declareEncodable(CachedDisplayAsPeers.self, f: { CachedDisplayAsPeers(decoder: $0) }) declareEncodable(CachedDisplayAsPeers.self, f: { CachedDisplayAsPeers(decoder: $0) })
declareEncodable(WallpapersState.self, f: { WallpapersState(decoder: $0) }) declareEncodable(WallpapersState.self, f: { WallpapersState(decoder: $0) })
declareEncodable(WallpaperDataResource.self, f: { WallpaperDataResource(decoder: $0) }) declareEncodable(WallpaperDataResource.self, f: { WallpaperDataResource(decoder: $0) })
declareEncodable(ForwardHideSendersNamesMessageAttribute.self, f: { ForwardHideSendersNamesMessageAttribute(decoder: $0) })
return return
}() }()

View File

@ -3,7 +3,6 @@ import Postbox
import TelegramApi import TelegramApi
import SwiftSignalKit import SwiftSignalKit
public enum EnqueueMessageGrouping { public enum EnqueueMessageGrouping {
case none case none
case auto case auto
@ -114,6 +113,8 @@ private func filterMessageAttributesForOutgoingMessage(_ attributes: [MessageAtt
return true return true
case _ as EmojiSearchQueryMessageAttribute: case _ as EmojiSearchQueryMessageAttribute:
return true return true
case _ as ForwardHideSendersNamesMessageAttribute:
return true
default: default:
return false return false
} }
@ -131,6 +132,8 @@ private func filterMessageAttributesForForwardedMessage(_ attributes: [MessageAt
return true return true
case _ as OutgoingScheduleInfoMessageAttribute: case _ as OutgoingScheduleInfoMessageAttribute:
return true return true
case _ as ForwardHideSendersNamesMessageAttribute:
return true
default: default:
return false return false
} }
@ -560,6 +563,14 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
var forwardInfo: StoreMessageForwardInfo? var forwardInfo: StoreMessageForwardInfo?
var hideSendersNames = false
for attribute in requestedAttributes {
if let _ = attribute as? ForwardHideSendersNamesMessageAttribute {
hideSendersNames = true
break
}
}
if sourceMessage.id.namespace == Namespaces.Message.Cloud && peerId.namespace != Namespaces.Peer.SecretChat { if sourceMessage.id.namespace == Namespaces.Message.Cloud && peerId.namespace != Namespaces.Peer.SecretChat {
attributes.append(ForwardSourceInfoAttribute(messageId: sourceMessage.id)) attributes.append(ForwardSourceInfoAttribute(messageId: sourceMessage.id))
@ -606,7 +617,9 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
} }
} }
if let sourceForwardInfo = sourceMessage.forwardInfo { if hideSendersNames {
} else if let sourceForwardInfo = sourceMessage.forwardInfo {
forwardInfo = StoreMessageForwardInfo(authorId: sourceForwardInfo.author?.id, sourceId: sourceForwardInfo.source?.id, sourceMessageId: sourceForwardInfo.sourceMessageId, date: sourceForwardInfo.date, authorSignature: sourceForwardInfo.authorSignature, psaType: nil, flags: []) forwardInfo = StoreMessageForwardInfo(authorId: sourceForwardInfo.author?.id, sourceId: sourceForwardInfo.source?.id, sourceMessageId: sourceForwardInfo.sourceMessageId, date: sourceForwardInfo.date, authorSignature: sourceForwardInfo.authorSignature, psaType: nil, flags: [])
} else { } else {
if sourceMessage.id.peerId != account.peerId { if sourceMessage.id.peerId != account.peerId {

View File

@ -697,6 +697,7 @@ public final class PendingMessageManager {
return .complete() return .complete()
} else if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { } else if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
var isForward = false var isForward = false
var hideSendersNames = false
var replyMessageId: Int32? var replyMessageId: Int32?
var scheduleTime: Int32? var scheduleTime: Int32?
@ -714,6 +715,8 @@ public final class PendingMessageManager {
} else if let attribute = attribute as? OutgoingScheduleInfoMessageAttribute { } else if let attribute = attribute as? OutgoingScheduleInfoMessageAttribute {
flags |= Int32(1 << 10) flags |= Int32(1 << 10)
scheduleTime = attribute.scheduleTime scheduleTime = attribute.scheduleTime
} else if let _ = attribute as? ForwardHideSendersNamesMessageAttribute {
hideSendersNames = true
} }
} }
@ -722,6 +725,9 @@ public final class PendingMessageManager {
if messages.contains(where: { $0.0.groupingKey != nil }) { if messages.contains(where: { $0.0.groupingKey != nil }) {
flags |= (1 << 9) flags |= (1 << 9)
} }
if hideSendersNames {
flags |= (1 << 11)
}
var forwardIds: [(MessageId, Int64)] = [] var forwardIds: [(MessageId, Int64)] = []
for (message, content) in messages { for (message, content) in messages {

View File

@ -1,7 +1,6 @@
import Foundation import Foundation
import Postbox import Postbox
public class AuthorSignatureMessageAttribute: MessageAttribute { public class AuthorSignatureMessageAttribute: MessageAttribute {
public let signature: String public let signature: String

View File

@ -0,0 +1,13 @@
import Foundation
import Postbox
public class ForwardHideSendersNamesMessageAttribute: MessageAttribute {
public init() {
}
required public init(decoder: PostboxDecoder) {
}
public func encode(_ encoder: PostboxEncoder) {
}
}

View File

@ -5285,7 +5285,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if let strongSelf = self { if let strongSelf = self {
strongSelf.commitPurposefulAction() strongSelf.commitPurposefulAction()
if let forwardMessageIds = strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds { if let forwardMessageIds = strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds {
strongSelf.forwardMessages(messageIds: forwardMessageIds, resetCurrent: true) strongSelf.forwardMessages(messageIds: forwardMessageIds, hideSendersNames: strongSelf.presentationInterfaceState.interfaceState.forwardMessageHideSendersNames, resetCurrent: true)
} }
} }
}, forwardMessages: { [weak self] messages in }, forwardMessages: { [weak self] messages in
@ -5294,6 +5294,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let forwardMessageIds = messages.map { $0.id }.sorted() let forwardMessageIds = messages.map { $0.id }.sorted()
strongSelf.forwardMessages(messageIds: forwardMessageIds) strongSelf.forwardMessages(messageIds: forwardMessageIds)
} }
}, updateForwardMessageHideSendersNames: { [weak self] value in
if let strongSelf = self {
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { $0.updatedInterfaceState({ $0.withUpdatedForwardMessageHideSendersNames(value) }) })
}
}, shareSelectedMessages: { [weak self] in }, shareSelectedMessages: { [weak self] in
if let strongSelf = self, let selectedIds = strongSelf.presentationInterfaceState.interfaceState.selectionState?.selectedIds, !selectedIds.isEmpty { if let strongSelf = self, let selectedIds = strongSelf.presentationInterfaceState.interfaceState.selectionState?.selectedIds, !selectedIds.isEmpty {
strongSelf.commitPurposefulAction() strongSelf.commitPurposefulAction()
@ -11000,16 +11004,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
} }
private func forwardMessages(messageIds: [MessageId], resetCurrent: Bool = false) { private func forwardMessages(messageIds: [MessageId], hideSendersNames: Bool = false, resetCurrent: Bool = false) {
let _ = (self.context.account.postbox.transaction { transaction -> [Message] in let _ = (self.context.account.postbox.transaction { transaction -> [Message] in
return messageIds.compactMap(transaction.getMessage) return messageIds.compactMap(transaction.getMessage)
} }
|> deliverOnMainQueue).start(next: { [weak self] messages in |> deliverOnMainQueue).start(next: { [weak self] messages in
self?.forwardMessages(messages: messages, resetCurrent: resetCurrent) self?.forwardMessages(messages: messages, hideSendersNames: hideSendersNames, resetCurrent: resetCurrent)
}) })
} }
private func forwardMessages(messages: [Message], resetCurrent: Bool) { private func forwardMessages(messages: [Message], hideSendersNames: Bool = false, resetCurrent: Bool) {
let _ = self.presentVoiceMessageDiscardAlert(action: { let _ = self.presentVoiceMessageDiscardAlert(action: {
var filter: ChatListNodePeersFilter = [.onlyWriteable, .includeSavedMessages, .excludeDisabled, .doNotSearchMessages] var filter: ChatListNodePeersFilter = [.onlyWriteable, .includeSavedMessages, .excludeDisabled, .doNotSearchMessages]
var hasPublicPolls = false var hasPublicPolls = false
@ -11154,7 +11158,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
if resetCurrent { if resetCurrent {
strongSelf.updateChatPresentationInterfaceState(animated: false, interactive: true, { $0.updatedInterfaceState({ $0.withUpdatedForwardMessageIds(nil) }) }) strongSelf.updateChatPresentationInterfaceState(animated: false, interactive: true, { $0.updatedInterfaceState({ $0.withUpdatedForwardMessageIds(nil).withUpdatedForwardMessageHideSendersNames(false) }) })
} }
var isPinnedMessages = false var isPinnedMessages = false

View File

@ -988,7 +988,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if let _ = accessoryPanelNode as? ReplyAccessoryPanelNode { if let _ = accessoryPanelNode as? ReplyAccessoryPanelNode {
strongSelf.requestUpdateChatInterfaceState(.animated(duration: 0.4, curve: .spring), false, { $0.withUpdatedReplyMessageId(nil) }) strongSelf.requestUpdateChatInterfaceState(.animated(duration: 0.4, curve: .spring), false, { $0.withUpdatedReplyMessageId(nil) })
} else if let _ = accessoryPanelNode as? ForwardAccessoryPanelNode { } else if let _ = accessoryPanelNode as? ForwardAccessoryPanelNode {
strongSelf.requestUpdateChatInterfaceState(.animated(duration: 0.4, curve: .spring), false, { $0.withUpdatedForwardMessageIds(nil) }) strongSelf.requestUpdateChatInterfaceState(.animated(duration: 0.4, curve: .spring), false, { $0.withUpdatedForwardMessageIds(nil).withUpdatedForwardMessageHideSendersNames(false) })
} else if let _ = accessoryPanelNode as? EditAccessoryPanelNode { } else if let _ = accessoryPanelNode as? EditAccessoryPanelNode {
strongSelf.interfaceInteraction?.setupEditMessage(nil, { _ in }) strongSelf.interfaceInteraction?.setupEditMessage(nil, { _ in })
} else if let _ = accessoryPanelNode as? WebpagePreviewAccessoryPanelNode { } else if let _ = accessoryPanelNode as? WebpagePreviewAccessoryPanelNode {
@ -2352,8 +2352,12 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if !messages.isEmpty || self.chatPresentationInterfaceState.interfaceState.forwardMessageIds != nil { if !messages.isEmpty || self.chatPresentationInterfaceState.interfaceState.forwardMessageIds != nil {
if let forwardMessageIds = self.chatPresentationInterfaceState.interfaceState.forwardMessageIds { if let forwardMessageIds = self.chatPresentationInterfaceState.interfaceState.forwardMessageIds {
var attributes: [MessageAttribute] = []
if self.chatPresentationInterfaceState.interfaceState.forwardMessageHideSendersNames {
attributes.append(ForwardHideSendersNamesMessageAttribute())
}
for id in forwardMessageIds { for id in forwardMessageIds {
messages.append(.forward(source: id, grouping: .auto, attributes: [], correlationId: nil)) messages.append(.forward(source: id, grouping: .auto, attributes: attributes, correlationId: nil))
} }
} }
@ -2379,7 +2383,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if let strongSelf = self, let textInputPanelNode = strongSelf.inputPanelNode as? ChatTextInputPanelNode { if let strongSelf = self, let textInputPanelNode = strongSelf.inputPanelNode as? ChatTextInputPanelNode {
strongSelf.ignoreUpdateHeight = true strongSelf.ignoreUpdateHeight = true
textInputPanelNode.text = "" textInputPanelNode.text = ""
strongSelf.requestUpdateChatInterfaceState(.immediate, true, { $0.withUpdatedReplyMessageId(nil).withUpdatedForwardMessageIds(nil).withUpdatedComposeDisableUrlPreview(nil) }) strongSelf.requestUpdateChatInterfaceState(.immediate, true, { $0.withUpdatedReplyMessageId(nil).withUpdatedForwardMessageIds(nil).withUpdatedForwardMessageHideSendersNames(false).withUpdatedComposeDisableUrlPreview(nil) })
strongSelf.ignoreUpdateHeight = false strongSelf.ignoreUpdateHeight = false
} }
}, usedCorrelationId) }, usedCorrelationId)

View File

@ -49,10 +49,10 @@ func accessoryPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceS
} else if let forwardMessageIds = chatPresentationInterfaceState.interfaceState.forwardMessageIds { } else if let forwardMessageIds = chatPresentationInterfaceState.interfaceState.forwardMessageIds {
if let forwardPanelNode = currentPanel as? ForwardAccessoryPanelNode, forwardPanelNode.messageIds == forwardMessageIds { if let forwardPanelNode = currentPanel as? ForwardAccessoryPanelNode, forwardPanelNode.messageIds == forwardMessageIds {
forwardPanelNode.interfaceInteraction = interfaceInteraction forwardPanelNode.interfaceInteraction = interfaceInteraction
forwardPanelNode.updateThemeAndStrings(theme: chatPresentationInterfaceState.theme, strings: chatPresentationInterfaceState.strings) forwardPanelNode.updateThemeAndStrings(theme: chatPresentationInterfaceState.theme, strings: chatPresentationInterfaceState.strings, hideSendersNames: chatPresentationInterfaceState.interfaceState.forwardMessageHideSendersNames)
return forwardPanelNode return forwardPanelNode
} else { } else {
let panelNode = ForwardAccessoryPanelNode(context: context, messageIds: forwardMessageIds, theme: chatPresentationInterfaceState.theme, strings: chatPresentationInterfaceState.strings) let panelNode = ForwardAccessoryPanelNode(context: context, messageIds: forwardMessageIds, theme: chatPresentationInterfaceState.theme, strings: chatPresentationInterfaceState.strings, fontSize: chatPresentationInterfaceState.fontSize, nameDisplayOrder: chatPresentationInterfaceState.nameDisplayOrder, hideSendersNames: chatPresentationInterfaceState.interfaceState.forwardMessageHideSendersNames)
panelNode.interfaceInteraction = interfaceInteraction panelNode.interfaceInteraction = interfaceInteraction
return panelNode return panelNode
} }

View File

@ -60,6 +60,7 @@ final class ChatPanelInterfaceInteraction {
let forwardSelectedMessages: () -> Void let forwardSelectedMessages: () -> Void
let forwardCurrentForwardMessages: () -> Void let forwardCurrentForwardMessages: () -> Void
let forwardMessages: ([Message]) -> Void let forwardMessages: ([Message]) -> Void
let updateForwardMessageHideSendersNames: (Bool) -> Void
let shareSelectedMessages: () -> Void let shareSelectedMessages: () -> Void
let updateTextInputStateAndMode: (@escaping (ChatTextInputState, ChatInputMode) -> (ChatTextInputState, ChatInputMode)) -> Void let updateTextInputStateAndMode: (@escaping (ChatTextInputState, ChatInputMode) -> (ChatTextInputState, ChatInputMode)) -> Void
let updateInputModeAndDismissedButtonKeyboardMessageId: ((ChatPresentationInterfaceState) -> (ChatInputMode, MessageId?)) -> Void let updateInputModeAndDismissedButtonKeyboardMessageId: ((ChatPresentationInterfaceState) -> (ChatInputMode, MessageId?)) -> Void
@ -144,6 +145,7 @@ final class ChatPanelInterfaceInteraction {
forwardSelectedMessages: @escaping () -> Void, forwardSelectedMessages: @escaping () -> Void,
forwardCurrentForwardMessages: @escaping () -> Void, forwardCurrentForwardMessages: @escaping () -> Void,
forwardMessages: @escaping ([Message]) -> Void, forwardMessages: @escaping ([Message]) -> Void,
updateForwardMessageHideSendersNames: @escaping (Bool) -> Void,
shareSelectedMessages: @escaping () -> Void, shareSelectedMessages: @escaping () -> Void,
updateTextInputStateAndMode: @escaping ((ChatTextInputState, ChatInputMode) -> (ChatTextInputState, ChatInputMode)) -> Void, updateTextInputStateAndMode: @escaping ((ChatTextInputState, ChatInputMode) -> (ChatTextInputState, ChatInputMode)) -> Void,
updateInputModeAndDismissedButtonKeyboardMessageId: @escaping ((ChatPresentationInterfaceState) -> (ChatInputMode, MessageId?)) -> Void, updateInputModeAndDismissedButtonKeyboardMessageId: @escaping ((ChatPresentationInterfaceState) -> (ChatInputMode, MessageId?)) -> Void,
@ -227,6 +229,7 @@ final class ChatPanelInterfaceInteraction {
self.forwardSelectedMessages = forwardSelectedMessages self.forwardSelectedMessages = forwardSelectedMessages
self.forwardCurrentForwardMessages = forwardCurrentForwardMessages self.forwardCurrentForwardMessages = forwardCurrentForwardMessages
self.forwardMessages = forwardMessages self.forwardMessages = forwardMessages
self.updateForwardMessageHideSendersNames = updateForwardMessageHideSendersNames
self.shareSelectedMessages = shareSelectedMessages self.shareSelectedMessages = shareSelectedMessages
self.updateTextInputStateAndMode = updateTextInputStateAndMode self.updateTextInputStateAndMode = updateTextInputStateAndMode
self.updateInputModeAndDismissedButtonKeyboardMessageId = updateInputModeAndDismissedButtonKeyboardMessageId self.updateInputModeAndDismissedButtonKeyboardMessageId = updateInputModeAndDismissedButtonKeyboardMessageId

View File

@ -65,6 +65,7 @@ final class ChatRecentActionsController: TelegramBaseController {
}, forwardSelectedMessages: { }, forwardSelectedMessages: {
}, forwardCurrentForwardMessages: { }, forwardCurrentForwardMessages: {
}, forwardMessages: { _ in }, forwardMessages: { _ in
}, updateForwardMessageHideSendersNames: { _ in
}, shareSelectedMessages: { }, shareSelectedMessages: {
}, updateTextInputStateAndMode: { _ in }, updateTextInputStateAndMode: { _ in
}, updateInputModeAndDismissedButtonKeyboardMessageId: { _ in }, updateInputModeAndDismissedButtonKeyboardMessageId: { _ in

View File

@ -6,10 +6,13 @@ import Postbox
import SwiftSignalKit import SwiftSignalKit
import Display import Display
import TelegramPresentationData import TelegramPresentationData
import TelegramUIPreferences
import AccountContext import AccountContext
import LocalizedPeerData import LocalizedPeerData
import AlertUI import AlertUI
import PresentationDataUtils import PresentationDataUtils
import TextFormat
import Markdown
func textStringForForwardedMessage(_ message: Message, strings: PresentationStrings) -> (String, Bool) { func textStringForForwardedMessage(_ message: Message, strings: PresentationStrings) -> (String, Bool) {
for media in message.media { for media in message.media {
@ -76,6 +79,8 @@ func textStringForForwardedMessage(_ message: Message, strings: PresentationStri
final class ForwardAccessoryPanelNode: AccessoryPanelNode { final class ForwardAccessoryPanelNode: AccessoryPanelNode {
private let messageDisposable = MetaDisposable() private let messageDisposable = MetaDisposable()
let messageIds: [MessageId] let messageIds: [MessageId]
private var authors: String?
private var sourcePeer: (isPersonal: Bool, displayTitle: String)?
let closeButton: ASButtonNode let closeButton: ASButtonNode
let lineNode: ASImageNode let lineNode: ASImageNode
@ -87,14 +92,20 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode {
let context: AccountContext let context: AccountContext
var theme: PresentationTheme var theme: PresentationTheme
var strings: PresentationStrings var strings: PresentationStrings
var fontSize: PresentationFontSize
var nameDisplayOrder: PresentationPersonNameOrder
var hideSendersNames: Bool
private var validLayout: (size: CGSize, interfaceState: ChatPresentationInterfaceState)? private var validLayout: (size: CGSize, interfaceState: ChatPresentationInterfaceState)?
init(context: AccountContext, messageIds: [MessageId], theme: PresentationTheme, strings: PresentationStrings) { init(context: AccountContext, messageIds: [MessageId], theme: PresentationTheme, strings: PresentationStrings, fontSize: PresentationFontSize, nameDisplayOrder: PresentationPersonNameOrder, hideSendersNames: Bool) {
self.context = context self.context = context
self.messageIds = messageIds self.messageIds = messageIds
self.theme = theme self.theme = theme
self.strings = strings self.strings = strings
self.fontSize = fontSize
self.nameDisplayOrder = nameDisplayOrder
self.hideSendersNames = hideSendersNames
self.closeButton = ASButtonNode() self.closeButton = ASButtonNode()
self.closeButton.accessibilityLabel = strings.VoiceOver_DiscardPreparedContent self.closeButton.accessibilityLabel = strings.VoiceOver_DiscardPreparedContent
@ -133,6 +144,7 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode {
var authors = "" var authors = ""
var uniquePeerIds = Set<PeerId>() var uniquePeerIds = Set<PeerId>()
var text = "" var text = ""
var sourcePeer: (Bool, String)?
for message in messages { for message in messages {
if let author = message.effectiveAuthor, !uniquePeerIds.contains(author.id) { if let author = message.effectiveAuthor, !uniquePeerIds.contains(author.id) {
uniquePeerIds.insert(author.id) uniquePeerIds.insert(author.id)
@ -141,6 +153,9 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode {
} }
authors.append(author.compactDisplayTitle) authors.append(author.compactDisplayTitle)
} }
if let peer = message.peers[message.id.peerId] {
sourcePeer = (peer.id.namespace == Namespaces.Peer.CloudUser, peer.displayTitle(strings: strongSelf.strings, displayOrder: strongSelf.nameDisplayOrder))
}
} }
if messages.count == 1 { if messages.count == 1 {
let (string, _) = textStringForForwardedMessage(messages[0], strings: strings) let (string, _) = textStringForForwardedMessage(messages[0], strings: strings)
@ -149,7 +164,15 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode {
text = strings.ForwardedMessages(Int32(messages.count)) text = strings.ForwardedMessages(Int32(messages.count))
} }
strongSelf.titleNode.attributedText = NSAttributedString(string: authors, font: Font.medium(15.0), textColor: strongSelf.theme.chat.inputPanel.panelControlAccentColor) strongSelf.sourcePeer = sourcePeer
strongSelf.authors = authors
if strongSelf.hideSendersNames {
strongSelf.titleNode.attributedText = NSAttributedString(string: strongSelf.strings.Conversation_ForwardOptions_You, font: Font.medium(15.0), textColor: strongSelf.theme.chat.inputPanel.panelControlAccentColor)
} else {
strongSelf.titleNode.attributedText = NSAttributedString(string: authors, font: Font.medium(15.0), textColor: strongSelf.theme.chat.inputPanel.panelControlAccentColor)
}
strongSelf.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(15.0), textColor: strongSelf.theme.chat.inputPanel.secondaryTextColor) strongSelf.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(15.0), textColor: strongSelf.theme.chat.inputPanel.secondaryTextColor)
let headerString: String let headerString: String
@ -178,20 +201,27 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode {
} }
override func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) { override func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) {
if self.theme !== theme || self.strings !== strings { self.updateThemeAndStrings(theme: theme, strings: strings, hideSendersNames: self.hideSendersNames)
}
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, hideSendersNames: Bool) {
if self.theme !== theme || self.strings !== strings || self.hideSendersNames != hideSendersNames {
self.theme = theme self.theme = theme
self.strings = strings self.strings = strings
self.hideSendersNames = hideSendersNames
self.closeButton.setImage(PresentationResourcesChat.chatInputPanelCloseIconImage(theme), for: []) self.closeButton.setImage(PresentationResourcesChat.chatInputPanelCloseIconImage(theme), for: [])
self.lineNode.image = PresentationResourcesChat.chatInputPanelVerticalSeparatorLineImage(theme) self.lineNode.image = PresentationResourcesChat.chatInputPanelVerticalSeparatorLineImage(theme)
if let text = self.titleNode.attributedText?.string { if hideSendersNames {
self.titleNode.attributedText = NSAttributedString(string: text, font: Font.medium(15.0), textColor: self.theme.chat.inputPanel.panelControlAccentColor) self.titleNode.attributedText = NSAttributedString(string: strings.Conversation_ForwardOptions_You, font: Font.medium(15.0), textColor: self.theme.chat.inputPanel.panelControlAccentColor)
} else if let authors = self.authors {
self.titleNode.attributedText = NSAttributedString(string: authors, font: Font.medium(15.0), textColor: self.theme.chat.inputPanel.panelControlAccentColor)
} }
if let text = self.textNode.attributedText?.string { if let text = self.textNode.attributedText?.string {
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(15.0), textColor: self.theme.chat.inputPanel.primaryTextColor) self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(15.0), textColor: self.theme.chat.inputPanel.secondaryTextColor)
} }
if let (size, interfaceState) = self.validLayout { if let (size, interfaceState) = self.validLayout {
@ -229,9 +259,28 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode {
} }
@objc func closePressed() { @objc func closePressed() {
let alertController = textAlertController(context: self.context, title: self.strings.Conversation_CancelForwardTitle, text: self.strings.Conversation_CancelForwardText, actions: [TextAlertAction(type: .genericAction, title: self.strings.Conversation_CancelForwardSelectChat, action: { [weak self] in guard let (isPersonal, peerDisplayTitle) = self.sourcePeer else {
return
}
let messageCount = Int32(self.messageIds.count)
let messages = self.strings.Conversation_ForwardOptions_Messages(messageCount)
let string = isPersonal ? self.strings.Conversation_ForwardOptions_TextPersonal(messages, peerDisplayTitle) : self.strings.Conversation_ForwardOptions_Text(messages, peerDisplayTitle)
let font = Font.regular(floor(self.fontSize.baseDisplaySize * 15.0 / 17.0))
let boldFont = Font.semibold(floor(self.fontSize.baseDisplaySize * 15.0 / 17.0))
let body = MarkdownAttributeSet(font: font, textColor: self.theme.actionSheet.secondaryTextColor)
let bold = MarkdownAttributeSet(font: boldFont, textColor: self.theme.actionSheet.secondaryTextColor)
let title = NSAttributedString(string: self.strings.Conversation_ForwardOptions_Title(messageCount), font: Font.semibold(floor(self.fontSize.baseDisplaySize)), textColor: self.theme.actionSheet.primaryTextColor, paragraphAlignment: .center)
let text = addAttributesToStringWithRanges(string._tuple, body: body, argumentAttributes: [0: bold, 1: bold], textAlignment: .center)
let alertController = richTextAlertController(context: self.context, title: title, text: text, actions: [TextAlertAction(type: .genericAction, title: self.strings.Conversation_ForwardOptions_ForwardToAnotherChat, action: { [weak self] in
self?.interfaceInteraction?.forwardCurrentForwardMessages() self?.interfaceInteraction?.forwardCurrentForwardMessages()
}), TextAlertAction(type: .defaultAction, title: self.strings.Conversation_CancelForwardCancelForward, action: { [weak self] in }), TextAlertAction(type: .genericAction, title: self.hideSendersNames ? self.strings.Conversation_ForwardOptions_ShowSendersNames : self.strings.Conversation_ForwardOptions_HideSendersNames, action: { [weak self] in
if let strongSelf = self {
strongSelf.interfaceInteraction?.updateForwardMessageHideSendersNames(!strongSelf.hideSendersNames)
}
}), TextAlertAction(type: .destructiveAction, title: self.strings.Conversation_ForwardOptions_CancelForwarding, action: { [weak self] in
self?.dismiss?() self?.dismiss?()
})], actionLayout: .vertical) })], actionLayout: .vertical)
self.interfaceInteraction?.presentController(alertController, nil) self.interfaceInteraction?.presentController(alertController, nil)
@ -239,7 +288,7 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode {
@objc func tapGesture(_ recognizer: UITapGestureRecognizer) { @objc func tapGesture(_ recognizer: UITapGestureRecognizer) {
if case .ended = recognizer.state { if case .ended = recognizer.state {
self.interfaceInteraction?.forwardCurrentForwardMessages() self.closePressed()
} }
} }
} }

View File

@ -379,6 +379,7 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode {
forwardMessages() forwardMessages()
}, forwardCurrentForwardMessages: { }, forwardCurrentForwardMessages: {
}, forwardMessages: { _ in }, forwardMessages: { _ in
}, updateForwardMessageHideSendersNames: { _ in
}, shareSelectedMessages: { }, shareSelectedMessages: {
shareMessages() shareMessages()
}, updateTextInputStateAndMode: { _ in }, updateTextInputStateAndMode: { _ in

View File

@ -198,6 +198,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
}, forwardSelectedMessages: { }, forwardSelectedMessages: {
}, forwardCurrentForwardMessages: { }, forwardCurrentForwardMessages: {
}, forwardMessages: { _ in }, forwardMessages: { _ in
}, updateForwardMessageHideSendersNames: { _ in
}, shareSelectedMessages: { }, shareSelectedMessages: {
}, updateTextInputStateAndMode: { [weak self] f in }, updateTextInputStateAndMode: { [weak self] f in
if let strongSelf = self { if let strongSelf = self {