优化
This commit is contained in:
@@ -6,7 +6,8 @@
|
||||
"Bash(find /d/Test/MyApplication/app/src/main/assets -name \"vocab.txt\" -exec wc -l {} ;)",
|
||||
"WebSearch",
|
||||
"Bash(grep:*)",
|
||||
"Bash(find:*)"
|
||||
"Bash(find:*)",
|
||||
"Bash(ls:*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,7 +235,9 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
bottomNav.post {
|
||||
bottomNav.selectedItemId = R.id.home_graph
|
||||
openGlobal(R.id.loginFragment) // ✅ 退出登录后立刻打开登录页
|
||||
// ✅ clearBackStack=true:清空全局回退栈(如 PersonalSettings 等残留页面),
|
||||
// 避免用户从登录页返回时全局栈未清空导致底部 Tab 栏消失
|
||||
openGlobal(R.id.loginFragment, clearBackStack = true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -769,6 +769,9 @@ class MyInputMethodService : InputMethodService(), KeyboardEnvironment {
|
||||
aiKeyboard = null
|
||||
emojiKeyboard = null
|
||||
|
||||
// 深色模式切换时更新主题,下次键盘创建时使用新主题
|
||||
ThemeManager.onSystemConfigurationChanged(this)
|
||||
|
||||
super.onConfigurationChanged(newConfig)
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,17 @@ interface ApiService {
|
||||
suspend fun logout(
|
||||
): ApiResponse<Boolean>
|
||||
|
||||
//注销账户
|
||||
@POST("user/cancelAccount")
|
||||
suspend fun cancelAccount(
|
||||
): ApiResponse<Boolean>
|
||||
|
||||
//按 locale 查询提示信息
|
||||
@GET("keyboardWarningMessage/byLocale")
|
||||
suspend fun keyboardWarningMessage(
|
||||
@Query("locale") id: String
|
||||
): ApiResponse<keyboardWarningMessageResponse>
|
||||
|
||||
//发送验证邮件
|
||||
@POST("user/sendVerifyMail")
|
||||
suspend fun sendVerifyCode(
|
||||
|
||||
@@ -54,6 +54,12 @@ data class VerifyCodeRequest(
|
||||
val mailAddress: String,
|
||||
val verifyCode: String,
|
||||
)
|
||||
//注销账户
|
||||
data class keyboardWarningMessageResponse(
|
||||
val locale: String,
|
||||
val content: String,
|
||||
val updatedAt: String,
|
||||
)
|
||||
|
||||
//重置密码
|
||||
data class ResetPasswordRequest(
|
||||
|
||||
@@ -128,17 +128,24 @@ object ThemeManager {
|
||||
}
|
||||
|
||||
fun init(context: Context) {
|
||||
android.util.Log.d("1314520-ThemeManager", "init: currentThemeName=$currentThemeName")
|
||||
if (currentThemeName != null) return
|
||||
|
||||
val prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||
isManualTheme = prefs.getBoolean(KEY_IS_MANUAL_THEME, false)
|
||||
|
||||
val savedTheme = prefs.getString(KEY_CURRENT_THEME, "default") ?: "default"
|
||||
|
||||
// 默认主题不应视为手动模式,修正历史脏数据
|
||||
if (isManualTheme && (savedTheme == "default" || savedTheme == "default_darkness")) {
|
||||
isManualTheme = false
|
||||
prefs.edit().putBoolean(KEY_IS_MANUAL_THEME, false).apply()
|
||||
}
|
||||
|
||||
if (!isManualTheme) {
|
||||
updateThemeForSystemMode(context)
|
||||
context.registerSystemDarkModeListener()
|
||||
} else {
|
||||
val name = prefs.getString(KEY_CURRENT_THEME, "default") ?: "default"
|
||||
setCurrentTheme(context, name, true)
|
||||
setCurrentTheme(context, savedTheme, true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,6 +154,23 @@ object ThemeManager {
|
||||
setCurrentTheme(context, defaultTheme, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统配置变更时调用,非手动主题模式下自动切换深色/浅色主题
|
||||
*/
|
||||
fun onSystemConfigurationChanged(context: Context) {
|
||||
val dark = isDarkMode(context)
|
||||
// 默认主题始终跟随系统深色模式
|
||||
if (isManualTheme && (currentThemeName == "default" || currentThemeName == "default_darkness")) {
|
||||
isManualTheme = false
|
||||
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||
.edit().putBoolean(KEY_IS_MANUAL_THEME, false).apply()
|
||||
}
|
||||
android.util.Log.d("1314520-ThemeManager", "onSystemConfigurationChanged: isManualTheme=$isManualTheme, isDark=$dark, currentTheme=$currentThemeName")
|
||||
if (!isManualTheme) {
|
||||
updateThemeForSystemMode(context)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换当前主题:
|
||||
* - 更新 currentThemeName
|
||||
@@ -154,6 +178,7 @@ object ThemeManager {
|
||||
* - 重新加载该主题的全部图片到缓存
|
||||
*/
|
||||
fun setCurrentTheme(context: Context, themeName: String, isManual: Boolean = true) {
|
||||
android.util.Log.d("1314520-ThemeManager", "setCurrentTheme: themeName=$themeName, isManual=$isManual, old=$currentThemeName")
|
||||
currentThemeName = themeName
|
||||
isManualTheme = isManual
|
||||
|
||||
@@ -163,9 +188,11 @@ object ThemeManager {
|
||||
.putBoolean(KEY_IS_MANUAL_THEME, isManual)
|
||||
.apply()
|
||||
|
||||
// 如果是手动选择主题,取消系统模式监听
|
||||
// 如果是手动选择主题,取消系统模式监听;否则重新注册
|
||||
if (isManual) {
|
||||
context.unregisterSystemDarkModeListener()
|
||||
} else {
|
||||
context.registerSystemDarkModeListener()
|
||||
}
|
||||
|
||||
val newFilePathCache: MutableMap<String, File> = ConcurrentHashMap()
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.example.myapplication.ui.mine
|
||||
|
||||
import android.app.Dialog
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.example.myapplication.R
|
||||
|
||||
class CancelAccountDialogFragment(
|
||||
private val onConfirm: () -> Unit
|
||||
) : DialogFragment() {
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val dialog = Dialog(requireContext())
|
||||
dialog.setContentView(R.layout.dialog_cancel_account)
|
||||
dialog.setCancelable(true)
|
||||
|
||||
dialog.window?.apply {
|
||||
setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
setLayout(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
}
|
||||
|
||||
dialog.findViewById<View>(R.id.btn_cancel).setOnClickListener {
|
||||
dismiss()
|
||||
}
|
||||
dialog.findViewById<View>(R.id.btn_confirm).setOnClickListener {
|
||||
dismiss()
|
||||
onConfirm()
|
||||
}
|
||||
|
||||
return dialog
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,6 @@ class MineFragment : Fragment() {
|
||||
private lateinit var nickname: TextView
|
||||
private lateinit var vipIcon: ImageView
|
||||
private lateinit var time: TextView
|
||||
private lateinit var logout: TextView
|
||||
private lateinit var avatar: CircleImageView
|
||||
private lateinit var share: LinearLayout
|
||||
private lateinit var loadingOverlay: LoadingOverlay
|
||||
@@ -76,7 +75,6 @@ class MineFragment : Fragment() {
|
||||
nickname = view.findViewById(R.id.nickname)
|
||||
vipIcon = view.findViewById(R.id.vip_icon)
|
||||
time = view.findViewById(R.id.time)
|
||||
logout = view.findViewById(R.id.logout)
|
||||
avatar = view.findViewById(R.id.avatar)
|
||||
share = view.findViewById(R.id.click_Share)
|
||||
loadingOverlay = LoadingOverlay.attach(view.findViewById(R.id.rootCoordinator))
|
||||
@@ -123,17 +121,6 @@ class MineFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
logout.setOnClickListener {
|
||||
LogoutDialogFragment { doLogout() }
|
||||
.show(parentFragmentManager, "logout_dialog")
|
||||
|
||||
BehaviorReporter.report(
|
||||
isNewUser = false,
|
||||
"page_id" to "person_info",
|
||||
"element_id" to "logout_btn",
|
||||
)
|
||||
}
|
||||
|
||||
view.findViewById<ImageView>(R.id.imgLeft).setOnClickListener {
|
||||
// 使用事件总线打开充值页面
|
||||
AuthEventBus.emit(AuthEvent.OpenGlobalPage(R.id.rechargeFragment))
|
||||
@@ -321,36 +308,6 @@ class MineFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun doLogout() {
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
try {
|
||||
val response = RetrofitClient.apiService.logout()
|
||||
if (!isAdded) return@launch
|
||||
|
||||
if (response.code == 0) {
|
||||
EncryptedSharedPreferencesUtil.remove(requireContext(), "Personal_information")
|
||||
EncryptedSharedPreferencesUtil.remove(requireContext(), "user")
|
||||
|
||||
// 清空 UI
|
||||
nickname.text = ""
|
||||
time.text = ""
|
||||
renderVip(false, null)
|
||||
Glide.with(requireContext())
|
||||
.load(R.drawable.default_avatar)
|
||||
.placeholder(R.drawable.component_loading)
|
||||
.error(R.drawable.no_search_result)
|
||||
.into(avatar)
|
||||
|
||||
// 触发登出事件,让MainActivity打开登录页面
|
||||
AuthEventBus.emit(AuthEvent.Logout(returnTabTag = "tab_mine"))
|
||||
} else {
|
||||
Log.e(TAG, "logout fail code=${response.code}")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "logout exception", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun renderVip(isVip: Boolean?, vipLevel: Int?) {
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
package com.example.myapplication.ui.mine.myotherpages
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.webkit.WebView
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.TextView
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.example.myapplication.R
|
||||
import com.example.myapplication.network.AuthEvent
|
||||
import com.example.myapplication.network.AuthEventBus
|
||||
import com.example.myapplication.network.RetrofitClient
|
||||
import com.example.myapplication.ui.mine.CancelAccountDialogFragment
|
||||
import com.example.myapplication.utils.EncryptedSharedPreferencesUtil
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class CancelAccount : Fragment() {
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
return inflater.inflate(R.layout.cancel_account, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
view.findViewById<FrameLayout>(R.id.iv_close).setOnClickListener {
|
||||
AuthEventBus.emit(AuthEvent.UserUpdated)
|
||||
requireActivity().onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
|
||||
view.findViewById<TextView>(R.id.btn_delete).setOnClickListener {
|
||||
CancelAccountDialogFragment { doCancelAccount() }
|
||||
.show(parentFragmentManager, "cancel_account_dialog")
|
||||
}
|
||||
|
||||
loadWarningMessage(view)
|
||||
}
|
||||
|
||||
private fun loadWarningMessage(view: View) {
|
||||
val progressBar = view.findViewById<ProgressBar>(R.id.progressBar)
|
||||
val webView = view.findViewById<WebView>(R.id.webView)
|
||||
val tvEmpty = view.findViewById<TextView>(R.id.tvEmpty)
|
||||
|
||||
val locale = resources.configuration.locales[0]
|
||||
val apiLocale = when (locale.language) {
|
||||
"zh" -> "zh-CN"
|
||||
else -> "en-US"
|
||||
}
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
try {
|
||||
val response = RetrofitClient.apiService.keyboardWarningMessage(apiLocale)
|
||||
if (!isAdded) return@launch
|
||||
|
||||
val content = response.data?.content
|
||||
if (response.code == 0 && !content.isNullOrBlank()) {
|
||||
progressBar.visibility = View.GONE
|
||||
webView.visibility = View.VISIBLE
|
||||
webView.isNestedScrollingEnabled = false
|
||||
webView.setBackgroundColor(0x00000000)
|
||||
webView.loadDataWithBaseURL(
|
||||
null,
|
||||
content,
|
||||
"text/html; charset=UTF-8",
|
||||
"UTF-8",
|
||||
null
|
||||
)
|
||||
} else {
|
||||
progressBar.visibility = View.GONE
|
||||
tvEmpty.visibility = View.VISIBLE
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("CancelAccount", "loadWarningMessage exception", e)
|
||||
if (!isAdded) return@launch
|
||||
progressBar.visibility = View.GONE
|
||||
tvEmpty.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun doCancelAccount() {
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
try {
|
||||
val response = RetrofitClient.apiService.cancelAccount()
|
||||
if (!isAdded) return@launch
|
||||
|
||||
if (response.code == 0) {
|
||||
EncryptedSharedPreferencesUtil.remove(requireContext(), "Personal_information")
|
||||
EncryptedSharedPreferencesUtil.remove(requireContext(), "user")
|
||||
|
||||
AuthEventBus.emit(AuthEvent.Logout(returnTabTag = "tab_mine"))
|
||||
} else {
|
||||
Log.e("CancelAccount", "cancelAccount fail code=${response.code}")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("CancelAccount", "cancelAccount exception", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,8 @@ import com.example.myapplication.network.RetrofitClient
|
||||
import com.example.myapplication.network.User
|
||||
import com.example.myapplication.network.updateInfoRequest
|
||||
import com.example.myapplication.ui.common.LoadingOverlay
|
||||
import com.example.myapplication.ui.mine.LogoutDialogFragment
|
||||
import com.example.myapplication.utils.EncryptedSharedPreferencesUtil
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import de.hdodenhof.circleimageview.CircleImageView
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -45,6 +47,10 @@ import android.util.Log
|
||||
|
||||
class PersonalSettings : BottomSheetDialogFragment() {
|
||||
|
||||
companion object {
|
||||
private const val TAG = "PersonalSettings"
|
||||
}
|
||||
|
||||
private var user: User? = null
|
||||
|
||||
private lateinit var avatar: CircleImageView
|
||||
@@ -178,8 +184,25 @@ class PersonalSettings : BottomSheetDialogFragment() {
|
||||
Toast.makeText(requireContext(), getString(R.string.personal_settings_copy), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
//注销账号
|
||||
view.findViewById<View>(R.id.row_cancel_account).setOnClickListener {
|
||||
AuthEventBus.emit(AuthEvent.OpenGlobalPage(R.id.CancelAccount))
|
||||
}
|
||||
|
||||
// ===================== load & render =====================
|
||||
|
||||
// 退出登录
|
||||
view.findViewById<TextView>(R.id.logout).setOnClickListener {
|
||||
LogoutDialogFragment { doLogout() }
|
||||
.show(parentFragmentManager, "logout_dialog")
|
||||
|
||||
BehaviorReporter.report(
|
||||
isNewUser = false,
|
||||
"page_id" to "person_info",
|
||||
"element_id" to "logout_btn",
|
||||
)
|
||||
}
|
||||
|
||||
loadUser()
|
||||
|
||||
}
|
||||
@@ -213,7 +236,7 @@ class PersonalSettings : BottomSheetDialogFragment() {
|
||||
Glide.with(this)
|
||||
.load(u.avatarUrl)
|
||||
.placeholder(R.drawable.component_loading)
|
||||
.error(R.drawable.no_search_result)
|
||||
.error(R.drawable.default_avatar)
|
||||
.into(avatar)
|
||||
}
|
||||
|
||||
@@ -229,11 +252,48 @@ class PersonalSettings : BottomSheetDialogFragment() {
|
||||
cm.setPrimaryClip(ClipData.newPlainText("user_id", text))
|
||||
}
|
||||
|
||||
private suspend fun getUserdata(): ApiResponse<User>? =
|
||||
runCatching { RetrofitClient.apiService.getUser() }.getOrNull()
|
||||
private suspend fun getUserdata(): ApiResponse<User>? {
|
||||
Log.d(TAG, "getUserdata: 开始请求用户数据")
|
||||
return runCatching {
|
||||
RetrofitClient.apiService.getUser()
|
||||
}.onSuccess {
|
||||
Log.d(TAG, "getUserdata: 请求成功 code=${it.code}, data=${it.data}")
|
||||
}.onFailure {
|
||||
Log.e(TAG, "getUserdata: 请求异常", it)
|
||||
}.getOrNull()
|
||||
}
|
||||
|
||||
private suspend fun setupdateUserInfo(body: updateInfoRequest): ApiResponse<Boolean>? =
|
||||
runCatching { RetrofitClient.apiService.updateUserInfo(body) }.getOrNull()
|
||||
private suspend fun setupdateUserInfo(body: updateInfoRequest): ApiResponse<Boolean>? {
|
||||
Log.d(TAG, "setupdateUserInfo: 开始更新用户信息 body=$body")
|
||||
return runCatching {
|
||||
RetrofitClient.apiService.updateUserInfo(body)
|
||||
}.onSuccess {
|
||||
Log.d(TAG, "setupdateUserInfo: 更新成功 code=${it.code}, data=${it.data}")
|
||||
}.onFailure {
|
||||
Log.e(TAG, "setupdateUserInfo: 更新异常", it)
|
||||
}.getOrNull()
|
||||
}
|
||||
|
||||
private fun doLogout() {
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
try {
|
||||
val response = RetrofitClient.apiService.logout()
|
||||
if (!isAdded) return@launch
|
||||
|
||||
if (response.code == 0) {
|
||||
EncryptedSharedPreferencesUtil.remove(requireContext(), "Personal_information")
|
||||
EncryptedSharedPreferencesUtil.remove(requireContext(), "user")
|
||||
|
||||
dismiss()
|
||||
AuthEventBus.emit(AuthEvent.Logout(returnTabTag = "tab_mine"))
|
||||
} else {
|
||||
Log.e("PersonalSettings", "logout fail code=${response.code}")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("PersonalSettings", "logout exception", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val cameraPermissionLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
@@ -285,6 +345,7 @@ class PersonalSettings : BottomSheetDialogFragment() {
|
||||
}
|
||||
|
||||
private fun handleImageResult(uri: Uri) {
|
||||
// Log.d(TAG, "handleImageResult: 选择图片 uri=$uri")
|
||||
Glide.with(this)
|
||||
.load(uri)
|
||||
.placeholder(R.drawable.component_loading)
|
||||
@@ -297,6 +358,7 @@ class PersonalSettings : BottomSheetDialogFragment() {
|
||||
}
|
||||
|
||||
private suspend fun uploadAvatar(uri: Uri) {
|
||||
// Log.d(TAG, "1314520-uploadAvatar: 开始上传图片 uri=$uri")
|
||||
BehaviorReporter.report(
|
||||
isNewUser = false,
|
||||
"page_id" to "person_info",
|
||||
@@ -315,6 +377,8 @@ class PersonalSettings : BottomSheetDialogFragment() {
|
||||
val fileExtension = if (isPng) ".png" else ".jpg"
|
||||
val mediaType = if (isPng) "image/png" else "image/jpeg"
|
||||
|
||||
// Log.d(TAG, "1314520-uploadAvatar: mimeType=$mimeType, isPng=$isPng, fileExtension=$fileExtension")
|
||||
|
||||
// Temp file in app-private external files dir (no storage permission needed)
|
||||
val storageDir = requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES)
|
||||
val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
|
||||
@@ -322,9 +386,16 @@ class PersonalSettings : BottomSheetDialogFragment() {
|
||||
|
||||
// 先读取尺寸信息(inJustDecodeBounds)
|
||||
val boundsOptions = BitmapFactory.Options().apply { inJustDecodeBounds = true }
|
||||
resolver.openInputStream(uri)?.use { ins ->
|
||||
val boundsStream = resolver.openInputStream(uri)
|
||||
if (boundsStream == null) {
|
||||
Log.e(TAG, "1314520-uploadAvatar: openInputStream 返回 null,无法读取图片")
|
||||
return
|
||||
}
|
||||
boundsStream.use { ins ->
|
||||
BitmapFactory.decodeStream(ins, null, boundsOptions)
|
||||
} ?: return
|
||||
}
|
||||
|
||||
// Log.d(TAG, "1314520-uploadAvatar: 图片尺寸 ${boundsOptions.outWidth}x${boundsOptions.outHeight}")
|
||||
|
||||
// Calculate inSampleSize (粗略控制内存)
|
||||
var inSampleSize = 1
|
||||
@@ -352,10 +423,13 @@ class PersonalSettings : BottomSheetDialogFragment() {
|
||||
}
|
||||
|
||||
if (bitmap == null) {
|
||||
// Log.e(TAG, "1314520-uploadAvatar: bitmap 解码失败,无法生成位图")
|
||||
Toast.makeText(requireContext(),getString(R.string.Pop_up_window_PersonalSettings_3), Toast.LENGTH_SHORT).show()
|
||||
return
|
||||
}
|
||||
|
||||
// Log.d(TAG, "1314520-uploadAvatar: bitmap 解码成功 ${bitmap.width}x${bitmap.height}, inSampleSize=$inSampleSize")
|
||||
|
||||
// Compress to tempFile
|
||||
// 注意:用 outputStream 反复 compress 时不要在同一个 stream 上 truncate,
|
||||
// 最稳是每次重新打开 stream 写入。
|
||||
@@ -374,6 +448,7 @@ class PersonalSettings : BottomSheetDialogFragment() {
|
||||
}
|
||||
|
||||
if (tempFile.length() > maxSizeBytes) {
|
||||
Log.e(TAG, "1314520-uploadAvatar: 压缩后仍超过5MB, fileSize=${tempFile.length()}")
|
||||
Toast.makeText(requireContext(), getString(R.string.Pop_up_window_PersonalSettings_4), Toast.LENGTH_SHORT).show()
|
||||
bitmap.recycle()
|
||||
tempFile.delete()
|
||||
@@ -383,23 +458,30 @@ class PersonalSettings : BottomSheetDialogFragment() {
|
||||
val requestFile: RequestBody = RequestBody.create(mediaType.toMediaTypeOrNull(), tempFile)
|
||||
val body = MultipartBody.Part.createFormData("file", tempFile.name, requestFile)
|
||||
|
||||
// Log.d(TAG, "1314520-uploadAvatar: 准备上传 fileName=${tempFile.name}, fileSize=${tempFile.length()}, mediaType=$mediaType")
|
||||
|
||||
val response = RetrofitClient.createFileUploadService()
|
||||
.uploadFile("avatar", body)
|
||||
|
||||
// Log.d("1314520-PersonalSettings", "uploadAvatar: $response")
|
||||
|
||||
// Clean up
|
||||
bitmap.recycle()
|
||||
tempFile.delete()
|
||||
|
||||
if (response?.code == 0) {
|
||||
setupdateUserInfo(updateInfoRequest(avatarUrl = response.data))
|
||||
// Log.d(TAG, "1314520-uploadAvatar: 上传成功, avatarUrl=${response.data}, 开始更新用户信息")
|
||||
val updateResp = setupdateUserInfo(updateInfoRequest(avatarUrl = response.data))
|
||||
// Log.d(TAG, "1314520-uploadAvatar: 更新用户信息结果 code=${updateResp?.code}, data=${updateResp?.data}")
|
||||
Toast.makeText(requireContext(), R.string.personal_avatar_updated, Toast.LENGTH_SHORT).show()
|
||||
user = user?.copy(avatarUrl = response.data)
|
||||
} else {
|
||||
// Log.e(TAG, "1314520-uploadAvatar: 上传失败 code=${response?.code}, message=${response?.message}")
|
||||
Toast.makeText(requireContext(), R.string.personal_upload_failed, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Toast.makeText(requireContext(), R.string.personal_upload_failed, Toast.LENGTH_SHORT).show()
|
||||
Log.e("PersonalSettings", "Upload avatar error", e)
|
||||
Log.e("1314520-PersonalSettings", "Upload avatar error", e)
|
||||
} finally {
|
||||
loadingOverlay.hide()
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ class MySkin : Fragment() {
|
||||
// 如果当前主题是被删除的主题之一,切换到默认主题
|
||||
val currentTheme = com.example.myapplication.theme.ThemeManager.getCurrentThemeName()
|
||||
if (currentTheme != null && ids.any { it.toString() == currentTheme }) {
|
||||
com.example.myapplication.theme.ThemeManager.setCurrentTheme(requireContext(), "default")
|
||||
com.example.myapplication.theme.ThemeManager.setCurrentTheme(requireContext(), "default", false)
|
||||
}
|
||||
|
||||
adapter.removeByIds(ids.toSet())
|
||||
|
||||
7
app/src/main/res/drawable/bg_black_round_8dp.xml
Normal file
7
app/src/main/res/drawable/bg_black_round_8dp.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<solid android:color="#FF0000" />
|
||||
<corners android:radius="@dimen/sw_8dp" />
|
||||
|
||||
</shape>
|
||||
133
app/src/main/res/layout/cancel_account.xml
Normal file
133
app/src/main/res/layout/cancel_account.xml
Normal file
@@ -0,0 +1,133 @@
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/rootCoordinator"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#F6F7FB"
|
||||
tools:context=".ui.mine.myotherpages.CancelAccount">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- 标题和返回(固定顶部) -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="@dimen/sw_16dp"
|
||||
android:paddingEnd="@dimen/sw_16dp"
|
||||
android:paddingTop="@dimen/sw_16dp">
|
||||
<!-- 返回按钮 -->
|
||||
<FrameLayout
|
||||
android:id="@+id/iv_close"
|
||||
android:layout_width="@dimen/sw_46dp"
|
||||
android:layout_height="@dimen/sw_46dp">
|
||||
<ImageView
|
||||
android:layout_width="@dimen/sw_13dp"
|
||||
android:layout_height="@dimen/sw_13dp"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/more_icons"
|
||||
android:rotation="180"
|
||||
android:scaleType="fitCenter" />
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginEnd="@dimen/sw_49dp"
|
||||
android:gravity="center"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/cancel_account_title"
|
||||
android:textColor="#1B1F1A"
|
||||
android:textSize="@dimen/sw_16sp" />
|
||||
</LinearLayout>
|
||||
<!-- 提示信息 -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/sw_40dp"
|
||||
android:textStyle="bold"
|
||||
android:paddingStart="@dimen/sw_16dp"
|
||||
android:paddingEnd="@dimen/sw_16dp"
|
||||
android:gravity="center_vertical"
|
||||
android:text="@string/cancel_account_instruction"
|
||||
android:textColor="#1B1F1A"
|
||||
android:textSize="@dimen/sw_16sp" />
|
||||
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:fillViewport="true"
|
||||
android:overScrollMode="never">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:paddingStart="@dimen/sw_16dp"
|
||||
android:paddingEnd="@dimen/sw_16dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- 内容 -->
|
||||
<FrameLayout
|
||||
android:id="@+id/click_Notice"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/sw_64dp"
|
||||
android:layout_marginTop="@dimen/sw_20dp">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="@dimen/sw_16dp"
|
||||
android:layout_marginBottom="@dimen/sw_16dp" />
|
||||
|
||||
<WebView
|
||||
android:id="@+id/webView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvEmpty"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="@dimen/sw_16dp"
|
||||
android:layout_marginBottom="@dimen/sw_16dp"
|
||||
android:text="@string/search_not_data"
|
||||
android:textColor="#999999"
|
||||
android:textSize="@dimen/sw_14sp"
|
||||
android:visibility="gone" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
<!-- 删除按钮,固定在页面底部 -->
|
||||
<TextView
|
||||
android:id="@+id/btn_delete"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/sw_50dp"
|
||||
android:layout_marginStart="@dimen/sw_16dp"
|
||||
android:layout_marginEnd="@dimen/sw_16dp"
|
||||
android:layout_marginTop="@dimen/sw_10dp"
|
||||
android:layout_marginBottom="@dimen/sw_20dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/cancel_account_delete"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="@dimen/sw_16sp"
|
||||
android:textStyle="bold"
|
||||
android:background="@drawable/bg_black_round_8dp" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
54
app/src/main/res/layout/dialog_cancel_account.xml
Normal file
54
app/src/main/res/layout/dialog_cancel_account.xml
Normal file
@@ -0,0 +1,54 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/sw_24dp"
|
||||
android:background="@drawable/bg_dialog_round"
|
||||
android:layout_marginStart="@dimen/sw_24dp"
|
||||
android:layout_marginEnd="@dimen/sw_24dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<!-- 标题 -->
|
||||
<TextView
|
||||
android:text="@string/cancel_account_confirm_title"
|
||||
android:textSize="@dimen/sw_18sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="#222222"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<!-- 描述 -->
|
||||
<TextView
|
||||
android:layout_marginTop="@dimen/sw_12dp"
|
||||
android:text="@string/cancel_account_confirm_msg"
|
||||
android:textSize="@dimen/sw_14sp"
|
||||
android:textColor="#666666"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<!-- 按钮区 -->
|
||||
<LinearLayout
|
||||
android:layout_marginTop="@dimen/sw_24dp"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="end"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btn_cancel"
|
||||
android:text="@string/cancel"
|
||||
android:textSize="@dimen/sw_14sp"
|
||||
android:textColor="#666666"
|
||||
android:padding="@dimen/sw_12dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btn_confirm"
|
||||
android:text="@string/cancel_account_confirm_btn"
|
||||
android:textSize="@dimen/sw_14sp"
|
||||
android:textColor="#F44336"
|
||||
android:padding="@dimen/sw_12dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -508,18 +508,6 @@
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/logout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/sw_63dp"
|
||||
android:layout_marginTop="@dimen/sw_20dp"
|
||||
android:layout_marginBottom="@dimen/sw_20dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/mine_logout"
|
||||
android:textColor="#FF0000"
|
||||
android:textSize="@dimen/sw_16sp"
|
||||
android:textStyle="bold"
|
||||
android:background="@drawable/settings"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
android:layout_marginTop="@dimen/sw_24dp"
|
||||
android:background="@drawable/settings"
|
||||
android:orientation="vertical">
|
||||
<!-- Nickname -->
|
||||
<!-- 昵称 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/row_nickname"
|
||||
android:layout_width="match_parent"
|
||||
@@ -159,7 +159,7 @@
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Gender -->
|
||||
<!-- 性别 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/row_gender"
|
||||
android:layout_width="match_parent"
|
||||
@@ -247,6 +247,57 @@
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/sw_24dp"
|
||||
android:background="@drawable/settings"
|
||||
android:orientation="vertical">
|
||||
<!-- 注销账号 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/row_cancel_account"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/sw_64dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/sw_16dp"
|
||||
android:text="@string/personal_settings_cancel_account"
|
||||
android:textColor="#1B1F1A"
|
||||
android:textStyle="bold"
|
||||
android:textSize="@dimen/sw_16sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/sw_10dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:id="@+id/tv_userid_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text=""
|
||||
android:gravity="end"
|
||||
android:textColor="#1B1F1A"
|
||||
android:textStyle="bold"
|
||||
android:layout_weight="1"
|
||||
android:textSize="@dimen/sw_16sp" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/sw_9dp"
|
||||
android:layout_height="@dimen/sw_13dp"
|
||||
android:tint="#AFAFAF"
|
||||
android:layout_marginStart="@dimen/sw_12dp"
|
||||
android:layout_marginEnd="@dimen/sw_16dp"
|
||||
android:src="@drawable/more_icons" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
@@ -290,5 +341,21 @@
|
||||
</FrameLayout>
|
||||
</FrameLayout>
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<!-- 退出登录按钮,固定在页面底部 -->
|
||||
<TextView
|
||||
android:id="@+id/logout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/sw_63dp"
|
||||
android:layout_marginStart="@dimen/sw_16dp"
|
||||
android:layout_marginEnd="@dimen/sw_16dp"
|
||||
android:layout_marginTop="@dimen/sw_10dp"
|
||||
android:layout_marginBottom="@dimen/sw_20dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/mine_logout"
|
||||
android:textColor="#FF0000"
|
||||
android:textSize="@dimen/sw_16sp"
|
||||
android:textStyle="bold"
|
||||
android:background="@drawable/settings"/>
|
||||
</LinearLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
@@ -93,6 +93,13 @@
|
||||
android:label="Personal Settings"
|
||||
tools:layout="@layout/personal_settings" />
|
||||
|
||||
<!-- 注销账号 -->
|
||||
<fragment
|
||||
android:id="@+id/CancelAccount"
|
||||
android:name="com.example.myapplication.ui.mine.myotherpages.CancelAccount"
|
||||
android:label="Cancel Account"
|
||||
tools:layout="@layout/cancel_account" />
|
||||
|
||||
<!-- 键盘设置 -->
|
||||
<fragment
|
||||
android:id="@+id/MyKeyboard"
|
||||
|
||||
@@ -56,6 +56,9 @@
|
||||
<string name="Logout_confirm_title">确认退出登录</string>
|
||||
<string name="Logout_confirm_msg">您确认退出登录吗?</string>
|
||||
<string name="Logout_confirm_btn">退出登录</string>
|
||||
<string name="cancel_account_confirm_title">确认注销账号</string>
|
||||
<string name="cancel_account_confirm_msg">注销后账号将被停用,并清除本地登录数据,是否继续?</string>
|
||||
<string name="cancel_account_confirm_btn">确认</string>
|
||||
<!-- 个人设置页面 -->
|
||||
<string name="personal_settings_title">个人设置</string>
|
||||
<string name="personal_settings_nickname">昵称</string>
|
||||
@@ -68,6 +71,11 @@
|
||||
<string name="personal_choose_from_gallery">从相册选择</string>
|
||||
<string name="personal_take_photo">拍照</string>
|
||||
<string name="personal_upload_failed">上传失败</string>
|
||||
<string name="personal_settings_cancel_account">注销账号</string>
|
||||
<!-- 注销页面 -->
|
||||
<string name="cancel_account_instruction">注销账户须知</string>
|
||||
<string name="cancel_account_title">注销账号</string>
|
||||
<string name="cancel_account_delete">确认注销账户</string>
|
||||
<!-- 键盘人设 -->
|
||||
<string name="keyboard_title">我的人设</string>
|
||||
<string name="keyboard_delete_hint">删除人设</string>
|
||||
|
||||
@@ -57,6 +57,9 @@
|
||||
<string name="Logout_confirm_title">Confirm logging out</string>
|
||||
<string name="Logout_confirm_msg">Are you sure you want to log out?</string>
|
||||
<string name="Logout_confirm_btn">Log out</string>
|
||||
<string name="cancel_account_confirm_title">Confirm account cancellation</string>
|
||||
<string name="cancel_account_confirm_msg">After cancellation, your account will be deactivated and local login data will be cleared. Continue?</string>
|
||||
<string name="cancel_account_confirm_btn">Confirm</string>
|
||||
|
||||
|
||||
<!-- 个人设置页面 -->
|
||||
@@ -71,6 +74,11 @@
|
||||
<string name="personal_choose_from_gallery">Select from the photo album</string>
|
||||
<string name="personal_take_photo">Take a photo</string>
|
||||
<string name="personal_upload_failed">Upload failed</string>
|
||||
<string name="personal_settings_cancel_account">Cancel account</string>
|
||||
<!-- 注销页面 -->
|
||||
<string name="cancel_account_instruction">Cancel Account Notice</string>
|
||||
<string name="cancel_account_title">Cancel Account</string>
|
||||
<string name="cancel_account_delete">Confirm Cancel Account</string>
|
||||
<!-- 键盘人设 -->
|
||||
<string name="keyboard_title">My keyboard</string>
|
||||
<string name="keyboard_delete_hint">Delete character design</string>
|
||||
|
||||
Reference in New Issue
Block a user