Skip to content

Commit

Permalink
Merge branch 'develop' into upload-app-to-play-store
Browse files Browse the repository at this point in the history
  • Loading branch information
ohassine authored Jun 3, 2024
2 parents 5d4c042 + aee1880 commit e1a3762
Show file tree
Hide file tree
Showing 24 changed files with 346 additions and 293 deletions.
2 changes: 1 addition & 1 deletion Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ String defineBuildType(String flavor) {
// internal is used for wire beta builds
if (flavor == 'Beta') {
return 'Release'
} else if (flavor == 'Prod') {
} else if (flavor == 'Prod' || flavor == 'Fdroid') {
return "Compatrelease"
}
// use the scala client signing keys for testing upgrades.
Expand Down
29 changes: 14 additions & 15 deletions app/src/main/kotlin/com/wire/android/ui/WireActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ import com.wire.android.navigation.NavigationGraph
import com.wire.android.navigation.navigateToItem
import com.wire.android.navigation.rememberNavigator
import com.wire.android.ui.calling.getIncomingCallIntent
import com.wire.android.ui.calling.getOutgoingCallIntent
import com.wire.android.ui.calling.getOngoingCallIntent
import com.wire.android.ui.calling.getOutgoingCallIntent
import com.wire.android.ui.common.snackbar.LocalSnackbarHostState
import com.wire.android.ui.common.topappbar.CommonTopAppBar
import com.wire.android.ui.common.topappbar.CommonTopAppBarViewModel
Expand Down Expand Up @@ -151,7 +151,7 @@ class WireActivity : AppCompatActivity() {

WindowCompat.setDecorFitsSystemWindows(window, false)

lifecycleScope.launch(Dispatchers.Default) {
lifecycleScope.launch {

appLogger.i("$TAG persistent connection status")
viewModel.observePersistentConnectionStatus()
Expand All @@ -167,12 +167,11 @@ class WireActivity : AppCompatActivity() {
InitialAppState.LOGGED_IN -> HomeScreenDestination
}
appLogger.i("$TAG composable content")
withContext(Dispatchers.Main) {
setComposableContent(startDestination) {
appLogger.i("$TAG splash hide")
shouldKeepSplashOpen = false
handleDeepLink(intent, savedInstanceState)
}

setComposableContent(startDestination) {
appLogger.i("$TAG splash hide")
shouldKeepSplashOpen = false
handleDeepLink(intent, savedInstanceState)
}
}
}
Expand Down Expand Up @@ -237,17 +236,17 @@ class WireActivity : AppCompatActivity() {

// This setup needs to be done after the navigation graph is created, because building the graph takes some time,
// and if any NavigationCommand is executed before the graph is fully built, it will cause a NullPointerException.
setUpNavigation(navigator.navController, onComplete)
handleScreenshotCensoring()
handleDialogs(navigator::navigate)
SetUpNavigation(navigator.navController, onComplete)
HandleScreenshotCensoring()
HandleDialogs(navigator::navigate)
}
}
}
}
}

