Skip to content

Commit 4ccf2e2

Browse files
committed
add password logic
Signed-off-by: sowjanyakch <sowjanya.kch@gmail.com>
1 parent 5653263 commit 4ccf2e2

8 files changed

Lines changed: 190 additions & 9 deletions

File tree

app/src/main/java/com/nextcloud/talk/api/NcApiCoroutines.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import com.nextcloud.talk.models.json.invitation.InvitationOverall
1919
import com.nextcloud.talk.models.json.participants.AddParticipantOverall
2020
import com.nextcloud.talk.models.json.participants.TalkBan
2121
import com.nextcloud.talk.models.json.participants.TalkBanOverall
22+
import com.nextcloud.talk.models.json.passwordResult.PasswordResultOverall
2223
import com.nextcloud.talk.models.json.profile.ProfileOverall
2324
import com.nextcloud.talk.models.json.status.StatusOverall
2425
import com.nextcloud.talk.models.json.testNotification.TestNotificationOverall
@@ -374,4 +375,12 @@ interface NcApiCoroutines {
374375

375376
@GET
376377
suspend fun getScheduledMessage(@Header("Authorization") authorization: String, @Url url: String): ChatOverall
378+
379+
@FormUrlEncoded
380+
@POST
381+
suspend fun validatePassword(
382+
@Header("Authorization") authorization: String,
383+
@Url url: String,
384+
@Field("password") password: String
385+
): PasswordResultOverall
377386
}

