bg上传 初步
This commit is contained in:
parent
52cc3a4cf2
commit
a1f5a40ba5
|
|
@ -1,20 +1,15 @@
|
|||
package com.remax.visualnovel.entity.response
|
||||
|
||||
import android.net.Uri
|
||||
import com.remax.visualnovel.entity.model.base.BasePhoto
|
||||
|
||||
/**
|
||||
* Created by HJW on 2025/8/18
|
||||
*/
|
||||
|
||||
data class ChatBackground(
|
||||
var backgroundId: Int? = 0,
|
||||
var imgUrl: String? = "",
|
||||
var imageId: Long? = 0L,
|
||||
var imageUrl: String? = "",
|
||||
|
||||
var localUri: Uri? = null,
|
||||
var isDefault: Boolean = false,
|
||||
var select: Boolean = false,
|
||||
var isSelected: Boolean? = null,
|
||||
var deletable: Boolean = false,
|
||||
var isUploadLocalItem: Boolean = false
|
||||
) : BasePhoto() {
|
||||
override fun paramId(): Long {
|
||||
return imgUrl.hashCode().toLong()
|
||||
}
|
||||
}
|
||||
var isSelected: Boolean = false,
|
||||
var isCustomBg: Boolean = false,
|
||||
) : ChatBackgroundBase()
|
||||
|
|
|
|||
|
|
@ -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.drawable.Drawable
|
||||
import android.net.Uri
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
|
|
@ -112,6 +113,15 @@ fun ImageView.load(url: String?) {
|
|||
.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?) {
|
||||
Glide.with(context)
|
||||
.asBitmap()
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import androidx.core.graphics.toColorInt
|
|||
import com.remax.visualnovel.R
|
||||
import com.remax.visualnovel.databinding.LayoutChatMenuViewBinding
|
||||
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.ChatHistory
|
||||
import com.remax.visualnovel.entity.response.ChatMode
|
||||
|
|
@ -291,36 +292,30 @@ class ChatSettingView @JvmOverloads constructor(
|
|||
fun initBackgroundSelectView() {
|
||||
val items = listOf(
|
||||
ChatBackground(
|
||||
backgroundId = 1,
|
||||
imgUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png",
|
||||
imageId = 1,
|
||||
imageUrl = "https://vsn.s3.cn-north-1.amazonaws.com.cn/coverImage/fe8e3c7b-5b22-40f4-bacc-0183888c5149_test.png"
|
||||
),
|
||||
ChatBackground(
|
||||
backgroundId = 1,
|
||||
imgUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png",
|
||||
imageId = 1,
|
||||
imageUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png"
|
||||
),
|
||||
ChatBackground(
|
||||
backgroundId = 1,
|
||||
imgUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png",
|
||||
imageId = 1,
|
||||
imageUrl = "https://vsn.s3.cn-north-1.amazonaws.com.cn/coverImage/fe8e3c7b-5b22-40f4-bacc-0183888c5149_test.png"
|
||||
),
|
||||
ChatBackground(
|
||||
backgroundId = 1,
|
||||
imgUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png",
|
||||
imageId = 1,
|
||||
imageUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png"
|
||||
),
|
||||
ChatBackground(
|
||||
backgroundId = 1,
|
||||
imgUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png",
|
||||
imageId = 1,
|
||||
imageUrl = "https://vsn.s3.cn-north-1.amazonaws.com.cn/coverImage/fe8e3c7b-5b22-40f4-bacc-0183888c5149_test.png"
|
||||
),
|
||||
ChatBackground(
|
||||
backgroundId = 1,
|
||||
imgUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png",
|
||||
imageId = 1,
|
||||
imageUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png"
|
||||
),
|
||||
ChatBackground(
|
||||
backgroundId = 1,
|
||||
imgUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png",
|
||||
deletable = true
|
||||
),
|
||||
ChatBackground(
|
||||
isUploadLocalItem = true
|
||||
ChatBackgroundUpload(
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import android.widget.LinearLayout
|
|||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.drake.brv.annotaion.DividerOrientation
|
||||
import com.drake.brv.utils.addModels
|
||||
import com.drake.brv.utils.bindingAdapter
|
||||
import com.drake.brv.utils.divider
|
||||
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.LayoutSettingBgSubViewBinding
|
||||
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(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : android.widget.LinearLayout(context, attrs, defStyleAttr) {
|
||||
private lateinit var items: List<ChatBackground>
|
||||
) : LinearLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
private lateinit var items: List<ChatBackgroundBase>
|
||||
private var mBinding: LayoutSettingBgSubViewBinding
|
||||
|
||||
|
||||
|
|
@ -42,36 +58,104 @@ class ExpandBackgroundSubView @JvmOverloads constructor(
|
|||
orientation = DividerOrientation.VERTICAL
|
||||
}.setup {
|
||||
addType<ChatBackground>(R.layout.layout_item_setting_background)
|
||||
addType<ChatBackgroundUpload>(R.layout.layout_item_setting_background_upload)
|
||||
|
||||
onClick(R.id.root) {
|
||||
when (val item = getModel<Any>(it)) {
|
||||
is ChatBackground -> {
|
||||
val chatBackground = getModel<ChatBackground>()
|
||||
if (!chatBackground.select) {
|
||||
if (!chatBackground.isSelected) {
|
||||
itemsRv.bindingAdapter.models?.filterIsInstance<ChatBackground>()?.forEach { item ->
|
||||
item.select = item == chatBackground
|
||||
item.isSelected = item == chatBackground
|
||||
}
|
||||
itemsRv.bindingAdapter.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
is ChatBackgroundUpload -> {
|
||||
selectCustomBg()
|
||||
}
|
||||
}
|
||||
|
||||
/*when (itemViewType) {
|
||||
R.layout.layout_item_setting_background -> {
|
||||
|
||||
}
|
||||
|
||||
R.layout.layout_item_setting_background_upload -> {
|
||||
selectCustomBg()
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
onBind {
|
||||
when (itemViewType) {
|
||||
R.layout.layout_item_setting_background -> {
|
||||
val item = getModel<ChatBackground>()
|
||||
with(getBinding<LayoutItemSettingBackgroundBinding>()) {
|
||||
if (!item.imgUrl.isNullOrEmpty()) {
|
||||
//ivBackgroundSrc.load(item.imgUrl)
|
||||
if (!item.imageUrl.isNullOrEmpty()) {
|
||||
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
|
||||
ivBackgroundSrc.isVisible = !item.isUploadLocalItem
|
||||
ivDel.visibility = if (item.isCustomBg) VISIBLE else GONE
|
||||
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
|
||||
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 -> {
|
||||
data.imgUrl
|
||||
data.imageUrl
|
||||
}
|
||||
|
||||
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
|
||||
android:id="@+id/iv_selected_indi"
|
||||
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="grayf6">#fff6f6f6</color>
|
||||
<color name="gray28">#ff282828</color>
|
||||
<color name="grayf3">#fff3f4ff</color>
|
||||
|
||||
|
||||
<color name="red_ff3b30">#ffff3b30</color>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue