diff --git a/.gitmodules b/.gitmodules index d4b6047ecd..1a1053bf07 100644 --- a/.gitmodules +++ b/.gitmodules @@ -32,3 +32,6 @@ url=../tgcalls.git [submodule "build-system/bazel-rules/rules_xcodeproj"] path = build-system/bazel-rules/rules_xcodeproj url = https://github.com/MobileNativeFoundation/rules_xcodeproj.git +[submodule "submodules/LottieCpp/lottiecpp"] + path = submodules/LottieCpp/lottiecpp + url = https://github.com/ali-fareed/lottiecpp.git diff --git a/submodules/AttachmentUI/Sources/AttachmentPanel.swift b/submodules/AttachmentUI/Sources/AttachmentPanel.swift index 37c42cf21f..00a9cc0bea 100644 --- a/submodules/AttachmentUI/Sources/AttachmentPanel.swift +++ b/submodules/AttachmentUI/Sources/AttachmentPanel.swift @@ -991,14 +991,16 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate { let _ = (combineLatest( isReady, - captionIsAboveMedia |> take(1) + captionIsAboveMedia |> take(1), + ChatSendMessageContextScreen.initialData(context: strongSelf.context, currentMessageEffectId: nil) ) - |> deliverOnMainQueue).start(next: { [weak strongSelf] _, captionIsAboveMedia in + |> deliverOnMainQueue).start(next: { [weak strongSelf] _, captionIsAboveMedia, initialData in guard let strongSelf else { return } let controller = makeChatSendMessageActionSheetController( + initialData: initialData, context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peerId: strongSelf.presentationInterfaceState.chatLocation.peerId, @@ -1011,6 +1013,7 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate { } mediaPickerContext.setCaptionIsAboveMedia(value) }), + messageEffect: nil, attachment: true, canSendWhenOnline: sendWhenOnlineAvailable, forwardMessageIds: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? [] diff --git a/submodules/ChatInterfaceState/Sources/ChatInterfaceState.swift b/submodules/ChatInterfaceState/Sources/ChatInterfaceState.swift index c41ba0f8d1..1063ec0211 100644 --- a/submodules/ChatInterfaceState/Sources/ChatInterfaceState.swift +++ b/submodules/ChatInterfaceState/Sources/ChatInterfaceState.swift @@ -471,6 +471,7 @@ public final class ChatInterfaceState: Codable, Equatable { public let mediaDraftState: ChatInterfaceMediaDraftState? public let silentPosting: Bool public let inputLanguage: String? + public let sendMessageEffect: Int64? public var synchronizeableInputState: SynchronizeableChatInputState? { if self.composeInputState.inputText.string.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && self.replyMessageSubject == nil { @@ -521,9 +522,10 @@ public final class ChatInterfaceState: Codable, Equatable { self.mediaDraftState = nil self.silentPosting = false self.inputLanguage = nil + self.sendMessageEffect = nil } - public init(timestamp: Int32, composeInputState: ChatTextInputState, composeDisableUrlPreviews: [String], replyMessageSubject: ReplyMessageSubject?, forwardMessageIds: [EngineMessage.Id]?, forwardOptionsState: ChatInterfaceForwardOptionsState?, editMessage: ChatEditMessageState?, selectionState: ChatInterfaceSelectionState?, messageActionsState: ChatInterfaceMessageActionsState, historyScrollState: ChatInterfaceHistoryScrollState?, mediaRecordingMode: ChatTextInputMediaRecordingButtonMode, mediaDraftState: ChatInterfaceMediaDraftState?, silentPosting: Bool, inputLanguage: String?) { + public init(timestamp: Int32, composeInputState: ChatTextInputState, composeDisableUrlPreviews: [String], replyMessageSubject: ReplyMessageSubject?, forwardMessageIds: [EngineMessage.Id]?, forwardOptionsState: ChatInterfaceForwardOptionsState?, editMessage: ChatEditMessageState?, selectionState: ChatInterfaceSelectionState?, messageActionsState: ChatInterfaceMessageActionsState, historyScrollState: ChatInterfaceHistoryScrollState?, mediaRecordingMode: ChatTextInputMediaRecordingButtonMode, mediaDraftState: ChatInterfaceMediaDraftState?, silentPosting: Bool, inputLanguage: String?, sendMessageEffect: Int64?) { self.timestamp = timestamp self.composeInputState = composeInputState self.composeDisableUrlPreviews = composeDisableUrlPreviews @@ -538,6 +540,7 @@ public final class ChatInterfaceState: Codable, Equatable { self.mediaDraftState = mediaDraftState self.silentPosting = silentPosting self.inputLanguage = inputLanguage + self.sendMessageEffect = sendMessageEffect } public init(from decoder: Decoder) throws { @@ -609,6 +612,8 @@ public final class ChatInterfaceState: Codable, Equatable { self.silentPosting = ((try? container.decode(Int32.self, forKey: "sip")) ?? 0) != 0 self.inputLanguage = try? container.decodeIfPresent(String.self, forKey: "inputLanguage") + + self.sendMessageEffect = try? container.decodeIfPresent(Int64.self, forKey: "sendMessageEffect") } public func encode(to encoder: Encoder) throws { @@ -665,6 +670,8 @@ public final class ChatInterfaceState: Codable, Equatable { } else { try container.encodeNil(forKey: "inputLanguage") } + + try container.encodeIfPresent(self.sendMessageEffect, forKey: "sendMessageEffect") } public static func ==(lhs: ChatInterfaceState, rhs: ChatInterfaceState) -> Bool { @@ -699,17 +706,20 @@ public final class ChatInterfaceState: Codable, Equatable { if lhs.inputLanguage != rhs.inputLanguage { return false } + if lhs.sendMessageEffect != rhs.sendMessageEffect { + return false + } return lhs.composeInputState == rhs.composeInputState && lhs.replyMessageSubject == rhs.replyMessageSubject && lhs.selectionState == rhs.selectionState && lhs.editMessage == rhs.editMessage } public func withUpdatedComposeInputState(_ inputState: ChatTextInputState) -> ChatInterfaceState { let updatedComposeInputState = inputState - return ChatInterfaceState(timestamp: self.timestamp, composeInputState: updatedComposeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) + return ChatInterfaceState(timestamp: self.timestamp, composeInputState: updatedComposeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect) } public func withUpdatedComposeDisableUrlPreviews(_ disableUrlPreviews: [String]) -> ChatInterfaceState { - return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: disableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) + return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: disableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect) } public func withUpdatedEffectiveInputState(_ inputState: ChatTextInputState) -> ChatInterfaceState { @@ -721,19 +731,19 @@ public final class ChatInterfaceState: Codable, Equatable { updatedComposeInputState = inputState } - return ChatInterfaceState(timestamp: self.timestamp, composeInputState: updatedComposeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: updatedEditMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) + return ChatInterfaceState(timestamp: self.timestamp, composeInputState: updatedComposeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: updatedEditMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect) } public func withUpdatedReplyMessageSubject(_ replyMessageSubject: ReplyMessageSubject?) -> ChatInterfaceState { - return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) + return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect) } public func withUpdatedForwardMessageIds(_ forwardMessageIds: [EngineMessage.Id]?) -> ChatInterfaceState { - return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) + return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect) } public func withUpdatedForwardOptionsState(_ forwardOptionsState: ChatInterfaceForwardOptionsState?) -> ChatInterfaceState { - return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) + return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect) } public func withUpdatedSelectedMessages(_ messageIds: [EngineMessage.Id]) -> ChatInterfaceState { @@ -744,7 +754,7 @@ public final class ChatInterfaceState: Codable, Equatable { for messageId in messageIds { selectedIds.insert(messageId) } - return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds), messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) + return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds), messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect) } public func withToggledSelectedMessages(_ messageIds: [EngineMessage.Id], value: Bool) -> ChatInterfaceState { @@ -759,43 +769,47 @@ public final class ChatInterfaceState: Codable, Equatable { selectedIds.remove(messageId) } } - return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds), messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) + return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds), messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect) } public func withoutSelectionState() -> ChatInterfaceState { - return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: nil, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) + return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: nil, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect) } public func withUpdatedTimestamp(_ timestamp: Int32) -> ChatInterfaceState { - return ChatInterfaceState(timestamp: timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) + return ChatInterfaceState(timestamp: timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect) } public func withUpdatedEditMessage(_ editMessage: ChatEditMessageState?) -> ChatInterfaceState { - return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) + return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect) } public func withUpdatedMessageActionsState(_ f: (ChatInterfaceMessageActionsState) -> ChatInterfaceMessageActionsState) -> ChatInterfaceState { - return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: f(self.messageActionsState), historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) + return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: f(self.messageActionsState), historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect) } public func withUpdatedHistoryScrollState(_ historyScrollState: ChatInterfaceHistoryScrollState?) -> ChatInterfaceState { - return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) + return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect) } public func withUpdatedMediaRecordingMode(_ mediaRecordingMode: ChatTextInputMediaRecordingButtonMode) -> ChatInterfaceState { - return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) + return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect) } public func withUpdatedMediaDraftState(_ mediaDraftState: ChatInterfaceMediaDraftState?) -> ChatInterfaceState { - return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage) + return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect) } public func withUpdatedSilentPosting(_ silentPosting: Bool) -> ChatInterfaceState { - return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: silentPosting, inputLanguage: self.inputLanguage) + return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect) } public func withUpdatedInputLanguage(_ inputLanguage: String?) -> ChatInterfaceState { - return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: inputLanguage) + return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: inputLanguage, sendMessageEffect: self.sendMessageEffect) + } + + public func withUpdatedSendMessageEffect(_ sendMessageEffect: Int64?) -> ChatInterfaceState { + return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: sendMessageEffect) } public static func parse(_ state: OpaqueChatInterfaceState) -> ChatInterfaceState { diff --git a/submodules/ChatSendMessageActionUI/Sources/ChatSendMessageActionSheetController.swift b/submodules/ChatSendMessageActionUI/Sources/ChatSendMessageActionSheetController.swift index 45aeeef4e6..2e69f5f98b 100644 --- a/submodules/ChatSendMessageActionUI/Sources/ChatSendMessageActionSheetController.swift +++ b/submodules/ChatSendMessageActionUI/Sources/ChatSendMessageActionSheetController.swift @@ -16,6 +16,7 @@ public enum SendMessageActionSheetControllerParams { public let isScheduledMessages: Bool public let mediaPreview: ChatSendMessageContextScreenMediaPreview? public let mediaCaptionIsAbove: (Bool, (Bool) -> Void)? + public let messageEffect: (ChatSendMessageActionSheetControllerSendParameters.Effect?, (ChatSendMessageActionSheetControllerSendParameters.Effect?) -> Void)? public let attachment: Bool public let canSendWhenOnline: Bool public let forwardMessageIds: [EngineMessage.Id] @@ -24,6 +25,7 @@ public enum SendMessageActionSheetControllerParams { isScheduledMessages: Bool, mediaPreview: ChatSendMessageContextScreenMediaPreview?, mediaCaptionIsAbove: (Bool, (Bool) -> Void)?, + messageEffect: (ChatSendMessageActionSheetControllerSendParameters.Effect?, (ChatSendMessageActionSheetControllerSendParameters.Effect?) -> Void)?, attachment: Bool, canSendWhenOnline: Bool, forwardMessageIds: [EngineMessage.Id] @@ -31,6 +33,7 @@ public enum SendMessageActionSheetControllerParams { self.isScheduledMessages = isScheduledMessages self.mediaPreview = mediaPreview self.mediaCaptionIsAbove = mediaCaptionIsAbove + self.messageEffect = messageEffect self.attachment = attachment self.canSendWhenOnline = canSendWhenOnline self.forwardMessageIds = forwardMessageIds @@ -54,6 +57,7 @@ public enum SendMessageActionSheetControllerParams { } public func makeChatSendMessageActionSheetController( + initialData: ChatSendMessageContextScreen.InitialData, context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, peerId: EnginePeer.Id?, @@ -73,6 +77,7 @@ public func makeChatSendMessageActionSheetController( isPremium: Bool = false ) -> ChatSendMessageActionSheetController { return ChatSendMessageContextScreen( + initialData: initialData, context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, diff --git a/submodules/ChatSendMessageActionUI/Sources/ChatSendMessageContextScreen.swift b/submodules/ChatSendMessageActionUI/Sources/ChatSendMessageContextScreen.swift index 31abcd2afe..f1c5f4e417 100644 --- a/submodules/ChatSendMessageActionUI/Sources/ChatSendMessageContextScreen.swift +++ b/submodules/ChatSendMessageActionUI/Sources/ChatSendMessageContextScreen.swift @@ -53,6 +53,7 @@ public protocol ChatSendMessageContextScreenMediaPreview: AnyObject { final class ChatSendMessageContextScreenComponent: Component { typealias EnvironmentType = ViewControllerComponentContainer.Environment + let initialData: ChatSendMessageContextScreen.InitialData let context: AccountContext let updatedPresentationData: (initial: PresentationData, signal: Signal)? let peerId: EnginePeer.Id? @@ -72,6 +73,7 @@ final class ChatSendMessageContextScreenComponent: Component { let isPremium: Bool init( + initialData: ChatSendMessageContextScreen.InitialData, context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)?, peerId: EnginePeer.Id?, @@ -90,6 +92,7 @@ final class ChatSendMessageContextScreenComponent: Component { availableMessageEffects: AvailableMessageEffects?, isPremium: Bool ) { + self.initialData = initialData self.context = context self.updatedPresentationData = updatedPresentationData self.peerId = peerId @@ -319,6 +322,8 @@ final class ChatSendMessageContextScreenComponent: Component { switch component.params { case let .sendMessage(sendMessage): self.mediaCaptionIsAbove = sendMessage.mediaCaptionIsAbove?.0 ?? false + + self.selectedMessageEffect = component.initialData.messageEffect case let .editMessage(editMessage): self.mediaCaptionIsAbove = editMessage.mediaCaptionIsAbove?.0 ?? false } @@ -841,6 +846,12 @@ final class ChatSendMessageContextScreenComponent: Component { if !self.isUpdating { self.state?.updated(transition: .easeInOut(duration: 0.2)) } + if case let .sendMessage(sendMessage) = component.params { + let mappedEffect = self.selectedMessageEffect.flatMap { + return ChatSendMessageActionSheetControllerSendParameters.Effect(id: $0.id) + } + sendMessage.messageEffect?.1(mappedEffect) + } return } else { self.selectedMessageEffect = messageEffect @@ -849,6 +860,13 @@ final class ChatSendMessageContextScreenComponent: Component { self.state?.updated(transition: .easeInOut(duration: 0.2)) } + if case let .sendMessage(sendMessage) = component.params { + let mappedEffect = self.selectedMessageEffect.flatMap { + return ChatSendMessageActionSheetControllerSendParameters.Effect(id: $0.id) + } + sendMessage.messageEffect?.1(mappedEffect) + } + HapticFeedback().tap() } } else { @@ -858,6 +876,13 @@ final class ChatSendMessageContextScreenComponent: Component { self.state?.updated(transition: .easeInOut(duration: 0.2)) } + if case let .sendMessage(sendMessage) = component.params { + let mappedEffect = self.selectedMessageEffect.flatMap { + return ChatSendMessageActionSheetControllerSendParameters.Effect(id: $0.id) + } + sendMessage.messageEffect?.1(mappedEffect) + } + HapticFeedback().tap() } @@ -1319,6 +1344,14 @@ final class ChatSendMessageContextScreenComponent: Component { } public class ChatSendMessageContextScreen: ViewControllerComponentContainer, ChatSendMessageActionSheetController { + public final class InitialData { + fileprivate let messageEffect: AvailableMessageEffects.MessageEffect? + + init(messageEffect: AvailableMessageEffects.MessageEffect?) { + self.messageEffect = messageEffect + } + } + private let context: AccountContext private var processedDidAppear: Bool = false @@ -1335,6 +1368,7 @@ public class ChatSendMessageContextScreen: ViewControllerComponentContainer, Cha } public init( + initialData: InitialData, context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)?, peerId: EnginePeer.Id?, @@ -1358,6 +1392,7 @@ public class ChatSendMessageContextScreen: ViewControllerComponentContainer, Cha super.init( context: context, component: ChatSendMessageContextScreenComponent( + initialData: initialData, context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, @@ -1439,4 +1474,30 @@ public class ChatSendMessageContextScreen: ViewControllerComponentContainer, Cha } } } + + public static func initialData(context: AccountContext, currentMessageEffectId: Int64?) -> Signal { + let messageEffect: Signal + if let currentMessageEffectId { + messageEffect = context.engine.stickers.availableMessageEffects() + |> take(1) + |> map { availableMessageEffects -> AvailableMessageEffects.MessageEffect? in + guard let availableMessageEffects else { + return nil + } + for messageEffect in availableMessageEffects.messageEffects { + if messageEffect.id == currentMessageEffectId || messageEffect.effectSticker.fileId.id == currentMessageEffectId { + return messageEffect + } + } + return nil + } + } else { + messageEffect = .single(nil) + } + + return messageEffect + |> map { messageEffect -> InitialData in + return InitialData(messageEffect: messageEffect) + } + } } diff --git a/submodules/ChatSendMessageActionUI/Sources/MessageItemView.swift b/submodules/ChatSendMessageActionUI/Sources/MessageItemView.swift index cf48ea62ba..2666df9e8e 100644 --- a/submodules/ChatSendMessageActionUI/Sources/MessageItemView.swift +++ b/submodules/ChatSendMessageActionUI/Sources/MessageItemView.swift @@ -20,16 +20,16 @@ import MultilineTextComponent import ChatInputTextNode import EmojiTextAttachmentView -private final class EffectIcon: Component { - enum Content: Equatable { +public final class ChatSendMessageScreenEffectIcon: Component { + public enum Content: Equatable { case file(TelegramMediaFile) case text(String) } - let context: AccountContext - let content: Content + public let context: AccountContext + public let content: Content - init( + public init( context: AccountContext, content: Content ) { @@ -37,7 +37,7 @@ private final class EffectIcon: Component { self.content = content } - static func ==(lhs: EffectIcon, rhs: EffectIcon) -> Bool { + public static func ==(lhs: ChatSendMessageScreenEffectIcon, rhs: ChatSendMessageScreenEffectIcon) -> Bool { if lhs.context !== rhs.context { return false } @@ -47,19 +47,19 @@ private final class EffectIcon: Component { return true } - final class View: UIView { + public final class View: UIView { private var fileView: ReactionIconView? private var textView: ComponentView? - override init(frame: CGRect) { + override public init(frame: CGRect) { super.init(frame: frame) } - required init?(coder: NSCoder) { + required public init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - func update(component: EffectIcon, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: Transition) -> CGSize { + func update(component: ChatSendMessageScreenEffectIcon, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: Transition) -> CGSize { if case let .file(file) = component.content { let fileView: ReactionIconView if let current = self.fileView { @@ -126,11 +126,11 @@ private final class EffectIcon: Component { } } - func makeView() -> View { + public func makeView() -> View { return View(frame: CGRect()) } - func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: Transition) -> CGSize { + public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: Transition) -> CGSize { return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition) } } @@ -307,7 +307,7 @@ final class MessageItemView: UIView { effectIcon = ComponentView() self.effectIcon = effectIcon } - let effectIconContent: EffectIcon.Content + let effectIconContent: ChatSendMessageScreenEffectIcon.Content if let staticIcon = effect.staticIcon { effectIconContent = .file(staticIcon) } else { @@ -315,7 +315,7 @@ final class MessageItemView: UIView { } effectIconSize = effectIcon.update( transition: .immediate, - component: AnyComponent(EffectIcon( + component: AnyComponent(ChatSendMessageScreenEffectIcon( context: context, content: effectIconContent )), diff --git a/submodules/ChatSendMessageActionUI/Sources/SendButton.swift b/submodules/ChatSendMessageActionUI/Sources/SendButton.swift index 6d637852d1..160cadb066 100644 --- a/submodules/ChatSendMessageActionUI/Sources/SendButton.swift +++ b/submodules/ChatSendMessageActionUI/Sources/SendButton.swift @@ -32,7 +32,7 @@ final class SendButton: HighlightTrackingButton { private let iconView: UIImageView private var activityIndicator: RadialStatusNode? - private var didProcessSourceCustomContent: Bool = false + private var previousIsAnimatedIn: Bool? private var sourceCustomContentView: UIView? init(kind: Kind) { @@ -70,7 +70,8 @@ final class SendButton: HighlightTrackingButton { transition: Transition ) { let innerSize = CGSize(width: size.width - 5.5 * 2.0, height: 33.0) - transition.setFrame(view: self.containerView, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - innerSize.width) * 0.5), y: floorToScreenPixels((size.height - innerSize.height) * 0.5)), size: innerSize)) + let containerFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - innerSize.width) * 0.5), y: floorToScreenPixels((size.height - innerSize.height) * 0.5)), size: innerSize) + transition.setFrame(view: self.containerView, frame: containerFrame) transition.setCornerRadius(layer: self.containerView.layer, cornerRadius: innerSize.height * 0.5) if self.window != nil { @@ -97,13 +98,21 @@ final class SendButton: HighlightTrackingButton { self.backgroundLayer.backgroundColor = presentationData.theme.chat.inputPanel.actionControlFillColor.cgColor transition.setFrame(layer: self.backgroundLayer, frame: CGRect(origin: CGPoint(), size: innerSize)) - if !self.didProcessSourceCustomContent { - self.didProcessSourceCustomContent = true + if self.previousIsAnimatedIn != isAnimatedIn { + self.previousIsAnimatedIn = isAnimatedIn + + var sourceCustomContentViewAlpha: CGFloat = 1.0 + if let sourceCustomContentView = self.sourceCustomContentView { + sourceCustomContentViewAlpha = sourceCustomContentView.alpha + sourceCustomContentView.removeFromSuperview() + self.sourceCustomContentView = nil + } if let sourceSendButton = sourceSendButton as? ChatSendMessageActionSheetControllerSourceSendButtonNode { if let sourceCustomContentView = sourceSendButton.makeCustomContents() { self.sourceCustomContentView = sourceCustomContentView - self.iconView.superview?.insertSubview(sourceCustomContentView, belowSubview: self.iconView) + sourceCustomContentView.alpha = sourceCustomContentViewAlpha + self.addSubview(sourceCustomContentView) } } } @@ -118,11 +127,16 @@ final class SendButton: HighlightTrackingButton { } if let sourceCustomContentView = self.sourceCustomContentView { + var sourceCustomContentTransition = transition + if sourceCustomContentView.bounds.isEmpty { + sourceCustomContentTransition = .immediate + } + let sourceCustomContentSize = sourceCustomContentView.bounds.size - let sourceCustomContentFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((innerSize.width - sourceCustomContentSize.width) * 0.5) + UIScreenPixel, y: floorToScreenPixels((innerSize.height - sourceCustomContentSize.height) * 0.5)), size: sourceCustomContentSize) - transition.setPosition(view: sourceCustomContentView, position: sourceCustomContentFrame.center) - transition.setBounds(view: sourceCustomContentView, bounds: CGRect(origin: CGPoint(), size: sourceCustomContentFrame.size)) - transition.setAlpha(view: sourceCustomContentView, alpha: isAnimatedIn ? 0.0 : 1.0) + let sourceCustomContentFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((innerSize.width - sourceCustomContentSize.width) * 0.5) + UIScreenPixel, y: floorToScreenPixels((innerSize.height - sourceCustomContentSize.height) * 0.5)), size: sourceCustomContentSize).offsetBy(dx: containerFrame.minX, dy: containerFrame.minY) + sourceCustomContentTransition.setPosition(view: sourceCustomContentView, position: sourceCustomContentFrame.center) + sourceCustomContentTransition.setBounds(view: sourceCustomContentView, bounds: CGRect(origin: CGPoint(), size: sourceCustomContentFrame.size)) + sourceCustomContentTransition.setAlpha(view: sourceCustomContentView, alpha: isAnimatedIn ? 0.0 : 1.0) } if let icon = self.iconView.image { diff --git a/submodules/LottieCpp/lottiecpp b/submodules/LottieCpp/lottiecpp new file mode 160000 index 0000000000..61d31342c1 --- /dev/null +++ b/submodules/LottieCpp/lottiecpp @@ -0,0 +1 @@ +Subproject commit 61d31342c1289854326cbb3d9dedfbb9b3513a5b