diff --git a/app/src/main/java/com/example/defenseapplication/MyApplication.kt b/app/src/main/java/com/example/defenseapplication/MyApplication.kt index 44bc787..a99a17c 100644 --- a/app/src/main/java/com/example/defenseapplication/MyApplication.kt +++ b/app/src/main/java/com/example/defenseapplication/MyApplication.kt @@ -6,7 +6,6 @@ import bean.LoginBean import com.blankj.utilcode.util.Utils import com.example.defenseapplication.bean.BaseInfo import com.example.defenseapplication.utils.ApiConfig -import com.example.defenseapplication.utils.LanguageHeaderManager import com.example.defenseapplication.utils.LanguageUtil import com.example.defenseapplication.utils.UserinfoUtil import com.google.gson.Gson @@ -21,7 +20,7 @@ class MyApplication : Application() { if (token != null) { ApiConfig.authToken = token }; - LanguageHeaderManager.init(this) + LanguageUtil.init(this) } override fun attachBaseContext(base: Context) { diff --git a/app/src/main/java/com/example/defenseapplication/adapter/LinkedUserAdapter.kt b/app/src/main/java/com/example/defenseapplication/adapter/LinkedUserAdapter.kt index 1a96c8c..63f0e47 100644 --- a/app/src/main/java/com/example/defenseapplication/adapter/LinkedUserAdapter.kt +++ b/app/src/main/java/com/example/defenseapplication/adapter/LinkedUserAdapter.kt @@ -4,6 +4,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView +import com.example.defenseapplication.R import com.example.defenseapplication.databinding.ItemLinkedUserBinding data class LinkedUser( @@ -54,10 +55,11 @@ class LinkedUserAdapter( ) : RecyclerView.ViewHolder(binding.root) { fun bind(item: LinkedUser, position: Int) { + val context = binding.root.context binding.tvUserName.text = item.name binding.tvTime.text = item.time - binding.tvPhone.text = "手机号码:${item.phone}" - binding.tvIdCard.text = "身份证号:${item.idCard}" + binding.tvPhone.text = context.getString(R.string.linked_user_phone_label, item.phone) + binding.tvIdCard.text = context.getString(R.string.linked_user_idcard_label, item.idCard) binding.root.setOnClickListener { onItemClick(item, position) diff --git a/app/src/main/java/com/example/defenseapplication/base/BaseActivity.kt b/app/src/main/java/com/example/defenseapplication/base/BaseActivity.kt index 590076c..bb19a2a 100644 --- a/app/src/main/java/com/example/defenseapplication/base/BaseActivity.kt +++ b/app/src/main/java/com/example/defenseapplication/base/BaseActivity.kt @@ -1,13 +1,20 @@ package com.example.defenseapplication.base +import android.content.Context import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.example.defenseapplication.utils.ActivityManager +import com.example.defenseapplication.utils.LanguageUtil open class BaseActivity : AppCompatActivity() { + override fun attachBaseContext(newBase: Context) { + super.attachBaseContext(LanguageUtil.attachBaseContext(newBase)) + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + LanguageUtil.init(this) ActivityManager.addActivity(this) } diff --git a/app/src/main/java/com/example/defenseapplication/home/HomeActivity.kt b/app/src/main/java/com/example/defenseapplication/home/HomeActivity.kt index db2426d..1cd7eda 100644 --- a/app/src/main/java/com/example/defenseapplication/home/HomeActivity.kt +++ b/app/src/main/java/com/example/defenseapplication/home/HomeActivity.kt @@ -1,18 +1,17 @@ package com.example.defenseapplication.home import android.os.Bundle -import android.util.Log -import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AppCompatActivity import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat import androidx.fragment.app.Fragment import com.example.defenseapplication.R +import com.example.defenseapplication.base.BaseActivity import com.example.defenseapplication.databinding.HomeActivityBinding import com.example.defenseapplication.databinding.HomeMenuFragmentBinding import com.gyf.immersionbar.ImmersionBar -class HomeActivity : AppCompatActivity() { +class HomeActivity : BaseActivity() { // ViewBinding 核心对象 private lateinit var binding: HomeActivityBinding diff --git a/app/src/main/java/com/example/defenseapplication/home/PersonalFragment.kt b/app/src/main/java/com/example/defenseapplication/home/PersonalFragment.kt index bda27fa..ed3d0c3 100644 --- a/app/src/main/java/com/example/defenseapplication/home/PersonalFragment.kt +++ b/app/src/main/java/com/example/defenseapplication/home/PersonalFragment.kt @@ -16,11 +16,14 @@ import com.example.defenseapplication.liveVideo.LinkedUserActivity import com.example.defenseapplication.personal.FaceManagementActivity import com.example.defenseapplication.personal.PasswordManagementActivity import com.example.defenseapplication.personal.PersonalProfileActivity +import com.example.defenseapplication.utils.AppLanguage import com.example.defenseapplication.utils.LanguageUtil import com.example.defenseapplication.utils.RetrofitNetwork import com.example.defenseapplication.utils.UserinfoUtil +import com.example.defenseapplication.utils.ActivityManager import com.example.defenseapplication.view.FamilySwitchDialog import com.example.defenseapplication.view.LanguageDialog +import com.example.defenseapplication.home.HomeActivity import com.gyf.immersionbar.ImmersionBar import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -155,18 +158,23 @@ class PersonalFragment : Fragment() { * 更新当前语言显示 */ private fun updateCurrentLanguageDisplay() { - val currentLang = LanguageUtil.getCurrentLanguage(requireContext()) - binding.tvCurrentLanguage.text = LanguageUtil.getLanguageDisplayName(currentLang) + binding.tvCurrentLanguage.text = LanguageUtil.currentLanguage.let { + if (it == AppLanguage.SIMPLIFIED_CHINESE) "中文" else "English" + } } /** * 显示语言选择对话框 */ private fun showLanguageDialog() { - val dialog = LanguageDialog(requireContext()) { language -> - LanguageUtil.switchLanguage(requireContext(), language) - // 刷新当前页面以应用新语言 - requireActivity().recreate() + val dialog = LanguageDialog(requireContext()) { appLanguage -> + LanguageUtil.switchLanguage(requireContext(), appLanguage) + // 关闭所有 Activity,重启到首页 + ActivityManager.finishAllActivities() + val intent = Intent(requireContext(), HomeActivity::class.java) + intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK + startActivity(intent) + requireActivity().finish() } dialog.show() } diff --git a/app/src/main/java/com/example/defenseapplication/liveVideo/SettingsActivity.kt b/app/src/main/java/com/example/defenseapplication/liveVideo/SettingsActivity.kt index e64a405..178a311 100644 --- a/app/src/main/java/com/example/defenseapplication/liveVideo/SettingsActivity.kt +++ b/app/src/main/java/com/example/defenseapplication/liveVideo/SettingsActivity.kt @@ -13,7 +13,6 @@ import com.example.defenseapplication.utils.DeviceIdEvent import com.example.defenseapplication.utils.LanguageUtil import com.example.defenseapplication.utils.RetrofitNetwork import com.example.defenseapplication.view.CustomDialogFragmentText -import com.example.defenseapplication.view.LanguageDialog import com.example.defenseapplication.view.RecognitionModeDialog import com.gyf.immersionbar.ImmersionBar import kotlinx.coroutines.CoroutineScope diff --git a/app/src/main/java/com/example/defenseapplication/utils/ApiConfig.kt b/app/src/main/java/com/example/defenseapplication/utils/ApiConfig.kt index 1df4bce..c640cb4 100644 --- a/app/src/main/java/com/example/defenseapplication/utils/ApiConfig.kt +++ b/app/src/main/java/com/example/defenseapplication/utils/ApiConfig.kt @@ -162,11 +162,10 @@ object ApiConfig { fun createHeadersInterceptor() = Interceptor { chain -> val requestBuilder = chain.request().newBuilder() val token = authToken - val langHeader = LanguageHeaderManager.getLanguageHeaderValue() // 添加必要的请求头 requestBuilder.header("clientid", "428a8310cd442757ae699df5d894f051") - requestBuilder.header("content-language", langHeader) + requestBuilder.header("content-language", LanguageUtil.getLanguageHeaderValue()) // 如果有 token,添加 Authorization 头 if (token.isNotBlank()) { diff --git a/app/src/main/java/com/example/defenseapplication/utils/LanguageHeaderManager.kt b/app/src/main/java/com/example/defenseapplication/utils/LanguageHeaderManager.kt index 048209d..79ef604 100644 --- a/app/src/main/java/com/example/defenseapplication/utils/LanguageHeaderManager.kt +++ b/app/src/main/java/com/example/defenseapplication/utils/LanguageHeaderManager.kt @@ -1,37 +1,13 @@ package com.example.defenseapplication.utils import android.content.Context -import androidx.core.content.edit - -enum class AppLanguage(val code: String) { - ENGLISH("en_US"), - SIMPLIFIED_CHINESE("zh_CN"), - TRADITIONAL_CHINESE("zh_TW") -} +/** + * HTTP 请求头的语言值管理,统一由 LanguageUtil 提供 + * @deprecated Use LanguageUtil.getLanguageHeaderValue() directly + */ object LanguageHeaderManager { - private const val PREF_NAME = "app_lang_pref" - private const val KEY_LANGUAGE = "selected_language" - private var currentLanguage: AppLanguage = AppLanguage.ENGLISH - - fun init(context: Context) { - val prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) - val langCode = prefs.getString(KEY_LANGUAGE, AppLanguage.ENGLISH.code) - currentLanguage = AppLanguage.values().find { it.code == langCode } ?: AppLanguage.ENGLISH - } - - fun getCurrentLanguage(): AppLanguage = currentLanguage - - fun switchLanguage(context: Context, language: AppLanguage) { - currentLanguage = language - // 持久化 - context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE).edit { - putString(KEY_LANGUAGE, language.code) - apply() - } - // 可选:更新应用 Locale、重启 Activity 等 - } - - fun getLanguageHeaderValue(): String = currentLanguage.code + @Deprecated("Use LanguageUtil.getLanguageHeaderValue() instead", ReplaceWith("LanguageUtil.getLanguageHeaderValue()")) + fun getLanguageHeaderValue(): String = LanguageUtil.getLanguageHeaderValue() } \ No newline at end of file diff --git a/app/src/main/java/com/example/defenseapplication/utils/LanguageUtil.kt b/app/src/main/java/com/example/defenseapplication/utils/LanguageUtil.kt index ecc5778..231a0c3 100644 --- a/app/src/main/java/com/example/defenseapplication/utils/LanguageUtil.kt +++ b/app/src/main/java/com/example/defenseapplication/utils/LanguageUtil.kt @@ -3,77 +3,128 @@ package com.example.defenseapplication.utils import android.content.Context import android.content.SharedPreferences import android.content.res.Configuration -import android.content.res.Resources import android.os.Build import android.os.LocaleList import java.util.Locale +enum class AppLanguage(val code: String, val locale: Locale) { + ENGLISH("en_US", Locale.US), + SIMPLIFIED_CHINESE("zh_CN", Locale.SIMPLIFIED_CHINESE); + + companion object { + fun fromCode(code: String): AppLanguage { + return values().find { it.code == code } ?: SIMPLIFIED_CHINESE + } + } +} + object LanguageUtil { private const val PREF_NAME = "language_pref" private const val KEY_LANGUAGE = "selected_language" - const val LANGUAGE_CHINESE = "zh" - const val LANGUAGE_ENGLISH = "en" + @JvmStatic + var currentLanguage: AppLanguage = AppLanguage.SIMPLIFIED_CHINESE + private set /** - * 切换语言 - * @param context 上下文 - * @param language 语言代码: "zh" 中文, "en" 英文 + * 初始化语言,从持久化中恢复 + */ + fun init(context: Context) { + val prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) + var code = prefs.getString(KEY_LANGUAGE, null) + if (code == null) { + // 兼容旧数据:尝试从 app_lang_pref 读取(LanguageHeaderManager 旧存储路径) + val oldPrefs = context.getSharedPreferences("app_lang_pref", Context.MODE_PRIVATE) + code = oldPrefs.getString("selected_language", AppLanguage.SIMPLIFIED_CHINESE.code) + ?: AppLanguage.SIMPLIFIED_CHINESE.code + // 迁移到新存储路径 + prefs.edit().putString(KEY_LANGUAGE, code).apply() + } + currentLanguage = AppLanguage.fromCode(code) + } + + /** + * 切换语言,同时更新 app locale 和 HTTP header + * @param language AppLanguage.ENGLISH 或 AppLanguage.SIMPLIFIED_CHINESE + */ + fun switchLanguage(context: Context, language: AppLanguage) { + currentLanguage = language + saveLanguage(context, language.code) + } + + /** + * 兼容旧代码:使用字符串 "zh" / "en" 切换 */ fun switchLanguage(context: Context, language: String) { - saveLanguage(context, language) + val appLang = when (language) { + "zh" -> AppLanguage.SIMPLIFIED_CHINESE + else -> AppLanguage.ENGLISH + } + switchLanguage(context, appLang) } /** - * 获取当前设置的语言 + * 获取当前设置的语言代码 "zh" / "en" */ fun getCurrentLanguage(context: Context): String { - val prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) - return prefs.getString(KEY_LANGUAGE, LANGUAGE_CHINESE) ?: LANGUAGE_CHINESE + return currentLanguage.name.lowercase().let { + if (it.contains("chinese")) "zh" else "en" + } } + /** + * 获取 HTTP header 的语言值 "en_US" / "zh_CN" + */ + fun getLanguageHeaderValue(): String = currentLanguage.code + /** * 保存语言设置 */ - private fun saveLanguage(context: Context, language: String) { + private fun saveLanguage(context: Context, languageCode: String) { val prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) - prefs.edit().putString(KEY_LANGUAGE, language).apply() + prefs.edit().putString(KEY_LANGUAGE, languageCode).apply() } /** * 判断当前是否是中文 */ fun isChinese(context: Context): Boolean { - return getCurrentLanguage(context) == LANGUAGE_CHINESE + return currentLanguage == AppLanguage.SIMPLIFIED_CHINESE } /** - * 获取本地化的 Context(用于在应用内切换语言) - * 在 attachBaseContext 中调用 + * 获取本地化的 Context(在 attachBaseContext 中调用) */ fun attachBaseContext(context: Context): Context { - val language = getCurrentLanguage(context) - return createLocalizedContext(context, language) + val locale = getSavedLocale(context) + return createLocalizedContext(context, locale) + } + + /** + * 读取已保存的语言 locale(attachBaseContext 中使用,此时 currentLanguage 可能尚未初始化) + */ + private fun getSavedLocale(context: Context): Locale { + val prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) + val code = prefs.getString(KEY_LANGUAGE, AppLanguage.SIMPLIFIED_CHINESE.code) + ?: AppLanguage.SIMPLIFIED_CHINESE.code + return AppLanguage.fromCode(code).locale } /** * 创建本地化的 Context */ - private fun createLocalizedContext(context: Context, language: String): Context { - val locale = Locale(language) + private fun createLocalizedContext(context: Context, locale: Locale): Context { Locale.setDefault(locale) val resources = context.resources val configuration = resources.configuration return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - // Android 7.0 及以上 val localeList = LocaleList(locale) configuration.setLocales(localeList) context.createConfigurationContext(configuration) } else { - // Android 7.0 以下 configuration.locale = locale resources.updateConfiguration(configuration, resources.displayMetrics) context @@ -84,8 +135,7 @@ object LanguageUtil { * 更新应用语言(用于在 Activity 中动态切换) */ fun updateResources(context: Context): Context { - val language = getCurrentLanguage(context) - val locale = Locale(language) + val locale = currentLanguage.locale Locale.setDefault(locale) val resources = context.resources @@ -107,8 +157,8 @@ object LanguageUtil { */ fun getLanguageDisplayName(language: String): String { return when (language) { - LANGUAGE_CHINESE -> "中文" - LANGUAGE_ENGLISH -> "English" + "zh" -> "中文" + "en" -> "English" else -> "中文" } } diff --git a/app/src/main/java/com/example/defenseapplication/view/LanguageDialog.kt b/app/src/main/java/com/example/defenseapplication/view/LanguageDialog.kt index 05dd8be..d5d5cba 100644 --- a/app/src/main/java/com/example/defenseapplication/view/LanguageDialog.kt +++ b/app/src/main/java/com/example/defenseapplication/view/LanguageDialog.kt @@ -9,6 +9,7 @@ import android.view.WindowManager import android.widget.LinearLayout import android.widget.TextView import com.example.defenseapplication.R +import com.example.defenseapplication.utils.AppLanguage import com.example.defenseapplication.utils.LanguageUtil /** @@ -16,7 +17,7 @@ import com.example.defenseapplication.utils.LanguageUtil */ class LanguageDialog( context: Context, - private val onLanguageSelected: (String) -> Unit + private val onLanguageSelected: (AppLanguage) -> Unit ) : Dialog(context, R.style.BottomDialogStyle) { override fun onCreate(savedInstanceState: Bundle?) { @@ -43,22 +44,21 @@ class LanguageDialog( val tvEnglish = findViewById(R.id.tvEnglish) val tvCancel = findViewById(R.id.tvCancel) - val currentLang = LanguageUtil.getCurrentLanguage(context) + val currentLang = LanguageUtil.currentLanguage - // 根据当前语言高亮显示 - if (currentLang == LanguageUtil.LANGUAGE_CHINESE) { + if (currentLang == AppLanguage.SIMPLIFIED_CHINESE) { tvChinese.setTextColor(context.getColor(R.color.green)) } else { tvEnglish.setTextColor(context.getColor(R.color.green)) } llChinese.setOnClickListener { - onLanguageSelected(LanguageUtil.LANGUAGE_CHINESE) + onLanguageSelected(AppLanguage.SIMPLIFIED_CHINESE) dismiss() } llEnglish.setOnClickListener { - onLanguageSelected(LanguageUtil.LANGUAGE_ENGLISH) + onLanguageSelected(AppLanguage.ENGLISH) dismiss() } diff --git a/app/src/main/res/drawable/english.png b/app/src/main/res/drawable/english.png index db72030..77c1fab 100644 Binary files a/app/src/main/res/drawable/english.png and b/app/src/main/res/drawable/english.png differ diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index c2d8ae0..078965c 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -470,4 +470,6 @@ 上传中... 上传失败 最多添加11个用户 + 手机号码:%s + 身份证号:%s \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7fd985e..ffe04ff 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -474,4 +474,6 @@ Select Date Select Time A maximum of 11 users can be added + Phone: %s + ID: %s \ No newline at end of file