From 75c84c452bb1270bb4259ca66a5a3cb3c7e0d3f2 Mon Sep 17 00:00:00 2001 From: Nicholas Tinsley Date: Wed, 14 Aug 2024 15:48:45 -0400 Subject: [PATCH] Convert MessageDetailFragment to Kotlin. --- .../MessageDetailsFragment.java | 188 ------------------ .../messagedetails/MessageDetailsFragment.kt | 168 ++++++++++++++++ 2 files changed, 168 insertions(+), 188 deletions(-) delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsFragment.java create mode 100644 app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsFragment.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsFragment.java b/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsFragment.java deleted file mode 100644 index 3a429d0852..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsFragment.java +++ /dev/null @@ -1,188 +0,0 @@ -package org.thoughtcrime.securesms.messagedetails; - -import android.content.DialogInterface; -import android.os.Bundle; -import android.view.View; -import android.widget.FrameLayout; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.fragment.app.DialogFragment; -import androidx.lifecycle.ViewModelProvider; -import androidx.recyclerview.widget.RecyclerView; - -import com.bumptech.glide.Glide; -import com.bumptech.glide.RequestManager; - -import org.thoughtcrime.securesms.R; -import org.thoughtcrime.securesms.components.FullScreenDialogFragment; -import org.thoughtcrime.securesms.conversation.colors.Colorizer; -import org.thoughtcrime.securesms.conversation.colors.RecyclerViewColorizer; -import org.thoughtcrime.securesms.conversation.ui.edit.EditMessageHistoryDialog; -import org.thoughtcrime.securesms.database.model.MessageRecord; -import org.thoughtcrime.securesms.giph.mp4.GiphyMp4PlaybackController; -import org.thoughtcrime.securesms.giph.mp4.GiphyMp4ProjectionPlayerHolder; -import org.thoughtcrime.securesms.giph.mp4.GiphyMp4ProjectionRecycler; -import org.thoughtcrime.securesms.messagedetails.MessageDetailsAdapter.MessageDetailsViewState; -import org.thoughtcrime.securesms.messagedetails.MessageDetailsViewModel.Factory; -import org.thoughtcrime.securesms.recipients.RecipientId; -import org.thoughtcrime.securesms.safety.SafetyNumberBottomSheet; -import org.thoughtcrime.securesms.util.Material3OnScrollHelper; -import org.thoughtcrime.securesms.util.MessageRecordUtil; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -public final class MessageDetailsFragment extends FullScreenDialogFragment implements MessageDetailsAdapter.Callbacks { - - private static final String MESSAGE_ID_EXTRA = "message_id"; - private static final String RECIPIENT_EXTRA = "recipient_id"; - - private RequestManager requestManager; - private MessageDetailsViewModel viewModel; - private MessageDetailsAdapter adapter; - private Colorizer colorizer; - private RecyclerViewColorizer recyclerViewColorizer; - - public static @NonNull DialogFragment create(@NonNull MessageRecord message, @NonNull RecipientId recipientId) { - DialogFragment dialogFragment = new MessageDetailsFragment(); - Bundle args = new Bundle(); - - args.putLong(MESSAGE_ID_EXTRA, message.getId()); - args.putParcelable(RECIPIENT_EXTRA, recipientId); - - dialogFragment.setArguments(args); - - return dialogFragment; - } - - @Override - protected int getTitle() { - return R.string.AndroidManifest__message_details; - } - - @Override - protected int getDialogLayoutResource() { - return R.layout.message_details_fragment; - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - requestManager = Glide.with(this); - - initializeList(view); - initializeViewModel(); - initializeVideoPlayer(view); - } - - @Override - public void onDismiss(@NonNull DialogInterface dialog) { - super.onDismiss(dialog); - - if (getActivity() instanceof Callback) { - ((Callback) getActivity()).onMessageDetailsFragmentDismissed(); - } else if (getParentFragment() instanceof Callback) { - ((Callback) getParentFragment()).onMessageDetailsFragmentDismissed(); - } - } - - private void initializeList(@NonNull View view) { - RecyclerView list = view.findViewById(R.id.message_details_list); - View toolbarShadow = view.findViewById(R.id.toolbar_shadow); - - colorizer = new Colorizer(); - adapter = new MessageDetailsAdapter(getViewLifecycleOwner(), requestManager, colorizer, this); - recyclerViewColorizer = new RecyclerViewColorizer(list); - - list.setAdapter(adapter); - list.setItemAnimator(null); - new Material3OnScrollHelper(requireActivity(), toolbarShadow, getViewLifecycleOwner()).attach(list); - } - - private void initializeViewModel() { - final RecipientId recipientId = requireArguments().getParcelable(RECIPIENT_EXTRA); - final Long messageId = requireArguments().getLong(MESSAGE_ID_EXTRA, -1); - final Factory factory = new Factory(recipientId, messageId); - - viewModel = new ViewModelProvider(this, factory).get(MessageDetailsViewModel.class); - viewModel.getMessageDetails().observe(this, details -> { - if (details == null) { - dismissAllowingStateLoss(); - } else { - adapter.submitList(convertToRows(details)); - } - }); - viewModel.getRecipient().observe(this, recipient -> recyclerViewColorizer.setChatColors(recipient.getChatColors())); - } - - private void initializeVideoPlayer(@NonNull View view) { - FrameLayout videoContainer = view.findViewById(R.id.video_container); - RecyclerView recyclerView = view.findViewById(R.id.message_details_list); - List holders = GiphyMp4ProjectionPlayerHolder.injectVideoViews(requireContext(), getLifecycle(), videoContainer, 1); - GiphyMp4ProjectionRecycler callback = new GiphyMp4ProjectionRecycler(holders); - - GiphyMp4PlaybackController.attach(recyclerView, callback, 1); - } - - private List> convertToRows(MessageDetails details) { - List> list = new ArrayList<>(); - - list.add(new MessageDetailsViewState<>(details.getConversationMessage(), MessageDetailsViewState.MESSAGE_HEADER)); - - if (MessageRecordUtil.isEditMessage(details.getConversationMessage().getMessageRecord())) { - list.add(new MessageDetailsViewState<>(details.getConversationMessage().getMessageRecord(), MessageDetailsViewState.EDIT_HISTORY)); - } - - if (details.getConversationMessage().getMessageRecord().isOutgoing()) { - addRecipients(list, RecipientHeader.NOT_SENT, details.getNotSent()); - addRecipients(list, RecipientHeader.VIEWED, details.getViewed()); - addRecipients(list, RecipientHeader.READ, details.getRead()); - addRecipients(list, RecipientHeader.DELIVERED, details.getDelivered()); - addRecipients(list, RecipientHeader.SENT_TO, details.getSent()); - addRecipients(list, RecipientHeader.PENDING, details.getPending()); - addRecipients(list, RecipientHeader.SKIPPED, details.getSkipped()); - } else { - addRecipients(list, RecipientHeader.SENT_FROM, details.getSent()); - } - - return list; - } - - private boolean addRecipients(List> list, RecipientHeader header, Collection recipients) { - if (recipients.isEmpty()) { - return false; - } - - list.add(new MessageDetailsViewState<>(header, MessageDetailsViewState.RECIPIENT_HEADER)); - for (RecipientDeliveryStatus status : recipients) { - list.add(new MessageDetailsViewState<>(status, MessageDetailsViewState.RECIPIENT)); - } - return true; - } - - @Override - public void onErrorClicked(@NonNull MessageRecord messageRecord) { - SafetyNumberBottomSheet - .forMessageRecord(requireContext(), messageRecord) - .show(getChildFragmentManager()); - } - - @Override - public void onViewEditHistoryClicked(MessageRecord record) { - if (record.isOutgoing()) { - EditMessageHistoryDialog.show(getParentFragmentManager(), record.getToRecipient().getId(), record); - } else { - EditMessageHistoryDialog.show(getParentFragmentManager(), record.getFromRecipient().getId(), record); - } - } - - @Override - public void onInternalDetailsClicked(MessageRecord record) { - InternalMessageDetailsFragment.create(record).show(getParentFragmentManager(), InternalMessageDetailsFragment.class.getSimpleName()); - } - - public interface Callback { - void onMessageDetailsFragmentDismissed(); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsFragment.kt new file mode 100644 index 0000000000..544d732e16 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsFragment.kt @@ -0,0 +1,168 @@ +package org.thoughtcrime.securesms.messagedetails + +import android.content.DialogInterface +import android.os.Bundle +import android.view.View +import android.widget.FrameLayout +import androidx.fragment.app.DialogFragment +import androidx.lifecycle.ViewModelProvider +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.bumptech.glide.RequestManager +import org.thoughtcrime.securesms.R +import org.thoughtcrime.securesms.components.FullScreenDialogFragment +import org.thoughtcrime.securesms.conversation.colors.Colorizer +import org.thoughtcrime.securesms.conversation.colors.RecyclerViewColorizer +import org.thoughtcrime.securesms.conversation.ui.edit.EditMessageHistoryDialog.Companion.show +import org.thoughtcrime.securesms.database.model.MessageRecord +import org.thoughtcrime.securesms.giph.mp4.GiphyMp4PlaybackController +import org.thoughtcrime.securesms.giph.mp4.GiphyMp4ProjectionPlayerHolder +import org.thoughtcrime.securesms.giph.mp4.GiphyMp4ProjectionRecycler +import org.thoughtcrime.securesms.messagedetails.InternalMessageDetailsFragment.Companion.create +import org.thoughtcrime.securesms.messagedetails.MessageDetailsAdapter.MessageDetailsViewState +import org.thoughtcrime.securesms.recipients.Recipient +import org.thoughtcrime.securesms.recipients.RecipientId +import org.thoughtcrime.securesms.safety.SafetyNumberBottomSheet.forMessageRecord +import org.thoughtcrime.securesms.util.Material3OnScrollHelper + +class MessageDetailsFragment : FullScreenDialogFragment(), MessageDetailsAdapter.Callbacks { + private lateinit var requestManager: RequestManager + private lateinit var viewModel: MessageDetailsViewModel + private lateinit var adapter: MessageDetailsAdapter + private lateinit var colorizer: Colorizer + private lateinit var recyclerViewColorizer: RecyclerViewColorizer + + override fun getTitle() = R.string.AndroidManifest__message_details + + override fun getDialogLayoutResource() = R.layout.message_details_fragment + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + requestManager = Glide.with(this) + + initializeList(view) + initializeViewModel() + initializeVideoPlayer(view) + } + + override fun onDismiss(dialog: DialogInterface) { + super.onDismiss(dialog) + + if (activity is Callback) { + (activity as Callback?)!!.onMessageDetailsFragmentDismissed() + } else if (parentFragment is Callback) { + (parentFragment as Callback?)!!.onMessageDetailsFragmentDismissed() + } + } + + private fun initializeList(view: View) { + val list = view.findViewById(R.id.message_details_list) + val toolbarShadow = view.findViewById(R.id.toolbar_shadow) + + colorizer = Colorizer() + adapter = MessageDetailsAdapter(viewLifecycleOwner, requestManager, colorizer, this) + recyclerViewColorizer = RecyclerViewColorizer(list) + + list.adapter = adapter + list.itemAnimator = null + Material3OnScrollHelper(requireActivity(), toolbarShadow, viewLifecycleOwner).attach(list) + } + + private fun initializeViewModel() { + val recipientId = requireArguments().getParcelable(RECIPIENT_EXTRA) + val messageId = requireArguments().getLong(MESSAGE_ID_EXTRA, -1) + val factory = MessageDetailsViewModel.Factory(recipientId, messageId) + + viewModel = ViewModelProvider(this, factory)[MessageDetailsViewModel::class.java] + viewModel.messageDetails.observe(this) { details: MessageDetails? -> + if (details == null) { + dismissAllowingStateLoss() + } else { + adapter.submitList(convertToRows(details)) + } + } + viewModel.recipient.observe(this) { recipient: Recipient -> recyclerViewColorizer.setChatColors(recipient.chatColors) } + } + + private fun initializeVideoPlayer(view: View) { + val videoContainer = view.findViewById(R.id.video_container) + val recyclerView = view.findViewById(R.id.message_details_list) + val holders = GiphyMp4ProjectionPlayerHolder.injectVideoViews(requireContext(), lifecycle, videoContainer, 1) + val callback = GiphyMp4ProjectionRecycler(holders) + + GiphyMp4PlaybackController.attach(recyclerView, callback, 1) + } + + private fun convertToRows(details: MessageDetails): List> { + val list: MutableList> = ArrayList() + + list.add(MessageDetailsViewState(details.conversationMessage, MessageDetailsViewState.MESSAGE_HEADER)) + + if (details.conversationMessage.messageRecord.isEditMessage) { + list.add(MessageDetailsViewState(details.conversationMessage.messageRecord, MessageDetailsViewState.EDIT_HISTORY)) + } + + if (details.conversationMessage.messageRecord.isOutgoing) { + addRecipients(list, RecipientHeader.NOT_SENT, details.notSent) + addRecipients(list, RecipientHeader.VIEWED, details.viewed) + addRecipients(list, RecipientHeader.READ, details.read) + addRecipients(list, RecipientHeader.DELIVERED, details.delivered) + addRecipients(list, RecipientHeader.SENT_TO, details.sent) + addRecipients(list, RecipientHeader.PENDING, details.pending) + addRecipients(list, RecipientHeader.SKIPPED, details.skipped) + } else { + addRecipients(list, RecipientHeader.SENT_FROM, details.sent) + } + + return list + } + + private fun addRecipients(list: MutableList>, header: RecipientHeader, recipients: Collection): Boolean { + if (recipients.isEmpty()) { + return false + } + + list.add(MessageDetailsViewState(header, MessageDetailsViewState.RECIPIENT_HEADER)) + for (status in recipients) { + list.add(MessageDetailsViewState(status, MessageDetailsViewState.RECIPIENT)) + } + return true + } + + override fun onErrorClicked(messageRecord: MessageRecord) { + forMessageRecord(requireContext(), messageRecord) + .show(childFragmentManager) + } + + override fun onViewEditHistoryClicked(record: MessageRecord) { + if (record.isOutgoing) { + show(parentFragmentManager, record.toRecipient.id, record) + } else { + show(parentFragmentManager, record.fromRecipient.id, record) + } + } + + override fun onInternalDetailsClicked(record: MessageRecord) { + create(record).show(parentFragmentManager, InternalMessageDetailsFragment::class.java.simpleName) + } + + interface Callback { + fun onMessageDetailsFragmentDismissed() + } + + companion object { + private const val MESSAGE_ID_EXTRA = "message_id" + private const val RECIPIENT_EXTRA = "recipient_id" + + fun create(message: MessageRecord, recipientId: RecipientId): DialogFragment { + val dialogFragment: DialogFragment = MessageDetailsFragment() + val args = Bundle() + + args.putLong(MESSAGE_ID_EXTRA, message.id) + args.putParcelable(RECIPIENT_EXTRA, recipientId) + + dialogFragment.arguments = args + + return dialogFragment + } + } +}