优化时间弹窗
This commit is contained in:
@@ -31,7 +31,7 @@ import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.util.Hashtable
|
||||
|
||||
//邀请二维码
|
||||
class InvitationCodeActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var binding: InvitationCodeActivityBinding
|
||||
|
||||
@@ -1,20 +1,34 @@
|
||||
package com.example.defenseapplication.personal
|
||||
|
||||
import android.Manifest
|
||||
import android.content.ContentResolver
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.provider.MediaStore
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import android.widget.Toast
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.example.defenseapplication.R
|
||||
import com.example.defenseapplication.bean.UpdateUserInfo
|
||||
import com.example.defenseapplication.bean.UserInfoBean
|
||||
import com.example.defenseapplication.databinding.PersonalProfileActivityBinding
|
||||
import com.example.defenseapplication.utils.OssUtil
|
||||
import com.example.defenseapplication.utils.RetrofitNetwork
|
||||
import com.example.defenseapplication.view.AvatarSelectDialog
|
||||
import com.example.defenseapplication.view.CustomDialogFragmentText
|
||||
import com.example.defenseapplication.view.PhoneModifyDialogFragment
|
||||
import com.gyf.immersionbar.ImmersionBar
|
||||
@@ -22,11 +36,78 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
//个人资料
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
class PersonalProfileActivity : AppCompatActivity() {
|
||||
private lateinit var binding: PersonalProfileActivityBinding
|
||||
private var userInfo: UserInfoBean? = null
|
||||
|
||||
// 拍照返回的文件
|
||||
private var photoFile: File? = null
|
||||
|
||||
// 请求权限回调
|
||||
private val requestPermissionsLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.RequestMultiplePermissions()
|
||||
) { permissions ->
|
||||
val cameraGranted = permissions[Manifest.permission.CAMERA] ?: false
|
||||
val storageGranted = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
permissions[Manifest.permission.READ_MEDIA_IMAGES] ?: false
|
||||
} else {
|
||||
permissions[Manifest.permission.READ_EXTERNAL_STORAGE] ?: false
|
||||
}
|
||||
val writeStorageGranted = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
true
|
||||
} else {
|
||||
permissions[Manifest.permission.WRITE_EXTERNAL_STORAGE] ?: false
|
||||
}
|
||||
|
||||
if (!cameraGranted) {
|
||||
Toast.makeText(this, getString(R.string.camera_permission_denied), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
if (!storageGranted) {
|
||||
Toast.makeText(this, getString(R.string.storage_permission_denied), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU && !writeStorageGranted) {
|
||||
Toast.makeText(this, getString(R.string.write_storage_permission_denied), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
// 拍照结果回调
|
||||
private val takePhotoLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.TakePicture()
|
||||
) { success ->
|
||||
if (success && photoFile != null) {
|
||||
Log.d("PersonalProfile", "拍照成功,文件路径: ${photoFile?.absolutePath}")
|
||||
uploadAvatar(photoFile!!.absolutePath)
|
||||
} else {
|
||||
Toast.makeText(this, getString(R.string.take_photo_failed), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
// 相册选择结果回调
|
||||
private val selectAlbumLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
if (result.resultCode == RESULT_OK && result.data != null) {
|
||||
val uri = result.data?.data
|
||||
uri?.let {
|
||||
val filePath = getFilePathFromUri(it)
|
||||
if (filePath != null) {
|
||||
Log.d("PersonalProfile", "相册选择成功,文件路径: $filePath")
|
||||
uploadAvatar(filePath)
|
||||
} else {
|
||||
Toast.makeText(this, getString(R.string.get_file_failed), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = PersonalProfileActivityBinding.inflate(layoutInflater)
|
||||
@@ -37,6 +118,8 @@ class PersonalProfileActivity : AppCompatActivity() {
|
||||
.init()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
userInfo = intent.getParcelableExtra("userInfo", UserInfoBean::class.java)
|
||||
} else {
|
||||
userInfo = intent.getParcelableExtra("userInfo")
|
||||
}
|
||||
initView()
|
||||
}
|
||||
@@ -49,11 +132,11 @@ class PersonalProfileActivity : AppCompatActivity() {
|
||||
userInfo?.let { info ->
|
||||
Log.d("头像", "头像 URL = ${info.avatar}")
|
||||
val requestOptions = RequestOptions()
|
||||
.placeholder(R.drawable.img) // 加载中显示
|
||||
.error(R.drawable.img) // 失败时显示
|
||||
.placeholder(R.drawable.img)
|
||||
.error(R.drawable.img)
|
||||
|
||||
Glide.with(this)
|
||||
.load(info.avatar) // 如果 avatar 为 null,Glide 会直接回调 error
|
||||
.load(info.avatar)
|
||||
.apply(requestOptions)
|
||||
.circleCrop()
|
||||
.into(binding.ivAvatar)
|
||||
@@ -61,6 +144,10 @@ class PersonalProfileActivity : AppCompatActivity() {
|
||||
binding.tvPhone.text = info.phonenumber ?: ""
|
||||
}
|
||||
|
||||
binding.ivAvatar.setOnClickListener {
|
||||
showAvatarSelectDialog()
|
||||
}
|
||||
|
||||
binding.itemNickname.setOnClickListener {
|
||||
showNicknameDialog()
|
||||
}
|
||||
@@ -151,4 +238,188 @@ class PersonalProfileActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showAvatarSelectDialog() {
|
||||
AvatarSelectDialog(this)
|
||||
.setOnTakePhotoListener {
|
||||
checkCameraPermission { granted ->
|
||||
if (granted) {
|
||||
takePhoto()
|
||||
}
|
||||
}
|
||||
}
|
||||
.setOnSelectAlbumListener {
|
||||
checkStoragePermission { granted ->
|
||||
if (granted) {
|
||||
selectAlbum()
|
||||
}
|
||||
}
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查相机权限
|
||||
*/
|
||||
private fun checkCameraPermission(callback: (Boolean) -> Unit) {
|
||||
val permissions = mutableListOf(Manifest.permission.CAMERA)
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
||||
permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
}
|
||||
|
||||
val allGranted = permissions.all {
|
||||
ContextCompat.checkSelfPermission(this, it) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
|
||||
if (allGranted) {
|
||||
callback(true)
|
||||
} else {
|
||||
requestPermissionsLauncher.launch(permissions.toTypedArray())
|
||||
callback(false)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查存储权限
|
||||
*/
|
||||
private fun checkStoragePermission(callback: (Boolean) -> Unit) {
|
||||
val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
Manifest.permission.READ_MEDIA_IMAGES
|
||||
} else {
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
}
|
||||
|
||||
if (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED) {
|
||||
callback(true)
|
||||
} else {
|
||||
requestPermissionsLauncher.launch(arrayOf(permission))
|
||||
callback(false)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用系统相机拍照
|
||||
*/
|
||||
private fun takePhoto() {
|
||||
try {
|
||||
photoFile = createImageFile()
|
||||
val photoUri = FileProvider.getUriForFile(
|
||||
this,
|
||||
"$packageName.fileprovider",
|
||||
photoFile!!
|
||||
)
|
||||
takePhotoLauncher.launch(photoUri)
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
Toast.makeText(this, getString(R.string.create_file_failed), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建图片文件
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
private fun createImageFile(): File {
|
||||
val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
|
||||
val storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
|
||||
return File.createTempFile(
|
||||
"JPEG_${timeStamp}_",
|
||||
".jpg",
|
||||
storageDir
|
||||
).apply {
|
||||
// 保存文件路径以便后续使用
|
||||
Log.d("PersonalProfile", "创建图片文件: $absolutePath")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用系统相册选择图片
|
||||
*/
|
||||
private fun selectAlbum() {
|
||||
val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
|
||||
intent.type = "image/*"
|
||||
selectAlbumLauncher.launch(intent)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 Uri 获取文件路径
|
||||
*/
|
||||
private fun getFilePathFromUri(uri: Uri): String? {
|
||||
val contentResolver: ContentResolver = contentResolver
|
||||
val inputStream: InputStream? = contentResolver.openInputStream(uri)
|
||||
inputStream?.use {
|
||||
try {
|
||||
val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
|
||||
val storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
|
||||
val file = File(storageDir, "JPEG_${timeStamp}_temp.jpg")
|
||||
|
||||
FileOutputStream(file).use { outputStream ->
|
||||
val buffer = ByteArray(1024)
|
||||
var bytesRead: Int
|
||||
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
|
||||
outputStream.write(buffer, 0, bytesRead)
|
||||
}
|
||||
}
|
||||
return file.absolutePath
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
return null
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传头像到 OSS 并更新个人信息
|
||||
*/
|
||||
private fun uploadAvatar(filePath: String) {
|
||||
Toast.makeText(this, getString(R.string.uploading), Toast.LENGTH_SHORT).show()
|
||||
|
||||
OssUtil.uploadFileAsync(this, filePath, "avatar") { ossUrl ->
|
||||
runOnUiThread {
|
||||
if (ossUrl != null) {
|
||||
Log.d("PersonalProfile", "OSS 上传成功,URL: $ossUrl")
|
||||
updateAvatar(ossUrl)
|
||||
} else {
|
||||
Toast.makeText(this@PersonalProfileActivity, getString(R.string.upload_failed), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用修改个人信息接口更新头像
|
||||
*/
|
||||
private fun updateAvatar(avatarUrl: String) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
val request = UpdateUserInfo(
|
||||
userId = userInfo?.userId,
|
||||
avatar = avatarUrl
|
||||
)
|
||||
val response = RetrofitNetwork.getNetworkService().updateUserInfo(request)
|
||||
withContext(Dispatchers.Main) {
|
||||
if (response.code == 200) {
|
||||
// 更新本地头像显示
|
||||
Glide.with(this@PersonalProfileActivity)
|
||||
.load(avatarUrl)
|
||||
.apply(RequestOptions()
|
||||
.placeholder(R.drawable.img)
|
||||
.error(R.drawable.img))
|
||||
.circleCrop()
|
||||
.into(binding.ivAvatar)
|
||||
userInfo = userInfo?.copy(avatar = avatarUrl)
|
||||
Toast.makeText(this@PersonalProfileActivity, getString(R.string.operation_success), Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
Toast.makeText(this@PersonalProfileActivity, getString(R.string.operation_failed), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(this@PersonalProfileActivity, getString(R.string.network_error), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user