diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/drafts/DraftRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/drafts/DraftRepository.kt index 802b2ade14a..dc121893d18 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/drafts/DraftRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/drafts/DraftRepository.kt @@ -70,12 +70,18 @@ class DraftRepository( val TAG = Log.tag(DraftRepository::class.java) } - fun getShareOrDraftData(): Maybe> { + fun getShareOrDraftData(): Maybe> { return MaybeCompat.fromCallable { getShareOrDraftDataInternal() } .observeOn(Schedulers.io()) } - private fun getShareOrDraftDataInternal(): Pair? { + /** + * Loads share data from the intent and draft data from the database and provides a one-spot initial + * load of data. + * + * Note: Voice note drafts are handled differently and via the [DraftViewModel.state] + */ + private fun getShareOrDraftDataInternal(): Pair? { val shareText = conversationArguments?.draftText val shareMedia = conversationArguments?.draftMedia val shareContentType = conversationArguments?.draftContentType @@ -130,11 +136,6 @@ class DraftRepository( return ShareOrDraftData.SetLocation(location, draftText) to drafts } - val audio: Uri? = drafts.firstOrNull { it.type == DraftTable.Draft.AUDIO }?.let { Uri.parse(it.value) } - if (audio != null) { - return ShareOrDraftData.SetMedia(audio, SlideFactory.MediaType.AUDIO, null) to drafts - } - val quote: ConversationMessage? = drafts.firstOrNull { it.type == DraftTable.Draft.QUOTE }?.let { loadDraftQuoteInternal(it.value) } if (quote != null) { return ShareOrDraftData.SetQuote(quote, draftText) to drafts @@ -148,6 +149,8 @@ class DraftRepository( if (draftText != null) { return ShareOrDraftData.SetText(draftText) to drafts } + + return null to drafts } // no share or draft diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/drafts/DraftViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/drafts/DraftViewModel.kt index 63a5c605e19..c965e0ab354 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/drafts/DraftViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/drafts/DraftViewModel.kt @@ -175,7 +175,13 @@ class DraftViewModel @JvmOverloads constructor( store.update { saveDrafts(it.copyAndSetDrafts(drafts = drafts)) } } } - .map { (data, _) -> data } + .flatMap { (data, _) -> + if (data == null) { + Maybe.empty() + } else { + Maybe.just(data) + } + } .observeOn(AndroidSchedulers.mainThread()) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt index a9f518fe9aa..859cc237774 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt @@ -180,6 +180,7 @@ import org.thoughtcrime.securesms.conversation.v2.groups.ConversationGroupCallVi import org.thoughtcrime.securesms.conversation.v2.groups.ConversationGroupViewModel import org.thoughtcrime.securesms.conversation.v2.items.InteractiveConversationElement import org.thoughtcrime.securesms.conversation.v2.keyboard.AttachmentKeyboardFragment +import org.thoughtcrime.securesms.database.DraftTable import org.thoughtcrime.securesms.database.model.IdentityRecord import org.thoughtcrime.securesms.database.model.InMemoryMessageRecord import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord @@ -551,7 +552,20 @@ class ConversationFragment : override fun onPause() { super.onPause() - ApplicationDependencies.getMessageNotifier().clearVisibleThread() + + if (!args.conversationScreenType.isInBubble) { + ApplicationDependencies.getMessageNotifier().clearVisibleThread() + } + + if (activity?.isFinishing == true) { + activity?.overridePendingTransition(R.anim.fade_scale_in, R.anim.slide_to_end) + } + + inputPanel.onPause() + + // todo [cfv2] setLastSeen(System.currentTimeMillis()) + // todo [cfv2] markLastSeen() + motionEventRelay.setDrain(null) EventBus.getDefault().unregister(this) } @@ -849,6 +863,15 @@ class ConversationFragment : .subscribeBy { data -> handleShareOrDraftData(data) } .addTo(disposables) + disposables.add( + draftViewModel + .state + .subscribe { + inputPanel.voiceNoteDraft = it.voiceNoteDraft + updateToggleButtonState() + } + ) + initializeSearch() initializeLinkPreviews() initializeStickerSuggestions() @@ -1201,12 +1224,13 @@ class ConversationFragment : when (data) { is ShareOrDraftData.SendKeyboardImage -> sendMessageWithoutComposeInput(slide = data.slide, clearCompose = false) is ShareOrDraftData.SendSticker -> sendMessageWithoutComposeInput(slide = data.slide, clearCompose = true) + is ShareOrDraftData.SetText -> composeText.setDraftText(data.text) + is ShareOrDraftData.SetLocation -> attachmentManager.setLocation(data.location, MediaConstraints.getPushMediaConstraints()) is ShareOrDraftData.SetEditMessage -> { composeText.setDraftText(data.draftText) inputPanel.enterEditMessageMode(GlideApp.with(this), data.messageEdit, true) } - is ShareOrDraftData.SetLocation -> attachmentManager.setLocation(data.location, MediaConstraints.getPushMediaConstraints()) is ShareOrDraftData.SetMedia -> { composeText.setDraftText(data.text) setMedia(data.media, data.mediaType) @@ -1217,7 +1241,6 @@ class ConversationFragment : handleReplyToMessage(data.quote) } - is ShareOrDraftData.SetText -> composeText.setDraftText(data.text) is ShareOrDraftData.StartSendMedia -> { val recipientId = viewModel.recipientSnapshot?.id ?: return conversationActivityResultContracts.launchMediaEditor(data.mediaList, recipientId, data.text) @@ -1543,6 +1566,19 @@ class ConversationFragment : return } + if (inputPanel.isRecordingInLockedMode) { + inputPanel.releaseRecordingLock() + return + } + + if (slideDeck == null) { + val voiceNote: DraftTable.Draft? = draftViewModel.voiceNoteDraft + if (voiceNote != null) { + sendMessageWithoutComposeInput(slide = AudioSlide.createFromVoiceNoteDraft(requireContext(), voiceNote), clearCompose = true) + return + } + } + val metricId = viewModel.recipientSnapshot?.let { if (it.isGroup) SignalLocalMetrics.GroupMessageSend.start() else SignalLocalMetrics.IndividualMessageSend.start() } val send: Completable = viewModel.sendMessage( @@ -3557,7 +3593,7 @@ class ConversationFragment : } override fun saveEphemeralVoiceNoteDraft(draft: VoiceNoteDraft) { - draftViewModel.cancelEphemeralVoiceNoteDraft(draft.asDraft()) + draftViewModel.saveEphemeralVoiceNoteDraft(draft.asDraft()) } } } diff --git a/app/src/spinner/java/org/thoughtcrime/securesms/database/MessageBitmaskColumnTransformer.kt b/app/src/spinner/java/org/thoughtcrime/securesms/database/MessageBitmaskColumnTransformer.kt index ab617a26c48..8617993e975 100644 --- a/app/src/spinner/java/org/thoughtcrime/securesms/database/MessageBitmaskColumnTransformer.kt +++ b/app/src/spinner/java/org/thoughtcrime/securesms/database/MessageBitmaskColumnTransformer.kt @@ -1,8 +1,9 @@ package org.thoughtcrime.securesms.database import android.database.Cursor -import org.signal.core.util.requireLong +import org.signal.core.util.requireString import org.signal.spinner.ColumnTransformer +import org.signal.spinner.DefaultColumnTransformer import org.thoughtcrime.securesms.database.MessageTypes.BAD_DECRYPT_TYPE import org.thoughtcrime.securesms.database.MessageTypes.BASE_DRAFT_TYPE import org.thoughtcrime.securesms.database.MessageTypes.BASE_INBOX_TYPE @@ -66,8 +67,13 @@ object MessageBitmaskColumnTransformer : ColumnTransformer { return columnName == "type" || columnName == "msg_box" } + @Suppress("FoldInitializerAndIfToElvis") override fun transform(tableName: String?, columnName: String, cursor: Cursor): String? { - val type = cursor.requireLong(columnName) + val type: Long? = cursor.requireString(columnName)?.toLongOrNull() + + if (type == null) { + return DefaultColumnTransformer.transform(tableName, columnName, cursor) + } val describe = """ isOutgoingMessageType:${isOutgoingMessageType(type)}