更新重置密码
This commit is contained in:
@@ -6,6 +6,7 @@ import com.aiosman.riderpro.data.api.GoogleRegisterRequestBody
|
|||||||
import com.aiosman.riderpro.data.api.LoginUserRequestBody
|
import com.aiosman.riderpro.data.api.LoginUserRequestBody
|
||||||
import com.aiosman.riderpro.data.api.RegisterMessageChannelRequestBody
|
import com.aiosman.riderpro.data.api.RegisterMessageChannelRequestBody
|
||||||
import com.aiosman.riderpro.data.api.RegisterRequestBody
|
import com.aiosman.riderpro.data.api.RegisterRequestBody
|
||||||
|
import com.aiosman.riderpro.data.api.ResetPasswordRequestBody
|
||||||
import com.aiosman.riderpro.data.api.UpdateNoticeRequestBody
|
import com.aiosman.riderpro.data.api.UpdateNoticeRequestBody
|
||||||
import com.aiosman.riderpro.entity.AccountFavouriteEntity
|
import com.aiosman.riderpro.entity.AccountFavouriteEntity
|
||||||
import com.aiosman.riderpro.entity.AccountLikeEntity
|
import com.aiosman.riderpro.entity.AccountLikeEntity
|
||||||
@@ -339,6 +340,9 @@ interface AccountService {
|
|||||||
suspend fun updateNotice(payload: UpdateNoticeRequestBody)
|
suspend fun updateNotice(payload: UpdateNoticeRequestBody)
|
||||||
|
|
||||||
suspend fun registerMessageChannel(client: String, identifier: String)
|
suspend fun registerMessageChannel(client: String, identifier: String)
|
||||||
|
|
||||||
|
suspend fun resetPassword(email: String)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class AccountServiceImpl : AccountService {
|
class AccountServiceImpl : AccountService {
|
||||||
@@ -455,4 +459,12 @@ class AccountServiceImpl : AccountService {
|
|||||||
ApiClient.api.registerMessageChannel(RegisterMessageChannelRequestBody(client, identifier))
|
ApiClient.api.registerMessageChannel(RegisterMessageChannelRequestBody(client, identifier))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun resetPassword(email: String) {
|
||||||
|
ApiClient.api.resetPassword(
|
||||||
|
ResetPasswordRequestBody(
|
||||||
|
username = email
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,6 @@ import android.icu.text.SimpleDateFormat
|
|||||||
import android.icu.util.TimeZone
|
import android.icu.util.TimeZone
|
||||||
import com.aiosman.riderpro.AppStore
|
import com.aiosman.riderpro.AppStore
|
||||||
import com.aiosman.riderpro.ConstVars
|
import com.aiosman.riderpro.ConstVars
|
||||||
import com.aiosman.riderpro.data.ServiceException
|
|
||||||
import com.auth0.android.jwt.JWT
|
import com.auth0.android.jwt.JWT
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
|
|||||||
@@ -92,7 +92,10 @@ data class RegisterMessageChannelRequestBody(
|
|||||||
@SerializedName("identifier")
|
@SerializedName("identifier")
|
||||||
val identifier: String,
|
val identifier: String,
|
||||||
)
|
)
|
||||||
|
data class ResetPasswordRequestBody(
|
||||||
|
@SerializedName("username")
|
||||||
|
val username: String,
|
||||||
|
)
|
||||||
interface RiderProAPI {
|
interface RiderProAPI {
|
||||||
@POST("register")
|
@POST("register")
|
||||||
suspend fun register(@Body body: RegisterRequestBody): Response<Unit>
|
suspend fun register(@Body body: RegisterRequestBody): Response<Unit>
|
||||||
@@ -270,4 +273,8 @@ interface RiderProAPI {
|
|||||||
@Path("id") id: Int
|
@Path("id") id: Int
|
||||||
): Response<Unit>
|
): Response<Unit>
|
||||||
|
|
||||||
|
@POST("account/my/password/reset")
|
||||||
|
suspend fun resetPassword(
|
||||||
|
@Body body: ResetPasswordRequestBody
|
||||||
|
): Response<Unit>
|
||||||
}
|
}
|
||||||
@@ -28,6 +28,7 @@ import com.aiosman.riderpro.LocalAnimatedContentScope
|
|||||||
import com.aiosman.riderpro.LocalNavController
|
import com.aiosman.riderpro.LocalNavController
|
||||||
import com.aiosman.riderpro.LocalSharedTransitionScope
|
import com.aiosman.riderpro.LocalSharedTransitionScope
|
||||||
import com.aiosman.riderpro.ui.account.AccountEditScreen2
|
import com.aiosman.riderpro.ui.account.AccountEditScreen2
|
||||||
|
import com.aiosman.riderpro.ui.account.ResetPasswordScreen
|
||||||
import com.aiosman.riderpro.ui.comment.CommentsScreen
|
import com.aiosman.riderpro.ui.comment.CommentsScreen
|
||||||
import com.aiosman.riderpro.ui.favourite.FavouriteNoticeScreen
|
import com.aiosman.riderpro.ui.favourite.FavouriteNoticeScreen
|
||||||
import com.aiosman.riderpro.ui.follower.FollowerListScreen
|
import com.aiosman.riderpro.ui.follower.FollowerListScreen
|
||||||
@@ -80,6 +81,7 @@ sealed class NavigationRoute(
|
|||||||
data object Search : NavigationRoute("Search")
|
data object Search : NavigationRoute("Search")
|
||||||
data object FollowerList : NavigationRoute("FollowerList/{id}")
|
data object FollowerList : NavigationRoute("FollowerList/{id}")
|
||||||
data object FollowingList : NavigationRoute("FollowingList/{id}")
|
data object FollowingList : NavigationRoute("FollowingList/{id}")
|
||||||
|
data object ResetPassword : NavigationRoute("ResetPassword")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -262,6 +264,13 @@ fun NavigationController(
|
|||||||
FollowingListScreen(it.arguments?.getInt("id")!!)
|
FollowingListScreen(it.arguments?.getInt("id")!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
composable(route = NavigationRoute.ResetPassword.route) {
|
||||||
|
CompositionLocalProvider(
|
||||||
|
LocalAnimatedContentScope provides this,
|
||||||
|
) {
|
||||||
|
ResetPasswordScreen()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,160 @@
|
|||||||
|
package com.aiosman.riderpro.ui.account
|
||||||
|
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.material.CircularProgressIndicator
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.aiosman.riderpro.LocalNavController
|
||||||
|
import com.aiosman.riderpro.R
|
||||||
|
import com.aiosman.riderpro.data.AccountService
|
||||||
|
import com.aiosman.riderpro.data.AccountServiceImpl
|
||||||
|
import com.aiosman.riderpro.ui.comment.NoticeScreenHeader
|
||||||
|
import com.aiosman.riderpro.ui.composables.ActionButton
|
||||||
|
import com.aiosman.riderpro.ui.composables.StatusBarSpacer
|
||||||
|
import com.aiosman.riderpro.ui.composables.TextInputField
|
||||||
|
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ResetPasswordScreen() {
|
||||||
|
var username by remember { mutableStateOf("") }
|
||||||
|
val accountService: AccountService = AccountServiceImpl()
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
val context = LocalContext.current
|
||||||
|
var isSendSuccess by remember { mutableStateOf<Boolean?>(null) }
|
||||||
|
var isLoading by remember { mutableStateOf(false) }
|
||||||
|
val navController = LocalNavController.current
|
||||||
|
|
||||||
|
fun resetPassword() {
|
||||||
|
scope.launch {
|
||||||
|
isLoading = true
|
||||||
|
try {
|
||||||
|
accountService.resetPassword(username)
|
||||||
|
isSendSuccess = true
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show()
|
||||||
|
isSendSuccess = false
|
||||||
|
} finally {
|
||||||
|
isLoading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
StatusBarSpacer()
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.padding(
|
||||||
|
start = 16.dp,
|
||||||
|
end = 16.dp,
|
||||||
|
top = 16.dp,
|
||||||
|
bottom = 0.dp
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
NoticeScreenHeader(
|
||||||
|
"RECOVER ACCOUNT",
|
||||||
|
moreIcon = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(horizontal = 24.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Spacer(modifier = Modifier.height(36.dp))
|
||||||
|
|
||||||
|
if (isSendSuccess != null) {
|
||||||
|
if (isSendSuccess!!) {
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
Text(
|
||||||
|
text = "Reset password email has been sent to your email address",
|
||||||
|
style = TextStyle(
|
||||||
|
color = Color(0xFF333333),
|
||||||
|
fontSize = 14.sp,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
Text(
|
||||||
|
text = "Failed to send reset password email",
|
||||||
|
style = TextStyle(
|
||||||
|
color = Color(0xFF333333),
|
||||||
|
fontSize = 14.sp,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(40.dp))
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier.noRippleClickable {
|
||||||
|
navController.popBackStack()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.drawable.rider_pro_nav_back),
|
||||||
|
contentDescription = "Back",
|
||||||
|
modifier = Modifier.size(24.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
androidx.compose.material3.Text(
|
||||||
|
stringResource(R.string.back_upper),
|
||||||
|
color = Color.Black,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Spacer(modifier = Modifier.height(120.dp))
|
||||||
|
TextInputField(
|
||||||
|
text = username,
|
||||||
|
onValueChange = { username = it },
|
||||||
|
label = stringResource(R.string.login_email_label),
|
||||||
|
hint = stringResource(R.string.text_hint_email),
|
||||||
|
enabled = !isLoading
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(72.dp))
|
||||||
|
if (isLoading) {
|
||||||
|
CircularProgressIndicator()
|
||||||
|
} else {
|
||||||
|
ActionButton(
|
||||||
|
modifier = Modifier
|
||||||
|
.width(345.dp)
|
||||||
|
.height(48.dp),
|
||||||
|
text = "Recover Account",
|
||||||
|
backgroundImage = R.mipmap.rider_pro_signup_red_bg
|
||||||
|
) {
|
||||||
|
resetPassword()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,7 +43,8 @@ fun TextInputField(
|
|||||||
password: Boolean = false,
|
password: Boolean = false,
|
||||||
label: String? = null,
|
label: String? = null,
|
||||||
hint: String? = null,
|
hint: String? = null,
|
||||||
error: String? = null
|
error: String? = null,
|
||||||
|
enabled: Boolean = true
|
||||||
) {
|
) {
|
||||||
var showPassword by remember { mutableStateOf(!password) }
|
var showPassword by remember { mutableStateOf(!password) }
|
||||||
var isFocused by remember { mutableStateOf(false) }
|
var isFocused by remember { mutableStateOf(false) }
|
||||||
@@ -74,6 +75,7 @@ fun TextInputField(
|
|||||||
),
|
),
|
||||||
visualTransformation = if (showPassword) VisualTransformation.None else PasswordVisualTransformation(),
|
visualTransformation = if (showPassword) VisualTransformation.None else PasswordVisualTransformation(),
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
|
enabled = enabled
|
||||||
)
|
)
|
||||||
if (password) {
|
if (password) {
|
||||||
Image(
|
Image(
|
||||||
|
|||||||
@@ -197,7 +197,9 @@ fun UserAuthScreen() {
|
|||||||
fontSize = 12.sp
|
fontSize = 12.sp
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
Text(stringResource(R.string.forgot_password), fontSize = 12.sp)
|
Text(stringResource(R.string.forgot_password), fontSize = 12.sp, modifier = Modifier.noRippleClickable {
|
||||||
|
navController.navigate(NavigationRoute.ResetPassword.route)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.height(64.dp))
|
Spacer(modifier = Modifier.height(64.dp))
|
||||||
@@ -210,7 +212,6 @@ fun UserAuthScreen() {
|
|||||||
) {
|
) {
|
||||||
onLogin()
|
onLogin()
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(48.dp))
|
Spacer(modifier = Modifier.height(48.dp))
|
||||||
Text(stringResource(R.string.or_login_with), color = Color(0xFF999999))
|
Text(stringResource(R.string.or_login_with), color = Color(0xFF999999))
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|||||||
Reference in New Issue
Block a user