@Composable
private fun setUpNavigation(
private fun SetUpNavigation(
navController: NavHostController,
onComplete: () -> Unit,
) {
Expand Down Expand Up @@ -281,7 +280,7 @@ class WireActivity : AppCompatActivity() {
}

@Composable
private fun handleScreenshotCensoring() {
private fun HandleScreenshotCensoring() {
LaunchedEffect(viewModel.globalAppState.screenshotCensoringEnabled) {
if (viewModel.globalAppState.screenshotCensoringEnabled) {
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
Expand All @@ -293,7 +292,7 @@ class WireActivity : AppCompatActivity() {

@Suppress("ComplexMethod")
@Composable
private fun handleDialogs(navigate: (NavigationCommand) -> Unit) {
private fun HandleDialogs(navigate: (NavigationCommand) -> Unit) {
val context = LocalContext.current
with(featureFlagNotificationViewModel.featureFlagState) {
if (shouldShowTeamAppLockDialog) {
Expand Down Expand Up @@ -471,7 +470,7 @@ class WireActivity : AppCompatActivity() {
override fun onResume() {
super.onResume()

lifecycleScope.launch(Dispatchers.Default) {
lifecycleScope.launch {
lockCodeTimeManager.get().observeAppLock()
// Listen to one flow in a lifecycle-aware manner using flowWithLifecycle
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.input.TextFieldState
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
Expand All @@ -33,8 +35,6 @@ import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.ramcosta.composedestinations.annotation.Destination
Expand All @@ -53,6 +53,7 @@ import com.wire.android.ui.common.dialogs.CancelLoginDialogContent
import com.wire.android.ui.common.dialogs.CancelLoginDialogState
import com.wire.android.ui.common.error.CoreFailureErrorDialog
import com.wire.android.ui.common.scaffold.WireScaffold
import com.wire.android.ui.common.textfield.DefaultPassword
import com.wire.android.ui.common.textfield.WirePasswordTextField
import com.wire.android.ui.common.textfield.WireTextFieldState
import com.wire.android.ui.common.textfield.clearAutofillTree
Expand All @@ -63,18 +64,21 @@ import com.wire.android.ui.destinations.E2EIEnrollmentScreenDestination
import com.wire.android.ui.destinations.HomeScreenDestination
import com.wire.android.ui.destinations.InitialSyncScreenDestination
import com.wire.android.ui.destinations.RemoveDeviceScreenDestination
import com.wire.android.ui.theme.WireTheme
import com.wire.android.ui.theme.wireDimensions
import com.wire.android.ui.theme.wireTypography
import com.wire.android.util.ui.PreviewMultipleThemes

@RootNavGraph
@Destination(
style = PopUpNavigationAnimation::class,
)
@Composable
fun RegisterDeviceScreen(navigator: Navigator) {
val viewModel: RegisterDeviceViewModel = hiltViewModel()
val clearSessionViewModel: ClearSessionViewModel = hiltViewModel()
val clearSessionState: ClearSessionState = clearSessionViewModel.state
fun RegisterDeviceScreen(
navigator: Navigator,
viewModel: RegisterDeviceViewModel = hiltViewModel(),
clearSessionViewModel: ClearSessionViewModel = hiltViewModel(),
) {
clearAutofillTree()
when (val flowState = viewModel.state.flowState) {
is RegisterDeviceFlowState.Success -> {
Expand All @@ -92,8 +96,8 @@ fun RegisterDeviceScreen(navigator: Navigator) {
else ->
RegisterDeviceContent(
state = viewModel.state,
clearSessionState = clearSessionState,
onPasswordChange = viewModel::onPasswordChange,
passwordTextState = viewModel.passwordTextState,
clearSessionState = clearSessionViewModel.state,
onContinuePressed = viewModel::onContinue,
onErrorDismiss = viewModel::onErrorDismiss,
onBackButtonClicked = clearSessionViewModel::onBackButtonClicked,
Expand All @@ -106,13 +110,14 @@ fun RegisterDeviceScreen(navigator: Navigator) {
@Composable
private fun RegisterDeviceContent(
state: RegisterDeviceState,
passwordTextState: TextFieldState,
clearSessionState: ClearSessionState,
onPasswordChange: (TextFieldValue) -> Unit,
onContinuePressed: () -> Unit,
onErrorDismiss: () -> Unit,
onBackButtonClicked: () -> Unit,
onCancelLoginClicked: () -> Unit,
onProceedLoginClicked: () -> Unit
onProceedLoginClicked: () -> Unit,
modifier: Modifier = Modifier,
) {
BackHandler {
onBackButtonClicked()
Expand All @@ -136,6 +141,7 @@ private fun RegisterDeviceContent(
}

WireScaffold(
modifier = modifier,
topBar = {
WireCenterAlignedTopAppBar(
elevation = 0.dp,
Expand All @@ -161,7 +167,7 @@ private fun RegisterDeviceContent(
)
.testTag("registerText")
)
PasswordTextField(state = state, onPasswordChange = onPasswordChange)
PasswordTextField(state = state, passwordTextState = passwordTextState)
Spacer(modifier = Modifier.weight(1f))
WirePrimaryButton(
text = stringResource(R.string.label_add_device),
Expand All @@ -182,28 +188,31 @@ private fun RegisterDeviceContent(
}

@Composable
private fun PasswordTextField(state: RegisterDeviceState, onPasswordChange: (TextFieldValue) -> Unit) {
private fun PasswordTextField(
state: RegisterDeviceState,
passwordTextState: TextFieldState,
modifier: Modifier = Modifier,
) {
val keyboardController = LocalSoftwareKeyboardController.current
WirePasswordTextField(
value = state.password,
onValueChange = onPasswordChange,
textState = passwordTextState,
state = when (state.flowState) {
is RegisterDeviceFlowState.Error.InvalidCredentialsError ->
WireTextFieldState.Error(stringResource(id = R.string.remove_device_invalid_password))

else -> WireTextFieldState.Default
},
imeAction = ImeAction.Done,
onImeAction = { keyboardController?.hide() },
modifier = Modifier
keyboardOptions = KeyboardOptions.DefaultPassword.copy(imeAction = ImeAction.Done),
onKeyboardAction = { keyboardController?.hide() },
modifier = modifier
.padding(horizontal = MaterialTheme.wireDimensions.spacing16x)
.testTag("password field"),
autofill = true
autoFill = true
)
}

@Composable
@Preview
fun PreviewRegisterDeviceScreen() {
RegisterDeviceContent(RegisterDeviceState(), ClearSessionState(), {}, {}, {}, {}, {}, {})
@PreviewMultipleThemes
fun PreviewRegisterDeviceScreen() = WireTheme {
RegisterDeviceContent(RegisterDeviceState(), TextFieldState(), ClearSessionState(), {}, {}, {}, {}, {})
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,19 @@

package com.wire.android.ui.authentication.devices.register

import androidx.compose.ui.text.input.TextFieldValue
import com.wire.kalium.logic.CoreFailure
import com.wire.kalium.logic.data.conversation.ClientId
import com.wire.kalium.logic.data.user.UserId

data class RegisterDeviceState(
val password: TextFieldValue = TextFieldValue(""),
val continueEnabled: Boolean = false,
val flowState: RegisterDeviceFlowState = RegisterDeviceFlowState.Default
)

sealed class RegisterDeviceFlowState {
object Default : RegisterDeviceFlowState()
object Loading : RegisterDeviceFlowState()
object TooManyDevices : RegisterDeviceFlowState()
data object Default : RegisterDeviceFlowState()
data object Loading : RegisterDeviceFlowState()
data object TooManyDevices : RegisterDeviceFlowState()
data class Success(
val initialSyncCompleted: Boolean,
val isE2EIRequired: Boolean,
Expand All @@ -41,7 +39,7 @@ sealed class RegisterDeviceFlowState {
) : RegisterDeviceFlowState()

sealed class Error : RegisterDeviceFlowState() {
object InvalidCredentialsError : Error()
data object InvalidCredentialsError : Error()
data class GenericError(val coreFailure: CoreFailure) : Error()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,22 @@

package com.wire.android.ui.authentication.devices.register

import androidx.compose.foundation.text.input.TextFieldState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.text.input.TextFieldValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.wire.android.BuildConfig
import com.wire.android.datastore.UserDataStore
import com.wire.android.ui.common.textfield.textAsFlow
import com.wire.kalium.logic.feature.client.GetOrRegisterClientUseCase
import com.wire.kalium.logic.feature.client.RegisterClientResult
import com.wire.kalium.logic.feature.client.RegisterClientUseCase
import com.wire.kalium.logic.feature.user.IsPasswordRequiredUseCase
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
Expand All @@ -43,6 +46,7 @@ class RegisterDeviceViewModel @Inject constructor(
private val userDataStore: UserDataStore,
) : ViewModel() {

val passwordTextState: TextFieldState = TextFieldState()
var state: RegisterDeviceState by mutableStateOf(RegisterDeviceState())
private set

Expand All @@ -62,11 +66,10 @@ class RegisterDeviceViewModel @Inject constructor(
}
}
}
}

fun onPasswordChange(newText: TextFieldValue) {
if (state.password != newText) {
state = state.copy(password = newText, flowState = RegisterDeviceFlowState.Default, continueEnabled = newText.text.isNotEmpty())
viewModelScope.launch {
passwordTextState.textAsFlow().distinctUntilChanged().collectLatest {
state = state.copy(flowState = RegisterDeviceFlowState.Default, continueEnabled = it.isNotEmpty())
}
}
}

Expand Down Expand Up @@ -122,7 +125,7 @@ class RegisterDeviceViewModel @Inject constructor(

fun onContinue() {
viewModelScope.launch {
registerClient(state.password.text)
registerClient(passwordTextState.text.toString())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
package com.wire.android.ui.authentication.devices.remove

import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.input.TextFieldState
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
Expand All @@ -30,12 +32,12 @@ import androidx.compose.ui.platform.SoftwareKeyboardController
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.TextFieldValue
import com.wire.android.R
import com.wire.android.ui.common.WireDialog
import com.wire.android.ui.common.WireDialogButtonProperties
import com.wire.android.ui.common.WireDialogButtonType
import com.wire.android.ui.common.button.WireButtonState
import com.wire.android.ui.common.textfield.DefaultPassword
import com.wire.android.ui.common.textfield.WirePasswordTextField
import com.wire.android.ui.common.textfield.WireTextFieldState
import com.wire.android.ui.theme.wireDimensions
Expand All @@ -45,16 +47,18 @@ import com.wire.android.util.deviceDateTimeFormat
fun RemoveDeviceDialog(
errorState: RemoveDeviceError,
state: RemoveDeviceDialogState.Visible,
onPasswordChange: (TextFieldValue) -> Unit,
passwordTextState: TextFieldState,
onDialogDismiss: () -> Unit,
onRemoveConfirm: () -> Unit
onRemoveConfirm: () -> Unit,
modifier: Modifier = Modifier,
) {
var keyboardController: SoftwareKeyboardController? = null
val onDialogDismissHideKeyboard: () -> Unit = {
keyboardController?.hide()
onDialogDismiss()
}
WireDialog(
modifier = modifier,
title = stringResource(R.string.remove_device_dialog_title),
text = state.device.name.asString() + "\n" +
stringResource(
Expand Down Expand Up @@ -84,22 +88,21 @@ fun RemoveDeviceDialog(
keyboardController = LocalSoftwareKeyboardController.current
val focusRequester = remember { FocusRequester() }
WirePasswordTextField(
value = state.password,
onValueChange = onPasswordChange,
textState = passwordTextState,
state = when {
errorState is RemoveDeviceError.InvalidCredentialsError ->
WireTextFieldState.Error(stringResource(id = R.string.remove_device_invalid_password))

state.loading -> WireTextFieldState.Disabled
else -> WireTextFieldState.Default
},
imeAction = ImeAction.Done,
onImeAction = { keyboardController?.hide() },
keyboardOptions = KeyboardOptions.DefaultPassword.copy(imeAction = ImeAction.Done),
onKeyboardAction = { keyboardController?.hide() },
modifier = Modifier
.focusRequester(focusRequester)
.padding(bottom = MaterialTheme.wireDimensions.spacing8x)
.testTag("remove device password field"),
autofill = true
autoFill = true
)
LaunchedEffect(Unit) { // executed only once when showing the dialog
focusRequester.requestFocus()
Expand Down
Loading

0 comments on commit e1a3762

Please sign in to comment.