bg上传 初步
This commit is contained in:
parent
52cc3a4cf2
commit
a1f5a40ba5
|
|
@ -1,20 +1,15 @@
|
||||||
package com.remax.visualnovel.entity.response
|
package com.remax.visualnovel.entity.response
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
import com.remax.visualnovel.entity.model.base.BasePhoto
|
import com.remax.visualnovel.entity.model.base.BasePhoto
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by HJW on 2025/8/18
|
|
||||||
*/
|
|
||||||
data class ChatBackground(
|
data class ChatBackground(
|
||||||
var backgroundId: Int? = 0,
|
var imageId: Long? = 0L,
|
||||||
var imgUrl: String? = "",
|
var imageUrl: String? = "",
|
||||||
|
|
||||||
|
var localUri: Uri? = null,
|
||||||
var isDefault: Boolean = false,
|
var isDefault: Boolean = false,
|
||||||
var select: Boolean = false,
|
var isSelected: Boolean = false,
|
||||||
var isSelected: Boolean? = null,
|
var isCustomBg: Boolean = false,
|
||||||
var deletable: Boolean = false,
|
) : ChatBackgroundBase()
|
||||||
var isUploadLocalItem: Boolean = false
|
|
||||||
) : BasePhoto() {
|
|
||||||
override fun paramId(): Long {
|
|
||||||
return imgUrl.hashCode().toLong()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.remax.visualnovel.entity.response
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
|
import com.remax.visualnovel.entity.model.base.BasePhoto
|
||||||
|
|
||||||
|
|
||||||
|
abstract class ChatBackgroundBase(
|
||||||
|
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.remax.visualnovel.entity.response
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
|
|
||||||
|
|
||||||
|
data class ChatBackgroundUpload(
|
||||||
|
var imageId: Long? = 0L,
|
||||||
|
var imageUrl: String? = "",
|
||||||
|
var localUri: Uri? = null,
|
||||||
|
) : ChatBackgroundBase()
|
||||||
|
|
@ -2,6 +2,7 @@ package com.remax.visualnovel.extension.glide
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.net.Uri
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
|
@ -112,6 +113,15 @@ fun ImageView.load(url: String?) {
|
||||||
.into(this)
|
.into(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ImageView.load(uri: Uri) {
|
||||||
|
visibility = View.VISIBLE
|
||||||
|
Glide.with(context)
|
||||||
|
.load(uri)
|
||||||
|
.centerCrop()
|
||||||
|
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
|
||||||
|
.into(this)
|
||||||
|
}
|
||||||
|
|
||||||
fun TextView.loadNinePatch(nineImageUrl: String?) {
|
fun TextView.loadNinePatch(nineImageUrl: String?) {
|
||||||
Glide.with(context)
|
Glide.with(context)
|
||||||
.asBitmap()
|
.asBitmap()
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import androidx.core.graphics.toColorInt
|
||||||
import com.remax.visualnovel.R
|
import com.remax.visualnovel.R
|
||||||
import com.remax.visualnovel.databinding.LayoutChatMenuViewBinding
|
import com.remax.visualnovel.databinding.LayoutChatMenuViewBinding
|
||||||
import com.remax.visualnovel.entity.response.ChatBackground
|
import com.remax.visualnovel.entity.response.ChatBackground
|
||||||
|
import com.remax.visualnovel.entity.response.ChatBackgroundUpload
|
||||||
import com.remax.visualnovel.entity.response.ChatBubble
|
import com.remax.visualnovel.entity.response.ChatBubble
|
||||||
import com.remax.visualnovel.entity.response.ChatHistory
|
import com.remax.visualnovel.entity.response.ChatHistory
|
||||||
import com.remax.visualnovel.entity.response.ChatMode
|
import com.remax.visualnovel.entity.response.ChatMode
|
||||||
|
|
@ -291,36 +292,30 @@ class ChatSettingView @JvmOverloads constructor(
|
||||||
fun initBackgroundSelectView() {
|
fun initBackgroundSelectView() {
|
||||||
val items = listOf(
|
val items = listOf(
|
||||||
ChatBackground(
|
ChatBackground(
|
||||||
backgroundId = 1,
|
imageId = 1,
|
||||||
imgUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png",
|
imageUrl = "https://vsn.s3.cn-north-1.amazonaws.com.cn/coverImage/fe8e3c7b-5b22-40f4-bacc-0183888c5149_test.png"
|
||||||
),
|
),
|
||||||
ChatBackground(
|
ChatBackground(
|
||||||
backgroundId = 1,
|
imageId = 1,
|
||||||
imgUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png",
|
imageUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png"
|
||||||
),
|
),
|
||||||
ChatBackground(
|
ChatBackground(
|
||||||
backgroundId = 1,
|
imageId = 1,
|
||||||
imgUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png",
|
imageUrl = "https://vsn.s3.cn-north-1.amazonaws.com.cn/coverImage/fe8e3c7b-5b22-40f4-bacc-0183888c5149_test.png"
|
||||||
),
|
),
|
||||||
ChatBackground(
|
ChatBackground(
|
||||||
backgroundId = 1,
|
imageId = 1,
|
||||||
imgUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png",
|
imageUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png"
|
||||||
),
|
),
|
||||||
ChatBackground(
|
ChatBackground(
|
||||||
backgroundId = 1,
|
imageId = 1,
|
||||||
imgUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png",
|
imageUrl = "https://vsn.s3.cn-north-1.amazonaws.com.cn/coverImage/fe8e3c7b-5b22-40f4-bacc-0183888c5149_test.png"
|
||||||
),
|
),
|
||||||
ChatBackground(
|
ChatBackground(
|
||||||
backgroundId = 1,
|
imageId = 1,
|
||||||
imgUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png",
|
imageUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png"
|
||||||
),
|
),
|
||||||
ChatBackground(
|
ChatBackgroundUpload(
|
||||||
backgroundId = 1,
|
|
||||||
imgUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png",
|
|
||||||
deletable = true
|
|
||||||
),
|
|
||||||
ChatBackground(
|
|
||||||
isUploadLocalItem = true
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import android.widget.LinearLayout
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.drake.brv.annotaion.DividerOrientation
|
import com.drake.brv.annotaion.DividerOrientation
|
||||||
|
import com.drake.brv.utils.addModels
|
||||||
import com.drake.brv.utils.bindingAdapter
|
import com.drake.brv.utils.bindingAdapter
|
||||||
import com.drake.brv.utils.divider
|
import com.drake.brv.utils.divider
|
||||||
import com.drake.brv.utils.grid
|
import com.drake.brv.utils.grid
|
||||||
|
|
@ -17,13 +18,28 @@ import com.remax.visualnovel.R
|
||||||
import com.remax.visualnovel.databinding.LayoutItemSettingBackgroundBinding
|
import com.remax.visualnovel.databinding.LayoutItemSettingBackgroundBinding
|
||||||
import com.remax.visualnovel.databinding.LayoutSettingBgSubViewBinding
|
import com.remax.visualnovel.databinding.LayoutSettingBgSubViewBinding
|
||||||
import com.remax.visualnovel.entity.response.ChatBackground
|
import com.remax.visualnovel.entity.response.ChatBackground
|
||||||
|
import com.remax.visualnovel.entity.response.ChatBackgroundBase
|
||||||
|
import com.remax.visualnovel.entity.response.ChatBackgroundUpload
|
||||||
|
import com.remax.visualnovel.extension.glide.load
|
||||||
|
import com.remax.visualnovel.extension.toast
|
||||||
|
import com.remax.visualnovel.utils.imagepick.EpalPickerPresenter
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.ImagePicker
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.bean.ImageItem
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.bean.MimeType
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.bean.PickerError
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.bean.SelectMode
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.data.OnImagePickCompleteListener2
|
||||||
|
import com.remax.visualnovel.widget.imageviewer.utils.activity
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ExpandBackgroundSubView @JvmOverloads constructor(
|
class ExpandBackgroundSubView @JvmOverloads constructor(
|
||||||
context: Context,
|
context: Context,
|
||||||
attrs: AttributeSet? = null,
|
attrs: AttributeSet? = null,
|
||||||
defStyleAttr: Int = 0
|
defStyleAttr: Int = 0
|
||||||
) : android.widget.LinearLayout(context, attrs, defStyleAttr) {
|
) : LinearLayout(context, attrs, defStyleAttr) {
|
||||||
private lateinit var items: List<ChatBackground>
|
|
||||||
|
private lateinit var items: List<ChatBackgroundBase>
|
||||||
private var mBinding: LayoutSettingBgSubViewBinding
|
private var mBinding: LayoutSettingBgSubViewBinding
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -42,36 +58,104 @@ class ExpandBackgroundSubView @JvmOverloads constructor(
|
||||||
orientation = DividerOrientation.VERTICAL
|
orientation = DividerOrientation.VERTICAL
|
||||||
}.setup {
|
}.setup {
|
||||||
addType<ChatBackground>(R.layout.layout_item_setting_background)
|
addType<ChatBackground>(R.layout.layout_item_setting_background)
|
||||||
|
addType<ChatBackgroundUpload>(R.layout.layout_item_setting_background_upload)
|
||||||
|
|
||||||
onClick(R.id.root) {
|
onClick(R.id.root) {
|
||||||
|
when (val item = getModel<Any>(it)) {
|
||||||
|
is ChatBackground -> {
|
||||||
val chatBackground = getModel<ChatBackground>()
|
val chatBackground = getModel<ChatBackground>()
|
||||||
if (!chatBackground.select) {
|
if (!chatBackground.isSelected) {
|
||||||
itemsRv.bindingAdapter.models?.filterIsInstance<ChatBackground>()?.forEach { item ->
|
itemsRv.bindingAdapter.models?.filterIsInstance<ChatBackground>()?.forEach { item ->
|
||||||
item.select = item == chatBackground
|
item.isSelected = item == chatBackground
|
||||||
}
|
}
|
||||||
itemsRv.bindingAdapter.notifyDataSetChanged()
|
itemsRv.bindingAdapter.notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
is ChatBackgroundUpload -> {
|
||||||
|
selectCustomBg()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*when (itemViewType) {
|
||||||
|
R.layout.layout_item_setting_background -> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
R.layout.layout_item_setting_background_upload -> {
|
||||||
|
selectCustomBg()
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
onBind {
|
onBind {
|
||||||
|
when (itemViewType) {
|
||||||
|
R.layout.layout_item_setting_background -> {
|
||||||
val item = getModel<ChatBackground>()
|
val item = getModel<ChatBackground>()
|
||||||
with(getBinding<LayoutItemSettingBackgroundBinding>()) {
|
with(getBinding<LayoutItemSettingBackgroundBinding>()) {
|
||||||
if (!item.imgUrl.isNullOrEmpty()) {
|
if (!item.imageUrl.isNullOrEmpty()) {
|
||||||
//ivBackgroundSrc.load(item.imgUrl)
|
ivBackgroundSrc.load(item.imageUrl)
|
||||||
|
} else if (item.localUri != null) {
|
||||||
|
ivBackgroundSrc.load(item.localUri!!)
|
||||||
}
|
}
|
||||||
ivDel.visibility = if (item.deletable) VISIBLE else GONE
|
|
||||||
|
|
||||||
ivUpload.isVisible = item.isUploadLocalItem
|
ivDel.visibility = if (item.isCustomBg) VISIBLE else GONE
|
||||||
ivBackgroundSrc.isVisible = !item.isUploadLocalItem
|
ivBackgroundSrc.isVisible = item.isSelected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
R.layout.layout_item_setting_background_upload -> {
|
||||||
|
val item = getModel<ChatBackgroundUpload>()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setItems(newItems: List<ChatBackground>) {
|
fun setItems(newItems: List<ChatBackgroundBase>) {
|
||||||
items = newItems
|
items = newItems
|
||||||
mBinding.itemsRv.models = items
|
mBinding.itemsRv.models = items
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun selectCustomBg(showCamera: Boolean = true) {
|
||||||
|
ImagePicker.withMulti(EpalPickerPresenter())
|
||||||
|
.setMaxCount(1)
|
||||||
|
.setSelectMode(SelectMode.MODE_SINGLE)
|
||||||
|
.setColumnCount(3)
|
||||||
|
.mimeTypes(MimeType.ofImage())
|
||||||
|
.filterMimeTypes(MimeType.GIF)
|
||||||
|
.showCamera(showCamera)
|
||||||
|
.setPreview(true)
|
||||||
|
.setSinglePickImageOrVideoType(true)
|
||||||
|
.pick(activity, object : OnImagePickCompleteListener2 {
|
||||||
|
override fun onPickFailed(error: PickerError?) {
|
||||||
|
activity?.toast(error?.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onImagePickComplete(items: ArrayList<ImageItem>?) {
|
||||||
|
appendCustomBg(items)
|
||||||
|
uploadImageAndRequest(items)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun appendCustomBg(items: ArrayList<ImageItem>?) {
|
||||||
|
val customBgList = items?.map { imageItem ->
|
||||||
|
ChatBackground(
|
||||||
|
imageId = imageItem.id,
|
||||||
|
imageUrl = imageItem.path,
|
||||||
|
localUri = imageItem.uri
|
||||||
|
)
|
||||||
|
}
|
||||||
|
mBinding.itemsRv.addModels(customBgList)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun uploadImageAndRequest(items: ArrayList<ImageItem>?) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,272 @@
|
||||||
|
package com.remax.visualnovel.utils.imagepick
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ImageView
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
|
import com.bumptech.glide.load.DataSource
|
||||||
|
import com.bumptech.glide.load.DecodeFormat
|
||||||
|
import com.bumptech.glide.load.engine.GlideException
|
||||||
|
import com.bumptech.glide.load.resource.gif.GifDrawable
|
||||||
|
import com.bumptech.glide.request.RequestListener
|
||||||
|
import com.bumptech.glide.request.RequestOptions
|
||||||
|
import com.bumptech.glide.request.target.Target
|
||||||
|
import com.remax.visualnovel.R
|
||||||
|
import com.remax.visualnovel.app.widget.LoadingDialog
|
||||||
|
import com.remax.visualnovel.extension.findActivityContext
|
||||||
|
import com.remax.visualnovel.extension.toast
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.adapter.PickerItemAdapter
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.bean.ImageItem
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.bean.selectconfig.BaseSelectConfig
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.data.ICameraExecutor
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.data.IReloadExecutor
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.data.ProgressSceneEnum
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.presenter.IPickerPresenter
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.views.PickerUiConfig
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.views.PickerUiProvider
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.views.base.PickerControllerView
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.views.base.PickerFolderItemView
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.views.base.SingleCropControllerView
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.views.wrapper.BottomBar
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.views.wrapper.FolderItemView
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.views.wrapper.TitleBar
|
||||||
|
import com.remax.visualnovel.widget.uitoken.handleUIToken
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by HJW on 2020/10/13
|
||||||
|
*/
|
||||||
|
class EpalPickerPresenter(private val isAlbum: Boolean = false) : IPickerPresenter {
|
||||||
|
/**
|
||||||
|
* 提示
|
||||||
|
*
|
||||||
|
* @param context 上下文
|
||||||
|
* @param msg 提示文本
|
||||||
|
*/
|
||||||
|
override fun tip(context: Context?, msg: String?) {
|
||||||
|
context?.let {
|
||||||
|
if (!msg.isNullOrBlank()) {
|
||||||
|
it.toast(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择超过数量限制提示
|
||||||
|
*
|
||||||
|
* @param context 上下文
|
||||||
|
* @param maxCount 最大数量
|
||||||
|
*/
|
||||||
|
override fun overMaxCountTip(context: Context?, maxCount: Int) {
|
||||||
|
tip(context, String.format(context?.getString(R.string.upload_up_to_images) ?: "", maxCount))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示loading加载框,注意需要调用show方法
|
||||||
|
*
|
||||||
|
* @param activity 启动加载框的activity
|
||||||
|
* @param progressSceneEnum {@link ProgressSceneEnum}
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 当progressSceneEnum==当ProgressSceneEnum.loadMediaItem 时,代表在加载媒体文件时显示加载框
|
||||||
|
* 目前框架内规定,当文件夹内媒体文件少于1000时,强制不显示加载框,大于1000时才会执行此方法
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* 当progressSceneEnum==当ProgressSceneEnum.crop 时,代表是剪裁页面的加载框
|
||||||
|
* </p>
|
||||||
|
* @return DialogInterface 对象,用于关闭加载框,返回null代表不显示加载框
|
||||||
|
*/
|
||||||
|
override fun showProgressDialog(activity: Activity?, progressSceneEnum: ProgressSceneEnum?): DialogInterface {
|
||||||
|
return LoadingDialog().build(activity!!).getDialog().thisShow()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拦截选择器取消操作,用于弹出二次确认框
|
||||||
|
*
|
||||||
|
* @param activity 当前选择器页面
|
||||||
|
* @param selectedList 当前已经选择的文件列表
|
||||||
|
* @return true:则拦截选择器取消, false,不处理选择器取消操作
|
||||||
|
*/
|
||||||
|
override fun interceptPickerCancel(activity: Activity?, selectedList: ArrayList<ImageItem>?): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 图片点击事件拦截,如果返回true,则不会执行选中操纵,如果要拦截此事件并且要执行选中
|
||||||
|
* 请调用如下代码:
|
||||||
|
* <p>
|
||||||
|
* adapter.preformCheckItem()
|
||||||
|
* <p>
|
||||||
|
* <p>
|
||||||
|
* 此方法可以用来跳转到任意一个页面,比如自定义的预览
|
||||||
|
*
|
||||||
|
* @param activity 上下文
|
||||||
|
* @param imageItem 当前图片
|
||||||
|
* @param selectImageList 当前选中列表
|
||||||
|
* @param allSetImageList 当前文件夹所有图片
|
||||||
|
* @param selectConfig 选择器配置项,如果是微信样式,则selectConfig继承自MultiSelectConfig
|
||||||
|
* 如果是小红书剪裁样式,则继承自CropSelectConfig
|
||||||
|
* @param adapter 当前列表适配器,用于刷新数据
|
||||||
|
* @param isClickCheckBox 是否点击item右上角的选中框
|
||||||
|
* @param reloadExecutor 刷新器
|
||||||
|
* @return 是否拦截
|
||||||
|
*/
|
||||||
|
override fun interceptItemClick(
|
||||||
|
activity: Activity?,
|
||||||
|
imageItem: ImageItem?,
|
||||||
|
selectImageList: ArrayList<ImageItem>?,
|
||||||
|
allSetImageList: ArrayList<ImageItem>?,
|
||||||
|
selectConfig: BaseSelectConfig?,
|
||||||
|
adapter: PickerItemAdapter?,
|
||||||
|
isClickCheckBox: Boolean,
|
||||||
|
reloadExecutor: IReloadExecutor?
|
||||||
|
): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拍照点击事件拦截
|
||||||
|
*
|
||||||
|
* @param activity 当前activity
|
||||||
|
* @param takePhoto 拍照接口
|
||||||
|
* @return 是否拦截
|
||||||
|
*/
|
||||||
|
override fun interceptCameraClick(activity: Activity?, takePhoto: ICameraExecutor?): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片加载,在安卓10上,外部存储的图片路径只能用Uri加载,私有目录的图片可以用绝对路径加载
|
||||||
|
* 所以这个方法务必需要区分有uri和无uri的情况
|
||||||
|
* 一般媒体库直接扫描出来的图片是含有uri的,而剪裁生成的图片保存在私有目录中,因此没有uri,只有绝对路径
|
||||||
|
* 所以这里需要做一个兼容处理
|
||||||
|
*
|
||||||
|
* @param view imageView
|
||||||
|
* @param item 图片信息
|
||||||
|
* @param size 加载尺寸
|
||||||
|
* @param isThumbnail 是否是缩略图
|
||||||
|
*/
|
||||||
|
override fun displayImage(view: View?, imageItem: ImageItem?, size: Int, isThumbnail: Boolean) {
|
||||||
|
imageItem?.let { item ->
|
||||||
|
view?.let { v ->
|
||||||
|
(v.context.findActivityContext() as? Activity)?.also { act ->
|
||||||
|
if (!act.isDestroyed) {
|
||||||
|
val loadPath = if (item.uri != null) item.uri.toString() else item.path
|
||||||
|
Glide.with(act).load(loadPath)
|
||||||
|
.apply(RequestOptions().format(if (isThumbnail) DecodeFormat.PREFER_RGB_565 else DecodeFormat.PREFER_ARGB_8888))
|
||||||
|
// .override(if (isThumbnail) size else Target.SIZE_ORIGINAL)
|
||||||
|
.listener(object : RequestListener<Drawable> {
|
||||||
|
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>, isFirstResource: Boolean): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResourceReady(
|
||||||
|
resource: Drawable,
|
||||||
|
model: Any,
|
||||||
|
target: Target<Drawable>?,
|
||||||
|
dataSource: DataSource,
|
||||||
|
isFirstResource: Boolean
|
||||||
|
): Boolean {
|
||||||
|
return if (resource is GifDrawable) {
|
||||||
|
if (item.isGif || loadPath.toString().substring(loadPath.toString().lastIndexOf(".") + 1) == "gif") {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
if (!loadPath.startsWith("http")) {
|
||||||
|
(v as ImageView).setImageBitmap(resource.firstFrame)
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
.into(view as ImageView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拦截选择器完成按钮点击事件
|
||||||
|
*
|
||||||
|
* @param activity 当前选择器activity
|
||||||
|
* @param selectedList 已选中的列表
|
||||||
|
* @return true:则拦截选择器完成回调, false,执行默认的选择器回调
|
||||||
|
*/
|
||||||
|
override fun interceptPickerCompleteClick(activity: Activity?, selectedList: ArrayList<ImageItem>?, selectConfig: BaseSelectConfig?): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置自定义ui显示样式,不可返回null
|
||||||
|
* 该方法返回一个PickerUiConfig对象
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 该对象可以配置如下信息:
|
||||||
|
* 1.主题色
|
||||||
|
* 2.相关页面背景色
|
||||||
|
* 3.选择器标题栏,底部栏,item,文件夹列表item,预览页面,剪裁页面的定制
|
||||||
|
* <p>
|
||||||
|
* <p>
|
||||||
|
* 详细使用方法参考 (@link https://github.com/yangpeixing/YImagePicker/blob/master/YPX_ImagePicker_androidx/app/src/main/java/com/ypx/imagepickerdemo/style/WeChatPresenter.java)
|
||||||
|
*
|
||||||
|
* @param context 上下文
|
||||||
|
* @return PickerUiConfig
|
||||||
|
*/
|
||||||
|
override fun getUiConfig(context: Context?): PickerUiConfig {
|
||||||
|
val uiConfig = PickerUiConfig()
|
||||||
|
with(uiConfig) {
|
||||||
|
//设置主题色
|
||||||
|
themeColor = context?.handleUIToken(R.string.color_primary_normal)?.color ?: 0
|
||||||
|
//设置是否显示状态栏
|
||||||
|
isShowStatusBar = true
|
||||||
|
//设置状态栏颜色
|
||||||
|
statusBarColor = context?.handleUIToken(R.string.color_background_default)?.color ?: 0
|
||||||
|
//设置选择器背景
|
||||||
|
pickerBackgroundColor = context?.handleUIToken(R.string.color_background_default)?.color ?: 0
|
||||||
|
//设置单图剪裁背景色
|
||||||
|
singleCropBackgroundColor = context?.handleUIToken(R.string.color_background_default)?.color ?: 0
|
||||||
|
//设置预览页面背景色
|
||||||
|
previewBackgroundColor = context?.handleUIToken(R.string.color_background_default)?.color ?: 0
|
||||||
|
//设置选择器文件夹打开方向
|
||||||
|
folderListOpenDirection = PickerUiConfig.DIRECTION_TOP
|
||||||
|
//设置文件夹列表距离顶部/底部边距
|
||||||
|
folderListOpenMaxMargin = 120
|
||||||
|
//设置小红书剪裁区域的背景色
|
||||||
|
cropViewBackgroundColor = context?.handleUIToken(R.string.color_background_default)?.color ?: 0
|
||||||
|
pickerUiProvider = object : PickerUiProvider() {
|
||||||
|
override fun getTitleBar(context: Context?): PickerControllerView {
|
||||||
|
return TitleBar(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFolderItemView(context: Context?): PickerFolderItemView {
|
||||||
|
return FolderItemView(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSingleCropControllerView(context: Context?): SingleCropControllerView {
|
||||||
|
return com.remax.visualnovel.widget.imagepicker.views.wrapper.SingleCropControllerView(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getBottomBar(context: Context?): PickerControllerView {
|
||||||
|
return BottomBar(context, isAlbum)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getPreviewControllerView(context: Context): com.remax.visualnovel.widget.imagepicker.views.wrapper.PreviewControllerView {
|
||||||
|
return super.getPreviewControllerView(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uiConfig
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,178 @@
|
||||||
|
package com.remax.visualnovel.utils.imagepick
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import com.remax.visualnovel.extension.toast
|
||||||
|
import com.remax.visualnovel.manager.login.LoginManager
|
||||||
|
import com.remax.visualnovel.utils.spannablex.utils.dp
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.ImagePicker
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.bean.ImageItem
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.bean.MimeType
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.bean.PickerError
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.bean.SelectMode
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.bean.selectconfig.CropConfig
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.data.OnImagePickCompleteListener
|
||||||
|
import com.remax.visualnovel.widget.imagepicker.data.OnImagePickCompleteListener2
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by HJW on 2020/10/13
|
||||||
|
*/
|
||||||
|
class ImagePickUtils {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择单张图片(无剪裁)
|
||||||
|
*/
|
||||||
|
fun pickOneWithoutCrop(activity: Activity, showCamera: Boolean = true, imagePickCompleteListener: OnImagePickCompleteListener) {
|
||||||
|
ImagePicker.withMulti(EpalPickerPresenter())
|
||||||
|
.setMaxCount(1)
|
||||||
|
//设置单选模式,当maxCount==1时,可执行单选(下次选中会取消上一次选中)
|
||||||
|
.setSelectMode(SelectMode.MODE_SINGLE)
|
||||||
|
.setColumnCount(3)
|
||||||
|
.mimeTypes(MimeType.ofImage())
|
||||||
|
//设置需要过滤掉加载的文件类型
|
||||||
|
.filterMimeTypes(MimeType.GIF)
|
||||||
|
.showCamera(showCamera)
|
||||||
|
.setPreview(true)
|
||||||
|
//设置图片和视频单一类型选择
|
||||||
|
.setSinglePickImageOrVideoType(true)
|
||||||
|
.pick(activity, object : OnImagePickCompleteListener2 {
|
||||||
|
override fun onPickFailed(error: PickerError?) {
|
||||||
|
activity.toast(error?.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onImagePickComplete(items: ArrayList<ImageItem>?) {
|
||||||
|
imagePickCompleteListener.onImagePickComplete(items)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户选择头像
|
||||||
|
* VIP才可以选择gif图
|
||||||
|
*/
|
||||||
|
fun pickHeadWithCrop(activity: Activity, margin: Int? = null, cropTaskFrame: Int? = null, onImagePickCompleteListener: OnImagePickCompleteListener) {
|
||||||
|
val mimeTypes = mutableSetOf(MimeType.JPEG, MimeType.PNG, MimeType.BMP, MimeType.WEBP)
|
||||||
|
ImagePicker.withMulti(EpalPickerPresenter())
|
||||||
|
.setMaxCount(1)
|
||||||
|
//设置单选模式,当maxCount==1时,可执行单选(下次选中会取消上一次选中)
|
||||||
|
.setSelectMode(SelectMode.MODE_SINGLE)
|
||||||
|
.setColumnCount(3)
|
||||||
|
.mimeTypes(mimeTypes)
|
||||||
|
.showCamera(true)
|
||||||
|
.setPreview(true)
|
||||||
|
//设置图片和视频单一类型选择
|
||||||
|
.setSinglePickImageOrVideoType(true)
|
||||||
|
.cropAsCircle()
|
||||||
|
.cropRectMinMargin(margin ?: 48.dp)
|
||||||
|
.setCropTaskFrame(cropTaskFrame ?: 0)
|
||||||
|
//设置剪裁模式,留白或充满 CropConfig.STYLE_GAP 或 CropConfig.STYLE_FILL
|
||||||
|
.cropStyle(CropConfig.STYLE_FILL)
|
||||||
|
//x y 比例
|
||||||
|
.setCropRatio(1, 1)
|
||||||
|
//剪裁完成的图片是否保存在DCIM目录下
|
||||||
|
//true:存储在DCIM下 false:存储在 data/包名/files/imagePicker/ 目录下
|
||||||
|
.cropSaveInDCIM(false)
|
||||||
|
.crop(activity, object : OnImagePickCompleteListener2 {
|
||||||
|
override fun onPickFailed(error: PickerError?) {
|
||||||
|
activity.toast(error?.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onImagePickComplete(items: ArrayList<ImageItem>?) {
|
||||||
|
onImagePickCompleteListener.onImagePickComplete(items)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择单张图片(有剪裁,无gif,默认1 :1)
|
||||||
|
*/
|
||||||
|
fun pickOneWithCrop(
|
||||||
|
activity: Activity,
|
||||||
|
x: Int = 1,
|
||||||
|
y: Int = 1,
|
||||||
|
onImagePickCompleteListener: OnImagePickCompleteListener,
|
||||||
|
showCamera: Boolean = true
|
||||||
|
) {
|
||||||
|
ImagePicker.withMulti(EpalPickerPresenter())
|
||||||
|
.setMaxCount(1)
|
||||||
|
//设置单选模式,当maxCount==1时,可执行单选(下次选中会取消上一次选中)
|
||||||
|
.setSelectMode(SelectMode.MODE_SINGLE)
|
||||||
|
.setColumnCount(3)
|
||||||
|
.mimeTypes(MimeType.ofImage())
|
||||||
|
//设置需要过滤掉加载的文件类型
|
||||||
|
.filterMimeTypes(MimeType.GIF)
|
||||||
|
.showCamera(showCamera)
|
||||||
|
.setPreview(true)
|
||||||
|
//设置图片和视频单一类型选择z
|
||||||
|
.setSinglePickImageOrVideoType(true)
|
||||||
|
.cropRectMinMargin(48.dp)
|
||||||
|
//设置剪裁模式,留白或充满 CropConfig.STYLE_GAP 或 CropConfig.STYLE_FILL
|
||||||
|
.cropStyle(CropConfig.STYLE_FILL)
|
||||||
|
//x y 比例
|
||||||
|
.setCropRatio(x, y)
|
||||||
|
//剪裁完成的图片是否保存在DCIM目录下
|
||||||
|
//true:存储在DCIM下 false:存储在 data/包名/files/imagePicker/ 目录下
|
||||||
|
.cropSaveInDCIM(false)
|
||||||
|
.crop(activity, object : OnImagePickCompleteListener2 {
|
||||||
|
override fun onPickFailed(error: PickerError?) {
|
||||||
|
activity.toast(error?.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onImagePickComplete(items: ArrayList<ImageItem>?) {
|
||||||
|
onImagePickCompleteListener.onImagePickComplete(items)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 直接剪裁头像
|
||||||
|
* UI圆形显示,输出是1:1
|
||||||
|
*/
|
||||||
|
fun cropCircleImage(activity: Activity, imageUrl: String, onImagePickCompleteListener: OnImagePickCompleteListener) {
|
||||||
|
ImagePicker.crop(activity, EpalPickerPresenter(), CropConfig().apply {
|
||||||
|
this.cropStyle = CropConfig.STYLE_FILL
|
||||||
|
isCircle = true
|
||||||
|
saveInDCIM(false)
|
||||||
|
cropRectMargin = 48.dp
|
||||||
|
}, imageUrl, onImagePickCompleteListener)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择多张图片(无剪裁)
|
||||||
|
*/
|
||||||
|
fun pickMaxCount(
|
||||||
|
activity: Activity,
|
||||||
|
maxCount: Int,
|
||||||
|
onImagePickCompleteListener: OnImagePickCompleteListener,
|
||||||
|
showCamera: Boolean = false,
|
||||||
|
filterGif: Boolean = true,
|
||||||
|
isAlbum: Boolean = false
|
||||||
|
) {
|
||||||
|
val presenter = EpalPickerPresenter(isAlbum)
|
||||||
|
ImagePicker.withMulti(presenter)
|
||||||
|
.setMaxCount(maxCount)
|
||||||
|
.setColumnCount(3)
|
||||||
|
.mimeTypes(MimeType.ofImage())
|
||||||
|
//设置需要过滤掉加载的文件类型
|
||||||
|
.filterMimeTypes(if (filterGif) MimeType.GIF else null)
|
||||||
|
.setPreview(true)
|
||||||
|
.showCamera(showCamera)
|
||||||
|
//设置图片和视频单一类型选择
|
||||||
|
.setSinglePickImageOrVideoType(true)
|
||||||
|
.pick(activity, object : OnImagePickCompleteListener2 {
|
||||||
|
override fun onPickFailed(error: PickerError?) {
|
||||||
|
activity.toast(error?.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onImagePickComplete(items: ArrayList<ImageItem>?) {
|
||||||
|
onImagePickCompleteListener.onImagePickComplete(items)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -51,7 +51,7 @@ class MyImageLoader : ImageLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
is ChatBackground -> {
|
is ChatBackground -> {
|
||||||
data.imgUrl
|
data.imageUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
is CustomAlbumData -> {
|
is CustomAlbumData -> {
|
||||||
|
|
|
||||||
|
|
@ -46,17 +46,6 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
|
||||||
android:id="@+id/iv_upload"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:src="@mipmap/icon_upload_image"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/iv_selected_indi"
|
android:id="@+id/iv_selected_indi"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/root"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="@dimen/dp_10">
|
||||||
|
|
||||||
|
<com.remax.visualnovel.widget.roundedimageview.RoundedImageView
|
||||||
|
android:id="@+id/iv_background_src"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:src="@color/grayf3"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
app:riv_corner_radius="@dimen/dp_10"
|
||||||
|
app:layout_constraintDimensionRatio="h,87:116"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/iv_upload"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@mipmap/icon_upload_image"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
@ -193,6 +193,8 @@
|
||||||
<color name="gray9">#ff999999</color>
|
<color name="gray9">#ff999999</color>
|
||||||
<color name="grayf6">#fff6f6f6</color>
|
<color name="grayf6">#fff6f6f6</color>
|
||||||
<color name="gray28">#ff282828</color>
|
<color name="gray28">#ff282828</color>
|
||||||
|
<color name="grayf3">#fff3f4ff</color>
|
||||||
|
|
||||||
|
|
||||||
<color name="red_ff3b30">#ffff3b30</color>
|
<color name="red_ff3b30">#ffff3b30</color>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue