mirror of
https://github.com/bitwarden/android.git
synced 2026-06-06 22:42:58 -05:00
BIT-1498: Allow external navigation to Add Send screen (#685)
This commit is contained in:
committed by
Álison Fernandes
parent
bdca79d862
commit
eeb22dbfee
@@ -31,6 +31,13 @@ class MainActivity : AppCompatActivity() {
|
||||
var shouldShowSplashScreen = true
|
||||
installSplashScreen().setKeepOnScreenCondition { shouldShowSplashScreen }
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
mainViewModel.trySendAction(
|
||||
MainAction.ReceiveFirstIntent(
|
||||
intent = intent,
|
||||
),
|
||||
)
|
||||
|
||||
// Within the app the language will change dynamically and will be managed
|
||||
// by the OS, but we need to ensure we properly set the language when
|
||||
// upgrading from older versions that handle this differently.
|
||||
|
||||
@@ -4,10 +4,12 @@ import android.content.Intent
|
||||
import android.os.Parcelable
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||
import com.x8bit.bitwarden.data.auth.repository.util.getCaptchaCallbackTokenResult
|
||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppTheme
|
||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@@ -21,6 +23,7 @@ import javax.inject.Inject
|
||||
@HiltViewModel
|
||||
class MainViewModel @Inject constructor(
|
||||
private val authRepository: AuthRepository,
|
||||
private val intentManager: IntentManager,
|
||||
settingsRepository: SettingsRepository,
|
||||
) : BaseViewModel<MainState, Unit, MainAction>(
|
||||
MainState(
|
||||
@@ -37,6 +40,7 @@ class MainViewModel @Inject constructor(
|
||||
override fun handleAction(action: MainAction) {
|
||||
when (action) {
|
||||
is MainAction.Internal.ThemeUpdate -> handleAppThemeUpdated(action)
|
||||
is MainAction.ReceiveFirstIntent -> handleFirstIntentReceived(action)
|
||||
is MainAction.ReceiveNewIntent -> handleNewIntentReceived(action)
|
||||
}
|
||||
}
|
||||
@@ -45,8 +49,22 @@ class MainViewModel @Inject constructor(
|
||||
mutableStateFlow.update { it.copy(theme = action.theme) }
|
||||
}
|
||||
|
||||
private fun handleFirstIntentReceived(action: MainAction.ReceiveFirstIntent) {
|
||||
val shareData = intentManager.getShareDataFromIntent(action.intent)
|
||||
when {
|
||||
shareData != null -> {
|
||||
authRepository.specialCircumstance =
|
||||
UserState.SpecialCircumstance.ShareNewSend(
|
||||
data = shareData,
|
||||
shouldFinishWhenComplete = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleNewIntentReceived(action: MainAction.ReceiveNewIntent) {
|
||||
val captchaCallbackTokenResult = action.intent.getCaptchaCallbackTokenResult()
|
||||
val shareData = intentManager.getShareDataFromIntent(action.intent)
|
||||
when {
|
||||
captchaCallbackTokenResult != null -> {
|
||||
authRepository.setCaptchaCallbackTokenResult(
|
||||
@@ -54,6 +72,16 @@ class MainViewModel @Inject constructor(
|
||||
)
|
||||
}
|
||||
|
||||
shareData != null -> {
|
||||
authRepository.specialCircumstance =
|
||||
UserState.SpecialCircumstance.ShareNewSend(
|
||||
data = shareData,
|
||||
// Allow users back into the already-running app when completing the
|
||||
// Send task.
|
||||
shouldFinishWhenComplete = false,
|
||||
)
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
@@ -71,6 +99,11 @@ data class MainState(
|
||||
* Models actions for the [MainActivity].
|
||||
*/
|
||||
sealed class MainAction {
|
||||
/**
|
||||
* Receive first Intent by the application.
|
||||
*/
|
||||
data class ReceiveFirstIntent(val intent: Intent) : MainAction()
|
||||
|
||||
/**
|
||||
* Receive Intent by the application.
|
||||
*/
|
||||
|
||||
@@ -48,6 +48,15 @@ interface AuthRepository : AuthenticatorProvider {
|
||||
*/
|
||||
var specialCircumstance: UserState.SpecialCircumstance?
|
||||
|
||||
/**
|
||||
* Tracks whether there is an additional account that is pending login/registration in order to
|
||||
* have multiple accounts available.
|
||||
*
|
||||
* This allows a direct view into and modification of [UserState.hasPendingAccountAddition].
|
||||
* Note that this call has no effect when there is no [UserState] information available.
|
||||
*/
|
||||
var hasPendingAccountAddition: Boolean
|
||||
|
||||
/**
|
||||
* Attempt to delete the current account and logout them out upon success.
|
||||
*/
|
||||
|
||||
@@ -73,6 +73,7 @@ class AuthRepositoryImpl(
|
||||
dispatcherManager: DispatcherManager,
|
||||
private val elapsedRealtimeMillisProvider: () -> Long = { SystemClock.elapsedRealtime() },
|
||||
) : AuthRepository {
|
||||
private val mutableHasPendingAccountAdditionStateFlow = MutableStateFlow<Boolean>(false)
|
||||
private val mutableSpecialCircumstanceStateFlow =
|
||||
MutableStateFlow<UserState.SpecialCircumstance?>(null)
|
||||
|
||||
@@ -107,12 +108,20 @@ class AuthRepositoryImpl(
|
||||
authDiskSource.userStateFlow,
|
||||
authDiskSource.userOrganizationsListFlow,
|
||||
vaultRepository.vaultStateFlow,
|
||||
mutableHasPendingAccountAdditionStateFlow,
|
||||
mutableSpecialCircumstanceStateFlow,
|
||||
) { userStateJson, userOrganizationsList, vaultState, specialCircumstance ->
|
||||
) {
|
||||
userStateJson,
|
||||
userOrganizationsList,
|
||||
vaultState,
|
||||
hasPendingAccountAddition,
|
||||
specialCircumstance,
|
||||
->
|
||||
userStateJson
|
||||
?.toUserState(
|
||||
vaultState = vaultState,
|
||||
userOrganizationsList = userOrganizationsList,
|
||||
hasPendingAccountAddition = hasPendingAccountAddition,
|
||||
specialCircumstance = specialCircumstance,
|
||||
vaultUnlockTypeProvider = ::getVaultUnlockType,
|
||||
)
|
||||
@@ -125,6 +134,7 @@ class AuthRepositoryImpl(
|
||||
?.toUserState(
|
||||
vaultState = vaultRepository.vaultStateFlow.value,
|
||||
userOrganizationsList = authDiskSource.userOrganizationsList,
|
||||
hasPendingAccountAddition = mutableHasPendingAccountAdditionStateFlow.value,
|
||||
specialCircumstance = mutableSpecialCircumstanceStateFlow.value,
|
||||
vaultUnlockTypeProvider = ::getVaultUnlockType,
|
||||
),
|
||||
@@ -140,6 +150,9 @@ class AuthRepositoryImpl(
|
||||
override var specialCircumstance: UserState.SpecialCircumstance?
|
||||
by mutableSpecialCircumstanceStateFlow::value
|
||||
|
||||
override var hasPendingAccountAddition: Boolean
|
||||
by mutableHasPendingAccountAdditionStateFlow::value
|
||||
|
||||
override suspend fun deleteAccount(password: String): DeleteAccountResult {
|
||||
val profile = authDiskSource.userState?.activeAccount?.profile
|
||||
?: return DeleteAccountResult.Error
|
||||
@@ -218,7 +231,7 @@ class AuthRepositoryImpl(
|
||||
userId = userStateJson.activeUserId,
|
||||
)
|
||||
vaultRepository.sync()
|
||||
specialCircumstance = null
|
||||
hasPendingAccountAddition = false
|
||||
LoginResult.Success
|
||||
}
|
||||
|
||||
@@ -268,8 +281,8 @@ class AuthRepositoryImpl(
|
||||
val previousActiveUserId = currentUserState.activeUserId
|
||||
|
||||
if (userId == previousActiveUserId) {
|
||||
// No switching to do but clear any special circumstances
|
||||
specialCircumstance = null
|
||||
// No switching to do but clear any pending account additions
|
||||
hasPendingAccountAddition = false
|
||||
return SwitchAccountResult.NoChange
|
||||
}
|
||||
|
||||
@@ -284,8 +297,8 @@ class AuthRepositoryImpl(
|
||||
// Clear data for the previous user
|
||||
vaultRepository.clearUnlockedData()
|
||||
|
||||
// Clear any special circumstances
|
||||
specialCircumstance = null
|
||||
// Clear any pending account additions
|
||||
hasPendingAccountAddition = false
|
||||
|
||||
return SwitchAccountResult.AccountSwitched
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.x8bit.bitwarden.data.auth.repository.model
|
||||
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState.Account
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||
|
||||
/**
|
||||
* Represents the overall "user state" of the current active user as well as any users that may be
|
||||
@@ -10,11 +11,14 @@ import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||
* @property activeUserId The ID of the current active user.
|
||||
* @property accounts A mapping between user IDs and the [Account] information associated with
|
||||
* that user.
|
||||
* @property hasPendingAccountAddition Returns `true` if there is an additional account that is
|
||||
* pending login/registration in order to have multiple accounts available.
|
||||
* @property specialCircumstance A special circumstance (if any) that may be present.
|
||||
*/
|
||||
data class UserState(
|
||||
val activeUserId: String,
|
||||
val accounts: List<Account>,
|
||||
val hasPendingAccountAddition: Boolean = false,
|
||||
val specialCircumstance: SpecialCircumstance? = null,
|
||||
) {
|
||||
init {
|
||||
@@ -27,12 +31,6 @@ data class UserState(
|
||||
val activeAccount: Account
|
||||
get() = accounts.first { it.userId == activeUserId }
|
||||
|
||||
/**
|
||||
* Returns `true` if a new user is in the process of being added, `false` otherwise.
|
||||
*/
|
||||
val hasPendingAccountAddition: Boolean
|
||||
get() = specialCircumstance == SpecialCircumstance.PendingAccountAddition
|
||||
|
||||
/**
|
||||
* Basic account information about a given user.
|
||||
*
|
||||
@@ -65,11 +63,12 @@ data class UserState(
|
||||
* Represents a special account-related circumstance.
|
||||
*/
|
||||
sealed class SpecialCircumstance {
|
||||
|
||||
/**
|
||||
* There is an additional account that is pending login/registration in order to have
|
||||
* multiple accounts available.
|
||||
* The app was launched in order to create/share a new Send using the given [data].
|
||||
*/
|
||||
data object PendingAccountAddition : SpecialCircumstance()
|
||||
data class ShareNewSend(
|
||||
val data: IntentManager.ShareData,
|
||||
val shouldFinishWhenComplete: Boolean,
|
||||
) : SpecialCircumstance()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ fun UserStateJson.toUpdatedUserStateJson(
|
||||
fun UserStateJson.toUserState(
|
||||
vaultState: VaultState,
|
||||
userOrganizationsList: List<UserOrganizations>,
|
||||
hasPendingAccountAddition: Boolean,
|
||||
specialCircumstance: UserState.SpecialCircumstance?,
|
||||
vaultUnlockTypeProvider: (userId: String) -> VaultUnlockType,
|
||||
): UserState =
|
||||
@@ -77,5 +78,6 @@ fun UserStateJson.toUserState(
|
||||
vaultUnlockType = vaultUnlockTypeProvider(userId),
|
||||
)
|
||||
},
|
||||
hasPendingAccountAddition = hasPendingAccountAddition,
|
||||
specialCircumstance = specialCircumstance,
|
||||
)
|
||||
|
||||
@@ -31,7 +31,7 @@ import java.time.Clock
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* Provides repositories in the auth package.
|
||||
* Provides managers in the platform package.
|
||||
*/
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
|
||||
@@ -98,7 +98,7 @@ class VaultUnlockViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
private fun handleAddAccountClick() {
|
||||
authRepository.specialCircumstance = UserState.SpecialCircumstance.PendingAccountAddition
|
||||
authRepository.hasPendingAccountAddition = true
|
||||
}
|
||||
|
||||
private fun handleDismissDialog() {
|
||||
|
||||
@@ -20,9 +20,12 @@ import com.x8bit.bitwarden.ui.auth.feature.vaultunlock.vaultUnlockDestination
|
||||
import com.x8bit.bitwarden.ui.platform.feature.splash.SPLASH_ROUTE
|
||||
import com.x8bit.bitwarden.ui.platform.feature.splash.navigateToSplash
|
||||
import com.x8bit.bitwarden.ui.platform.feature.splash.splashDestination
|
||||
import com.x8bit.bitwarden.ui.platform.feature.vaultunlocked.VAULT_UNLOCKED_FOR_NEW_SEND_GRAPH_ROUTE
|
||||
import com.x8bit.bitwarden.ui.platform.feature.vaultunlocked.VAULT_UNLOCKED_GRAPH_ROUTE
|
||||
import com.x8bit.bitwarden.ui.platform.feature.vaultunlocked.navigateToVaultUnlockedForNewSendGraph
|
||||
import com.x8bit.bitwarden.ui.platform.feature.vaultunlocked.navigateToVaultUnlockedGraph
|
||||
import com.x8bit.bitwarden.ui.platform.feature.vaultunlocked.vaultUnlockedGraph
|
||||
import com.x8bit.bitwarden.ui.platform.feature.vaultunlocked.vaultUnlockedGraphForNewSend
|
||||
import com.x8bit.bitwarden.ui.platform.theme.RootTransitionProviders
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@@ -31,6 +34,7 @@ import java.util.concurrent.atomic.AtomicReference
|
||||
/**
|
||||
* Controls root level [NavHost] for the app.
|
||||
*/
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
fun RootNavScreen(
|
||||
viewModel: RootNavViewModel = hiltViewModel(),
|
||||
@@ -66,6 +70,7 @@ fun RootNavScreen(
|
||||
authGraph(navController)
|
||||
vaultUnlockDestination()
|
||||
vaultUnlockedGraph(navController)
|
||||
vaultUnlockedGraphForNewSend(navController)
|
||||
}
|
||||
|
||||
val targetRoute = when (state) {
|
||||
@@ -73,6 +78,7 @@ fun RootNavScreen(
|
||||
RootNavState.Splash -> SPLASH_ROUTE
|
||||
RootNavState.VaultLocked -> VAULT_UNLOCK_ROUTE
|
||||
is RootNavState.VaultUnlocked -> VAULT_UNLOCKED_GRAPH_ROUTE
|
||||
RootNavState.VaultUnlockedForNewSend -> VAULT_UNLOCKED_FOR_NEW_SEND_GRAPH_ROUTE
|
||||
}
|
||||
val currentRoute = navController.currentDestination?.rootLevelRoute()
|
||||
|
||||
@@ -102,6 +108,9 @@ fun RootNavScreen(
|
||||
RootNavState.Splash -> navController.navigateToSplash(rootNavOptions)
|
||||
RootNavState.VaultLocked -> navController.navigateToVaultUnlock(rootNavOptions)
|
||||
is RootNavState.VaultUnlocked -> navController.navigateToVaultUnlockedGraph(rootNavOptions)
|
||||
RootNavState.VaultUnlockedForNewSend -> {
|
||||
navController.navigateToVaultUnlockedForNewSendGraph(rootNavOptions)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,9 +51,18 @@ class RootNavViewModel @Inject constructor(
|
||||
userState.hasPendingAccountAddition -> RootNavState.Auth
|
||||
|
||||
userState.activeAccount.isVaultUnlocked -> {
|
||||
RootNavState.VaultUnlocked(
|
||||
activeUserId = userState.activeAccount.userId,
|
||||
)
|
||||
when (userState.specialCircumstance) {
|
||||
is UserState.SpecialCircumstance.ShareNewSend -> {
|
||||
RootNavState.VaultUnlockedForNewSend
|
||||
}
|
||||
|
||||
null,
|
||||
-> {
|
||||
RootNavState.VaultUnlocked(
|
||||
activeUserId = userState.activeAccount.userId,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else -> RootNavState.VaultLocked
|
||||
@@ -91,6 +100,12 @@ sealed class RootNavState : Parcelable {
|
||||
data class VaultUnlocked(
|
||||
val activeUserId: String,
|
||||
) : RootNavState()
|
||||
|
||||
/**
|
||||
* App should show the new send screen for an unlocked user.
|
||||
*/
|
||||
@Parcelize
|
||||
data object VaultUnlockedForNewSend : RootNavState()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,6 +14,8 @@ import com.x8bit.bitwarden.ui.tools.feature.generator.generatorModalDestination
|
||||
import com.x8bit.bitwarden.ui.tools.feature.generator.navigateToGeneratorModal
|
||||
import com.x8bit.bitwarden.ui.tools.feature.generator.passwordhistory.navigateToPasswordHistory
|
||||
import com.x8bit.bitwarden.ui.tools.feature.generator.passwordhistory.passwordHistoryDestination
|
||||
import com.x8bit.bitwarden.ui.tools.feature.send.addsend.ADD_SEND_AS_ROOT_ROUTE
|
||||
import com.x8bit.bitwarden.ui.tools.feature.send.addsend.addSendAsRootDestination
|
||||
import com.x8bit.bitwarden.ui.tools.feature.send.addsend.addSendDestination
|
||||
import com.x8bit.bitwarden.ui.tools.feature.send.addsend.model.AddSendType
|
||||
import com.x8bit.bitwarden.ui.tools.feature.send.addsend.navigateToAddSend
|
||||
@@ -30,6 +32,7 @@ import com.x8bit.bitwarden.ui.vault.feature.qrcodescan.vaultQrCodeScanDestinatio
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultAddEditType
|
||||
|
||||
const val VAULT_UNLOCKED_GRAPH_ROUTE: String = "vault_unlocked_graph"
|
||||
const val VAULT_UNLOCKED_FOR_NEW_SEND_GRAPH_ROUTE: String = "vault_unlocked_for_new_send_graph"
|
||||
|
||||
/**
|
||||
* Navigate to the vault unlocked screen.
|
||||
@@ -38,6 +41,13 @@ fun NavController.navigateToVaultUnlockedGraph(navOptions: NavOptions? = null) {
|
||||
navigate(VAULT_UNLOCKED_GRAPH_ROUTE, navOptions)
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate to the vault unlocked graph for a new send.
|
||||
*/
|
||||
fun NavController.navigateToVaultUnlockedForNewSendGraph(navOptions: NavOptions? = null) {
|
||||
navigate(VAULT_UNLOCKED_FOR_NEW_SEND_GRAPH_ROUTE, navOptions)
|
||||
}
|
||||
|
||||
/**
|
||||
* Add vault unlocked destinations to the root nav graph.
|
||||
*/
|
||||
@@ -107,3 +117,17 @@ fun NavGraphBuilder.vaultUnlockedGraph(
|
||||
generatorModalDestination(onNavigateBack = { navController.popBackStack() })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add vault unlocked destinations for the new send flow to the root nav graph.
|
||||
*/
|
||||
fun NavGraphBuilder.vaultUnlockedGraphForNewSend(
|
||||
navController: NavController,
|
||||
) {
|
||||
navigation(
|
||||
startDestination = ADD_SEND_AS_ROOT_ROUTE,
|
||||
route = VAULT_UNLOCKED_FOR_NEW_SEND_GRAPH_ROUTE,
|
||||
) {
|
||||
addSendAsRootDestination(onNavigateBack = { navController.popBackStack() })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.x8bit.bitwarden.ui.platform.manager.di
|
||||
|
||||
import android.content.Context
|
||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManagerImpl
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
|
||||
/**
|
||||
* Provides UI-based managers in the platform package.
|
||||
*/
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
class PlatformUiManagerModule {
|
||||
@Provides
|
||||
fun provideIntentManager(
|
||||
@ApplicationContext context: Context,
|
||||
): IntentManager =
|
||||
IntentManagerImpl(
|
||||
context = context,
|
||||
)
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import androidx.compose.runtime.Composable
|
||||
/**
|
||||
* A manager class for simplifying the handling of Android Intents within a given context.
|
||||
*/
|
||||
@Suppress("TooManyFunctions")
|
||||
interface IntentManager {
|
||||
|
||||
/**
|
||||
@@ -61,6 +62,11 @@ interface IntentManager {
|
||||
*/
|
||||
fun getFileDataFromIntent(activityResult: ActivityResult): FileData?
|
||||
|
||||
/**
|
||||
* Processes the [intent] and attempts to derive [ShareData] information from it.
|
||||
*/
|
||||
fun getShareDataFromIntent(intent: Intent): ShareData?
|
||||
|
||||
/**
|
||||
* Creates an intent for choosing a file saved to disk.
|
||||
*/
|
||||
@@ -74,4 +80,24 @@ interface IntentManager {
|
||||
val uri: Uri,
|
||||
val sizeBytes: Long,
|
||||
)
|
||||
|
||||
/**
|
||||
* Represents data for a share request coming from outside the app.
|
||||
*/
|
||||
sealed class ShareData {
|
||||
/**
|
||||
* The data required to create a new Text Send.
|
||||
*/
|
||||
data class TextSend(
|
||||
val subject: String?,
|
||||
val text: String,
|
||||
) : ShareData()
|
||||
|
||||
/**
|
||||
* The data required to create a new File Send.
|
||||
*/
|
||||
data class FileSend(
|
||||
val fileData: IntentManager.FileData,
|
||||
) : ShareData()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +122,31 @@ class IntentManagerImpl(
|
||||
return if (uri != null) getLocalFileData(uri) else getCameraFileData()
|
||||
}
|
||||
|
||||
@Suppress("ReturnCount")
|
||||
override fun getShareDataFromIntent(intent: Intent): IntentManager.ShareData? {
|
||||
if (intent.action != Intent.ACTION_SEND) return null
|
||||
return if (intent.type?.contains("text/") == true) {
|
||||
val subject = intent.getStringExtra(Intent.EXTRA_SUBJECT)
|
||||
val title = intent.getStringExtra(Intent.EXTRA_TEXT) ?: return null
|
||||
IntentManager.ShareData.TextSend(
|
||||
subject = subject,
|
||||
text = title,
|
||||
)
|
||||
} else {
|
||||
getFileDataFromIntent(
|
||||
ActivityResult(
|
||||
Activity.RESULT_OK,
|
||||
intent,
|
||||
),
|
||||
)
|
||||
?.let {
|
||||
IntentManager.ShareData.FileSend(
|
||||
fileData = it,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun createFileChooserIntent(withCameraIntents: Boolean): Intent {
|
||||
val chooserIntent = Intent.createChooser(
|
||||
Intent(Intent.ACTION_OPEN_DOCUMENT)
|
||||
|
||||
@@ -20,6 +20,8 @@ private const val ADD_SEND_ITEM_TYPE: String = "add_send_item_type"
|
||||
private const val ADD_SEND_ROUTE: String =
|
||||
"$ADD_SEND_ITEM_PREFIX/{$ADD_SEND_ITEM_TYPE}?$EDIT_ITEM_ID={$EDIT_ITEM_ID}"
|
||||
|
||||
const val ADD_SEND_AS_ROOT_ROUTE: String = ADD_SEND_ITEM_PREFIX
|
||||
|
||||
/**
|
||||
* Class to retrieve send add & edit arguments from the [SavedStateHandle].
|
||||
*/
|
||||
@@ -28,9 +30,10 @@ data class AddSendArgs(
|
||||
val sendAddType: AddSendType,
|
||||
) {
|
||||
constructor(savedStateHandle: SavedStateHandle) : this(
|
||||
sendAddType = when (requireNotNull(savedStateHandle[ADD_SEND_ITEM_TYPE])) {
|
||||
sendAddType = when (savedStateHandle.get<String>(ADD_SEND_ITEM_TYPE)) {
|
||||
ADD_TYPE -> AddSendType.AddItem
|
||||
EDIT_TYPE -> AddSendType.EditItem(requireNotNull(savedStateHandle[EDIT_ITEM_ID]))
|
||||
null -> AddSendType.AddItem
|
||||
else -> throw IllegalStateException("Unknown VaultAddEditType.")
|
||||
},
|
||||
)
|
||||
@@ -52,6 +55,19 @@ fun NavGraphBuilder.addSendDestination(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the new send screen to the nav graph as a root destination for a nested graph.
|
||||
*/
|
||||
fun NavGraphBuilder.addSendAsRootDestination(
|
||||
onNavigateBack: () -> Unit,
|
||||
) {
|
||||
composableWithSlideTransitions(
|
||||
route = ADD_SEND_AS_ROOT_ROUTE,
|
||||
) {
|
||||
AddSendScreen(onNavigateBack = onNavigateBack)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate to the new send screen.
|
||||
*/
|
||||
|
||||
@@ -101,6 +101,9 @@ class AddSendViewModel @Inject constructor(
|
||||
) {
|
||||
|
||||
init {
|
||||
// TODO: Check the special circumstance to place in custom mode when a new send request is
|
||||
// initiated externally (BIT-1518).
|
||||
|
||||
when (val addSendType = state.addSendType) {
|
||||
AddSendType.AddItem -> Unit
|
||||
is AddSendType.EditItem -> {
|
||||
|
||||
@@ -205,7 +205,7 @@ class VaultViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
private fun handleAddAccountClick() {
|
||||
authRepository.specialCircumstance = UserState.SpecialCircumstance.PendingAccountAddition
|
||||
authRepository.hasPendingAccountAddition = true
|
||||
}
|
||||
|
||||
private fun handleSyncClick() {
|
||||
|
||||
Reference in New Issue
Block a user