优化ai对话页面,以及权限申请

This commit is contained in:
fengjignqi
2026-08-03 10:16:31 +08:00
parent 12fecfbe41
commit bc0c7adb41
19 changed files with 345 additions and 34 deletions

Binary file not shown.

View File

@@ -156,4 +156,7 @@ dependencies {
implementation 'com.github.yyued:SVGAPlayer-Android:2.6.1' implementation 'com.github.yyued:SVGAPlayer-Android:2.6.1'
//圆形视图库
implementation 'com.makeramen:roundedimageview:2.3.0'
} }

View File

@@ -1,7 +1,9 @@
package com.ck.ckcollar.app.ui.act.customer package com.ck.ckcollar.app.ui.act.customer
import android.Manifest
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.drawable.Drawable
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
@@ -25,6 +27,10 @@ import androidx.core.content.FileProvider
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.ck.ckcollar.app.CKApp import com.ck.ckcollar.app.CKApp
import com.ck.ckcollar.app.R import com.ck.ckcollar.app.R
import com.ck.ckcollar.app.action.ActionCode import com.ck.ckcollar.app.action.ActionCode
@@ -71,7 +77,6 @@ class CustomerActivity : CKBaseActivity() {
binding = ActivityCustomerBinding.inflate(layoutInflater) binding = ActivityCustomerBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
checkAppPermissions()
setTitleText(getString(R.string.customer_service4)) setTitleText(getString(R.string.customer_service4))
@@ -185,25 +190,32 @@ class CustomerActivity : CKBaseActivity() {
binding.editMessage.requestFocus() binding.editMessage.requestFocus()
KeyboardUtils.showKeyboard(binding.editMessage) KeyboardUtils.showKeyboard(binding.editMessage)
} }
//拍照
binding.conetnt1.setOnClickListener { binding.conetnt1.setOnClickListener {
if (TextUtils.isEmpty(path)) { if (TextUtils.isEmpty(path)) {
takePhoto() getPermissionRequst(
Manifest.permission.CAMERA,
REQUEST_CAMERA_PERMISSION
)
} else { } else {
toast(getString(R.string.only_one_photo)) toast(getString(R.string.only_one_photo))
} }
} }
//相册
binding.conetnt2.setOnClickListener { binding.conetnt2.setOnClickListener {
if (TextUtils.isEmpty(path)) { if (TextUtils.isEmpty(path)) {
//相册 val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
val i = Intent( Manifest.permission.READ_MEDIA_IMAGES
Intent.ACTION_PICK, } else {
MediaStore.Images.Media.EXTERNAL_CONTENT_URI Manifest.permission.READ_EXTERNAL_STORAGE
}
getPermissionRequst(
permission,
REQUEST_PHOTO_PERMISSION
) )
i.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,"image/*");
startActivityForResult(i, 56)
} else { } else {
toast(getString(R.string.only_one_photo)) toast(getString(R.string.only_one_photo))
} }
@@ -226,6 +238,21 @@ class CustomerActivity : CKBaseActivity() {
} }
override fun onPermissionsGranted(requestCode: Int, permissions: Array<String>) {
when (requestCode) {
REQUEST_CAMERA_PERMISSION -> takePhoto()
REQUEST_PHOTO_PERMISSION -> {
val intent = Intent(
Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
).apply {
setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*")
}
startActivityForResult(intent, 56)
}
}
}
override fun initData() { override fun initData() {
//getList() //getList()
@@ -658,14 +685,42 @@ class CustomerActivity : CKBaseActivity() {
if (!TextUtils.isEmpty(model.url)) { if (!TextUtils.isEmpty(model.url)) {
holder.binding.textTo.visibility = View.GONE holder.binding.textTo.visibility = View.GONE
holder.binding.imageContentTo.visibility = View.VISIBLE holder.binding.imageContentTo.visibility = View.VISIBLE
val imageView = holder.binding.imageContentTo
val imageUrl = model.url!!
imageView.setTag(imageUrl)
resetImageContentSize(imageView)
Glide.with(context) Glide.with(context)
.load( model.url) .load(imageUrl)
.placeholder(R.mipmap.image_default) .placeholder(R.mipmap.image_default)
.into(holder.binding.imageContentTo) .listener(object : RequestListener<Drawable> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
isFirstResource: Boolean
): Boolean = false
holder.binding.imageContentTo.setTag(model.url) override fun onResourceReady(
holder.binding.imageContentTo.setOnClickListener(imageClick) resource: Drawable,
model: Any,
target: Target<Drawable>?,
dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
if (imageView.tag == imageUrl) {
setImageContentSize(
imageView,
resource.intrinsicWidth,
resource.intrinsicHeight
)
}
return false
}
})
.into(imageView)
imageView.setOnClickListener(imageClick)
} else { } else {
holder.binding.textTo.visibility = View.VISIBLE holder.binding.textTo.visibility = View.VISIBLE
holder.binding.imageContentTo.visibility = View.GONE holder.binding.imageContentTo.visibility = View.GONE
@@ -680,6 +735,39 @@ class CustomerActivity : CKBaseActivity() {
} }
} }
private fun resetImageContentSize(imageView: View) {
val density = imageView.resources.displayMetrics.density
imageView.layoutParams = imageView.layoutParams.apply {
width = getMaxImageWidth(density)
height = (200 * density).toInt()
}
}
private fun setImageContentSize(imageView: View, sourceWidth: Int, sourceHeight: Int) {
if (sourceWidth <= 0 || sourceHeight <= 0) return
val density = imageView.resources.displayMetrics.density
val maxWidth = getMaxImageWidth(density).toFloat()
val maxHeight = (200 * density).toFloat()
val scale = minOf(
1f,
maxWidth / sourceWidth.toFloat(),
maxHeight / sourceHeight.toFloat()
)
imageView.layoutParams = imageView.layoutParams.apply {
width = (sourceWidth * scale).toInt().coerceAtLeast(1)
height = (sourceHeight * scale).toInt().coerceAtLeast(1)
}
}
private fun getMaxImageWidth(density: Float): Int {
val requestedWidth = (200 * density).toInt()
// Reserve the avatar, paddings, and the bubble's left inset.
val availableWidth = context.resources.displayMetrics.widthPixels - (155 * density).toInt()
return minOf(requestedWidth, availableWidth.coerceAtLeast(1))
}
override fun getItemCount(): Int { override fun getItemCount(): Int {
return data.size return data.size
} }
@@ -715,4 +803,9 @@ class CustomerActivity : CKBaseActivity() {
} }
} }
companion object {
private const val REQUEST_CAMERA_PERMISSION = 1001
private const val REQUEST_PHOTO_PERMISSION = 1002
}
} }

