| app/build.gradle.kts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/proguard-rules.pro | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/src/main/AndroidManifest.xml | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/src/main/java/com/example/smart/image/CompressEngine.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/src/main/java/com/example/smart/image/GlideEngine.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/src/main/java/com/example/smart/image/ImageProvider.kt | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/src/main/java/com/example/smart/image/SandboxEngine.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/src/main/java/com/example/smart/reqeust/RetrofitClient.kt | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/src/main/java/com/example/smart/ui/item/CreateItemActivity.kt | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/src/main/java/com/example/smart/ui/item/adapter/ImageShowAdapter.kt | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/src/main/res/drawable/ps_image_placeholder.xml | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| settings.gradle.kts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
app/build.gradle.kts
@@ -1,3 +1,6 @@ import java.text.SimpleDateFormat import java.util.Date plugins { id("com.android.application") id("org.jetbrains.kotlin.android") @@ -19,8 +22,8 @@ applicationId = "com.example.smart" minSdk = 28 targetSdk = 34 versionCode = 1103 versionName = "1.1.03" versionCode = 1104 versionName = "1.1.04" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { @@ -68,6 +71,16 @@ dataBinding = true } applicationVariants.configureEach { outputs.configureEach { if (this is com.android.build.gradle.internal.api.BaseVariantOutputImpl) { outputFileName = "岱观智评-${buildType.name}-${versionName}-${ SimpleDateFormat("yyyy-MM-dd").format(Date()) }.apk" } } } } dependencies { @@ -79,7 +92,7 @@ implementation(project(mapOf("path" to ":basecore"))) implementation(project(mapOf("path" to ":waterdrop"))) implementation(project(mapOf("path" to ":imageselector"))) // implementation(project(mapOf("path" to ":imageselector"))) implementation("com.google.android.material:material:1.10.0") implementation("androidx.legacy:legacy-support-v4:1.0.0") implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.6.1") @@ -108,7 +121,7 @@ implementation("com.github.loperSeven:DateTimePicker:0.1.0") //implementation("com.github.crazyandcoder:citypicker:6.0.2") implementation(project(":imageselector")) // implementation(project(":imageselector")) implementation("com.burhanrashid52:photoeditor:3.0.2") testImplementation("junit:junit:4.13.2") @@ -118,4 +131,12 @@ // dialog implementation("com.afollestad.material-dialogs:core:3.3.0") implementation("com.afollestad.material-dialogs:bottomsheets:3.3.0") // PictureSelector 基础 (必须) implementation("io.github.lucksiege:pictureselector:v3.11.2") // 图片压缩 (按需引入) implementation("io.github.lucksiege:compress:v3.11.2") // 图片裁剪 (按需引入) implementation("io.github.lucksiege:ucrop:v3.11.2") // 自定义相机 (按需引入) implementation("io.github.lucksiege:camerax:v3.11.2") } app/proguard-rules.pro
@@ -223,3 +223,11 @@ # 忽略高德地图 SDK 的可选依赖类 -dontwarn com.amap.ams.gnss.GnssSoftLocator -dontwarn net.jafama.FastMath #PictureSelector -keep class com.luck.picture.lib.** { *; } #如果引入了Camerax库请添加混淆 -keep class com.luck.lib.camerax.** { *; } #如果引入了Ucrop库请添加混淆 -dontwarn com.yalantis.ucrop** -keep class com.yalantis.ucrop** { *; } -keep interface com.yalantis.ucrop** { *; } app/src/main/AndroidManifest.xml
@@ -1,30 +1,38 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <!-- Required only if your app needs to access images or photos that other apps created. --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <!-- Required only if your app needs to access videos that other apps created. --> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <!-- Required only if your app needs to access audio files that other apps created. --> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" /> <uses-feature android:name="android.hardware.camera" android:required="false" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" tools:ignore="ProtectedPermissions" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.VIBRATE" /> <!-- Android 13版本适配,细化存储权限--> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <queries package="${applicationId}"> <intent> <action android:name="android.media.action.IMAGE_CAPTURE" /> </intent> <intent> <action android:name="android.media.action.ACTION_VIDEO_CAPTURE" /> </intent> </queries> <application android:name=".MyApp" android:allowBackup="true" @@ -44,22 +52,6 @@ android:name="com.amap.api.v2.apikey" android:value="f7d1365236067d9c589141debd24f995" /> <!-- 定位需要的服务 --> <service android:name="com.amap.api.location.APSService" /> <!-- 图片选择Activity--> <activity android:name="com.donkingliang.imageselector.ImageSelectorActivity" /> <!-- //图片预览Activity--> <activity android:name="com.donkingliang.imageselector.PreviewActivity" android:configChanges="orientation|keyboardHidden|screenSize" android:theme="@style/Theme.AppCompat.Light.NoActionBar" /> <!-- //图片剪切Activity--> <activity android:name="com.donkingliang.imageselector.ClipImageActivity" android:theme="@style/Theme.AppCompat.Light.NoActionBar" /> <activity android:name=".ui.exclude.ExcludeActivity" app/src/main/java/com/example/smart/image/CompressEngine.java
New file @@ -0,0 +1,44 @@ package com.example.smart.image; import android.content.Context; import android.net.Uri; import com.luck.picture.lib.engine.CompressFileEngine; import com.luck.picture.lib.interfaces.OnKeyValueResultCallbackListener; import java.io.File; import java.util.ArrayList; import top.zibin.luban.Luban; import top.zibin.luban.OnNewCompressListener; /** * 压缩引擎 */ public class CompressEngine implements CompressFileEngine { @Override public void onStartCompress(Context context, ArrayList<Uri> source, OnKeyValueResultCallbackListener call) { Luban.with(context).load(source).ignoreBy(100) .setCompressListener(new OnNewCompressListener() { @Override public void onStart() { } @Override public void onSuccess(String source, File compressFile) { if (call != null) { call.onCallback(source, compressFile.getAbsolutePath()); } } @Override public void onError(String source, Throwable e) { if (call != null) { call.onCallback(source, null); } } }).launch(); } } app/src/main/java/com/example/smart/image/GlideEngine.java
New file @@ -0,0 +1,116 @@ package com.example.smart.image; import android.content.Context; import android.widget.ImageView; import com.bumptech.glide.Glide; import com.bumptech.glide.load.resource.bitmap.CenterCrop; import com.bumptech.glide.load.resource.bitmap.RoundedCorners; import com.example.smart.R; import com.luck.picture.lib.engine.ImageEngine; import com.luck.picture.lib.utils.ActivityCompatHelper; /** * @author:luck * @date:2019-11-13 17:02 * @describe:Glide加载引擎 */ public class GlideEngine implements ImageEngine { /** * 加载图片 * * @param context 上下文 * @param url 资源url * @param imageView 图片承载控件 */ @Override public void loadImage(Context context, String url, ImageView imageView) { if (!ActivityCompatHelper.assertValidRequest(context)) { return; } Glide.with(context) .load(url) .into(imageView); } @Override public void loadImage(Context context, ImageView imageView, String url, int maxWidth, int maxHeight) { if (!ActivityCompatHelper.assertValidRequest(context)) { return; } Glide.with(context) .load(url) .override(maxWidth, maxHeight) .into(imageView); } /** * 加载相册目录封面 * * @param context 上下文 * @param url 图片路径 * @param imageView 承载图片ImageView */ @Override public void loadAlbumCover(Context context, String url, ImageView imageView) { if (!ActivityCompatHelper.assertValidRequest(context)) { return; } Glide.with(context) .asBitmap() .load(url) .override(180, 180) .sizeMultiplier(0.5f) .transform(new CenterCrop(), new RoundedCorners(8)) .placeholder(R.drawable.ps_image_placeholder) .into(imageView); } /** * 加载图片列表图片 * * @param context 上下文 * @param url 图片路径 * @param imageView 承载图片ImageView */ @Override public void loadGridImage(Context context, String url, ImageView imageView) { if (!ActivityCompatHelper.assertValidRequest(context)) { return; } Glide.with(context) .load(url) .override(200, 200) .centerCrop() .placeholder(R.drawable.ps_image_placeholder) .into(imageView); } @Override public void pauseRequests(Context context) { if (!ActivityCompatHelper.assertValidRequest(context)) { return; } Glide.with(context).pauseRequests(); } @Override public void resumeRequests(Context context) { if (!ActivityCompatHelper.assertValidRequest(context)) { return; } Glide.with(context).resumeRequests(); } private GlideEngine() { } private static final class InstanceHolder { static final GlideEngine instance = new GlideEngine(); } public static GlideEngine createGlideEngine() { return InstanceHolder.instance; } } app/src/main/java/com/example/smart/image/ImageProvider.kt
@@ -1,36 +1,31 @@ package com.example.smart.image import FileUploader import android.R import android.app.Activity import android.content.Context import android.content.Intent import android.graphics.Color import android.net.Uri import android.os.Build import android.os.Environment import android.provider.Settings import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.FragmentActivity import com.donkingliang.imageselector.ImageSelectorActivity import com.donkingliang.imageselector.entry.RequestConfig import com.donkingliang.imageselector.utils.ImageSelector import com.example.basecore.util.FileTools import com.example.basecore.util.LogUtils import com.example.smart.bean.ImageRef import com.example.smart.widget.dialog.LoadingDialog import java.util.ArrayList import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType import com.luck.picture.lib.entity.LocalMedia import com.luck.picture.lib.interfaces.OnResultCallbackListener import com.luck.picture.lib.style.PictureSelectorStyle import com.luck.picture.lib.style.SelectMainStyle import com.luck.picture.lib.style.TitleBarStyle class ImageProvider(val activity: Activity, val callback: IImageCallback) { private val REQUEST_CODE: Int = 6666 private var ossObjectName = "" private var maxCount = 1 val loadingDialog: LoadingDialog = LoadingDialog(activity) /** * oss object name */ @@ -54,79 +49,47 @@ } fun showImageSelect(maxCount: Int = 9) { // .backResId(android.support.v7.appcompat.R.drawable.abc_ic_ab_back_mtrl_am_alpha) // 标题 // val config = ISListConfig.Builder() // 是否多选, 默认true // .multiSelect(false) // 是否记住上次选中记录, 仅当multiSelect为true的时候配置,默认为true // .rememberSelected(false) // “确定”按钮背景色 // .btnBgColor(Color.GRAY) // “确定”按钮文字颜色 // .btnTextColor(Color.BLUE) // 使用沉浸式状态栏 // .statusBarColor(Color.parseColor("#3F51B5")) // 返回图标ResId // // .title("图片") // 标题文字颜色 // .titleColor(Color.WHITE) // TitleBar背景色 // .titleBgColor(Color.parseColor("#3F51B5")) // 裁剪大小。needCrop为true的时候配置 // .cropSize(1, 1, 200, 200) // .needCrop(true) // 第一个是否显示相机,默认true // .needCamera(false) // 最大选择图片数量,默认9 // .maxNum(maxCount) // .build() // // //// 跳转到图片选择器 // ISNav.getInstance().toListActivity(activity, config, REQUEST_CODE) if (!checkPer()) { val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION) intent.data = Uri.parse("package:" + activity.packageName) activity.startActivityForResult(intent, 0x00000012) return } val config = RequestConfig() config.useCamera = true config.isSingle = false config.maxSelectCount = maxCount config.canPreview = true this.maxCount = maxCount val intent = Intent(activity, ImageSelectorActivity::class.java) intent.putExtra(ImageSelector.KEY_CONFIG, config) if (activity is FragmentActivity) { val register = activity.activityResultRegistry.register( "101", ActivityResultContracts.StartActivityForResult() ) { if (it == null) { return@register //https://gitcode.com/gh_mirrors/pict/PictureSelector/?utm_source=gitcode_aigc_v1_t1&index=bottom&type=card&&uuid_tt_dd=10_37197039080-1778553766662-368769&isLogin=9&from_id=156450437&from_link=2b5eaab318b433d2570db6b0ce95c381 PictureSelector.create(activity) .openGallery(SelectMimeType.ofImage()) .setImageEngine(GlideEngine.createGlideEngine()) .setCompressEngine(CompressEngine()) .setSandboxFileEngine(SandboxEngine()) .isPreviewImage(true) .isDisplayCamera(true) .setImageSpanCount(3) .setSelectorUIStyle(PictureSelectorStyle().apply {//https://github.com/LuckSiege/PictureSelector/wiki/PictureSelector-3.0-%E4%B8%BB%E9%A2%98api%E8%AF%B4%E6%98%8E titleBarStyle = TitleBarStyle().apply { isHideCancelButton = true } onActivityResult(REQUEST_CODE, it.resultCode, it.data) selectMainStyle = SelectMainStyle().apply { isCompleteSelectRelativeTop = true//完成按钮从底部放在右上角 isPreviewSelectRelativeBottom = true//预览页选择按钮从顶部放在右下角 } register.launch(intent) } } fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (resultCode != AppCompatActivity.RESULT_OK) { }) .setMaxSelectNum(maxCount) .forResult(object : OnResultCallbackListener<LocalMedia?> { override fun onResult(result: ArrayList<LocalMedia?>?) { if (result == null) { return } if (requestCode == REQUEST_CODE && data != null) { onSelectPhotoSuccess(data) val filterNotNull = result.filterNotNull() if (filterNotNull.isEmpty()) { return } } private fun onSelectPhotoSuccess(data: Intent) { //获取选择器返回的数据 val images: ArrayList<String> = data.getStringArrayListExtra(ImageSelector.SELECT_RESULT) as ArrayList<String> val isCameraImage: Boolean = data.getBooleanExtra(ImageSelector.IS_CAMERA_IMAGE, false) val images = filterNotNull.mapNotNull { it.getAvailablePath() } LogUtils.e("images:$images") if (images.isEmpty()) { return } loadingDialog.show() if (maxCount == 1) { FileUploader.uploadFile(images[0], callback) { @@ -139,6 +102,10 @@ } } override fun onCancel() { } }) } /** * 上传绘制后的图片 @@ -149,44 +116,6 @@ loadingDialog.dismiss() } } // private val callBack = OssCallBack() // // private inner class OssCallBack : IOssCallBack { // override fun onAllListSuccess(ossPaths: MutableList<EntityRef>) { // super.onAllListSuccess(ossPaths) // loadingDialog.dismiss() // } // // override fun onSuccess(entityRef: EntityRef) { // activity.runOnUiThread { // if (maxCount == 1) { // loadingDialog.dismiss() // } // onUploadSuccess(entityRef) // } // } // // override fun onFailed() { // activity.runOnUiThread { // loadingDialog.dismiss() // onUploadFailed() // activity.toast("图片上传失败,请重新选择") // } // } // } // // private fun onUploadSuccess(entity: EntityRef) { // synchronized(this) { // callback.onUploadSuccess(entity) // } // } // // private fun onUploadFailed() { // synchronized(this) { // callback.onUploadFailed() // } // } interface IImageCallback { app/src/main/java/com/example/smart/image/SandboxEngine.java
New file @@ -0,0 +1,20 @@ package com.example.smart.image; import android.content.Context; import com.luck.picture.lib.engine.UriToFileTransformEngine; import com.luck.picture.lib.interfaces.OnKeyValueResultCallbackListener; import com.luck.picture.lib.utils.SandboxTransformUtils; /** * 沙盒引擎 访问沙盒外资源 */ public class SandboxEngine implements UriToFileTransformEngine { @Override public void onUriToFileAsyncTransform(Context context, String srcPath, String mineType, OnKeyValueResultCallbackListener call) { if (call != null) { String sandboxPath = SandboxTransformUtils.copyPathToSandbox(context, srcPath, mineType); call.onCallback(srcPath, sandboxPath); } } } app/src/main/java/com/example/smart/reqeust/RetrofitClient.kt
@@ -21,8 +21,8 @@ private const val DEFAULT_TIMEOUT = 30L // const val serverUrl = "http://47.108.113.190:8182/" const val serverUrl = "http://192.168.110.111:8182/" const val serverUrl = "http://47.108.113.190:8182/" // const val serverUrl = "http://192.168.110.111:8182/" private fun rootUrl(): String { return serverUrl app/src/main/java/com/example/smart/ui/item/CreateItemActivity.kt
@@ -390,9 +390,4 @@ super.onDestroy() MemberLiveData.clear() } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) mImageProvider.onActivityResult(requestCode, resultCode, data) } } app/src/main/java/com/example/smart/ui/item/adapter/ImageShowAdapter.kt
@@ -79,7 +79,7 @@ } holder.clear_img.setOnClickListener { data.remove(bean) notifyItemRemoved(position) notifyDataSetChanged() } } app/src/main/res/drawable/ps_image_placeholder.xml
New file @@ -0,0 +1,16 @@ <?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <shape> <size android:width="100dp" android:height="100dp" /> <solid android:color="@color/ps_color_light_grey" /> </shape> </item> <item> <bitmap android:gravity="center" android:src="@drawable/ps_ic_placeholder" /> </item> </layer-list> settings.gradle.kts
@@ -19,4 +19,4 @@ include(":app") include(":basecore") include(":waterdrop") include(":imageselector") //include(":imageselector")