diff --git a/.gradle/8.13/checksums/checksums.lock b/.gradle/8.13/checksums/checksums.lock index 599a56d..8e67f7d 100644 Binary files a/.gradle/8.13/checksums/checksums.lock and b/.gradle/8.13/checksums/checksums.lock differ diff --git a/.gradle/8.13/checksums/md5-checksums.bin b/.gradle/8.13/checksums/md5-checksums.bin index b286f8c..414ea54 100644 Binary files a/.gradle/8.13/checksums/md5-checksums.bin and b/.gradle/8.13/checksums/md5-checksums.bin differ diff --git a/.gradle/8.13/checksums/sha1-checksums.bin b/.gradle/8.13/checksums/sha1-checksums.bin index 3876b6b..f0ba4bc 100644 Binary files a/.gradle/8.13/checksums/sha1-checksums.bin and b/.gradle/8.13/checksums/sha1-checksums.bin differ diff --git a/.gradle/8.13/executionHistory/executionHistory.bin b/.gradle/8.13/executionHistory/executionHistory.bin index e7e43d9..d721741 100644 Binary files a/.gradle/8.13/executionHistory/executionHistory.bin and b/.gradle/8.13/executionHistory/executionHistory.bin differ diff --git a/.gradle/8.13/executionHistory/executionHistory.lock b/.gradle/8.13/executionHistory/executionHistory.lock index 4439e13..785e621 100644 Binary files a/.gradle/8.13/executionHistory/executionHistory.lock and b/.gradle/8.13/executionHistory/executionHistory.lock differ diff --git a/.gradle/8.13/fileHashes/fileHashes.bin b/.gradle/8.13/fileHashes/fileHashes.bin index ad6a029..8c433b7 100644 Binary files a/.gradle/8.13/fileHashes/fileHashes.bin and b/.gradle/8.13/fileHashes/fileHashes.bin differ diff --git a/.gradle/8.13/fileHashes/fileHashes.lock b/.gradle/8.13/fileHashes/fileHashes.lock index a01f6c6..54a9ba9 100644 Binary files a/.gradle/8.13/fileHashes/fileHashes.lock and b/.gradle/8.13/fileHashes/fileHashes.lock differ diff --git a/.gradle/8.13/fileHashes/resourceHashesCache.bin b/.gradle/8.13/fileHashes/resourceHashesCache.bin index b2a8d69..964f711 100644 Binary files a/.gradle/8.13/fileHashes/resourceHashesCache.bin and b/.gradle/8.13/fileHashes/resourceHashesCache.bin differ diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 2b92173..3b03661 100644 Binary files a/.gradle/buildOutputCleanup/buildOutputCleanup.lock and b/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ diff --git a/.gradle/file-system.probe b/.gradle/file-system.probe index 924a278..157400b 100644 Binary files a/.gradle/file-system.probe and b/.gradle/file-system.probe differ diff --git a/app/build.gradle b/app/build.gradle index 9e4f9c0..75e9a97 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -156,4 +156,7 @@ dependencies { implementation 'com.github.yyued:SVGAPlayer-Android:2.6.1' + //圆形视图库 + implementation 'com.makeramen:roundedimageview:2.3.0' + } \ No newline at end of file diff --git a/app/src/main/java/com/ck/ckcollar/app/ui/act/customer/CustomerActivity.kt b/app/src/main/java/com/ck/ckcollar/app/ui/act/customer/CustomerActivity.kt index de6e257..85434fe 100644 --- a/app/src/main/java/com/ck/ckcollar/app/ui/act/customer/CustomerActivity.kt +++ b/app/src/main/java/com/ck/ckcollar/app/ui/act/customer/CustomerActivity.kt @@ -1,7 +1,9 @@ package com.ck.ckcollar.app.ui.act.customer +import android.Manifest import android.content.Context import android.content.Intent +import android.graphics.drawable.Drawable import android.net.Uri import android.os.Build import android.os.Bundle @@ -25,6 +27,10 @@ import androidx.core.content.FileProvider import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView 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.R import com.ck.ckcollar.app.action.ActionCode @@ -71,7 +77,6 @@ class CustomerActivity : CKBaseActivity() { binding = ActivityCustomerBinding.inflate(layoutInflater) setContentView(binding.root) super.onCreate(savedInstanceState) - checkAppPermissions() setTitleText(getString(R.string.customer_service4)) @@ -185,25 +190,32 @@ class CustomerActivity : CKBaseActivity() { binding.editMessage.requestFocus() KeyboardUtils.showKeyboard(binding.editMessage) } + //拍照 binding.conetnt1.setOnClickListener { if (TextUtils.isEmpty(path)) { - takePhoto() + getPermissionRequst( + Manifest.permission.CAMERA, + REQUEST_CAMERA_PERMISSION + ) } else { toast(getString(R.string.only_one_photo)) } } + //相册 binding.conetnt2.setOnClickListener { if (TextUtils.isEmpty(path)) { - //相册 - val i = Intent( - Intent.ACTION_PICK, - MediaStore.Images.Media.EXTERNAL_CONTENT_URI + val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + Manifest.permission.READ_MEDIA_IMAGES + } else { + Manifest.permission.READ_EXTERNAL_STORAGE + } + getPermissionRequst( + permission, + REQUEST_PHOTO_PERMISSION ) - i.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,"image/*"); - startActivityForResult(i, 56) } else { toast(getString(R.string.only_one_photo)) } @@ -226,6 +238,21 @@ class CustomerActivity : CKBaseActivity() { } + override fun onPermissionsGranted(requestCode: Int, permissions: Array) { + 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() { //getList() @@ -658,14 +685,42 @@ class CustomerActivity : CKBaseActivity() { if (!TextUtils.isEmpty(model.url)) { holder.binding.textTo.visibility = View.GONE holder.binding.imageContentTo.visibility = View.VISIBLE + val imageView = holder.binding.imageContentTo + val imageUrl = model.url!! + imageView.setTag(imageUrl) + resetImageContentSize(imageView) Glide.with(context) - .load( model.url) + .load(imageUrl) .placeholder(R.mipmap.image_default) - .into(holder.binding.imageContentTo) + .listener(object : RequestListener { + override fun onLoadFailed( + e: GlideException?, + model: Any?, + target: Target?, + isFirstResource: Boolean + ): Boolean = false - holder.binding.imageContentTo.setTag(model.url) - holder.binding.imageContentTo.setOnClickListener(imageClick) + override fun onResourceReady( + resource: Drawable, + model: Any, + target: Target?, + dataSource: DataSource, + isFirstResource: Boolean + ): Boolean { + if (imageView.tag == imageUrl) { + setImageContentSize( + imageView, + resource.intrinsicWidth, + resource.intrinsicHeight + ) + } + return false + } + }) + .into(imageView) + + imageView.setOnClickListener(imageClick) } else { holder.binding.textTo.visibility = View.VISIBLE 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 { return data.size } @@ -715,4 +803,9 @@ class CustomerActivity : CKBaseActivity() { } } -} \ No newline at end of file + + companion object { + private const val REQUEST_CAMERA_PERMISSION = 1001 + private const val REQUEST_PHOTO_PERMISSION = 1002 + } +} diff --git a/app/src/main/java/com/ck/ckcollar/app/ui/act/home/fragment/HomeFragment.kt b/app/src/main/java/com/ck/ckcollar/app/ui/act/home/fragment/HomeFragment.kt index df572ac..f8a6c92 100644 --- a/app/src/main/java/com/ck/ckcollar/app/ui/act/home/fragment/HomeFragment.kt +++ b/app/src/main/java/com/ck/ckcollar/app/ui/act/home/fragment/HomeFragment.kt @@ -1,8 +1,10 @@ package com.ck.ckcollar.app.ui.act.home.fragment +import android.Manifest import android.app.Activity.RESULT_OK import android.content.Context import android.content.Intent +import android.graphics.drawable.ColorDrawable import android.graphics.drawable.GradientDrawable.Orientation import android.net.Uri import android.os.Build @@ -10,11 +12,16 @@ import android.os.Bundle import android.os.Environment import android.provider.MediaStore import android.text.TextUtils +import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.view.WindowManager import android.widget.ImageView 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.lifecycle.Observer import androidx.recyclerview.widget.RecyclerView @@ -67,6 +74,25 @@ import kotlin.random.Random 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 var collarDatas = listOf() @@ -111,6 +137,11 @@ class HomeFragment : CKBaseFragment() { if (!checkCameraPermissions()){ CKAlertDialog(activity!!,getString(R.string.alert),getString(R.string.camera_alert),object : CKAlertDialog.AlertClickListener{ override fun onBack(isConfirm: Boolean) { + if(isConfirm){ + requestCameraPermission(CameraAction.SCAN) + }else{ + + } } }).show() @@ -126,7 +157,7 @@ class HomeFragment : CKBaseFragment() { CKAlertDialog(activity!!,getString(R.string.alert),getString(R.string.camera_alert),object : CKAlertDialog.AlertClickListener{ override fun onBack(isConfirm: Boolean) { - + if (isConfirm) requestCameraPermission(CameraAction.TAKE_PHOTO) } }).show() 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(R.id.permissionTopTitle).text = getString(R.string.camera) + view.findViewById(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() { var data = PreferencesUtils.getString(activity!!, Const.PET_DATA, "") @@ -768,4 +843,4 @@ class HomeFragment : CKBaseFragment() { imageView ) } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/ck/ckcollar/app/ui/act/login/LoginActivity.kt b/app/src/main/java/com/ck/ckcollar/app/ui/act/login/LoginActivity.kt index 3b3d9cc..0d79807 100644 --- a/app/src/main/java/com/ck/ckcollar/app/ui/act/login/LoginActivity.kt +++ b/app/src/main/java/com/ck/ckcollar/app/ui/act/login/LoginActivity.kt @@ -51,7 +51,7 @@ class LoginActivity : CKBaseActivity() { // api = WXAPIFactory.createWXAPI(this, Const.WX_APP_ID, false); setStatusBarColor(R.attr.mainBackground) //检测权限 - checkAppPermissions() +// checkAppPermissions() } diff --git a/app/src/main/java/com/ck/ckcollar/app/ui/act/welcome/WelcomeActivity.kt b/app/src/main/java/com/ck/ckcollar/app/ui/act/welcome/WelcomeActivity.kt index 18b5fed..c45fe6d 100644 --- a/app/src/main/java/com/ck/ckcollar/app/ui/act/welcome/WelcomeActivity.kt +++ b/app/src/main/java/com/ck/ckcollar/app/ui/act/welcome/WelcomeActivity.kt @@ -59,11 +59,12 @@ class WelcomeActivity : CKBaseActivity() { view.btnCome.setOnClickListener { val toPermisstionActivity = PreferencesUtils.getBolean(this@WelcomeActivity, Const.PERMISSIONS_FIRST,false) as Boolean - if (!toPermisstionActivity){ - toActivity(PermisstionActivity::class.java, DataCollection()) - }else{ - toActivity(LoginActivity::class.java, DataCollection()) - } +// if (!toPermisstionActivity){ +// toActivity(PermisstionActivity::class.java, DataCollection()) +// }else{ +// toActivity(LoginActivity::class.java, DataCollection()) +// } + toActivity(LoginActivity::class.java, DataCollection()) finish() } diff --git a/app/src/main/java/com/ck/ckcollar/app/ui/base/CKBaseActivity.kt b/app/src/main/java/com/ck/ckcollar/app/ui/base/CKBaseActivity.kt index d2bcd60..86ac113 100644 --- a/app/src/main/java/com/ck/ckcollar/app/ui/base/CKBaseActivity.kt +++ b/app/src/main/java/com/ck/ckcollar/app/ui/base/CKBaseActivity.kt @@ -1,15 +1,20 @@ package com.ck.ckcollar.app.ui.base import android.Manifest +import android.content.pm.PackageManager +import android.graphics.drawable.ColorDrawable import android.graphics.Color import android.os.Build import android.os.Bundle import android.util.TypedValue import android.view.View +import android.view.Gravity import android.view.WindowManager import android.widget.ImageButton import android.widget.ImageView import android.widget.TextView +import androidx.activity.result.contract.ActivityResultContracts +import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatDelegate import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat @@ -18,6 +23,7 @@ import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat import com.ck.ckcollar.app.CKApp import com.ck.ckcollar.app.R +import com.ck.ckcollar.app.ui.dialog.CKAlertDialog import com.tt.kit.base.TTBaseActivity import com.tt.kit.utils.TTLog import com.tt.kit.utils.TTUtils @@ -26,6 +32,27 @@ import pub.devrel.easypermissions.EasyPermissions open class CKBaseActivity : TTBaseActivity(){ + private var permissionDialog: AlertDialog? = null + private var pendingPermissionRequestCode: Int? = null + private var pendingPermissions: Array = 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(Manifest.permission.CAMERA, Manifest.permission.READ_MEDIA_IMAGES,Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE) var perms_tiramisu = listOf(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE) @@ -208,10 +235,118 @@ open class CKBaseActivity : TTBaseActivity(){ } fun checkCameraPermissions() : Boolean{ - + var a = 0; return EasyPermissions.hasPermissions(this, *perms_carmra.toTypedArray()) } + fun hasRecordPermission(permission: String): Boolean { + return hasRecordPermission(arrayOf(permission)) + } + + fun hasRecordPermission(permissions: Array): 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, + 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, + 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(R.id.permissionTopTitle).text = title + view.findViewById(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) { + } + + protected open fun onPermissionsDenied( + requestCode: Int, + permissions: Array, + permanentlyDenied: Boolean + ) { + } + fun requstPermissions(){ var perms = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { perms_ @@ -228,6 +363,9 @@ open class CKBaseActivity : TTBaseActivity(){ ActivityCompat.requestPermissions(this, perms.toTypedArray(), 1001) } override fun onDestroy() { + hidePermissionDialog() + pendingPermissionRequestCode = null + pendingPermissions = emptyArray() super.onDestroy() CKApp.app.activitys.remove(this) } @@ -245,4 +383,4 @@ open class CKBaseActivity : TTBaseActivity(){ override fun onPause() { super.onPause() } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/ck/ckcollar/app/ui/base/CKLHBaseActivity.kt b/app/src/main/java/com/ck/ckcollar/app/ui/base/CKLHBaseActivity.kt index 13b9130..8f9db3d 100644 --- a/app/src/main/java/com/ck/ckcollar/app/ui/base/CKLHBaseActivity.kt +++ b/app/src/main/java/com/ck/ckcollar/app/ui/base/CKLHBaseActivity.kt @@ -74,9 +74,9 @@ open class CKLHBaseActivity : TTBaseActivity(){ // getWindow().setStatusBarColor(Color.TRANSPARENT); - if (!checkPermissions()){ - requstPermissions() - } +// if (!checkPermissions()){ +// requstPermissions() +// } } diff --git a/app/src/main/res/layout/layout_item_ai_customer_message.xml b/app/src/main/res/layout/layout_item_ai_customer_message.xml index c836a63..9c40d57 100644 --- a/app/src/main/res/layout/layout_item_ai_customer_message.xml +++ b/app/src/main/res/layout/layout_item_ai_customer_message.xml @@ -118,19 +118,19 @@ android:textSize="14sp"> - + app:riv_corner_radius="8dp"/> - \ 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 3d24aa1..a4390df 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -584,8 +584,9 @@ 请先选择商品 注销%s绑定的账号 请选择原因 - 请在设置中允许访问相机 + 宠盾需要您的授权,使用相机功能来进行扫码和拍照 + 宠盾需要您的授权,访问相册以选择照片 请输入问题 宠物常识 - \ No newline at end of file +