Convert MainActivity to Kotlin.

This commit is contained in:
Alex Hart
2025-03-25 09:11:16 -03:00
committed by Cody Henthorne
parent e22c403b10
commit bf83914357
8 changed files with 291 additions and 318 deletions

View File

@@ -0,0 +1,257 @@
/*
* Copyright 2025 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.view.ViewTreeObserver
import androidx.core.content.ContextCompat
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.signal.core.util.concurrent.LifecycleDisposable
import org.signal.core.util.getSerializableCompat
import org.signal.donations.StripeApi
import org.thoughtcrime.securesms.calls.YouAreAlreadyInACallSnackbar.show
import org.thoughtcrime.securesms.components.ConnectivityWarningBottomSheet
import org.thoughtcrime.securesms.components.DebugLogsPromptDialogFragment
import org.thoughtcrime.securesms.components.DeviceSpecificNotificationBottomSheet
import org.thoughtcrime.securesms.components.PromptBatterySaverDialogFragment
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity.Companion.manageSubscriptions
import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaController
import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaControllerOwner
import org.thoughtcrime.securesms.conversationlist.RelinkDevicesReminderBottomSheetFragment
import org.thoughtcrime.securesms.conversationlist.RestoreCompleteBottomSheetDialog
import org.thoughtcrime.securesms.devicetransfer.olddevice.OldDeviceExitActivity
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.net.DeviceTransferBlockingInterceptor
import org.thoughtcrime.securesms.notifications.VitalsViewModel
import org.thoughtcrime.securesms.stories.Stories
import org.thoughtcrime.securesms.stories.tabs.ConversationListTab
import org.thoughtcrime.securesms.stories.tabs.ConversationListTabRepository
import org.thoughtcrime.securesms.stories.tabs.ConversationListTabsViewModel
import org.thoughtcrime.securesms.util.AppStartup
import org.thoughtcrime.securesms.util.CachedInflater
import org.thoughtcrime.securesms.util.CommunicationActions
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme
import org.thoughtcrime.securesms.util.SplashScreenUtil
import org.thoughtcrime.securesms.util.WindowUtil
import org.thoughtcrime.securesms.util.viewModel
class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner, MainNavigator.NavigatorProvider {
companion object {
private const val KEY_STARTING_TAB = "STARTING_TAB"
const val RESULT_CONFIG_CHANGED = Activity.RESULT_FIRST_USER + 901
@JvmStatic
fun clearTop(context: Context): Intent {
return Intent(context, MainActivity::class.java)
.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP)
}
@JvmStatic
fun clearTopAndOpenTab(context: Context, startingTab: ConversationListTab): Intent {
return clearTop(context).putExtra(KEY_STARTING_TAB, startingTab)
}
}
private val dynamicTheme = DynamicNoActionBarTheme()
private val navigator = MainNavigator(this)
private val lifecycleDisposable = LifecycleDisposable()
private lateinit var mediaController: VoiceNoteMediaController
override val voiceNoteMediaController: VoiceNoteMediaController
get() = mediaController
private val conversationListTabsViewModel: ConversationListTabsViewModel by viewModel {
val startingTab = intent.extras?.getSerializableCompat(KEY_STARTING_TAB, ConversationListTab::class.java)
ConversationListTabsViewModel(startingTab ?: ConversationListTab.CHATS, ConversationListTabRepository())
}
private val vitalsViewModel: VitalsViewModel by viewModel {
VitalsViewModel(application)
}
private var onFirstRender = false
override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
AppStartup.getInstance().onCriticalRenderEventStart()
super.onCreate(savedInstanceState, ready)
setContentView(R.layout.main_activity)
val content: View = findViewById(android.R.id.content)
content.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
// Use pre draw listener to delay drawing frames till conversation list is ready
return if (onFirstRender) {
content.viewTreeObserver.removeOnPreDrawListener(this)
true
} else {
false
}
}
})
lifecycleDisposable.bindTo(this)
mediaController = VoiceNoteMediaController(this, true)
conversationListTabsViewModel
handleDeepLinkIntent(intent)
CachedInflater.from(this).clear()
updateNavigationBarColor()
lifecycleDisposable += vitalsViewModel.vitalsState.subscribe(this::presentVitalsState)
}
override fun getIntent(): Intent {
return super.getIntent().setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
handleDeepLinkIntent(intent)
val extras = intent.extras ?: return
val startingTab = extras.getSerializableCompat(KEY_STARTING_TAB, ConversationListTab::class.java)
when (startingTab) {
ConversationListTab.CHATS -> conversationListTabsViewModel.onChatsSelected()
ConversationListTab.CALLS -> conversationListTabsViewModel.onCallsSelected()
ConversationListTab.STORIES -> {
if (Stories.isFeatureEnabled()) {
conversationListTabsViewModel.onStoriesSelected()
}
}
null -> Unit
}
}
override fun onPreCreate() {
super.onPreCreate()
dynamicTheme.onCreate(this)
}
override fun onResume() {
super.onResume()
dynamicTheme.onResume(this)
if (SignalStore.misc.shouldShowLinkedDevicesReminder) {
SignalStore.misc.shouldShowLinkedDevicesReminder = false
RelinkDevicesReminderBottomSheetFragment.show(supportFragmentManager)
}
if (SignalStore.registration.restoringOnNewDevice) {
SignalStore.registration.restoringOnNewDevice = false
RestoreCompleteBottomSheetDialog.show(supportFragmentManager)
} else if (SignalStore.misc.isOldDeviceTransferLocked) {
MaterialAlertDialogBuilder(this)
.setTitle(R.string.OldDeviceTransferLockedDialog__complete_registration_on_your_new_device)
.setMessage(R.string.OldDeviceTransferLockedDialog__your_signal_account_has_been_transferred_to_your_new_device)
.setPositiveButton(R.string.OldDeviceTransferLockedDialog__done) { _, _ -> OldDeviceExitActivity.exit(this) }
.setNegativeButton(R.string.OldDeviceTransferLockedDialog__cancel_and_activate_this_device) { _, _ ->
SignalStore.misc.isOldDeviceTransferLocked = false
DeviceTransferBlockingInterceptor.getInstance().unblockNetwork()
}
.setCancelable(false)
.show()
}
updateNavigationBarColor()
vitalsViewModel.checkSlowNotificationHeuristics()
}
override fun onStop() {
super.onStop()
SplashScreenUtil.setSplashScreenThemeIfNecessary(this, SignalStore.settings.theme)
}
override fun onBackPressed() {
if (!navigator.onBackPressed()) {
super.onBackPressed()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == MainNavigator.REQUEST_CONFIG_CHANGES && resultCode == RESULT_CONFIG_CHANGED) {
recreate()
}
}
override fun onFirstRender() {
onFirstRender = true
}
override fun getNavigator(): MainNavigator {
return navigator
}
private fun handleDeepLinkIntent(intent: Intent) {
handleGroupLinkInIntent(intent)
handleProxyInIntent(intent)
handleSignalMeIntent(intent)
handleCallLinkInIntent(intent)
handleDonateReturnIntent(intent)
}
private fun updateNavigationBarColor() {
WindowUtil.setNavigationBarColor(this, ContextCompat.getColor(this, R.color.signal_colorSurface2))
}
@SuppressLint("NewApi")
private fun presentVitalsState(state: VitalsViewModel.State) {
when (state) {
VitalsViewModel.State.NONE -> Unit
VitalsViewModel.State.PROMPT_SPECIFIC_BATTERY_SAVER_DIALOG -> DeviceSpecificNotificationBottomSheet.show(supportFragmentManager)
VitalsViewModel.State.PROMPT_GENERAL_BATTERY_SAVER_DIALOG -> PromptBatterySaverDialogFragment.show(supportFragmentManager)
VitalsViewModel.State.PROMPT_DEBUGLOGS_FOR_NOTIFICATIONS -> DebugLogsPromptDialogFragment.show(this, DebugLogsPromptDialogFragment.Purpose.NOTIFICATIONS)
VitalsViewModel.State.PROMPT_DEBUGLOGS_FOR_CRASH -> DebugLogsPromptDialogFragment.show(this, DebugLogsPromptDialogFragment.Purpose.CRASH)
VitalsViewModel.State.PROMPT_CONNECTIVITY_WARNING -> ConnectivityWarningBottomSheet.show(supportFragmentManager)
VitalsViewModel.State.PROMPT_DEBUGLOGS_FOR_CONNECTIVITY_WARNING -> DebugLogsPromptDialogFragment.show(this, DebugLogsPromptDialogFragment.Purpose.CONNECTIVITY_WARNING)
}
}
private fun handleGroupLinkInIntent(intent: Intent) {
intent.data?.let { data ->
CommunicationActions.handlePotentialGroupLinkUrl(this, data.toString())
}
}
private fun handleProxyInIntent(intent: Intent) {
intent.data?.let { data ->
CommunicationActions.handlePotentialProxyLinkUrl(this, data.toString())
}
}
private fun handleSignalMeIntent(intent: Intent) {
intent.data?.let { data ->
CommunicationActions.handlePotentialSignalMeUrl(this, data.toString())
}
}
private fun handleCallLinkInIntent(intent: Intent) {
intent.data?.let { data ->
CommunicationActions.handlePotentialCallLinkUrl(this, data.toString()) {
show(findViewById(android.R.id.content))
}
}
}
private fun handleDonateReturnIntent(intent: Intent) {
intent.data?.let { data ->
if (data.toString().startsWith(StripeApi.RETURN_URL_IDEAL)) {
startActivity(manageSubscriptions(this))
}
}
}
}