View File

@@ -1,8 +1,10 @@
package com.ck.ckcollar.app.ui.act.home.fragment package com.ck.ckcollar.app.ui.act.home.fragment
import android.Manifest
import android.app.Activity.RESULT_OK import android.app.Activity.RESULT_OK
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.GradientDrawable.Orientation import android.graphics.drawable.GradientDrawable.Orientation
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
@@ -10,11 +12,16 @@ import android.os.Bundle
import android.os.Environment import android.os.Environment
import android.provider.MediaStore import android.provider.MediaStore
import android.text.TextUtils import android.text.TextUtils
import android.view.Gravity
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowManager
import android.widget.ImageView import android.widget.ImageView
import android.widget.PopupWindow import android.widget.PopupWindow
import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@@ -67,6 +74,25 @@ import kotlin.random.Random
class HomeFragment : CKBaseFragment() { class HomeFragment : CKBaseFragment() {
private enum class CameraAction { SCAN, TAKE_PHOTO }
private var pendingCameraAction: CameraAction? = null
private var permissionTopDialog: AlertDialog? = null
private val cameraPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { granted ->
hideCameraPermissionTopDialog()
val action = pendingCameraAction
pendingCameraAction = null
if (granted) {
when (action) {
CameraAction.SCAN -> startScan()
CameraAction.TAKE_PHOTO -> takePhoto()
null -> Unit
}
}
}
lateinit var homeBinding: FragmentHomeBinding lateinit var homeBinding: FragmentHomeBinding
var collarDatas = listOf<CollarTypeModel.TypeDataModel>() var collarDatas = listOf<CollarTypeModel.TypeDataModel>()
@@ -111,6 +137,11 @@ class HomeFragment : CKBaseFragment() {
if (!checkCameraPermissions()){ if (!checkCameraPermissions()){
CKAlertDialog(activity!!,getString(R.string.alert),getString(R.string.camera_alert),object : CKAlertDialog.AlertClickListener{ CKAlertDialog(activity!!,getString(R.string.alert),getString(R.string.camera_alert),object : CKAlertDialog.AlertClickListener{
override fun onBack(isConfirm: Boolean) { override fun onBack(isConfirm: Boolean) {
if(isConfirm){
requestCameraPermission(CameraAction.SCAN)
}else{
}
} }
}).show() }).show()
@@ -126,7 +157,7 @@ class HomeFragment : CKBaseFragment() {
CKAlertDialog(activity!!,getString(R.string.alert),getString(R.string.camera_alert),object : CKAlertDialog.AlertClickListener{ CKAlertDialog(activity!!,getString(R.string.alert),getString(R.string.camera_alert),object : CKAlertDialog.AlertClickListener{
override fun onBack(isConfirm: Boolean) { override fun onBack(isConfirm: Boolean) {
if (isConfirm) requestCameraPermission(CameraAction.TAKE_PHOTO)
} }
}).show() }).show()
return@setOnClickListener return@setOnClickListener
@@ -201,6 +232,50 @@ class HomeFragment : CKBaseFragment() {
} }
} }
private fun requestCameraPermission(action: CameraAction) {
pendingCameraAction = action
showCameraPermissionTopDialog()
permissionTopDialog?.window?.decorView?.post {
if (isAdded && pendingCameraAction == action) {
cameraPermissionLauncher.launch(Manifest.permission.CAMERA)
}
}
}
private fun showCameraPermissionTopDialog() {
permissionTopDialog?.dismiss()
val view = layoutInflater.inflate(R.layout.permission_top_dialog, null)
view.findViewById<TextView>(R.id.permissionTopTitle).text = getString(R.string.camera)
view.findViewById<TextView>(R.id.permissionTopContent).text = getString(R.string.camera_alert)
permissionTopDialog = AlertDialog.Builder(requireContext())
.setView(view)
.create()
.also { dialog ->
dialog.setCanceledOnTouchOutside(false)
dialog.setCancelable(false)
dialog.show()
dialog.window?.apply {
setBackgroundDrawable(ColorDrawable(android.graphics.Color.TRANSPARENT))
setGravity(Gravity.TOP)
setLayout(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT
)
}
}
}
private fun hideCameraPermissionTopDialog() {
permissionTopDialog?.dismiss()
permissionTopDialog = null
}
override fun onDestroyView() {
hideCameraPermissionTopDialog()
pendingCameraAction = null
super.onDestroyView()
}
override fun initData() { override fun initData() {
var data = PreferencesUtils.getString(activity!!, Const.PET_DATA, "") var data = PreferencesUtils.getString(activity!!, Const.PET_DATA, "")

View File

@@ -51,7 +51,7 @@ class LoginActivity : CKBaseActivity() {
// api = WXAPIFactory.createWXAPI(this, Const.WX_APP_ID, false); // api = WXAPIFactory.createWXAPI(this, Const.WX_APP_ID, false);
setStatusBarColor(R.attr.mainBackground) setStatusBarColor(R.attr.mainBackground)
//检测权限 //检测权限
checkAppPermissions() // checkAppPermissions()
} }

View File

@@ -59,11 +59,12 @@ class WelcomeActivity : CKBaseActivity() {
view.btnCome.setOnClickListener { view.btnCome.setOnClickListener {
val toPermisstionActivity = PreferencesUtils.getBolean(this@WelcomeActivity, val toPermisstionActivity = PreferencesUtils.getBolean(this@WelcomeActivity,
Const.PERMISSIONS_FIRST,false) as Boolean Const.PERMISSIONS_FIRST,false) as Boolean
if (!toPermisstionActivity){ // if (!toPermisstionActivity){
toActivity(PermisstionActivity::class.java, DataCollection()) // toActivity(PermisstionActivity::class.java, DataCollection())
}else{ // }else{
// toActivity(LoginActivity::class.java, DataCollection())
// }
toActivity(LoginActivity::class.java, DataCollection()) toActivity(LoginActivity::class.java, DataCollection())
}
finish() finish()
} }

View File

@@ -1,15 +1,20 @@
package com.ck.ckcollar.app.ui.base package com.ck.ckcollar.app.ui.base
import android.Manifest import android.Manifest
import android.content.pm.PackageManager
import android.graphics.drawable.ColorDrawable
import android.graphics.Color import android.graphics.Color
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.TypedValue import android.util.TypedValue
import android.view.View import android.view.View
import android.view.Gravity
import android.view.WindowManager import android.view.WindowManager
import android.widget.ImageButton import android.widget.ImageButton
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
@@ -18,6 +23,7 @@ import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import com.ck.ckcollar.app.CKApp import com.ck.ckcollar.app.CKApp
import com.ck.ckcollar.app.R import com.ck.ckcollar.app.R
import com.ck.ckcollar.app.ui.dialog.CKAlertDialog
import com.tt.kit.base.TTBaseActivity import com.tt.kit.base.TTBaseActivity
import com.tt.kit.utils.TTLog import com.tt.kit.utils.TTLog
import com.tt.kit.utils.TTUtils import com.tt.kit.utils.TTUtils
@@ -26,6 +32,27 @@ import pub.devrel.easypermissions.EasyPermissions
open class CKBaseActivity : TTBaseActivity(){ open class CKBaseActivity : TTBaseActivity(){
private var permissionDialog: AlertDialog? = null
private var pendingPermissionRequestCode: Int? = null
private var pendingPermissions: Array<String> = emptyArray()
private val permissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { result ->
hidePermissionDialog()
val requestCode = pendingPermissionRequestCode ?: return@registerForActivityResult
val requestedPermissions = pendingPermissions
pendingPermissionRequestCode = null
pendingPermissions = emptyArray()
val denied = result.filterValues { !it }.keys.toTypedArray()
if (denied.isEmpty()) {
onPermissionsGranted(requestCode, requestedPermissions)
} else {
val permanentlyDenied = denied.all { !ActivityCompat.shouldShowRequestPermissionRationale(this, it) }
onPermissionsDenied(requestCode, denied, permanentlyDenied)
}
}
var perms_= listOf<String>(Manifest.permission.CAMERA, Manifest.permission.READ_MEDIA_IMAGES,Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE) var perms_= listOf<String>(Manifest.permission.CAMERA, Manifest.permission.READ_MEDIA_IMAGES,Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE)
var perms_tiramisu = listOf<String>(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE) var perms_tiramisu = listOf<String>(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE)
@@ -208,10 +235,118 @@ open class CKBaseActivity : TTBaseActivity(){
} }
fun checkCameraPermissions() : Boolean{ fun checkCameraPermissions() : Boolean{
var a = 0;
return EasyPermissions.hasPermissions(this, *perms_carmra.toTypedArray()) return EasyPermissions.hasPermissions(this, *perms_carmra.toTypedArray())
} }
fun hasRecordPermission(permission: String): Boolean {
return hasRecordPermission(arrayOf(permission))
}
fun hasRecordPermission(permissions: Array<String>): Boolean {
return permissions.all {
ContextCompat.checkSelfPermission(this, it) == PackageManager.PERMISSION_GRANTED
}
}
fun getPermissionRequst(
permission: String,
requestCode: Int
) {
val isCameraPermission = permission == Manifest.permission.CAMERA
getPermissionRequst(
permission,
getString(if (isCameraPermission) R.string.camera else R.string.photo),
getString(if (isCameraPermission) R.string.camera_alert else R.string.photo_permission_alert),
requestCode
)
}
fun getPermissionRequst(
permission: String,
title: String,
content: String,
requestCode: Int
) {
getMorePermissionRequst(arrayOf(permission), title, content, requestCode)
}
fun getMorePermissionRequst(
permissions: Array<String>,
title: String,
content: String,
requestCode: Int
) {
if (hasRecordPermission(permissions)) {
onPermissionsGranted(requestCode, permissions)
return
}
CKAlertDialog(this, getString(R.string.alert), content, object : CKAlertDialog.AlertClickListener {
override fun onBack(isConfirm: Boolean) {
if (isConfirm) {
requestSystemPermissions(permissions, title, content, requestCode)
} else {
onPermissionsDenied(requestCode, permissions, false)
}
}
}).show()
}
private fun requestSystemPermissions(
permissions: Array<String>,
title: String,
content: String,
requestCode: Int
) {
pendingPermissionRequestCode = requestCode
pendingPermissions = permissions
showPermissionDialog(title, content)
permissionDialog?.window?.decorView?.post {
if (!isFinishing && pendingPermissionRequestCode == requestCode) {
permissionLauncher.launch(permissions)
}
}
}
private fun showPermissionDialog(title: String, content: String) {
hidePermissionDialog()
val view = layoutInflater.inflate(R.layout.permission_top_dialog, null)
view.findViewById<TextView>(R.id.permissionTopTitle).text = title
view.findViewById<TextView>(R.id.permissionTopContent).text = content
permissionDialog = AlertDialog.Builder(this)
.setView(view)
.create()
.also { dialog ->
dialog.setCanceledOnTouchOutside(false)
dialog.setCancelable(false)
dialog.show()
dialog.window?.apply {
setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
setGravity(Gravity.TOP)
setLayout(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT
)
}
}
}
private fun hidePermissionDialog() {
permissionDialog?.dismiss()
permissionDialog = null
}
protected open fun onPermissionsGranted(requestCode: Int, permissions: Array<String>) {
}
protected open fun onPermissionsDenied(
requestCode: Int,
permissions: Array<String>,
permanentlyDenied: Boolean
) {
}
fun requstPermissions(){ fun requstPermissions(){
var perms = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { var perms = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
perms_ perms_
@@ -228,6 +363,9 @@ open class CKBaseActivity : TTBaseActivity(){
ActivityCompat.requestPermissions(this, perms.toTypedArray(), 1001) ActivityCompat.requestPermissions(this, perms.toTypedArray(), 1001)
} }
override fun onDestroy() { override fun onDestroy() {
hidePermissionDialog()
pendingPermissionRequestCode = null
pendingPermissions = emptyArray()
super.onDestroy() super.onDestroy()
CKApp.app.activitys.remove(this) CKApp.app.activitys.remove(this)
} }

View File

@@ -74,9 +74,9 @@ open class CKLHBaseActivity : TTBaseActivity(){
// getWindow().setStatusBarColor(Color.TRANSPARENT); // getWindow().setStatusBarColor(Color.TRANSPARENT);
if (!checkPermissions()){ // if (!checkPermissions()){
requstPermissions() // requstPermissions()
} // }
} }

View File

@@ -118,19 +118,19 @@
android:textSize="14sp"></com.ck.ckcollar.app.widget.CKTextView> android:textSize="14sp"></com.ck.ckcollar.app.widget.CKTextView>
<com.ck.ckcollar.app.widget.CKImageView <com.makeramen.roundedimageview.RoundedImageView
android:id="@+id/imageContentTo" android:id="@+id/imageContentTo"
android:textIsSelectable="true" android:textIsSelectable="true"
android:layout_width="wrap_content" android:layout_width="200dp"
android:layout_height="wrap_content" android:layout_height="200dp"
android:textColor="@color/textColor" android:textColor="@color/textColor"
android:background="@drawable/bg_message_to"
android:paddingVertical="3dp" android:paddingVertical="3dp"
android:paddingHorizontal="5dp" android:paddingHorizontal="5dp"
android:layout_marginTop="3dp" android:layout_marginTop="3dp"
android:maxWidth="200dp" android:maxWidth="200dp"
android:scaleType="fitCenter"
android:visibility="gone" android:visibility="gone"
></com.ck.ckcollar.app.widget.CKImageView> app:riv_corner_radius="8dp"/>
</com.ck.ckcollar.app.widget.CKLinearLayout> </com.ck.ckcollar.app.widget.CKLinearLayout>
<com.ck.ckcollar.app.widget.CKRoundImageView <com.ck.ckcollar.app.widget.CKRoundImageView

View File

@@ -584,7 +584,8 @@
<string name="please_choose_product">请先选择商品</string> <string name="please_choose_product">请先选择商品</string>
<string name="cancel_account_phone">注销%s绑定的账号</string> <string name="cancel_account_phone">注销%s绑定的账号</string>
<string name="please_choose_data">请选择原因</string> <string name="please_choose_data">请选择原因</string>
<string name="camera_alert">请在设置中允许访问相机</string> <string name="camera_alert">宠盾需要您的授权,使用相机功能来进行扫码和拍照</string>
<string name="photo_permission_alert">宠盾需要您的授权,访问相册以选择照片</string>
<string name="input_question">请输入问题</string> <string name="input_question">请输入问题</string>
<string name="pet_note">宠物常识</string> <string name="pet_note">宠物常识</string>