diff --git a/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt index 02c569749e..a6511d34d7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt @@ -97,7 +97,6 @@ import org.signal.mediasend.MediaSendActivityContract import org.thoughtcrime.securesms.backup.v2.ArchiveRestoreProgress import org.thoughtcrime.securesms.backup.v2.ui.verify.VerifyBackupKeyActivity import org.thoughtcrime.securesms.calls.YouAreAlreadyInACallSnackbar.show -import org.thoughtcrime.securesms.calls.links.details.CallLinkDetailsActivity import org.thoughtcrime.securesms.calls.log.CallLogFilter import org.thoughtcrime.securesms.calls.log.CallLogFragment import org.thoughtcrime.securesms.calls.new.NewCallActivity @@ -140,6 +139,7 @@ import org.thoughtcrime.securesms.main.MainContentLayoutData import org.thoughtcrime.securesms.main.MainMegaphoneState import org.thoughtcrime.securesms.main.MainNavigationBar import org.thoughtcrime.securesms.main.MainNavigationDetailLocation +import org.thoughtcrime.securesms.main.MainNavigationDetailLocationEffect import org.thoughtcrime.securesms.main.MainNavigationListLocation import org.thoughtcrime.securesms.main.MainNavigationRail import org.thoughtcrime.securesms.main.MainNavigationViewModel @@ -156,7 +156,6 @@ import org.thoughtcrime.securesms.main.chatNavGraphBuilder import org.thoughtcrime.securesms.main.navigateToDetailLocation import org.thoughtcrime.securesms.main.rememberDetailNavHostController import org.thoughtcrime.securesms.main.rememberFocusRequester -import org.thoughtcrime.securesms.main.rememberMainNavigationDetailLocation import org.thoughtcrime.securesms.main.storiesNavGraphBuilder import org.thoughtcrime.securesms.mediasend.camerax.CameraXUtil import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionActivity @@ -447,7 +446,7 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner val chatNavGraphState = ChatNavGraphState.remember(windowSizeClass) val mutableInteractionSource = remember { MutableInteractionSource() } - val mainNavigationDetailLocation by rememberMainNavigationDetailLocation(mainNavigationViewModel, chatNavGraphState::writeGraphicsLayerToBitmap) + MainNavigationDetailLocationEffect(mainNavigationViewModel, chatNavGraphState::writeGraphicsLayerToBitmap) val chatsNavHostController = rememberDetailNavHostController( onRequestFocus = rememberFocusRequester( @@ -477,24 +476,28 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner storiesNavGraphBuilder() } - LaunchedEffect(mainNavigationDetailLocation) { + LaunchedEffect(Unit) { mainNavigationViewModel.clearEarlyDetailLocation() - when (mainNavigationDetailLocation) { - is MainNavigationDetailLocation.Empty -> { - when (mainNavigationState.currentListLocation) { - MainNavigationListLocation.CHATS, MainNavigationListLocation.ARCHIVE -> chatsNavHostController - MainNavigationListLocation.CALLS -> callsNavHostController - MainNavigationListLocation.STORIES -> storiesNavHostController - }.navigateToDetailLocation(mainNavigationDetailLocation) - } + mainNavigationViewModel.detailLocation.collect { location -> + when (location) { + is MainNavigationDetailLocation.Empty -> { + when (mainNavigationState.currentListLocation) { + MainNavigationListLocation.CHATS, MainNavigationListLocation.ARCHIVE -> chatsNavHostController + MainNavigationListLocation.CALLS -> callsNavHostController + MainNavigationListLocation.STORIES -> storiesNavHostController + }.navigateToDetailLocation(location) + } - is MainNavigationDetailLocation.Chats -> { - chatNavGraphState.writeGraphicsLayerToBitmap() - chatsNavHostController.navigateToDetailLocation(mainNavigationDetailLocation) - } + is MainNavigationDetailLocation.Chats -> { + if (location is MainNavigationDetailLocation.Chats.Conversation) { + chatNavGraphState.writeGraphicsLayerToBitmap() + } + chatsNavHostController.navigateToDetailLocation(location) + } - is MainNavigationDetailLocation.Calls -> callsNavHostController.navigateToDetailLocation(mainNavigationDetailLocation) - is MainNavigationDetailLocation.Stories -> storiesNavHostController.navigateToDetailLocation(mainNavigationDetailLocation) + is MainNavigationDetailLocation.Calls -> callsNavHostController.navigateToDetailLocation(location) + is MainNavigationDetailLocation.Stories -> storiesNavHostController.navigateToDetailLocation(location) + } } } @@ -752,27 +755,7 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner val coroutine = rememberCoroutineScope() return remember(scaffoldNavigator, coroutine) { - mainNavigationViewModel.wrapNavigator(coroutine, scaffoldNavigator) { detailLocation -> - when (detailLocation) { - is MainNavigationDetailLocation.Chats.Conversation -> { - startActivity( - ConversationIntents.createBuilderSync(this, detailLocation.conversationArgs.recipientId, detailLocation.conversationArgs.threadId) - .withArgs(detailLocation.conversationArgs) - .build() - ) - } - - is MainNavigationDetailLocation.Calls.CallLinks.CallLinkDetails -> { - startActivity(CallLinkDetailsActivity.createIntent(this, detailLocation.callLinkRoomId)) - } - - is MainNavigationDetailLocation.Calls.CallLinks.EditCallLinkName -> { - error("Unexpected subroute EditCallLinkName.") - } - - MainNavigationDetailLocation.Empty -> Unit - } - } + mainNavigationViewModel.wrapNavigator(coroutine, scaffoldNavigator) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/FullScreenDialogFragment.java b/app/src/main/java/org/thoughtcrime/securesms/components/FullScreenDialogFragment.java index b2dfdd0a34..1fd3167b2b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/FullScreenDialogFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/FullScreenDialogFragment.java @@ -47,7 +47,10 @@ public abstract class FullScreenDialogFragment extends DialogFragment { @Override public void onResume() { super.onResume(); - WindowUtil.initializeScreenshotSecurity(requireContext(), requireDialog().getWindow()); + + if (getShowsDialog()) { + WindowUtil.initializeScreenshotSecurity(requireContext(), requireDialog().getWindow()); + } } protected void onNavigateUp() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/WrapperDialogFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/WrapperDialogFragment.kt index f0d7a8b13c..58ca56ac02 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/WrapperDialogFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/WrapperDialogFragment.kt @@ -6,6 +6,7 @@ import android.view.View import androidx.activity.OnBackPressedCallback import androidx.fragment.app.DialogFragment import androidx.fragment.app.Fragment +import org.signal.core.ui.initializeScreenshotSecurity import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.util.fragments.findListener @@ -57,6 +58,11 @@ abstract class WrapperDialogFragment : DialogFragment(R.layout.fragment_containe } } + override fun onResume() { + super.onResume() + dialog?.window?.initializeScreenshotSecurity() + } + open fun onHandleBackPressed() { dismissAllowingStateLoss() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/CheckoutNavHostFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/CheckoutNavHostFragment.kt index 16f713a586..503e15808b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/CheckoutNavHostFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/CheckoutNavHostFragment.kt @@ -30,26 +30,28 @@ class CheckoutNavHostFragment : NavHostFragment() { get() = requireArguments().getSerializableCompat(ARG_TYPE, InAppPaymentType::class.java)!! override fun onCreate(savedInstanceState: Bundle?) { - if (savedInstanceState == null) { - val navGraph = navController.navInflater.inflate(R.navigation.checkout) - navGraph.setStartDestination( - when (inAppPaymentType) { - InAppPaymentType.UNKNOWN -> error("Unsupported start destination") - InAppPaymentType.ONE_TIME_GIFT -> R.id.giftFlowStartFragment - InAppPaymentType.ONE_TIME_DONATION, InAppPaymentType.RECURRING_DONATION -> R.id.donateToSignalFragment - InAppPaymentType.RECURRING_BACKUP -> error("Unsupported start destination") - } - ) + val navGraph = navController.navInflater.inflate(R.navigation.checkout) + navGraph.setStartDestination( + when (inAppPaymentType) { + InAppPaymentType.UNKNOWN -> error("Unsupported start destination") + InAppPaymentType.ONE_TIME_GIFT -> R.id.giftFlowStartFragment + InAppPaymentType.ONE_TIME_DONATION, InAppPaymentType.RECURRING_DONATION -> R.id.donateToSignalFragment + InAppPaymentType.RECURRING_BACKUP -> error("Unsupported start destination") + } + ) - val startBundle = when (inAppPaymentType) { + val startBundle = if (savedInstanceState == null) { + when (inAppPaymentType) { InAppPaymentType.UNKNOWN -> error("Unknown payment type") InAppPaymentType.ONE_TIME_GIFT, InAppPaymentType.RECURRING_BACKUP -> null InAppPaymentType.ONE_TIME_DONATION, InAppPaymentType.RECURRING_DONATION -> DonateToSignalFragmentArgs.Builder(inAppPaymentType).build().toBundle() } - - navController.setGraph(navGraph, startBundle) + } else { + null } + navController.setGraph(navGraph, startBundle) + super.onCreate(savedInstanceState) } } 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 57c8da03bb..ec4a93bcd5 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 @@ -57,6 +57,7 @@ import androidx.core.view.ViewCompat import androidx.core.view.doOnPreDraw import androidx.core.view.isInvisible import androidx.core.view.isVisible +import androidx.fragment.app.DialogFragment import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentResultListener import androidx.fragment.app.activityViewModels @@ -279,6 +280,7 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.linkpreview.LinkPreview import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModelV2 import org.thoughtcrime.securesms.longmessage.LongMessageFragment +import org.thoughtcrime.securesms.main.MainNavigationDetailLocation import org.thoughtcrime.securesms.main.MainNavigationListLocation import org.thoughtcrime.securesms.main.MainNavigationViewModel import org.thoughtcrime.securesms.main.MainSnackbarHostKey @@ -412,6 +414,7 @@ class ConversationFragment : private const val ACTION_PINNED_SHORTCUT = "action_pinned_shortcut" private const val SAVED_STATE_IS_SEARCH_REQUESTED = "is_search_requested" private const val EMOJI_SEARCH_FRAGMENT_TAG = "EmojiSearchFragment" + private const val MESSAGE_DETAILS_TAG = "MessageDetailsFragment" private const val SCROLL_HEADER_ANIMATION_DURATION: Long = 100L private const val SCROLL_HEADER_CLOSE_DELAY: Long = SCROLL_HEADER_ANIMATION_DURATION * 4 @@ -780,6 +783,10 @@ class ConversationFragment : } keyboardEvents = null + if (!requireActivity().isChangingConfigurations) { + (requireActivity().supportFragmentManager.findFragmentByTag(MESSAGE_DETAILS_TAG) as? DialogFragment)?.dismissAllowingStateLoss() + } + super.onDestroyView() if (pinnedShortcutReceiver != null) { requireActivity().unregisterReceiver(pinnedShortcutReceiver) @@ -2793,7 +2800,11 @@ class ConversationFragment : private fun handleDisplayDetails(conversationMessage: ConversationMessage) { val recipientSnapshot = viewModel.recipientSnapshot ?: return - MessageDetailsFragment.create(conversationMessage.messageRecord, recipientSnapshot.id).show(childFragmentManager, null) + if (requireActivity() is MainActivity) { + mainNavigationViewModel.goTo(MainNavigationDetailLocation.Chats.MessageDetails(recipientSnapshot.id, conversationMessage.messageRecord.id)) + } else { + MessageDetailsFragment.create(conversationMessage.messageRecord, recipientSnapshot.id).show(requireActivity().supportFragmentManager, MESSAGE_DETAILS_TAG) + } } private fun handleDeleteMessages(messageParts: Set) { @@ -3309,8 +3320,10 @@ class ConversationFragment : .show(childFragmentManager) } else if (messageRecord.hasFailedWithNetworkFailures()) { ConversationDialogs.displayMessageCouldNotBeSentDialog(requireContext(), messageRecord) + } else if (requireActivity() is MainActivity) { + mainNavigationViewModel.goTo(MainNavigationDetailLocation.Chats.MessageDetails(recipientId, messageRecord.id)) } else { - MessageDetailsFragment.create(messageRecord, recipientId).show(childFragmentManager, null) + MessageDetailsFragment.create(messageRecord, recipientId).show(requireActivity().supportFragmentManager, MESSAGE_DETAILS_TAG) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/main/ChatsNavHost.kt b/app/src/main/java/org/thoughtcrime/securesms/main/ChatsNavHost.kt index d71a14b606..d41bae0b74 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/main/ChatsNavHost.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/main/ChatsNavHost.kt @@ -13,6 +13,8 @@ import androidx.compose.animation.core.updateTransition import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -50,6 +52,8 @@ import org.thoughtcrime.securesms.compose.FragmentBackPressedState import org.thoughtcrime.securesms.conversation.ConversationArgs import org.thoughtcrime.securesms.conversation.ConversationIntents import org.thoughtcrime.securesms.conversation.v2.ConversationFragment +import org.thoughtcrime.securesms.messagedetails.MessageDetailsFragment +import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.serialization.JsonSerializableNavType import org.thoughtcrime.securesms.window.AppScaffoldAnimationDefaults import org.thoughtcrime.securesms.window.AppScaffoldAnimationState @@ -73,8 +77,8 @@ fun NavGraphBuilder.chatNavGraphBuilder( val context = LocalContext.current // Because it can take a long time to load content, we use a "fake" chat list image to delay displaying - // the fragment and prevent pop-in - var shouldDisplayFragment by remember { mutableStateOf(false) } + // the fragment and prevent pop-in. When there's no bitmap (e.g. returning from a sub-route), skip the animation. + var shouldDisplayFragment by remember { mutableStateOf(chatNavGraphState.chatBitmap == null) } val transition: Transition = updateTransition(shouldDisplayFragment) val bitmap = chatNavGraphState.chatBitmap @@ -126,16 +130,42 @@ fun NavGraphBuilder.chatNavGraphBuilder( fragment.viewLifecycleOwner.lifecycleScope.launch { fragment.repeatOnLifecycle(Lifecycle.State.STARTED) { fragment.didFirstFrameRender.collectLatest { - shouldDisplayFragment = it - if (!it) { - delay(150.milliseconds) - shouldDisplayFragment = true + if (!shouldDisplayFragment) { + shouldDisplayFragment = it + if (!it) { + delay(150.milliseconds) + shouldDisplayFragment = true + } } } } } } } + + composable( + typeMap = mapOf( + typeOf() to JsonSerializableNavType(RecipientId.serializer()) + ) + ) { navBackStackEntry -> + val context = LocalContext.current + val route = navBackStackEntry.toRoute() + val fragmentState = key(route) { rememberFragmentState() } + + LaunchedEffect(Unit) { + (context as? MainNavigator.NavigatorProvider)?.onFirstRender() + } + + AndroidFragment( + clazz = MessageDetailsFragment::class.java, + fragmentState = fragmentState, + arguments = MessageDetailsFragment.args(route.recipientId, route.messageId), + modifier = Modifier.fillMaxSize() + .background(MaterialTheme.colorScheme.background) + .statusBarsPadding() + .navigationBarsPadding() + ) + } } @Composable diff --git a/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityComponents.kt b/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityComponents.kt index 0d1781e2a2..eaf5d80c4d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityComponents.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityComponents.kt @@ -17,7 +17,6 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.State import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -65,10 +64,10 @@ fun EmptyDetailScreen() { * utilizing collectAsStateWithLifecycle. Then the latest value is remembered as a saveable using the default [MainNavigationDetailLocation.Saver] */ @Composable -fun rememberMainNavigationDetailLocation( +fun MainNavigationDetailLocationEffect( mainNavigationViewModel: MainNavigationViewModel, onWillFocusPrimary: suspend () -> Unit = {} -): State { +) { val state = rememberSaveable( stateSaver = MainNavigationDetailLocation.Saver( mainNavigationViewModel.earlyNavigationDetailLocationRequested @@ -84,7 +83,9 @@ fun rememberMainNavigationDetailLocation( if (it == MainNavigationDetailLocation.Empty) { ThreePaneScaffoldRole.Secondary } else { - onWillFocusPrimary() + if (it.isContentRoot) { + onWillFocusPrimary() + } ThreePaneScaffoldRole.Primary } ) @@ -93,8 +94,6 @@ fun rememberMainNavigationDetailLocation( state.value = it } } - - return state } @Composable @@ -147,6 +146,7 @@ fun rememberDetailNavHostController( fun NavHostController.navigateToDetailLocation(location: MainNavigationDetailLocation) { navigate(location) { + launchSingleTop = true if (location.isContentRoot) { popUpTo(graph.id) { inclusive = true } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/main/MainNavigationDetailLocation.kt b/app/src/main/java/org/thoughtcrime/securesms/main/MainNavigationDetailLocation.kt index 2ac98638b3..7ed272af65 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/main/MainNavigationDetailLocation.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/main/MainNavigationDetailLocation.kt @@ -65,6 +65,13 @@ sealed class MainNavigationDetailLocation : Parcelable { @IgnoredOnParcel override val controllerKey: RecipientId = conversationArgs.recipientId } + + @Serializable + data class MessageDetails(val recipientId: RecipientId, val messageId: Long) : Chats() { + @Transient + @IgnoredOnParcel + override val controllerKey: RecipientId = recipientId + } } /** diff --git a/app/src/main/java/org/thoughtcrime/securesms/main/MainNavigationViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/main/MainNavigationViewModel.kt index ea3e54e5ac..5bdff0a369 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/main/MainNavigationViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/main/MainNavigationViewModel.kt @@ -66,7 +66,6 @@ class MainNavigationViewModel( private var navigator: AppScaffoldNavigator? = null private var navigatorScope: CoroutineScope? = null - private var goToLegacyDetailLocation: ((MainNavigationDetailLocation) -> Unit)? = null private val internalDetailLocation = MutableSharedFlow() val detailLocation: SharedFlow = internalDetailLocation @@ -159,8 +158,7 @@ class MainNavigationViewModel( * Sets the navigator on the view-model. This wraps the given navigator in our own delegating implementation * such that we can react to navigateTo/Back signals and maintain proper state for internalDetailLocation. */ - fun wrapNavigator(composeScope: CoroutineScope, threePaneScaffoldNavigator: ThreePaneScaffoldNavigator, goToLegacyDetailLocation: (MainNavigationDetailLocation) -> Unit): AppScaffoldNavigator { - this.goToLegacyDetailLocation = goToLegacyDetailLocation + fun wrapNavigator(composeScope: CoroutineScope, threePaneScaffoldNavigator: ThreePaneScaffoldNavigator): AppScaffoldNavigator { this.navigatorScope = composeScope this.navigator = Nav(threePaneScaffoldNavigator) diff --git a/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsFragment.kt index 784699021b..ba45e1fab2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsFragment.kt @@ -1,12 +1,15 @@ package org.thoughtcrime.securesms.messagedetails -import android.content.DialogInterface import android.net.Uri import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.widget.FrameLayout import android.widget.Toast -import androidx.fragment.app.DialogFragment +import androidx.appcompat.widget.Toolbar +import androidx.core.os.bundleOf +import androidx.fragment.app.Fragment import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.RecyclerView @@ -15,7 +18,7 @@ import com.bumptech.glide.RequestManager import org.signal.core.util.logging.Log import org.signal.ringrtc.CallLinkRootKey import org.thoughtcrime.securesms.R -import org.thoughtcrime.securesms.components.FullScreenDialogFragment +import org.thoughtcrime.securesms.components.WrapperDialogFragment import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaControllerOwner import org.thoughtcrime.securesms.components.voice.VoiceNotePlaybackState import org.thoughtcrime.securesms.contactshare.Contact @@ -46,7 +49,7 @@ import org.thoughtcrime.securesms.stickers.StickerLocator import org.thoughtcrime.securesms.util.Material3OnScrollHelper import org.thoughtcrime.securesms.util.fragments.requireListener -class MessageDetailsFragment : FullScreenDialogFragment(), MessageDetailsAdapter.Callbacks { +class MessageDetailsFragment : Fragment(), MessageDetailsAdapter.Callbacks { private lateinit var requestManager: RequestManager private lateinit var viewModel: MessageDetailsViewModel private lateinit var adapter: MessageDetailsAdapter @@ -55,9 +58,16 @@ class MessageDetailsFragment : FullScreenDialogFragment(), MessageDetailsAdapter private fun getVoiceNoteMediaController() = requireListener().voiceNoteMediaController - override fun getTitle() = R.string.AndroidManifest__message_details + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + val view = inflater.inflate(R.layout.full_screen_dialog_fragment, container, false) + inflater.inflate(R.layout.message_details_fragment, view.findViewById(R.id.full_screen_dialog_content), true) - override fun getDialogLayoutResource() = R.layout.message_details_fragment + val toolbar: Toolbar = view.findViewById(R.id.full_screen_dialog_toolbar) + toolbar.setTitle(R.string.AndroidManifest__message_details) + toolbar.setNavigationOnClickListener { requireActivity().onBackPressedDispatcher.onBackPressed() } + + return view + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { requestManager = Glide.with(this) @@ -67,16 +77,6 @@ class MessageDetailsFragment : FullScreenDialogFragment(), MessageDetailsAdapter 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) @@ -96,14 +96,14 @@ class MessageDetailsFragment : FullScreenDialogFragment(), MessageDetailsAdapter val factory = MessageDetailsViewModel.Factory(recipientId, messageId) viewModel = ViewModelProvider(this, factory)[MessageDetailsViewModel::class.java] - viewModel.messageDetails.observe(this) { details: MessageDetails? -> + viewModel.messageDetails.observe(viewLifecycleOwner) { details: MessageDetails? -> if (details == null) { - dismissAllowingStateLoss() + requireActivity().onBackPressedDispatcher.onBackPressed() } else { adapter.submitList(convertToRows(details)) } } - viewModel.recipient.observe(this) { recipient: Recipient -> recyclerViewColorizer.setChatColors(recipient.chatColors) } + viewModel.recipient.observe(viewLifecycleOwner) { recipient: Recipient -> recyclerViewColorizer.setChatColors(recipient.chatColors) } } private fun initializeVideoPlayer(view: View) { @@ -413,8 +413,12 @@ class MessageDetailsFragment : FullScreenDialogFragment(), MessageDetailsAdapter Toast.makeText(requireContext(), "Can't touch this.", Toast.LENGTH_SHORT).show() } - interface Callback { - fun onMessageDetailsFragmentDismissed() + class Dialog : WrapperDialogFragment() { + override fun getWrappedFragment(): Fragment { + return MessageDetailsFragment().apply { + arguments = this@Dialog.requireArguments() + } + } } companion object { @@ -422,16 +426,17 @@ class MessageDetailsFragment : FullScreenDialogFragment(), MessageDetailsAdapter 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() + fun args(recipientId: RecipientId, messageId: Long): Bundle { + return bundleOf( + MESSAGE_ID_EXTRA to messageId, + RECIPIENT_EXTRA to recipientId + ) + } - args.putLong(MESSAGE_ID_EXTRA, message.id) - args.putParcelable(RECIPIENT_EXTRA, recipientId) - - dialogFragment.arguments = args - - return dialogFragment + fun create(message: MessageRecord, recipientId: RecipientId): Dialog { + return Dialog().apply { + arguments = args(recipientId, message.id) + } } } }