Skip to content

Commit 8569d78

Browse files
committed
add password logic
Signed-off-by: sowjanyakch <sowjanya.kch@gmail.com>
1 parent 87949c1 commit 8569d78

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
@@ -591,6 +591,7 @@ fun ConversationOptions(
591591
@Composable
592592
fun ShowChangePassword(onDismiss: () -> Unit, conversationCreationViewModel: ConversationCreationViewModel) {
593593
var changedPassword by rememberSaveable { mutableStateOf("") }
594+
val passwordValidationState by conversationCreationViewModel.validPasswordViewState.collectAsState()
594595
Dialog(onDismissRequest = {
595596
onDismiss()
596597
}) {
@@ -609,17 +610,42 @@ fun ShowChangePassword(onDismiss: () -> Unit, conversationCreationViewModel: Con
609610
verticalArrangement = Arrangement.Center,
610611
horizontalAlignment = Alignment.CenterHorizontally
611612
) {
613+
val validatePasswordUrl = conversationCreationViewModel.currentUser.capabilities?.passwordCapability?.api?.validatePasswordApi
612614
Text(text = stringResource(id = R.string.nc_set_new_password), fontWeight = FontWeight.SemiBold)
613615
Spacer(modifier = Modifier.height(16.dp))
614616
OutlinedTextField(
615617
value = changedPassword,
616618
onValueChange = {
617619
changedPassword = it
620+
if (validatePasswordUrl != null) {
621+
conversationCreationViewModel.validatePassword(validatePasswordUrl, it)
622+
}
618623
},
619624
label = { Text(text = stringResource(id = R.string.nc_password)) },
620625
singleLine = true
621626
)
622-
Spacer(modifier = Modifier.height(16.dp))
627+
Spacer(modifier = Modifier.height(8.dp))
628+
when (passwordValidationState) {
629+
is ValidPasswordUiState.Success -> Text(
630+
text = (passwordValidationState as ValidPasswordUiState.Success).result.reason!!,
631+
color = if ((passwordValidationState as ValidPasswordUiState.Success).result.passed == false) {
632+
colorResource(
633+
id = R.color
634+
.nc_darkRed
635+
)
636+
} else {
637+
colorResource(id = R.color.nc_darkGreen)
638+
},
639+
modifier = Modifier.fillMaxWidth()
640+
)
641+
642+
is ValidPasswordUiState.Error -> {
643+
Text(text = (passwordValidationState as ValidPasswordUiState.Error).message)
644+
}
645+
646+
else -> {
647+
}
648+
}
623649

624650
Column(
625651
modifier = Modifier
@@ -634,7 +660,9 @@ fun ShowChangePassword(onDismiss: () -> Unit, conversationCreationViewModel: Con
634660
conversationCreationViewModel.isPasswordEnabled.value = true
635661
onDismiss()
636662
},
637-
enabled = changedPassword.isNotEmpty() && changedPassword.isNotBlank(),
663+
enabled = changedPassword.isNotEmpty() &&
664+
changedPassword.isNotBlank() &&
665+
(passwordValidationState as ValidPasswordUiState.Success).result.passed == true,
638666
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp)
639667
) {
640668
Text(text = stringResource(id = R.string.nc_change_password))
@@ -668,18 +696,48 @@ fun ShowChangePassword(onDismiss: () -> Unit, conversationCreationViewModel: Con
668696
@Composable
669697
fun ShowPasswordDialog(onDismiss: () -> Unit, conversationCreationViewModel: ConversationCreationViewModel) {
670698
var password by rememberSaveable { mutableStateOf("") }
699+
val passwordValidationState by conversationCreationViewModel.validPasswordViewState.collectAsState()
700+
val validatePasswordUrl = conversationCreationViewModel.currentUser.capabilities?.passwordCapability?.api?.validatePasswordApi
671701
AlertDialog(
672702
containerColor = colorResource(id = R.color.dialog_background),
673703
onDismissRequest = onDismiss,
674704
title = { Text(text = stringResource(id = R.string.nc_set_password)) },
675705
text = {
676-
TextField(
677-
value = password,
678-
onValueChange = {
679-
password = it
680-
},
681-
label = { Text(text = stringResource(id = R.string.nc_guest_access_password_dialog_hint)) }
682-
)
706+
Row {
707+
TextField(
708+
value = password,
709+
onValueChange = {
710+
password = it
711+
if (validatePasswordUrl != null) {
712+
conversationCreationViewModel.validatePassword(validatePasswordUrl, it)
713+
}
714+
},
715+
label = { Text(text = stringResource(id = R.string.nc_guest_access_password_dialog_hint)) }
716+
)
717+
Spacer(modifier = Modifier.height(8.dp))
718+
719+
when (passwordValidationState) {
720+
is ValidPasswordUiState.Success -> Text(
721+
text = (passwordValidationState as ValidPasswordUiState.Success).result.reason!!,
722+
color = if ((passwordValidationState as ValidPasswordUiState.Success).result.passed == false) {
723+
colorResource(
724+
id = R.color
725+
.nc_darkRed
726+
)
727+
} else {
728+
colorResource(id = R.color.nc_darkGreen)
729+
},
730+
modifier = Modifier.fillMaxWidth()
731+
)
732+
733+
is ValidPasswordUiState.Error -> {
734+
Text(text = (passwordValidationState as ValidPasswordUiState.Error).message)
735+
}
736+
737+
else -> {
738+
}
739+
}
740+
}
683741
},
684742
confirmButton = {
685743
TextButton(

app/src/main/java/com/nextcloud/talk/conversationcreation/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/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/ConversationCreationViewModel.kt

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

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

@@ -80,6 +84,24 @@ class ConversationCreationViewModel @Inject constructor(
8084
_conversationDescription.value = conversationDescription
8185
}
8286

87+
@Suppress("Detekt.TooGenericExceptionCaught")
88+
fun validatePassword(url: String, password: String) {
89+
val credentials = ApiUtils.getCredentials(_currentUser.username, _currentUser.token) ?: ""
90+
viewModelScope.launch {
91+
try {
92+
val passwordResult = repository.validatePassword(
93+
credentials,
94+
url,
95+
password
96+
)
97+
98+
_validPasswordViewState.value = ValidPasswordUiState.Success(passwordResult.ocs?.data!!)
99+
} catch (exception: Exception) {
100+
_validPasswordViewState.value = ValidPasswordUiState.Error(exception.message ?: "")
101+
}
102+
}
103+
}
104+
83105
@Suppress("Detekt.TooGenericExceptionCaught")
84106
fun createRoomAndAddParticipants(
85107
roomType: String,
@@ -257,3 +279,9 @@ sealed class AddParticipantsUiState {
257279
data class Success(val participants: List<Conversation>?) : AddParticipantsUiState()
258280
data class Error(val message: String) : AddParticipantsUiState()
259281
}
282+
283+
sealed class ValidPasswordUiState {
284+
data object None : ValidPasswordUiState()
285+
data class Success(val result: PasswordResult) : ValidPasswordUiState()
286+
data class Error(val message: String) : ValidPasswordUiState()
287+
}
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)