app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,7 @@ fun ConversationOptions(
596596
@Composable
597597
fun ShowChangePassword(onDismiss: () -> Unit, conversationCreationViewModel: ConversationCreationViewModel) {
598598
var changedPassword by rememberSaveable { mutableStateOf("") }
599+
val passwordValidationState by conversationCreationViewModel.validPasswordViewState.collectAsState()
599600
Dialog(onDismissRequest = {
600601
onDismiss()
601602
}) {
@@ -614,17 +615,42 @@ fun ShowChangePassword(onDismiss: () -> Unit, conversationCreationViewModel: Con
614615
verticalArrangement = Arrangement.Center,
615616
horizontalAlignment = Alignment.CenterHorizontally
616617
) {
618+
val validatePasswordUrl = conversationCreationViewModel.currentUser.capabilities?.passwordCapability?.api?.validatePasswordApi
617619
Text(text = stringResource(id = R.string.nc_set_new_password), fontWeight = FontWeight.SemiBold)
618620
Spacer(modifier = Modifier.height(16.dp))
619621
OutlinedTextField(
620622
value = changedPassword,
621623
onValueChange = {
622624
changedPassword = it
625+
if (validatePasswordUrl != null) {
626+
conversationCreationViewModel.validatePassword(validatePasswordUrl, it)
627+
}
623628
},
624629
label = { Text(text = stringResource(id = R.string.nc_password)) },
625630
singleLine = true
626631
)
627-
Spacer(modifier = Modifier.height(16.dp))
632+
Spacer(modifier = Modifier.height(8.dp))
633+
when (passwordValidationState) {
634+
is ValidPasswordUiState.Success -> Text(
635+
text = (passwordValidationState as ValidPasswordUiState.Success).result.reason!!,
636+
color = if ((passwordValidationState as ValidPasswordUiState.Success).result.passed == false) {
637+
colorResource(
638+
id = R.color
639+
.nc_darkRed
640+
)
641+
} else {
642+
colorResource(id = R.color.nc_darkGreen)
643+
},
644+
modifier = Modifier.fillMaxWidth()
645+
)
646+
647+
is ValidPasswordUiState.Error -> {
648+
Text(text = (passwordValidationState as ValidPasswordUiState.Error).message)
649+
}
650+
651+
else -> {
652+
}
653+
}
628654

629655
Column(
630656
modifier = Modifier
@@ -639,7 +665,9 @@ fun ShowChangePassword(onDismiss: () -> Unit, conversationCreationViewModel: Con
639665
conversationCreationViewModel.isPasswordEnabled.value = true
640666
onDismiss()
641667
},
642-
enabled = changedPassword.isNotEmpty() && changedPassword.isNotBlank(),
668+
enabled = changedPassword.isNotEmpty() &&
669+
changedPassword.isNotBlank() &&
670+
(passwordValidationState as ValidPasswordUiState.Success).result.passed == true,
643671
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp)
644672
) {
645673
Text(text = stringResource(id = R.string.nc_change_password))
@@ -673,18 +701,48 @@ fun ShowChangePassword(onDismiss: () -> Unit, conversationCreationViewModel: Con
673701
@Composable
674702
fun ShowPasswordDialog(onDismiss: () -> Unit, conversationCreationViewModel: ConversationCreationViewModel) {
675703
var password by rememberSaveable { mutableStateOf("") }
704+
val passwordValidationState by conversationCreationViewModel.validPasswordViewState.collectAsState()
705+
val validatePasswordUrl = conversationCreationViewModel.currentUser.capabilities?.passwordCapability?.api?.validatePasswordApi
676706
AlertDialog(
677707
containerColor = colorResource(id = R.color.dialog_background),
678708
onDismissRequest = onDismiss,
679709
title = { Text(text = stringResource(id = R.string.nc_set_password)) },
680710
text = {
681-
TextField(
682-
value = password,
683-
onValueChange = {
684-
password = it
685-
},
686-
label = { Text(text = stringResource(id = R.string.nc_guest_access_password_dialog_hint)) }
687-
)
711+
Row {
712+
TextField(
713+
value = password,
714+
onValueChange = {
715+
password = it
716+
if (validatePasswordUrl != null) {
717+
conversationCreationViewModel.validatePassword(validatePasswordUrl, it)
718+
}
719+
},
720+
label = { Text(text = stringResource(id = R.string.nc_guest_access_password_dialog_hint)) }
721+
)
722+
Spacer(modifier = Modifier.height(8.dp))
723+
724+
when (passwordValidationState) {
725+
is ValidPasswordUiState.Success -> Text(
726+
text = (passwordValidationState as ValidPasswordUiState.Success).result.reason!!,
727+
color = if ((passwordValidationState as ValidPasswordUiState.Success).result.passed == false) {
728+
colorResource(
729+
id = R.color
730+
.nc_darkRed
731+
)
732+
} else {
733+
colorResource(id = R.color.nc_darkGreen)
734+
},
735+
modifier = Modifier.fillMaxWidth()
736+
)
737+
738+
is ValidPasswordUiState.Error -> {
739+
Text(text = (passwordValidationState as ValidPasswordUiState.Error).message)
740+
}
741+
742+
else -> {
743+
}
744+
}
745+
}
688746
},
689747
confirmButton = {
690748
TextButton(

app/src/main/java/com/nextcloud/talk/conversationcreation/data/ConversationCreationRepository.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import com.nextcloud.talk.models.domain.ConversationModel
1313
import com.nextcloud.talk.models.json.conversations.RoomOverall
1414
import com.nextcloud.talk.models.json.generic.GenericOverall
1515
import com.nextcloud.talk.models.json.participants.AddParticipantOverall
16+
import com.nextcloud.talk.models.json.passwordResult.PasswordResultOverall
1617
import java.io.File
1718

1819
interface ConversationCreationRepository {
@@ -35,4 +36,5 @@ interface ConversationCreationRepository {
3536
roomToken: String
3637
): ConversationModel
3738
suspend fun allowGuests(credentials: String?, url: String, token: String, allow: Boolean): GenericOverall
39+
suspend fun validatePassword(credentials: String, url: String, password: String): PasswordResultOverall
3840
}

app/src/main/java/com/nextcloud/talk/conversationcreation/data/ConversationCreationRepositoryImpl.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import com.nextcloud.talk.models.domain.ConversationModel
1414
import com.nextcloud.talk.models.json.conversations.RoomOverall
1515
import com.nextcloud.talk.models.json.generic.GenericOverall
1616
import com.nextcloud.talk.models.json.participants.AddParticipantOverall
17+
import com.nextcloud.talk.models.json.passwordResult.PasswordResultOverall
1718
import com.nextcloud.talk.utils.Mimetype
1819
import okhttp3.MediaType.Companion.toMediaTypeOrNull
1920
import okhttp3.MultipartBody
@@ -121,4 +122,13 @@ class ConversationCreationRepositoryImpl @Inject constructor(private val ncApiCo
121122
}
122123
return result
123124
}
125+
126+
override suspend fun validatePassword(credentials: String, url: String, password: String): PasswordResultOverall {
127+
val passwordOverall = ncApiCoroutines.validatePassword(
128+
credentials,
129+
url,
130+
password
131+
)
132+
return passwordOverall
133+
}
124134
}

app/src/main/java/com/nextcloud/talk/conversationcreation/viewmodel/ConversationCreationViewModel.kt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import com.nextcloud.talk.models.RetrofitBucket
1919
import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser
2020
import com.nextcloud.talk.models.json.conversations.Conversation
2121
import com.nextcloud.talk.models.json.generic.GenericMeta
22+
import com.nextcloud.talk.models.json.passwordResult.PasswordResult
2223
import com.nextcloud.talk.repositories.conversations.ConversationsRepositoryImpl.Companion.STATUS_CODE_OK
2324
import com.nextcloud.talk.utils.ApiUtils
2425
import com.nextcloud.talk.utils.ApiUtils.getRetrofitBucketForAddParticipant
@@ -37,6 +38,9 @@ class ConversationCreationViewModel @Inject constructor(
3738
val selectedParticipants: StateFlow<List<AutocompleteUser>> = _selectedParticipants
3839
private val roomViewState = MutableStateFlow<RoomUIState>(RoomUIState.None)
3940

41+
private val _validPasswordViewState = MutableStateFlow<ValidPasswordUiState>(ValidPasswordUiState.None)
42+
val validPasswordViewState: StateFlow<ValidPasswordUiState> = _validPasswordViewState
43+
4044
private val _selectedImageUri = MutableStateFlow<Uri?>(null)
4145
val selectedImageUri: StateFlow<Uri?> = _selectedImageUri
4246

@@ -81,6 +85,24 @@ class ConversationCreationViewModel @Inject constructor(
8185
_conversationDescription.value = conversationDescription
8286
}
8387

88+
@Suppress("Detekt.TooGenericExceptionCaught")
89+
fun validatePassword(url: String, password: String) {
90+
val credentials = ApiUtils.getCredentials(_currentUser.username, _currentUser.token) ?: ""
91+
viewModelScope.launch {
92+
try {
93+
val passwordResult = repository.validatePassword(
94+
credentials,
95+
url,
96+
password
97+
)
98+
99+
_validPasswordViewState.value = ValidPasswordUiState.Success(passwordResult.ocs?.data!!)
100+
} catch (exception: Exception) {
101+
_validPasswordViewState.value = ValidPasswordUiState.Error(exception.message ?: "")
102+
}
103+
}
104+
}
105+
84106
@Suppress("Detekt.TooGenericExceptionCaught")
85107
fun createRoomAndAddParticipants(
86108
roomType: String,
@@ -254,3 +276,9 @@ sealed class AddParticipantsUiState {
254276
data class Success(val participants: List<Conversation>?) : AddParticipantsUiState()
255277
data class Error(val message: String) : AddParticipantsUiState()
256278
}
279+
280+
sealed class ValidPasswordUiState {
281+
data object None : ValidPasswordUiState()
282+
data class Success(val result: PasswordResult) : ValidPasswordUiState()
283+
data class Error(val message: String) : ValidPasswordUiState()
284+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Nextcloud Talk - Android Client
3+
*
4+
* SPDX-FileCopyrightText: 2026 Your Name <your@email.com>
5+
* SPDX-License-Identifier: GPL-3.0-or-later
6+
*/
7+
8+
package com.nextcloud.talk.models.json.passwordResult
9+
10+
import android.os.Parcelable
11+
import com.bluelinelabs.logansquare.annotation.JsonField
12+
import com.bluelinelabs.logansquare.annotation.JsonObject
13+
import kotlinx.parcelize.Parcelize
14+
15+
@Parcelize
16+
@JsonObject
17+
data class PasswordResult(
18+
@JsonField(name = ["passed"])
19+
var passed: Boolean?,
20+
@JsonField(name = ["reason"])
21+
var reason: String?
22+
) : Parcelable {
23+
// This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject'
24+
constructor() : this(null, null)
25+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Nextcloud Talk - Android Client
3+
*
4+
* SPDX-FileCopyrightText: 2026 Your Name <your@email.com>
5+
* SPDX-License-Identifier: GPL-3.0-or-later
6+
*/
7+
8+
package com.nextcloud.talk.models.json.passwordResult
9+
10+
import android.os.Parcelable
11+
import com.bluelinelabs.logansquare.annotation.JsonField
12+
import com.bluelinelabs.logansquare.annotation.JsonObject
13+
import com.nextcloud.talk.models.json.generic.GenericMeta
14+
import kotlinx.parcelize.Parcelize
15+
16+
@Parcelize
17+
@JsonObject
18+
data class PasswordResultOCS(
19+
@JsonField(name = ["meta"])
20+
var meta: GenericMeta?,
21+
@JsonField(name = ["data"])
22+
var data: PasswordResult?
23+
) : Parcelable {
24+
// This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject'
25+
constructor() : this(null, null)
26+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Nextcloud Talk - Android Client
3+
*
4+
* SPDX-FileCopyrightText: 2026 Your Name <your@email.com>
5+
* SPDX-License-Identifier: GPL-3.0-or-later
6+
*/
7+
8+
package com.nextcloud.talk.models.json.passwordResult
9+
10+
import android.os.Parcelable
11+
import com.bluelinelabs.logansquare.annotation.JsonField
12+
import com.bluelinelabs.logansquare.annotation.JsonObject
13+
import kotlinx.parcelize.Parcelize
14+
15+
@Parcelize
16+
@JsonObject
17+
data class PasswordResultOverall(
18+
@JsonField(name = ["ocs"])
19+
var ocs: PasswordResultOCS?
20+
) : Parcelable {
21+
// This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject'
22+
constructor() : this(null)
23+
}

0 commit comments

Comments
 (0)