This commit is contained in:
2024-08-13 22:32:27 +08:00
parent c99e168c53
commit d5067ca05b
9 changed files with 212 additions and 8 deletions

View File

@@ -2,5 +2,5 @@ package com.aiosman.riderpro
object ConstVars {
// api 地址
const val BASE_SERVER = "https://api.rider-pro.com"
const val BASE_SERVER = "https://8.137.22.101:8088"
}

View File

@@ -53,7 +53,7 @@ class MainActivity : ComponentActivity() {
try {
val resp = accountService.getMyAccount()
return true
} catch (e: ServiceException) {
} catch (e: Exception) {
return false
}
}

View File

@@ -2,6 +2,7 @@ package com.aiosman.riderpro.data
import com.aiosman.riderpro.AppStore
import com.aiosman.riderpro.data.api.ApiClient
import com.aiosman.riderpro.data.api.ChangePasswordRequestBody
import com.aiosman.riderpro.data.api.LoginUserRequestBody
import com.aiosman.riderpro.data.api.RegisterRequestBody
import com.aiosman.riderpro.test.TestDatabase
@@ -63,6 +64,7 @@ interface AccountService {
suspend fun updateAvatar(uri: String)
suspend fun updateProfile(avatar: UploadImage?, nickName: String?, bio: String?)
suspend fun registerUserWithPassword(loginName: String, password: String)
suspend fun changeAccountPassword(oldPassword: String, newPassword: String)
}
class TestAccountServiceImpl : AccountService {
@@ -120,4 +122,8 @@ class TestAccountServiceImpl : AccountService {
override suspend fun registerUserWithPassword(loginName: String, password: String) {
ApiClient.api.register(RegisterRequestBody(loginName, password))
}
override suspend fun changeAccountPassword(oldPassword: String, newPassword: String) {
ApiClient.api.changePassword(ChangePasswordRequestBody(oldPassword, newPassword))
}
}

View File

@@ -7,7 +7,39 @@ import okhttp3.OkHttpClient
import okhttp3.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.security.cert.CertificateException
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager
fun getUnsafeOkHttpClient(): OkHttpClient {
return try {
// Create a trust manager that does not validate certificate chains
val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
@Throws(CertificateException::class)
override fun checkClientTrusted(chain: Array<java.security.cert.X509Certificate>, authType: String) {}
@Throws(CertificateException::class)
override fun checkServerTrusted(chain: Array<java.security.cert.X509Certificate>, authType: String) {}
override fun getAcceptedIssuers(): Array<java.security.cert.X509Certificate> = arrayOf()
})
// Install the all-trusting trust manager
val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, trustAllCerts, java.security.SecureRandom())
// Create an ssl socket factory with our all-trusting manager
val sslSocketFactory = sslContext.socketFactory
OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager)
.hostnameVerifier { _, _ -> true }
.addInterceptor(AuthInterceptor())
.build()
} catch (e: Exception) {
throw RuntimeException(e)
}
}
class AuthInterceptor() : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val requestBuilder = chain.request().newBuilder()
@@ -21,9 +53,7 @@ object ApiClient {
const val BASE_API_URL = "${BASE_SERVER}/api/v1"
const val RETROFIT_URL = "${BASE_API_URL}/"
private val okHttpClient: OkHttpClient by lazy {
OkHttpClient.Builder()
.addInterceptor(AuthInterceptor())
.build()
getUnsafeOkHttpClient()
}
private val retrofit: Retrofit by lazy {
Retrofit.Builder()

View File

@@ -52,6 +52,13 @@ data class CommentRequestBody(
val content: String
)
data class ChangePasswordRequestBody(
@SerializedName("currentPassword")
val oldPassword: String = "",
@SerializedName("newPassword")
val newPassword: String = ""
)
interface RiderProAPI {
@POST("register")
suspend fun register(@Body body: RegisterRequestBody): Response<Unit>
@@ -136,6 +143,11 @@ interface RiderProAPI {
@Part("nickname") nickname: RequestBody?,
): Response<Unit>
@POST("account/my/password")
suspend fun changePassword(
@Body body: ChangePasswordRequestBody
): Response<Unit>
@GET("profile/{id}")
suspend fun getAccountProfileById(
@Path("id") id: Int

View File

@@ -1,5 +1,6 @@
package com.aiosman.riderpro.ui
import ChangePasswordScreen
import ImageViewer
import ModificationListScreen
import androidx.compose.animation.ExperimentalSharedTransitionApi
@@ -64,6 +65,7 @@ sealed class NavigationRoute(
data object EmailSignUp : NavigationRoute("EmailSignUp")
data object AccountEdit : NavigationRoute("AccountEditScreen")
data object ImageViewer : NavigationRoute("ImageViewer")
data object ChangePasswordScreen : NavigationRoute("ChangePasswordScreen")
}
@@ -184,6 +186,9 @@ fun NavigationController(
ImageViewer()
}
}
composable(route = NavigationRoute.ChangePasswordScreen.route) {
ChangePasswordScreen()
}
}

View File

@@ -0,0 +1,85 @@
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.unit.dp
import com.aiosman.riderpro.LocalNavController
import com.aiosman.riderpro.data.AccountService
import com.aiosman.riderpro.data.TestAccountServiceImpl
import kotlinx.coroutines.launch
class ChangePasswordViewModel {
val accountService :AccountService = TestAccountServiceImpl()
suspend fun changePassword(currentPassword: String, newPassword: String) {
accountService.changeAccountPassword(currentPassword, newPassword)
}
}
@Composable
fun ChangePasswordScreen(
) {
val viewModel = remember { ChangePasswordViewModel() }
var currentPassword by remember { mutableStateOf("") }
var newPassword by remember { mutableStateOf("") }
var confirmPassword by remember { mutableStateOf("") }
var errorMessage by remember { mutableStateOf("") }
val scope = rememberCoroutineScope()
val navController = LocalNavController.current
Scaffold { paddingValues ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues),
verticalArrangement = Arrangement.Center
) {
TextField(
value = currentPassword,
onValueChange = { currentPassword = it },
label = { Text("Current Password") },
visualTransformation = PasswordVisualTransformation(),
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = newPassword,
onValueChange = { newPassword = it },
label = { Text("New Password") },
visualTransformation = PasswordVisualTransformation(),
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = confirmPassword,
onValueChange = { confirmPassword = it },
label = { Text("Confirm New Password") },
visualTransformation = PasswordVisualTransformation(),
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
if (errorMessage.isNotEmpty()) {
Text(
text = errorMessage,
color = MaterialTheme.colorScheme.error,
modifier = Modifier.padding(bottom = 16.dp)
)
}
Button(
onClick = {
if (newPassword == confirmPassword) {
scope.launch {
viewModel.changePassword(currentPassword, newPassword)
navController.popBackStack()
}
} else {
errorMessage = "Passwords do not match"
}
},
modifier = Modifier.fillMaxWidth()
) {
Text("Change Password")
}
}
}
}

View File

@@ -76,7 +76,6 @@ fun ProfilePage() {
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Top,
) {
item {
Box(
modifier = Modifier
@@ -116,6 +115,13 @@ fun ProfilePage() {
}, text = {
Text("Edit")
})
DropdownMenuItem(onClick = {
scope.launch {
navController.navigate(NavigationRoute.ChangePasswordScreen.route)
}
}, text = {
Text("Change password")
})
}
}

View File

@@ -0,0 +1,60 @@
package com.aiosman.riderpro.ui.splash
import android.window.SplashScreen
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.aiosman.riderpro.R
@Composable
fun SplashScreen() {
Scaffold {
it
Box(
modifier = Modifier.fillMaxSize()
) {
// to bottom
Box(
contentAlignment = Alignment.TopCenter,
modifier = Modifier.padding(top = 211.dp)
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth()
) {
Image(
painter = painterResource(id = R.mipmap.rider_pro_logo),
contentDescription = "Rider Pro",
modifier = Modifier
.width(108.dp)
.height(45.dp)
)
Spacer(modifier = Modifier.height(32.dp))
Text(
"Connecting Riders".uppercase(),
fontSize = 28.sp,
fontWeight = FontWeight.Bold
)
Text("Worldwide".uppercase(), fontSize = 28.sp, fontWeight = FontWeight.Bold)
}
}
}
}
}