diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6f2fdea..c22c2d7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -80,7 +80,6 @@ dependencies { implementation(libs.okhttp3.logging.interceptor) - // implementation(libs.therouter) // ksp(libs.therouter.ksp) } diff --git a/app/src/main/java/com/kaixed/kchat/model/response/register/Data.kt b/app/src/main/java/com/kaixed/kchat/model/response/register/Data.kt deleted file mode 100644 index 82d3d67..0000000 --- a/app/src/main/java/com/kaixed/kchat/model/response/register/Data.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.kaixed.kchat.model.response.register - -import kotlinx.serialization.Serializable - -@Serializable -data class Data( - val avatarUrl: String, - val nickname: String, - val signature: String, - val status: String?, - val username: String -) diff --git a/app/src/main/java/com/kaixed/kchat/model/response/register/Register.kt b/app/src/main/java/com/kaixed/kchat/model/response/register/Register.kt index 9fc8ade..0a1abbb 100644 --- a/app/src/main/java/com/kaixed/kchat/model/response/register/Register.kt +++ b/app/src/main/java/com/kaixed/kchat/model/response/register/Register.kt @@ -4,7 +4,9 @@ import kotlinx.serialization.Serializable @Serializable data class Register( - val code: String, - val `data`: Data?, - val msg: String + val avatarUrl: String, + val nickname: String, + val signature: String, + val status: String?, + val username: String ) diff --git a/app/src/main/java/com/kaixed/kchat/model/search/SearchUser.kt b/app/src/main/java/com/kaixed/kchat/model/search/SearchUser.kt new file mode 100644 index 0000000..cf1f291 --- /dev/null +++ b/app/src/main/java/com/kaixed/kchat/model/search/SearchUser.kt @@ -0,0 +1,49 @@ +package com.kaixed.kchat.model.search + +import android.os.Parcel +import android.os.Parcelable +import kotlinx.serialization.Serializable + +/** + * @Author: kaixed + * @Date: 2024/9/22 22:58 + */ + +@Serializable +data class SearchUser( + val username: String, + val nickname: String, + val signature: String, + val avatarUrl: String, + val status: String?, +) : Parcelable { + constructor(parcel: Parcel) : this( + parcel.readString() ?: "", + parcel.readString() ?: "", + parcel.readString() ?: "", + parcel.readString() ?: "", + parcel.readString() + ) + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeString(username) + parcel.writeString(nickname) + parcel.writeString(signature) + parcel.writeString(avatarUrl) + parcel.writeString(status) + } + + override fun describeContents(): Int { + return 0 + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): SearchUser { + return SearchUser(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } +} diff --git a/app/src/main/java/com/kaixed/kchat/network/ApiResponse.kt b/app/src/main/java/com/kaixed/kchat/network/ApiResponse.kt new file mode 100644 index 0000000..ba73e59 --- /dev/null +++ b/app/src/main/java/com/kaixed/kchat/network/ApiResponse.kt @@ -0,0 +1,17 @@ +package com.kaixed.kchat.network + +/** + * @Author: kaixed + * @Date: 2024/11/23 13:25 + */ +data class ApiResponse( + val code: String, + val msg: String, + val `data`: T? +) : BaseResponse() { + + override fun isSuccess(): Boolean = code == "200" + override fun getResponseCode() = code + override fun getResponseData() = data + override fun getResponseMsg() = msg +} \ No newline at end of file diff --git a/app/src/main/java/com/kaixed/kchat/network/BaseResponse.kt b/app/src/main/java/com/kaixed/kchat/network/BaseResponse.kt new file mode 100644 index 0000000..0761c5c --- /dev/null +++ b/app/src/main/java/com/kaixed/kchat/network/BaseResponse.kt @@ -0,0 +1,12 @@ +package com.kaixed.kchat.network + +abstract class BaseResponse { + + abstract fun isSuccess(): Boolean + + abstract fun getResponseData(): T + + abstract fun getResponseCode(): String + + abstract fun getResponseMsg(): String +} \ No newline at end of file diff --git a/app/src/main/java/com/kaixed/kchat/network/NetResult.kt b/app/src/main/java/com/kaixed/kchat/network/NetResult.kt deleted file mode 100644 index 7a9d099..0000000 --- a/app/src/main/java/com/kaixed/kchat/network/NetResult.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.kaixed.kchat.network - -/** - * @Author: kaixed - * @Date: 2024/11/6 22:42 - */ -sealed class NetResult { - data class Loading(val message: String = "加载中...") : NetResult() - data class Success(val data: T) : NetResult() - data class Error(val exception: Throwable) : NetResult() -} \ No newline at end of file diff --git a/app/src/main/java/com/kaixed/kchat/network/NetworkHelper.kt b/app/src/main/java/com/kaixed/kchat/network/NetworkHelper.kt deleted file mode 100644 index 7f0c158..0000000 --- a/app/src/main/java/com/kaixed/kchat/network/NetworkHelper.kt +++ /dev/null @@ -1,60 +0,0 @@ -package com.kaixed.kchat.network - -import androidx.lifecycle.MutableLiveData -import kotlinx.serialization.KSerializer -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.Json -import okhttp3.Call -import okhttp3.Callback -import okhttp3.Response -import okio.IOException - -/** - * @Author: kaixed - * @Date: 2024/11/6 22:54 - */ -object NetworkHelper { - fun makeRequest( - url: String, - requestBody: Any? = null, - method: String = "POST", - serializer: KSerializer - ): MutableLiveData> { - val netResultLiveData = MutableLiveData>() - - netResultLiveData.postValue(NetResult.Loading()) - - val callback = object : Callback { - override fun onFailure(call: Call, e: IOException) { - netResultLiveData.postValue(NetResult.Error(e)) - } - - override fun onResponse(call: Call, response: Response) { - response.body?.string()?.let { responseBody -> - try { - val responseData = Json.decodeFromString(serializer, responseBody) - netResultLiveData.postValue(NetResult.Success(responseData)) - } catch (e: Exception) { - netResultLiveData.postValue(NetResult.Error(e)) - } - } - } - } - - when (method) { - "POST" -> { - val json = Json.encodeToString(requestBody) - NetworkRequest().postAsync(url, json, callback) - } - - "GET" -> { - NetworkRequest().getAsync(url, callback) - } - - else -> { - netResultLiveData.postValue(NetResult.Error(IllegalArgumentException("不支持的请求方法"))) - } - } - return netResultLiveData - } -} \ No newline at end of file diff --git a/app/src/main/java/com/kaixed/kchat/network/NetworkRequest.kt b/app/src/main/java/com/kaixed/kchat/network/NetworkRequest.kt deleted file mode 100644 index aa0d907..0000000 --- a/app/src/main/java/com/kaixed/kchat/network/NetworkRequest.kt +++ /dev/null @@ -1,76 +0,0 @@ -package com.kaixed.kchat.network - -import android.util.Log -import com.kaixed.kchat.network.OkhttpHelper.getInstance -import okhttp3.Callback -import okhttp3.MediaType.Companion.toMediaType -import okhttp3.MultipartBody -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.RequestBody -import okhttp3.RequestBody.Companion.toRequestBody - - -/** - * @Author: kaixed - * @Date: 2024/10/14 13:52 - */ - -class NetworkRequest { - - companion object { - const val TAG = "NetworkRequest" - } - - private val client: OkHttpClient = getInstance() - - fun postAsync(url: String, formBody: RequestBody, callback: Callback) { - val request = Request.Builder() - .url(url) - .post(formBody) - .build() - - val call = client.newCall(request) - call.enqueue(callback) - } - - fun postAsync(url: String, json: String, callback: Callback) { - val requestBody = json.toRequestBody("application/json".toMediaType()) - - val request = Request.Builder() - .url(url) - .post(requestBody) - .build() - - val call = client.newCall(request) - call.enqueue(callback) - } - - fun postAsync(url: String, multipartBody: MultipartBody, callback: Callback) { - - val contentType = "multipart/form-data; boundary=" + multipartBody.boundary - - Log.d("haha", contentType) - - val request = Request.Builder() - .url(url) - .post(multipartBody) - .addHeader("Connection", "keep-alive") - .addHeader("Content-Type", contentType) - .build() - - val call = client.newCall(request) - call.enqueue(callback) - } - - - fun getAsync(url: String, callback: Callback) { - val request = Request.Builder() - .url(url) - .get() - .build() - - val call = client.newCall(request) - call.enqueue(callback) - } -} diff --git a/app/src/main/java/com/kaixed/kchat/network/RetrofitClient.kt b/app/src/main/java/com/kaixed/kchat/network/RetrofitClient.kt index c0c1c04..34d9306 100644 --- a/app/src/main/java/com/kaixed/kchat/network/RetrofitClient.kt +++ b/app/src/main/java/com/kaixed/kchat/network/RetrofitClient.kt @@ -1,5 +1,6 @@ package com.kaixed.kchat.network +import com.kaixed.kchat.network.interceptor.SignInterceptor import com.kaixed.kchat.network.service.ContactService import com.kaixed.kchat.network.service.UserApiService import okhttp3.OkHttpClient @@ -14,6 +15,7 @@ import retrofit2.converter.gson.GsonConverterFactory object RetrofitClient { private const val BASE_URL = "https://app.kaixed.com/kchat/" +// private const val BASE_URL = "http://192.168.156.209:6196/" private val loggingInterceptor = HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY @@ -21,6 +23,7 @@ object RetrofitClient { private val client = OkHttpClient.Builder() .addInterceptor(loggingInterceptor) +// .addInterceptor(SignInterceptor()) // 添加签名拦截器 .build() diff --git a/app/src/main/java/com/kaixed/kchat/network/SignUtil.kt b/app/src/main/java/com/kaixed/kchat/network/SignUtil.kt new file mode 100644 index 0000000..d3e3931 --- /dev/null +++ b/app/src/main/java/com/kaixed/kchat/network/SignUtil.kt @@ -0,0 +1,115 @@ +package com.kaixed.kchat.network + +import com.google.gson.Gson +import com.google.gson.JsonObject +import com.google.gson.JsonParser +import com.kaixed.kchat.model.request.UserRequest +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.Request +import okhttp3.RequestBody.Companion.toRequestBody +import okio.Buffer +import java.io.IOException +import java.security.MessageDigest + +object SignUtil { + + // 生成签名 + fun generateSign(request: Request, timestamp: String): String { + val secretKey = "your_secret_key" + val stringBuilder = StringBuilder("timestamp=$timestamp") + + // 根据请求类型处理 GET 或 POST 请求 + when (request.method) { + "GET" -> appendUrlParams(request, stringBuilder) + "POST" -> appendPostParams(request, stringBuilder) + } + + // 拼接密钥并生成签名 + stringBuilder.append(secretKey) + println(stringBuilder.toString()) + return md5(stringBuilder.toString()) + } + + // 处理 GET 请求 URL 参数 + private fun appendUrlParams(request: Request, stringBuilder: StringBuilder) { + val url = request.url + url.queryParameterNames.forEach { name -> + val value = url.queryParameter(name) + stringBuilder.append("&$name=$value") + } + } + + // 处理 POST 请求参数,包括表单数据和 JSON 数据 + private fun appendPostParams(request: Request, stringBuilder: StringBuilder) { + val body = request.body + body?.let { + when (body.contentType()?.subtype) { + "x-www-form-urlencoded" -> appendFormParams(it, stringBuilder) + "json" -> appendJsonBody(it, stringBuilder) + } + } + } + + // 处理表单数据 + private fun appendFormParams(body: okhttp3.RequestBody, stringBuilder: StringBuilder) { + val formBody = body as okhttp3.FormBody + val sortedParams = (0 until formBody.size) + .map { Pair(formBody.name(it), formBody.value(it)) } + .sortedBy { it.first } + + sortedParams.forEach { (name, value) -> + stringBuilder.append("&$name=$value") + } + } + + // 处理 JSON 数据并排序 + private fun appendJsonBody(body: okhttp3.RequestBody, stringBuilder: StringBuilder) { + val jsonBody = getRequestBodyAsJsonObject(body) + jsonBody?.let { + val sortedJson = sortJson(it) + stringBuilder.append("&body=$sortedJson") + } + } + + // 读取 RequestBody 并解析为 JsonObject + private fun getRequestBodyAsJsonObject(body: okhttp3.RequestBody): JsonObject? { + val buffer = Buffer() + try { + body.writeTo(buffer) + val bodyString = buffer.readUtf8() + return JsonParser.parseString(bodyString).asJsonObject + } catch (e: IOException) { + e.printStackTrace() + return null + } + } + + // 排序 JSON 对象 + private fun sortJson(jsonObject: JsonObject): String { + return jsonObject.keySet() + .sorted() + .joinToString(",", "{", "}") { key -> "\"$key\":${jsonObject[key]}" } + } + + // MD5 加密函数 + private fun md5(input: String): String { + val digest = MessageDigest.getInstance("MD5") + val bytes = digest.digest(input.toByteArray()) + return bytes.joinToString("") { "%02x".format(it) } + } + + @JvmStatic + fun main(args: Array) { + val request = Request.Builder() + .url("https://app.kaixed.com/kchat/users/login/username") + .post( + Gson().toJson(UserRequest("username", "password")) + .toRequestBody("application/json".toMediaType()) + ) + .build() + + val timestamp = System.currentTimeMillis().toString() + val sign = generateSign(request, timestamp) + println("sign: $sign") + } +} diff --git a/app/src/main/java/com/kaixed/kchat/network/interceptor/SignInterceptor.kt b/app/src/main/java/com/kaixed/kchat/network/interceptor/SignInterceptor.kt new file mode 100644 index 0000000..0cc924b --- /dev/null +++ b/app/src/main/java/com/kaixed/kchat/network/interceptor/SignInterceptor.kt @@ -0,0 +1,37 @@ +package com.kaixed.kchat.network.interceptor + +import com.kaixed.kchat.network.SignUtil.generateSign +import okhttp3.Interceptor +import okhttp3.Response + +class SignInterceptor : Interceptor { + + override fun intercept(chain: Interceptor.Chain): Response { + val originalRequest = chain.request() + val urlPath = originalRequest.url.encodedPath + + val skipSignPaths = listOf( + "/users/avatar", + ) + + // 检查是否需要跳过签名 + if (skipSignPaths.any { urlPath.endsWith(it) }) { + // 直接放行请求,不做签名处理 + return chain.proceed(originalRequest) + } + + // 获取当前时间戳 + val timestamp = System.currentTimeMillis().toString() + + // 生成请求的签名 + val sign = generateSign(originalRequest, timestamp) + + // 创建新的请求,加入 sign 和 timestamp + val newRequest = originalRequest.newBuilder() + .addHeader("sign", sign) + .addHeader("timestamp", timestamp) + .build() + + return chain.proceed(newRequest) + } +} diff --git a/app/src/main/java/com/kaixed/kchat/network/service/ContactApiService.kt b/app/src/main/java/com/kaixed/kchat/network/service/ContactApiService.kt index a5999e4..8744b2c 100644 --- a/app/src/main/java/com/kaixed/kchat/network/service/ContactApiService.kt +++ b/app/src/main/java/com/kaixed/kchat/network/service/ContactApiService.kt @@ -1,12 +1,9 @@ package com.kaixed.kchat.network.service -import com.kaixed.kchat.model.friend.AcceptContactRequest -import com.kaixed.kchat.model.friend.ContactRequestResponse -import com.kaixed.kchat.model.response.ApplyFriend -import com.kaixed.kchat.model.response.friend.DeleteContact -import com.kaixed.kchat.model.response.friend.FriendList -import com.kaixed.kchat.model.response.friend.SearchFriends -import retrofit2.Response +import com.kaixed.kchat.data.objectbox.entity.Contact +import com.kaixed.kchat.model.friend.FriendRequestItem +import com.kaixed.kchat.model.search.User +import com.kaixed.kchat.network.ApiResponse import retrofit2.http.Field import retrofit2.http.FormUrlEncoded import retrofit2.http.GET @@ -20,7 +17,7 @@ interface ContactService { @POST("friend/request/list") suspend fun getContactRequestList( @Field("userId") username: String - ): Response + ): ApiResponse?> // 接受联系人请求 @FormUrlEncoded @@ -29,7 +26,7 @@ interface ContactService { @Field("requestId") contactId: String, @Field("receiverId") username: String, @Field("remark") remark: String - ): Response + ): ApiResponse // 添加联系人 @FormUrlEncoded @@ -38,26 +35,26 @@ interface ContactService { @Field("senderId") senderId: String, @Field("receiverId") receiverId: String, @Field("message") message: String - ): Response + ): ApiResponse // 搜索联系人 @GET("users/{username}") suspend fun searchContact( @Path("username") username: String - ): Response + ): ApiResponse // 获取联系人列表 @FormUrlEncoded @POST("friend/list") suspend fun getContactList( @Field("userId") username: String - ): Response + ): ApiResponse?> - // 删除好友 + // 删除联系人 @FormUrlEncoded @POST("friend/delete") suspend fun deleteContact( @Field("userId") username: String, @Field("contactId") contactId: String, - ): Response + ): ApiResponse } diff --git a/app/src/main/java/com/kaixed/kchat/network/service/UserApiService.kt b/app/src/main/java/com/kaixed/kchat/network/service/UserApiService.kt index acff838..e1f27bb 100644 --- a/app/src/main/java/com/kaixed/kchat/network/service/UserApiService.kt +++ b/app/src/main/java/com/kaixed/kchat/network/service/UserApiService.kt @@ -1,13 +1,15 @@ package com.kaixed.kchat.network.service +import com.kaixed.kchat.data.objectbox.entity.UserInfo import com.kaixed.kchat.model.request.RegisterRequest import com.kaixed.kchat.model.request.UserRequest import com.kaixed.kchat.model.response.friend.SearchFriends -import com.kaixed.kchat.model.response.login.Login import com.kaixed.kchat.model.response.register.Register -import com.kaixed.kchat.model.response.search.UserList +import com.kaixed.kchat.model.response.search.User import com.kaixed.kchat.model.response.user.ChangeNickname import com.kaixed.kchat.model.response.user.UploadAvatar +import com.kaixed.kchat.model.search.SearchUser +import com.kaixed.kchat.network.ApiResponse import okhttp3.MultipartBody import retrofit2.Response import retrofit2.http.Body @@ -29,7 +31,7 @@ interface UserApiService { @POST("users/register") suspend fun register( @Body registerRequest: RegisterRequest - ): Response + ): ApiResponse // 登录接口(根据用户名登录) @FormUrlEncoded @@ -37,7 +39,7 @@ interface UserApiService { suspend fun loginByUsername( @Field("username") username: String, @Field("password") password: String - ): Response + ): ApiResponse // 登录接口(根据电话登录) @FormUrlEncoded @@ -45,25 +47,25 @@ interface UserApiService { suspend fun loginByTelephone( @Field("telephone") telephone: String, @Field("password") password: String - ): Response + ): ApiResponse // 获取用户列表 @GET("userList/{username}") suspend fun getUserListByNickname( @Path("username") username: String - ): Response + ): ApiResponse> // 获取用户信息 @GET("users/{username}") suspend fun getUserInfo( @Path("username") username: String - ): Response + ): ApiResponse // 更改昵称接口 @POST("users/info") suspend fun changeNickname( @Body userRequest: UserRequest - ): Response + ): ApiResponse // 上传头像接口 @Multipart @@ -71,5 +73,5 @@ interface UserApiService { suspend fun uploadAvatar( @Part("username") username: String, @Part file: MultipartBody.Part - ): Response + ): ApiResponse } diff --git a/app/src/main/java/com/kaixed/kchat/repository/ContactRepository.kt b/app/src/main/java/com/kaixed/kchat/repository/ContactRepository.kt index 5f93e48..b38c7bf 100644 --- a/app/src/main/java/com/kaixed/kchat/repository/ContactRepository.kt +++ b/app/src/main/java/com/kaixed/kchat/repository/ContactRepository.kt @@ -1,20 +1,15 @@ package com.kaixed.kchat.repository -import android.util.Log import com.kaixed.kchat.data.objectbox.ObjectBox.get import com.kaixed.kchat.data.objectbox.entity.Contact import com.kaixed.kchat.data.objectbox.entity.Contact_ -import com.kaixed.kchat.model.friend.AcceptContactRequest -import com.kaixed.kchat.model.friend.ContactRequestResponse -import com.kaixed.kchat.model.response.ApplyFriend -import com.kaixed.kchat.model.response.friend.DeleteContact -import com.kaixed.kchat.model.response.friend.FriendList -import com.kaixed.kchat.model.response.friend.SearchFriends +import com.kaixed.kchat.model.friend.FriendRequestItem +import com.kaixed.kchat.model.search.User import com.kaixed.kchat.network.RetrofitClient import com.kaixed.kchat.utils.ConstantsUtil.getUsername +import com.kaixed.kchat.utils.Pinyin4jUtil +import com.kaixed.kchat.utils.handle.ContactUtil import io.objectbox.Box -import okhttp3.ResponseBody.Companion.toResponseBody -import retrofit2.Response class ContactRepository { @@ -25,12 +20,19 @@ class ContactRepository { } // 获取联系人请求列表 - suspend fun getContactRequestList(username: String): Response { + suspend fun getContactRequestList(username: String): Result?> { return try { - contactApiService.getContactRequestList(username) + val response = contactApiService.getContactRequestList(username) + if (response.isSuccess()) { + val searchUser = response.getResponseData() + searchUser?.let { + Result.success(searchUser) + } ?: Result.failure(Exception("没有好友申请")) + } else { + Result.failure(Exception(response.getResponseMsg())) + } } catch (e: Exception) { - Log.e("ContactRepository", "Get Contact Request List failed: ${e.message}") - Response.error(500, "".toResponseBody()) // 返回一个空的错误 Response + Result.failure(e) } } @@ -39,12 +41,20 @@ class ContactRepository { username: String, contactId: String, remark: String - ): Response { + ): Result { return try { - contactApiService.acceptContactRequest(contactId, username, remark) + val response = contactApiService.acceptContactRequest(contactId, username, remark) + if (response.isSuccess()) { + val searchUser = response.getResponseData() + searchUser?.let { + ContactUtil.handleContact(searchUser) + Result.success(searchUser) + } ?: Result.failure(Exception("添加好友失败")) + } else { + Result.failure(Exception(response.getResponseMsg())) + } } catch (e: Exception) { - Log.e("ContactRepository", "Accept Contact Request failed: ${e.message}") - Response.error(500, "".toResponseBody()) + Result.failure(e) } } @@ -52,47 +62,121 @@ class ContactRepository { suspend fun deleteContact( username: String, contactId: String, - ): Response { - try { - contactBox.query(Contact_.username.equal(contactId)) - return contactApiService.deleteContact(username, contactId) + ): Result { + return try { + val response = contactApiService.deleteContact(username, contactId) + if (response.isSuccess()) { + val searchUser = response.getResponseData() + searchUser?.let { + val con = + contactBox.query(Contact_.username.equal(contactId)).build().findFirst() + contactBox.remove(con!!) + Result.success(searchUser) + } ?: Result.failure(Exception("删除好友失败")) + } else { + Result.failure(Exception(response.getResponseMsg())) + } } catch (e: Exception) { - Log.e("ContactRepository", "Delete Contact failed: ${e.message}") - return Response.error(500, "".toResponseBody()) + Result.failure(e) } } // 添加联系人 - suspend fun addContact(contactId: String, message: String): Response { + suspend fun addContact(contactId: String, message: String): Result { return try { - contactApiService.addContact( + val response = contactApiService.addContact( senderId = contactId, receiverId = getUsername(), message = message ) + if (response.isSuccess()) { + val searchUser = response.getResponseData() + searchUser?.let { + Result.success(searchUser) + } ?: Result.failure(Exception("添加联系人失败")) + } else { + Result.failure(Exception(response.getResponseMsg())) + } } catch (e: Exception) { - Log.e("ContactRepository", "Add Contact failed: ${e.message}") - Response.error(500, "".toResponseBody()) + Result.failure(e) } } // 搜索联系人 - suspend fun searchContact(username: String): Response { + suspend fun searchContact(username: String): Result { return try { - contactApiService.searchContact(username) + val response = contactApiService.searchContact(username) + if (response.isSuccess()) { + val searchUser = response.getResponseData() + searchUser?.let { + Result.success(searchUser) + } ?: Result.failure(Exception("没有找到用户")) + } else { + Result.failure(Exception(response.getResponseMsg())) + } } catch (e: Exception) { - Log.e("ContactRepository", "Search Contact failed: ${e.message}") - Response.error(500, "".toResponseBody()) + Result.failure(e) } } // 获取联系人列表 - suspend fun getContactList(username: String): Response { + suspend fun getContactList(username: String): Result?> { return try { - contactApiService.getContactList(username) + val response = contactApiService.getContactList(username) + if (response.isSuccess()) { + val searchUsers = response.getResponseData() + searchUsers?.let { + + val uiFriendList = searchUsers?.map { networkItem -> + mapToFriendItem(networkItem) // 数据转换 + }?.sortedWith { f1, f2 -> + val str1 = f1.remarkquanpin ?: f1.quanpin ?: f1.nickname + val str2 = f2.remarkquanpin ?: f2.quanpin ?: f2.nickname + + val type1 = when { + str1.matches(Regex("[a-zA-Z]+")) -> 1 // 字母 + str1.matches(Regex("[0-9]+")) -> 2 // 数字 + else -> 3 // 特殊字符 + } + + val type2 = when { + str2.matches(Regex("[a-zA-Z]+")) -> 1 // 字母 + str2.matches(Regex("[0-9]+")) -> 2 // 数字 + else -> 3 // 特殊字符 + } + + // 比较类型,如果相同再按字母升序排序 + if (type1 != type2) { + type1 - type2 // 按类型排序 + } else { + str1.compareTo(str2) // 如果类型相同,按字母顺序排序 + } + } + + // 设置是否显示分组头 + uiFriendList?.forEachIndexed { index, item -> + item.showHeader = + (index == 0 || item.quanpin?.get(index) != uiFriendList[index - 1].quanpin?.get( + index - 1 + )) + } + + Result.success(searchUsers) + } ?: Result.failure(Exception("当前没有好友")) + } else { + Result.failure(Exception(response.getResponseMsg())) + } } catch (e: Exception) { - Log.e("ContactRepository", "Get Contact List failed: ${e.message}") - Response.error(500, "".toResponseBody()) + Result.failure(e) } } + + private fun mapToFriendItem(response: Contact): Contact { + val pinyin = Pinyin4jUtil.toPinyin(response.nickname) + response.remark?.let { + response.remarkquanpin = Pinyin4jUtil.toPinyin(it) + } + response.quanpin = pinyin + return response + } } diff --git a/app/src/main/java/com/kaixed/kchat/repository/UserAuthRepository.kt b/app/src/main/java/com/kaixed/kchat/repository/UserAuthRepository.kt new file mode 100644 index 0000000..7984b74 --- /dev/null +++ b/app/src/main/java/com/kaixed/kchat/repository/UserAuthRepository.kt @@ -0,0 +1,103 @@ +package com.kaixed.kchat.repository + +import com.kaixed.kchat.data.objectbox.ObjectBox.get +import com.kaixed.kchat.data.objectbox.entity.UserInfo +import com.kaixed.kchat.data.objectbox.entity.UserInfo_ +import com.kaixed.kchat.model.request.RegisterRequest +import com.kaixed.kchat.model.response.register.Register +import com.kaixed.kchat.network.RetrofitClient +import com.kaixed.kchat.utils.Constants.MMKV_USER_SESSION +import com.tencent.mmkv.MMKV +import io.objectbox.Box + +/** + * @Author: kaixed + * @Date: 2024/11/23 14:15 + */ +class UserAuthRepository { + + private val userApiService = RetrofitClient.userApiService + + private val userInfoBox: Box by lazy { get().boxFor(UserInfo::class.java) } + + private val mmkv by lazy { MMKV.mmkvWithID(MMKV_USER_SESSION) } + + // 用户注册 + suspend fun register(registerRequest: RegisterRequest): Result { + return try { + val response = userApiService.register(registerRequest) + if (response.isSuccess()) { + val register = response.getResponseData() + register?.let { + val userInfo = UserInfo( + username = register.username, + nickname = register.nickname, + avatarUrl = "", + signature = "", + telephone = registerRequest.telephone + ) + userInfoBox.put(userInfo) + + Result.success(register) + } ?: Result.failure(Exception("注册成功,但未返回用户数据")) + } else { + Result.failure(Exception(response.getResponseMsg())) + } + } catch (e: Exception) { + Result.failure(e) + } + } + + // 登录方法 + suspend fun loginByUsername(username: String, password: String): Result { + return try { + val response = userApiService.loginByUsername(username, password) + if (response.isSuccess()) { + val userInfo = response.getResponseData() + if (userInfo != null) { + updateDb(userInfo) + Result.success(userInfo) + } else { + Result.failure(Exception("登录成功,但未返回用户数据")) + } + } else { + Result.failure(Exception(response.getResponseMsg())) + } + } catch (e: Exception) { + Result.failure(e) + } + } + + private fun updateDb(userInfo: UserInfo) { + mmkv.apply { + encode("username", userInfo.username) + encode("nickname", userInfo.nickname) + encode("avatarUrl", userInfo.avatarUrl) + } + MMKV.defaultMMKV().encode("userLoginStatus", true) + val user = userInfoBox + .query(UserInfo_.username.equal(userInfo.username)) + .build() + .findFirst() + if (user == null) { + userInfoBox.put(userInfo) + } + } + + suspend fun loginByTelephone(telephone: String, password: String): Result { + return try { + val response = userApiService.loginByTelephone(telephone, password) + if (response.isSuccess()) { + val userInfo = response.getResponseData() + userInfo?.let { + updateDb(userInfo) + Result.success(userInfo) + } ?: Result.failure(Exception("登录成功,但未返回用户数据")) + } else { + Result.failure(Exception(response.getResponseMsg())) + } + } catch (e: Exception) { + Result.failure(e) + } + } +} diff --git a/app/src/main/java/com/kaixed/kchat/repository/UserProfileRepository.kt b/app/src/main/java/com/kaixed/kchat/repository/UserProfileRepository.kt new file mode 100644 index 0000000..62b68a6 --- /dev/null +++ b/app/src/main/java/com/kaixed/kchat/repository/UserProfileRepository.kt @@ -0,0 +1,98 @@ +package com.kaixed.kchat.repository + +import com.kaixed.kchat.data.objectbox.ObjectBox.get +import com.kaixed.kchat.data.objectbox.entity.UserInfo +import com.kaixed.kchat.data.objectbox.entity.UserInfo_ +import com.kaixed.kchat.model.request.UserRequest +import com.kaixed.kchat.model.search.SearchUser +import com.kaixed.kchat.network.RetrofitClient +import com.kaixed.kchat.utils.Constants.MMKV_USER_SESSION +import com.kaixed.kchat.utils.Constants.NICKNAME_KEY +import com.kaixed.kchat.utils.ConstantsUtil.getUsername +import com.tencent.mmkv.MMKV +import okhttp3.MultipartBody + +/** + * @Author: kaixed + * @Date: 2024/11/23 14:15 + */ +class UserProfileRepository { + + private val userApiService = RetrofitClient.userApiService + + // 获取用户信息 + suspend fun getUserInfo(username: String): Result { + return try { + val response = userApiService.getUserInfo(username) + if (response.isSuccess()) { + val searchUser = response.getResponseData() + searchUser?.let { + Result.success(searchUser) + } ?: Result.failure(Exception("用户不存在")) + } else { + Result.failure(Exception(response.getResponseMsg())) + } + } catch (e: Exception) { + Result.failure(e) + } + } + + // 修改昵称 + suspend fun changeNickname(userRequest: UserRequest): Result { + return try { + val response = userApiService.changeNickname(userRequest) + if (response.isSuccess()) { + updateNickname(response.getResponseData().toString()) + Result.success(true) + } else { + Result.failure(Exception(response.getResponseMsg())) + } + } catch (e: Exception) { + Result.failure(e) + } + } + + // 上传头像 + suspend fun uploadAvatar(file: MultipartBody.Part, username: String): Result { + return try { + val response = userApiService.uploadAvatar(username, file) + if (response.isSuccess()) { + val data = response.getResponseData() + data?.let { + updateDb(it) + Result.success(it) + } ?: Result.failure(Exception("请求成功,但返回数据为空")) + } else { + Result.failure(Exception(response.getResponseMsg())) + } + } catch (e: Exception) { + Result.failure(e) + } + } + + private fun updateNickname(newNickname: String) { + val userInfoBox = get().boxFor(UserInfo::class.java) + val user = userInfoBox + .query(UserInfo_.username.equal(getUsername())) + .build() + .findFirst() + + MMKV.mmkvWithID(MMKV_USER_SESSION).putString(NICKNAME_KEY, newNickname) + + user?.nickname = newNickname + + if (user != null) { + userInfoBox.put(user) + } + } + + private fun updateDb(url: String) { + val userInfoBox = get().boxFor(UserInfo::class.java) + val userInfo = + userInfoBox.query(UserInfo_.username.equal(getUsername())).build().findFirst() + if (userInfo != null) { + userInfo.avatarUrl = url + userInfoBox.put(userInfo) + } + } +} diff --git a/app/src/main/java/com/kaixed/kchat/repository/UserRepository.kt b/app/src/main/java/com/kaixed/kchat/repository/UserRepository.kt deleted file mode 100644 index 15046df..0000000 --- a/app/src/main/java/com/kaixed/kchat/repository/UserRepository.kt +++ /dev/null @@ -1,94 +0,0 @@ -package com.kaixed.kchat.repository - -import android.util.Log -import com.kaixed.kchat.model.request.RegisterRequest -import com.kaixed.kchat.model.request.UserRequest -import com.kaixed.kchat.model.response.friend.SearchFriends -import com.kaixed.kchat.model.response.login.Login -import com.kaixed.kchat.model.response.register.Register -import com.kaixed.kchat.model.response.search.UserList -import com.kaixed.kchat.network.RetrofitClient -import okhttp3.MultipartBody -import okhttp3.ResponseBody.Companion.toResponseBody -import retrofit2.Response - -class UserRepository { - - private val userApiService = RetrofitClient.userApiService - - // 用户注册 - suspend fun register(registerRequest: RegisterRequest): Response { - return try { - userApiService.register(registerRequest) - } catch (e: Exception) { - Log.e("UserRepository", "Register Failed: ${e.message}", e) - Response.error(500, "".toResponseBody()) - } - } - - // 登录请求(支持用户名或手机号) - suspend fun login( - username: String?, - password: String, - loginByUsername: Boolean - ): Response { - return try { - if (loginByUsername) { - // 用户名登录 - userApiService.loginByUsername(username ?: "", password) - } else { - // 电话号登录 - userApiService.loginByTelephone(username ?: "", password) - } - } catch (e: Exception) { - Log.e("UserRepository", "Login Failed: ${e.message}", e) - Response.error(500, "".toResponseBody()) // 返回一个空的错误 Response - } - } - - // 获取用户列表 - suspend fun getUserList(username: String): Response { - return try { - userApiService.getUserListByNickname(username) - } catch (e: Exception) { - Log.e("UserRepository", "Get User Info Failed: ${e.message}", e) - Response.error(500, "".toResponseBody()) - } - } - - // 获取用户信息 - suspend fun getUserInfo(username: String): Response { - return try { - userApiService.getUserInfo(username) - } catch (e: Exception) { - Log.e("UserRepository", "Get User List Failed: ${e.message}", e) - Response.error(500, "".toResponseBody()) - } - } - - // 修改昵称 - suspend fun changeNickname(userRequest: UserRequest): Response { - return try { - val response = userApiService.changeNickname(userRequest) - Response.success(response.isSuccessful) - } catch (e: Exception) { - Log.e("UserRepository", "Change Nickname Failed: ${e.message}", e) - Response.error(500, "".toResponseBody()) - } - } - - // 上传头像 - suspend fun uploadAvatar(file: MultipartBody.Part, username: String): Response { - return try { - val response = userApiService.uploadAvatar(username, file) - if (response.isSuccessful) { - Response.success(response.body()?.data) - } else { - Response.success(null) - } - } catch (e: Exception) { - Log.e("UserRepository", "Upload Avatar Failed: ${e.message}", e) - Response.error(500, "".toResponseBody()) - } - } -} diff --git a/app/src/main/java/com/kaixed/kchat/repository/UserSearchRepository.kt b/app/src/main/java/com/kaixed/kchat/repository/UserSearchRepository.kt new file mode 100644 index 0000000..69e0b04 --- /dev/null +++ b/app/src/main/java/com/kaixed/kchat/repository/UserSearchRepository.kt @@ -0,0 +1,30 @@ +package com.kaixed.kchat.repository + +import com.kaixed.kchat.model.response.search.User +import com.kaixed.kchat.network.RetrofitClient + +/** + * @Author: kaixed + * @Date: 2024/11/23 14:16 + */ +class UserSearchRepository { + + private val userApiService = RetrofitClient.userApiService + + // 获取用户列表 + suspend fun getUserList(username: String): Result> { + return try { + val response = userApiService.getUserListByNickname(username) + if (response.isSuccess()) { + val userList = response.getResponseData() + userList?.let { + Result.success(userList) + } ?: Result.failure(Exception("用户列表为空")) + } else { + Result.failure(Exception(response.getResponseMsg())) + } + } catch (e: Exception) { + Result.failure(e) + } + } +} diff --git a/app/src/main/java/com/kaixed/kchat/ui/activity/ApplyAddFriendActivity.kt b/app/src/main/java/com/kaixed/kchat/ui/activity/ApplyAddFriendActivity.kt index 17328aa..538e473 100644 --- a/app/src/main/java/com/kaixed/kchat/ui/activity/ApplyAddFriendActivity.kt +++ b/app/src/main/java/com/kaixed/kchat/ui/activity/ApplyAddFriendActivity.kt @@ -1,7 +1,6 @@ package com.kaixed.kchat.ui.activity import android.os.Bundle -import android.widget.Toast import androidx.activity.enableEdgeToEdge import androidx.activity.viewModels import com.kaixed.kchat.databinding.ActivityApplyAddFriendBinding @@ -29,14 +28,13 @@ class ApplyAddFriendActivity : BaseActivity() { private fun sendContactRequest(contactId: String?) { contactId?.let { - contactViewModel.addContactResponse - .observe(this) { value -> - runOnUiThread { - if (value?.code == "200") { - Toast.makeText(this, value.msg, Toast.LENGTH_SHORT).show() - finish() - } + contactViewModel.addContactResult + .observe(this) { result -> + result.onSuccess { + toast(result.getOrNull().toString()) + finish() } + result.onFailure { toast(it.message.toString()) } } contactViewModel.addContact(contactId, binding.etMessage.text.toString()) } diff --git a/app/src/main/java/com/kaixed/kchat/ui/activity/ApproveContactRequestActivity.kt b/app/src/main/java/com/kaixed/kchat/ui/activity/ApproveContactRequestActivity.kt index daaf214..fafc100 100644 --- a/app/src/main/java/com/kaixed/kchat/ui/activity/ApproveContactRequestActivity.kt +++ b/app/src/main/java/com/kaixed/kchat/ui/activity/ApproveContactRequestActivity.kt @@ -49,34 +49,33 @@ class ApproveContactRequestActivity : BaseActivity - value?.let { - if (value.code != "200") { - toast(it.msg) - } else { - value.data?.let { it1 -> - ContactUtil.handleContact(it1) + private fun acceptContactRequest(contactId: String, nickname: String) { + contactViewModel.acceptContactRequestResult + .observe(this) { result -> + + result.onSuccess { + val stackBuilder: TaskStackBuilder = TaskStackBuilder.create(this) + stackBuilder.addNextIntentWithParentStack( + Intent( + this, MainActivity::class.java + ) + ) + stackBuilder.addNextIntent( + Intent( + this, ChatActivity::class.java + ).apply { + putExtra("contactId", contactId) + putExtra("contactNickname", nickname) } - val stackBuilder: TaskStackBuilder = TaskStackBuilder.create(this) - stackBuilder.addNextIntentWithParentStack( - Intent( - this, MainActivity::class.java - ) - ) - stackBuilder.addNextIntent( - Intent( - this, ChatActivity::class.java - ).putExtra("friendId", contactId) - ) - stackBuilder.startActivities() - } + ) + stackBuilder.startActivities() } + + result.onFailure { toast(it.message.toString()) } } val remark = binding.etRemark.text.toString() diff --git a/app/src/main/java/com/kaixed/kchat/ui/activity/ContactRequestListActivity.kt b/app/src/main/java/com/kaixed/kchat/ui/activity/ContactRequestListActivity.kt index 4bd626f..ddd99f4 100644 --- a/app/src/main/java/com/kaixed/kchat/ui/activity/ContactRequestListActivity.kt +++ b/app/src/main/java/com/kaixed/kchat/ui/activity/ContactRequestListActivity.kt @@ -39,12 +39,16 @@ class ContactRequestListActivity : BaseActivity - if (value != null) { - items.addAll(value.data.toMutableList()) + contactViewModel.contactRequestListResult + .observe(this) { result -> + result.onSuccess { + items.addAll(result.getOrNull()?.toMutableList() ?: emptyList()) contactRequestListAdapter.notifyDataSetChanged() } + + result.onFailure { + toast(it.message.toString()) + } } contactViewModel.getContactRequestList(getUsername()) diff --git a/app/src/main/java/com/kaixed/kchat/ui/activity/DataSettingActivity.kt b/app/src/main/java/com/kaixed/kchat/ui/activity/DataSettingActivity.kt index 909a750..a5da98a 100644 --- a/app/src/main/java/com/kaixed/kchat/ui/activity/DataSettingActivity.kt +++ b/app/src/main/java/com/kaixed/kchat/ui/activity/DataSettingActivity.kt @@ -1,31 +1,22 @@ package com.kaixed.kchat.ui.activity -import android.app.Dialog -import android.content.Context import android.content.Intent -import android.graphics.Color -import android.graphics.drawable.ColorDrawable import android.os.Bundle -import android.os.Handler -import android.os.Looper -import android.view.Gravity -import android.view.LayoutInflater -import android.view.Window -import android.view.WindowManager import androidx.activity.enableEdgeToEdge import androidx.activity.viewModels +import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.kaixed.kchat.data.objectbox.ObjectBox.get import com.kaixed.kchat.data.objectbox.entity.Contact -import com.kaixed.kchat.data.objectbox.entity.Contact_ import com.kaixed.kchat.databinding.ActivityDataSettingBinding -import com.kaixed.kchat.databinding.DialogDeleteContactBinding import com.kaixed.kchat.ui.base.BaseActivity +import com.kaixed.kchat.ui.fragment.DeleteContactDialogFragment +import com.kaixed.kchat.ui.fragment.LoadingDialogFragment import com.kaixed.kchat.utils.ConstantsUtil.getUsername -import com.kaixed.kchat.utils.WidgetUtil import com.kaixed.kchat.viewmodel.ContactViewModel import io.objectbox.Box -class DataSettingActivity : BaseActivity() { +class DataSettingActivity : BaseActivity(), + DeleteContactDialogFragment.OnContactDeletedListener { private val contactViewModel by viewModels() @@ -33,6 +24,8 @@ class DataSettingActivity : BaseActivity() { private var contactId = "" + private val loadingDialogFragment by lazy { LoadingDialogFragment.newInstance("加载中...") } + override fun inflateBinding(): ActivityDataSettingBinding { return ActivityDataSettingBinding.inflate(layoutInflater) } @@ -40,11 +33,8 @@ class DataSettingActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() - binding = ActivityDataSettingBinding.inflate(layoutInflater) - setContentView(binding.root) setOnClick() - handleIntent(intent) } @@ -59,50 +49,35 @@ class DataSettingActivity : BaseActivity() { } binding.tvDelete.setOnClickListener { - val dialog = showDeleteDialog(this) - dialog.show() + val deleteDialogFragment = DeleteContactDialogFragment.newInstance(contactId) + deleteDialogFragment.show(supportFragmentManager, "DeleteContactDialogFragment") } } - private fun showDeleteDialog(context: Context): Dialog { - val binding = DialogDeleteContactBinding.inflate(LayoutInflater.from(context)) - val dialog = Dialog(context) - dialog.requestWindowFeature(Window.FEATURE_NO_TITLE) - dialog.setCancelable(false) - dialog.setContentView(binding.root) - dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) - - val layoutParams = WindowManager.LayoutParams().apply { - copyFrom(dialog.window?.attributes) - width = (context.resources.displayMetrics.widthPixels * 0.8).toInt() - gravity = Gravity.CENTER - } - dialog.window?.attributes = layoutParams - - binding.tvCancel.setOnClickListener { - dialog.dismiss() - } - - binding.tvDelete.setOnClickListener { - deleteContact(getUsername(), contactId) - } - - return dialog + override fun onContactDeleted() { + deleteContact(getUsername(), contactId) } private fun deleteContact(username: String, contactId: String) { - val dialog = WidgetUtil.showLoadingDialog(this, "删除中...") - dialog.show() - contactViewModel.deleteContact.observe(this) { - it?.let { - val con = contactBox.query(Contact_.username.equal(contactId)).build().findFirst() - contactBox.remove(con!!) - val handle = Handler(Looper.getMainLooper()) - handle.postDelayed({ - dialog.dismiss() - }, 1000) + loadingDialogFragment.show(supportFragmentManager, "LoadingDialogFragment") + + contactViewModel.deleteContactResult.observe(this) { result -> + result.onSuccess { + loadingDialogFragment.dismiss() + toast("删除成功") - } ?: toast("删除失败") + + val deleteIntent = Intent("com.kaixed.kchat.broadcast.UPDATE_CONTACT_LIST") + deleteIntent.putExtra("update", true) + LocalBroadcastManager.getInstance(this).sendBroadcast(deleteIntent) + + val intent = Intent(this, MainActivity::class.java).apply { + setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP) + } + startActivity(intent) + } + + result.onFailure { toast(it.message.toString()) } } contactViewModel.deleteContact(username, contactId) } diff --git a/app/src/main/java/com/kaixed/kchat/ui/activity/LoginActivity.kt b/app/src/main/java/com/kaixed/kchat/ui/activity/LoginActivity.kt index 229a9d2..df8414a 100644 --- a/app/src/main/java/com/kaixed/kchat/ui/activity/LoginActivity.kt +++ b/app/src/main/java/com/kaixed/kchat/ui/activity/LoginActivity.kt @@ -32,9 +32,6 @@ class LoginActivity : BaseActivity() { private val userViewModel: UserViewModel by viewModels() - private val userInfoBox: Box by lazy { get().boxFor(UserInfo::class.java) } - - private val mmkv by lazy { MMKV.mmkvWithID(MMKV_USER_SESSION) } private var previousKeyboardHeight = 0 private var loginByUsername = false @@ -68,39 +65,18 @@ class LoginActivity : BaseActivity() { if (username.isEmpty() || password.isEmpty()) { toast("请输入${if (loginByUsername) "用户名" else "手机号"}或密码") } - userViewModel.loginResponse.observe(this) { loginResult -> - loginResult?.let { - when (it.code) { - "A0201" -> toast("用户账户不存在") - "A0209" -> toast("用户密码错误") - else -> { - mmkv.apply { - encode("username", loginResult.data?.username) - encode("nickname", loginResult.data?.nickname) - encode("avatarUrl", loginResult.data?.avatarUrl) - } - MMKV.defaultMMKV().encode("userLoginStatus", true) - updateDb(loginResult.data!!) - navigateToMain() - } - } - } ?: toast("登录异常") + userViewModel.loginResult.observe(this) { loginResult -> + loginResult.onSuccess { + navigateToMain() + } + loginResult.onFailure { + toast(it.message.toString()) + } } - userViewModel.login(username, password, loginByUsername) - } - - private fun updateDb(userInfo: UserInfo) { - CoroutineScope(Dispatchers.IO).launch { - val user = userInfoBox - .query(UserInfo_.username.equal(userInfo.username)) - .build() - .findFirst() - if (user == null) { - userInfoBox.put(userInfo) - } - withContext(Dispatchers.Main) { - toast("登录成功") - } + if (loginByUsername) { + userViewModel.loginByUsername(username, password) + } else { + userViewModel.loginByTelephone(username, password) } } @@ -185,6 +161,7 @@ class LoginActivity : BaseActivity() { } private fun navigateToMain() { + toast("登录成功") val intent = Intent(this, MainActivity::class.java) startActivity(intent) finish() diff --git a/app/src/main/java/com/kaixed/kchat/ui/activity/MainActivity.kt b/app/src/main/java/com/kaixed/kchat/ui/activity/MainActivity.kt index 31d854f..376e6d2 100644 --- a/app/src/main/java/com/kaixed/kchat/ui/activity/MainActivity.kt +++ b/app/src/main/java/com/kaixed/kchat/ui/activity/MainActivity.kt @@ -21,6 +21,7 @@ import com.kaixed.kchat.ui.fragment.HomeFragment import com.kaixed.kchat.ui.fragment.MineFragment import com.kaixed.kchat.utils.ConstantsUtil.getUsername import com.kaixed.kchat.utils.ConstantsUtil.isFirstLaunchApp +import com.kaixed.kchat.utils.Pinyin4jUtil import com.kaixed.kchat.utils.WidgetUtil import com.kaixed.kchat.viewmodel.ContactViewModel import io.objectbox.Box @@ -76,8 +77,10 @@ class MainActivity : BaseActivity(), View.OnClickListener { dialog.show() delay(200) - contactViewModel.contactListResponse.observe(this@MainActivity) { contacts -> - contactBox.put(contacts ?: emptyList()) + contactViewModel.contactListResult.observe(this@MainActivity) { result -> + result.onSuccess { + contactBox.put(it ?: emptyList()) + } } contactViewModel.loadFriendList(getUsername()) diff --git a/app/src/main/java/com/kaixed/kchat/ui/activity/ProfileDetailActivity.kt b/app/src/main/java/com/kaixed/kchat/ui/activity/ProfileDetailActivity.kt index 43a68e9..ca0c5a3 100644 --- a/app/src/main/java/com/kaixed/kchat/ui/activity/ProfileDetailActivity.kt +++ b/app/src/main/java/com/kaixed/kchat/ui/activity/ProfileDetailActivity.kt @@ -81,12 +81,14 @@ class ProfileDetailActivity : BaseActivity() { val dialog = WidgetUtil.showLoadingDialog(this, "正在上传") dialog.show() - userViewModel.uploadAvatarResponse.observe(this) { value -> - value?.let { - userSessionMMKV.putString(AVATAR_URL, value) - updateDb(value, dialog) + userViewModel.uploadAvatarResult.observe(this) { result -> + result.onSuccess { + userSessionMMKV.putString(AVATAR_URL, it) + toast("上传成功") binding.ciAvatar.setItemIcon(uri) - } ?: run { + } + + result.onFailure { toast("上传失败") } } @@ -100,16 +102,7 @@ class ProfileDetailActivity : BaseActivity() { return MultipartBody.Part.createFormData("file", file.name, requestFile) } - private fun updateDb(url: String, dialog: Dialog) { - val userInfo = - userInfoBox.query(UserInfo_.username.equal(getUsername())).build().findFirst() - if (userInfo != null) { - userInfo.avatarUrl = url - userInfoBox.put(userInfo) - } - dialog.dismiss() - toast("上传成功") - } + private fun getPathFromUri(uri: Uri): String? { diff --git a/app/src/main/java/com/kaixed/kchat/ui/activity/RegisterActivity.kt b/app/src/main/java/com/kaixed/kchat/ui/activity/RegisterActivity.kt index cb93fb5..a25bb2c 100644 --- a/app/src/main/java/com/kaixed/kchat/ui/activity/RegisterActivity.kt +++ b/app/src/main/java/com/kaixed/kchat/ui/activity/RegisterActivity.kt @@ -28,7 +28,7 @@ class RegisterActivity : BaseActivity() { private var tvContinueEnable: Boolean = false - private val userViewmodel: UserViewModel by viewModels() + private val userViewModel: UserViewModel by viewModels() private val userInfoBox: Box by lazy { get().boxFor(UserInfo::class.java) } @@ -78,14 +78,15 @@ class RegisterActivity : BaseActivity() { signature: String, telephone: String ) { - userViewmodel.registerResponse.observe(this) { registerResult -> - when (registerResult?.code) { - "A0111" -> toast("用户名已存在,请重新注册") - "200" -> registerResult.data?.username?.let { - onRegisterSuccess(it, nickname, telephone) - } + userViewModel.registerResult.observe(this) { result -> + result.onSuccess { + toast("注册成功,请前往登录界面登录") + startActivity(Intent(this, LoginActivity::class.java)) + finish() + } - else -> toast("系统服务器异常") + result.onFailure { + toast(it.message.toString()) } } @@ -96,22 +97,7 @@ class RegisterActivity : BaseActivity() { signature = signature, telephone = telephone ) - - userViewmodel.register(registerRequest) - } - - private fun onRegisterSuccess(username: String, nickname: String, telephone: String) { - val userInfo = UserInfo( - username = username, - nickname = nickname, - avatarUrl = "", - signature = "", - telephone = telephone - ) - userInfoBox.put(userInfo) - toast("注册成功,请前往登录界面登录") - startActivity(Intent(this, LoginActivity::class.java)) - finish() + userViewModel.register(registerRequest) } diff --git a/app/src/main/java/com/kaixed/kchat/ui/activity/RenameActivity.kt b/app/src/main/java/com/kaixed/kchat/ui/activity/RenameActivity.kt index 5ad639e..f17b89c 100644 --- a/app/src/main/java/com/kaixed/kchat/ui/activity/RenameActivity.kt +++ b/app/src/main/java/com/kaixed/kchat/ui/activity/RenameActivity.kt @@ -8,17 +8,13 @@ import androidx.activity.viewModels import androidx.core.widget.addTextChangedListener import com.kaixed.kchat.data.objectbox.ObjectBox.get import com.kaixed.kchat.data.objectbox.entity.UserInfo -import com.kaixed.kchat.data.objectbox.entity.UserInfo_ import com.kaixed.kchat.databinding.ActivityRenameBinding import com.kaixed.kchat.model.request.UserRequest import com.kaixed.kchat.ui.base.BaseActivity -import com.kaixed.kchat.utils.Constants.MMKV_USER_SESSION -import com.kaixed.kchat.utils.Constants.NICKNAME_KEY import com.kaixed.kchat.utils.ConstantsUtil.getNickName import com.kaixed.kchat.utils.ConstantsUtil.getUsername import com.kaixed.kchat.utils.WidgetUtil import com.kaixed.kchat.viewmodel.UserViewModel -import com.tencent.mmkv.MMKV import io.objectbox.Box class RenameActivity : BaseActivity() { @@ -66,27 +62,19 @@ class RenameActivity : BaseActivity() { binding.ctb.setBtnEnable(false) val dialog = WidgetUtil.showLoadingDialog(this, "正在保存") dialog.show() - userViewModel.changeNicknameResponse.observe(this) { result -> - if (result) { - val user = userInfoBox - .query(UserInfo_.username.equal(username)) - .build() - .findFirst() + userViewModel.changeNicknameResult.observe(this) { result -> - MMKV.mmkvWithID(MMKV_USER_SESSION).putString(NICKNAME_KEY, newNickname) - - user?.nickname = newNickname - - if (user != null) { - userInfoBox.put(user) - } + result.onSuccess { binding.etNickname.setText(newNickname) updateSucceed = true - } else { + } + + result.onFailure { updateSucceed = false binding.etNickname.setText(oldNickname) } - binding.etNickname.setSelection(newNickname.length) + + binding.etNickname.setSelection(binding.etNickname.text.length) } Handler(Looper.getMainLooper()).postDelayed({ dialog.dismiss() diff --git a/app/src/main/java/com/kaixed/kchat/ui/activity/SearchFriendsActivity.kt b/app/src/main/java/com/kaixed/kchat/ui/activity/SearchFriendsActivity.kt index 2656416..8210514 100644 --- a/app/src/main/java/com/kaixed/kchat/ui/activity/SearchFriendsActivity.kt +++ b/app/src/main/java/com/kaixed/kchat/ui/activity/SearchFriendsActivity.kt @@ -90,23 +90,21 @@ class SearchFriendsActivity : BaseActivity() { loadingDialog = showLoadingDialog(this) val username = binding.etSearch.text.toString() - contactViewModel.searchContactResponse.observe(this) { value -> + contactViewModel.searchContactResult.observe(this) { result -> loadingDialog.dismiss() - value?.let { - if (value.code == "200") { - value.data?.let { - userItem = value.data - if (::userItem.isInitialized) { - setVisibility(true) - setContent() - } - } ?: run { - setVisibility(false) - binding.tvNothing.visibility = View.VISIBLE + result.onSuccess { + it?.let { + userItem = it + if (::userItem.isInitialized) { + setVisibility(true) + setContent() } - } + } + result.onFailure { + setVisibility(false) + binding.tvNothing.visibility = View.VISIBLE } } contactViewModel.searchContact(username) diff --git a/app/src/main/java/com/kaixed/kchat/ui/fragment/ContactFragment.kt b/app/src/main/java/com/kaixed/kchat/ui/fragment/ContactFragment.kt index 530ab6f..c664d82 100644 --- a/app/src/main/java/com/kaixed/kchat/ui/fragment/ContactFragment.kt +++ b/app/src/main/java/com/kaixed/kchat/ui/fragment/ContactFragment.kt @@ -1,12 +1,15 @@ package com.kaixed.kchat.ui.fragment +import android.content.BroadcastReceiver import android.content.Context +import android.content.Intent +import android.content.IntentFilter import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.viewModels -import androidx.lifecycle.lifecycleScope +import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.recyclerview.widget.LinearLayoutManager import com.kaixed.kchat.data.objectbox.entity.Contact import com.kaixed.kchat.databinding.FragmentContactBinding @@ -14,9 +17,7 @@ import com.kaixed.kchat.ui.adapter.FriendListAdapter import com.kaixed.kchat.ui.base.BaseFragment import com.kaixed.kchat.utils.ConstantsUtil.getUsername import com.kaixed.kchat.viewmodel.ContactViewModel -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext + class ContactFragment : BaseFragment() { @@ -41,12 +42,25 @@ class ContactFragment : BaseFragment() { return FragmentContactBinding.inflate(inflater, container, false) } + private val mReceiver: BroadcastReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + val update = intent.getBooleanExtra("update", false) // 获取单一的 boolean 类型值 + if (update) { + loadData() + } + } + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) context = requireContext() + loadData() loadFriendRequest() + + val filter = IntentFilter("com.kaixed.kchat.broadcast.UPDATE_CONTACT_LIST") + LocalBroadcastManager.getInstance(requireActivity()).registerReceiver(mReceiver, filter) } override fun onResume() { @@ -54,40 +68,50 @@ class ContactFragment : BaseFragment() { loadFriendRequest() } - private fun loadFriendRequest() { - contactViewModel.contactRequestListResponse.observe(viewLifecycleOwner) { response -> - if (response?.data?.isNotEmpty() == true) { - val contactRequest = response.data[response.data.size - 1] - friendAdapter.items[0].apply { - remark = - "${contactRequest.nickname}(${contactRequest.message})" - avatarUrl = contactRequest.avatarUrl - } - friendAdapter.notifyItemChanged(0) - } - } + override fun onStart() { + super.onStart() + loadFriendRequest() + } + override fun onDestroy() { + super.onDestroy() + LocalBroadcastManager.getInstance(requireActivity()).unregisterReceiver(mReceiver); + } + + private fun loadFriendRequest() { + contactViewModel.contactRequestListResult.observe(viewLifecycleOwner) { result -> + result.onSuccess { + val items = result.getOrNull()?.toMutableList() ?: emptyList() + if (items.isNotEmpty()) { + friendAdapter.items[0].apply { + remark = + "${items[items.size - 1].nickname}(${items[items.size - 1].message})" + avatarUrl = items[items.size - 1].avatarUrl + } + friendAdapter.notifyItemChanged(0) + } + } + result.onFailure { } + } contactViewModel.getContactRequestList(getUsername()) } + + private fun loadData() { loading = true binding.tvLoading.visibility = View.VISIBLE binding.recycleFriendList.visibility = View.INVISIBLE - lifecycleScope.launch(Dispatchers.IO) { - val contacts = contactViewModel.loadFriendListInDb() - val allItems = mutableListOf().apply { - addAll(getDefaultItems()) - addAll(contacts) - } - withContext(Dispatchers.Main) { - friendAdapter.updateData(allItems) - binding.tvLoading.visibility = View.GONE - binding.recycleFriendList.visibility = View.VISIBLE - loading = false - } + val contacts = contactViewModel.loadFriendListInDb() + val allItems = mutableListOf().apply { + addAll(getDefaultItems()) + addAll(contacts) } + friendAdapter.updateData(allItems) + binding.tvLoading.visibility = View.GONE + binding.recycleFriendList.visibility = View.VISIBLE + loading = false setupRecyclerView() } diff --git a/app/src/main/java/com/kaixed/kchat/ui/fragment/DeleteContactDialogFragment.kt b/app/src/main/java/com/kaixed/kchat/ui/fragment/DeleteContactDialogFragment.kt new file mode 100644 index 0000000..176e5f6 --- /dev/null +++ b/app/src/main/java/com/kaixed/kchat/ui/fragment/DeleteContactDialogFragment.kt @@ -0,0 +1,74 @@ +package com.kaixed.kchat.ui.fragment + +import android.app.Dialog +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import android.view.Window +import android.view.WindowManager +import androidx.fragment.app.DialogFragment +import com.kaixed.kchat.databinding.DialogDeleteContactBinding + +class DeleteContactDialogFragment : DialogFragment() { + + interface OnContactDeletedListener { + fun onContactDeleted() + } + + private lateinit var contactId: String + private var listener: OnContactDeletedListener? = null + + companion object { + fun newInstance(contactId: String): DeleteContactDialogFragment { + val fragment = DeleteContactDialogFragment() + val args = Bundle() + args.putString("contactId", contactId) + fragment.arguments = args + return fragment + } + } + + override fun onAttach(context: Context) { + super.onAttach(context) + if (context is OnContactDeletedListener) { + listener = context + } else { + throw RuntimeException("$context must implement OnContactDeletedListener") + } + } + + override fun onDetach() { + super.onDetach() + listener = null + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + contactId = arguments?.getString("contactId") ?: "" + + val binding = DialogDeleteContactBinding.inflate(layoutInflater) + val dialog = Dialog(requireContext()) + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE) + dialog.setCancelable(false) + dialog.setContentView(binding.root) + dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + + val layoutParams = WindowManager.LayoutParams().apply { + copyFrom(dialog.window?.attributes) + width = (requireContext().resources.displayMetrics.widthPixels * 0.8).toInt() + gravity = Gravity.CENTER + } + dialog.window?.attributes = layoutParams + + binding.tvCancel.setOnClickListener { + dialog.dismiss() + } + + binding.tvDelete.setOnClickListener { + listener?.onContactDeleted() + dialog.dismiss() + } + return dialog + } +} diff --git a/app/src/main/java/com/kaixed/kchat/ui/fragment/LoadingDialogFragment.kt b/app/src/main/java/com/kaixed/kchat/ui/fragment/LoadingDialogFragment.kt new file mode 100644 index 0000000..30e18e2 --- /dev/null +++ b/app/src/main/java/com/kaixed/kchat/ui/fragment/LoadingDialogFragment.kt @@ -0,0 +1,63 @@ +package com.kaixed.kchat.ui.fragment + +import android.app.Dialog +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Window +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.FragmentManager +import com.kaixed.kchat.databinding.DialogLoadingBinding +import com.kaixed.kchat.utils.DensityUtil.dpToPx + +class LoadingDialogFragment : DialogFragment() { + + // 设置加载文本 + private var loadingText: String = "" + + companion object { + // 通过这个方法设置加载文本,并创建实例 + fun newInstance(text: String): LoadingDialogFragment { + val fragment = LoadingDialogFragment() + val bundle = Bundle() + bundle.putString("loading_text", text) + fragment.arguments = bundle + return fragment + } + } + + // 创建对话框 + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val binding = DialogLoadingBinding.inflate(layoutInflater) + val dialog = Dialog(requireContext()) + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE) + dialog.setCancelable(false) + dialog.setContentView(binding.root) + dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + + dialog.setCancelable(false) // 禁止点击外部区域关闭对话框 + dialog.setCanceledOnTouchOutside(false) // 禁止点击外部区域消失 + + // 获取传入的 loading_text 参数 + loadingText = arguments?.getString("loading_text", "") ?: "加载中..." + binding.tvLoading.text = loadingText + + // 设置对话框的大小 + val params = binding.root.layoutParams + params.height = dpToPx(150) + params.width = dpToPx(150) + binding.root.layoutParams = params + + return dialog + } + + // 显示对话框 + fun showLoading(fragmentManager: FragmentManager) { + this.show(fragmentManager, "LoadingDialogFragment") + } + + // 关闭对话框 + fun dismissLoading() { + this.dismissAllowingStateLoss() + } +} diff --git a/app/src/main/java/com/kaixed/kchat/utils/Pinyin4jUtil.kt b/app/src/main/java/com/kaixed/kchat/utils/Pinyin4jUtil.kt index 3cc9c76..3457e22 100644 --- a/app/src/main/java/com/kaixed/kchat/utils/Pinyin4jUtil.kt +++ b/app/src/main/java/com/kaixed/kchat/utils/Pinyin4jUtil.kt @@ -1,11 +1,10 @@ package com.kaixed.kchat.utils -import com.kaixed.kchat.utils.Utils.isChinese -import com.kaixed.kchat.utils.Utils.isEnglish import net.sourceforge.pinyin4j.PinyinHelper import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat import net.sourceforge.pinyin4j.format.HanyuPinyinToneType + /** * @Author: kaixed * @Date: 2024/11/2 14:30 @@ -48,4 +47,12 @@ object Pinyin4jUtil { private fun isEnglishOrChinese(str: String): Boolean { return isChinese(str) || isEnglish(str) } + + private fun isChinese(str: String?): Boolean { + return str?.matches(".*[\\u4E00-\\u9FFF].*".toRegex()) ?: false + } + + private fun isEnglish(str: String?): Boolean { + return str != null && str.matches("^[a-zA-Z]+$".toRegex()) + } } \ No newline at end of file diff --git a/app/src/main/java/com/kaixed/kchat/utils/Utils.kt b/app/src/main/java/com/kaixed/kchat/utils/Utils.kt deleted file mode 100644 index 09dc25a..0000000 --- a/app/src/main/java/com/kaixed/kchat/utils/Utils.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.kaixed.kchat.utils - -/** - * @Author: kaixed - * @Date: 2024/11/2 13:21 - */ -object Utils { - - fun isChinese(str: String?): Boolean { - return str?.matches(".*[\\u4E00-\\u9FFF].*".toRegex()) ?: false - } - - fun isEnglish(str: String?): Boolean { - return str != null && str.matches("^[a-zA-Z]+$".toRegex()) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/kaixed/kchat/viewmodel/ContactViewModel.kt b/app/src/main/java/com/kaixed/kchat/viewmodel/ContactViewModel.kt index 2795954..54646a4 100644 --- a/app/src/main/java/com/kaixed/kchat/viewmodel/ContactViewModel.kt +++ b/app/src/main/java/com/kaixed/kchat/viewmodel/ContactViewModel.kt @@ -6,13 +6,9 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.kaixed.kchat.data.objectbox.ObjectBox.get import com.kaixed.kchat.data.objectbox.entity.Contact -import com.kaixed.kchat.model.friend.AcceptContactRequest -import com.kaixed.kchat.model.friend.ContactRequestResponse -import com.kaixed.kchat.model.response.ApplyFriend -import com.kaixed.kchat.model.response.friend.DeleteContact -import com.kaixed.kchat.model.response.friend.SearchFriends +import com.kaixed.kchat.model.friend.FriendRequestItem +import com.kaixed.kchat.model.search.User import com.kaixed.kchat.repository.ContactRepository -import com.kaixed.kchat.utils.Pinyin4jUtil import io.objectbox.Box import kotlinx.coroutines.launch @@ -21,86 +17,68 @@ class ContactViewModel : ViewModel() { private val contactRepository = ContactRepository() // 获取联系人请求列表 - private val _contactRequestListResponse = MutableLiveData() - val contactRequestListResponse: LiveData = _contactRequestListResponse + private val _contactRequestListResult = MutableLiveData?>>() + val contactRequestListResult: LiveData?>> = + _contactRequestListResult // 接受联系人请求 - private val _acceptContactRequestResponse = MutableLiveData() - val acceptContactRequestResponse: LiveData = - _acceptContactRequestResponse + private val _acceptContactRequestResult = MutableLiveData>() + val acceptContactRequestResult: LiveData> = + _acceptContactRequestResult // 添加联系人 - private val _addContactResponse = MutableLiveData() - val addContactResponse: LiveData = _addContactResponse + private val _addContactResult = MutableLiveData>() + val addContactResult: LiveData> = _addContactResult // 搜索联系人 - private val _searchContactResponse = MutableLiveData() - val searchContactResponse: LiveData = _searchContactResponse + private val _searchContactResult = MutableLiveData>() + val searchContactResult: LiveData> = _searchContactResult // 获取联系人列表 - private val _contactListResponse = MutableLiveData?>() - val contactListResponse: LiveData?> = _contactListResponse + private val _contactListResult = MutableLiveData?>>() + val contactListResult: LiveData?>> = _contactListResult // 删除联系人 - private val _deleteContact = MutableLiveData() - val deleteContact: LiveData = _deleteContact + private val _deleteContactResult = MutableLiveData>() + val deleteContactResult: LiveData> = _deleteContactResult + // 删除联系人 fun deleteContact(username: String, contactId: String) { viewModelScope.launch { - val response = contactRepository.deleteContact(username, contactId) - if (response.isSuccessful) { - _deleteContact.value = response.body() - } else { - _deleteContact.value = null - } + val result = contactRepository.deleteContact(username, contactId) + _deleteContactResult.postValue(result) } } // 获取联系人请求列表 fun getContactRequestList(username: String) { viewModelScope.launch { - val response = contactRepository.getContactRequestList(username) - if (response.isSuccessful) { - _contactRequestListResponse.value = response.body() - } else { - _contactRequestListResponse.value = null - } + val result = contactRepository.getContactRequestList(username) + _contactRequestListResult.postValue(result) } } // 接受联系人请求 fun acceptContactRequest(username: String, contactId: String, remark: String) { viewModelScope.launch { - val response = contactRepository.acceptContactRequest(username, contactId, remark) - if (response.isSuccessful) { - _acceptContactRequestResponse.value = response.body() - } else { - _acceptContactRequestResponse.value = null - } + val result = contactRepository.acceptContactRequest(username, contactId, remark) + _acceptContactRequestResult.postValue(result) } } // 添加联系人 fun addContact(contactId: String, message: String) { viewModelScope.launch { - val response = contactRepository.addContact(contactId, message) - if (response.isSuccessful) { - _addContactResponse.value = response.body() - } else { - _addContactResponse.value = null - } + val result = contactRepository.addContact(contactId, message) + _addContactResult.postValue(result) } } // 搜索联系人 fun searchContact(username: String) { viewModelScope.launch { - val response = contactRepository.searchContact(username) - if (response.isSuccessful) { - _searchContactResponse.value = response.body() - } else { - _searchContactResponse.value = null - } + val result = contactRepository.searchContact(username) + _searchContactResult.postValue(result) } } @@ -140,56 +118,8 @@ class ContactViewModel : ViewModel() { fun loadFriendList(username: String) { viewModelScope.launch { - val response = contactRepository.getContactList(username) - if (response.isSuccessful) { - val friendListResponse = response.body()?.data - val uiFriendList = friendListResponse?.map { networkItem -> - mapToFriendItem(networkItem) // 数据转换 - }?.sortedWith { f1, f2 -> - val str1 = f1.remarkquanpin ?: f1.quanpin ?: f1.nickname - val str2 = f2.remarkquanpin ?: f2.quanpin ?: f2.nickname - - val type1 = when { - str1.matches(Regex("[a-zA-Z]+")) -> 1 // 字母 - str1.matches(Regex("[0-9]+")) -> 2 // 数字 - else -> 3 // 特殊字符 - } - - val type2 = when { - str2.matches(Regex("[a-zA-Z]+")) -> 1 // 字母 - str2.matches(Regex("[0-9]+")) -> 2 // 数字 - else -> 3 // 特殊字符 - } - - // 比较类型,如果相同再按字母升序排序 - if (type1 != type2) { - type1 - type2 // 按类型排序 - } else { - str1.compareTo(str2) // 如果类型相同,按字母顺序排序 - } - } - - // 设置是否显示分组头 - uiFriendList?.forEachIndexed { index, item -> - item.showHeader = - (index == 0 || item.quanpin?.get(index) != uiFriendList[index - 1].quanpin?.get( - index - 1 - )) - } - - _contactListResponse.value = uiFriendList - } else { - _contactListResponse.value = null - } + val result = contactRepository.getContactList(username) + _contactListResult.postValue(result) } } - - private fun mapToFriendItem(response: Contact): Contact { - val pinyin = Pinyin4jUtil.toPinyin(response.nickname) - response.remark?.let { - response.remarkquanpin = Pinyin4jUtil.toPinyin(it) - } - response.quanpin = pinyin - return response - } } diff --git a/app/src/main/java/com/kaixed/kchat/viewmodel/UserViewModel.kt b/app/src/main/java/com/kaixed/kchat/viewmodel/UserViewModel.kt index 44a679f..ef0e9af 100644 --- a/app/src/main/java/com/kaixed/kchat/viewmodel/UserViewModel.kt +++ b/app/src/main/java/com/kaixed/kchat/viewmodel/UserViewModel.kt @@ -1,143 +1,98 @@ package com.kaixed.kchat.viewmodel -import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.kaixed.kchat.data.objectbox.entity.UserInfo import com.kaixed.kchat.model.request.RegisterRequest import com.kaixed.kchat.model.request.UserRequest -import com.kaixed.kchat.model.response.friend.SearchFriends -import com.kaixed.kchat.model.response.login.Login import com.kaixed.kchat.model.response.register.Register -import com.kaixed.kchat.model.response.search.UserList -import com.kaixed.kchat.repository.UserRepository +import com.kaixed.kchat.model.response.search.User +import com.kaixed.kchat.model.search.SearchUser +import com.kaixed.kchat.repository.UserAuthRepository +import com.kaixed.kchat.repository.UserProfileRepository +import com.kaixed.kchat.repository.UserSearchRepository import kotlinx.coroutines.launch import okhttp3.MultipartBody class UserViewModel : ViewModel() { - private val userRepo = UserRepository() + private val userAuthRepo = UserAuthRepository() - // 注册返回 - private val _registerResponse = MutableLiveData() - val registerResponse: LiveData = _registerResponse + private val userProfileRepo = UserProfileRepository() - // 获取用户列表返回 - private val _userListResponse = MutableLiveData() - val userListResponse: LiveData = _userListResponse + private val userSearchRepo = UserSearchRepository() - // 获取用户信息返回 - private val _userInfoResponse = MutableLiveData() - val userInfoResponse: LiveData = _userInfoResponse + private val _loginResult = MutableLiveData>() + val loginResult: LiveData> = _loginResult - // 修改昵称返回 - private val _changeNicknameResponse = MutableLiveData() - val changeNicknameResponse: LiveData = _changeNicknameResponse + fun loginByUsername(username: String, password: String) { + viewModelScope.launch { + val result = userAuthRepo.loginByUsername(username, password) + _loginResult.postValue(result) + } + } - // 上传头像返回 - private val _uploadAvatarResponse = MutableLiveData() - val uploadAvatarResponse: LiveData = _uploadAvatarResponse + fun loginByTelephone(username: String, password: String) { + viewModelScope.launch { + val result = userAuthRepo.loginByTelephone(username, password) + _loginResult.postValue(result) + } + } - // 登录返回 - private val _loginResponse = MutableLiveData() - val loginResponse: LiveData = _loginResponse + private val _registerResult = MutableLiveData>() + val registerResult: LiveData> = _registerResult // 注册请求 fun register(registerRequest: RegisterRequest) { viewModelScope.launch { - try { - val response = userRepo.register(registerRequest) - if (response.isSuccessful) { - _registerResponse.value = response.body() - } else { - _registerResponse.value = null - } - } catch (e: Exception) { - Log.e("UserViewModel", "Register failed: ${e.message}") - _registerResponse.value = null - } + val result = userAuthRepo.register(registerRequest) + _registerResult.postValue(result) } } - // 登录方法 - fun login(username: String?, password: String, loginByUsername: Boolean) { - viewModelScope.launch { - try { - val response = userRepo.login(username, password, loginByUsername) - if (response.isSuccessful) { - _loginResponse.value = response.body() - } else { - _loginResponse.value = null // 登录失败时 - } - } catch (e: Exception) { - Log.e("UserViewModel", "Login failed: ${e.message}") - _loginResponse.value = null - } - } - } + private val _userListResult = MutableLiveData>>() + val userListResult: LiveData>> = _userListResult // 获取用户列表 fun getUserList(username: String) { viewModelScope.launch { - try { - val response = userRepo.getUserList(username) - if (response.isSuccessful) { - _userListResponse.value = response.body() - } else { - _userListResponse.value = null - } - } catch (e: Exception) { - Log.e("UserViewModel", "Get User List failed: ${e.message}") - _userListResponse.value = null - } + val result = userSearchRepo.getUserList(username) + _userListResult.postValue(result) } } + private val _userInfoResult = MutableLiveData>() + val userInfoResult: LiveData> = _userInfoResult + // 获取用户信息 fun getUserInfo(username: String) { viewModelScope.launch { - try { - val response = userRepo.getUserInfo(username) - if (response.isSuccessful) { - _userInfoResponse.value = response.body() - } else { - _userInfoResponse.value = null - } - } catch (e: Exception) { - Log.e("UserViewModel", "Get User failed: ${e.message}") - _userInfoResponse.value = null - } + val result = userProfileRepo.getUserInfo(username) + _userInfoResult.postValue(result) } } + private val _changeNicknameResult = MutableLiveData>() + val changeNicknameResult: LiveData> = _changeNicknameResult + // 修改昵称 fun changeNickname(userRequest: UserRequest) { viewModelScope.launch { - try { - val response = userRepo.changeNickname(userRequest) - _changeNicknameResponse.value = response.isSuccessful - } catch (e: Exception) { - Log.e("UserViewModel", "Change Nickname failed: ${e.message}") - _changeNicknameResponse.value = false - } + val result = userProfileRepo.changeNickname(userRequest) + _changeNicknameResult.postValue(result) } } + private val _uploadAvatarResult = MutableLiveData>() + val uploadAvatarResult: LiveData> = _uploadAvatarResult + // 上传头像 fun uploadAvatar(file: MultipartBody.Part, username: String) { viewModelScope.launch { - try { - val response = userRepo.uploadAvatar(file, username) - if (response.isSuccessful) { - _uploadAvatarResponse.value = response.body() - } else { - _uploadAvatarResponse.value = null - } - } catch (e: Exception) { - Log.e("UserViewModel", "Upload Avatar failed: ${e.message}") - _uploadAvatarResponse.value = null - } + val result = userProfileRepo.uploadAvatar(file, username) + _uploadAvatarResult.postValue(result) } } } diff --git a/app/src/main/res/layout/activity_contacts_detail.xml b/app/src/main/res/layout/activity_contacts_detail.xml index e6e1b17..18a9ca1 100644 --- a/app/src/main/res/layout/activity_contacts_detail.xml +++ b/app/src/main/res/layout/activity_contacts_detail.xml @@ -55,7 +55,7 @@ android:layout_height="wrap_content" android:text="kid: kaixed" android:textSize="14sp" - app:layout_constraintStart_toStartOf="@id/tv_contact_name" + app:layout_constraintStart_toStartOf="@id/tv_remark" app:layout_constraintTop_toBottomOf="@id/tv_contact_name" /> - 192.168.235.209 + 192.168.156.209