自定义背景上传

This commit is contained in:
renhaoting 2025-11-05 17:24:02 +08:00
parent a1f5a40ba5
commit 8f171d3214
11 changed files with 132 additions and 115 deletions

View File

@ -55,6 +55,10 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity
android:name=".widget.imagepicker.activity.multi.MultiImagePickerActivity"
android:exported="false" >
</activity>
<activity <activity
android:name=".ui.main.MainActivity" android:name=".ui.main.MainActivity"

View File

@ -14,7 +14,7 @@ import com.remax.visualnovel.entity.request.SimpleDataDTO
import com.remax.visualnovel.entity.request.VoiceTTS import com.remax.visualnovel.entity.request.VoiceTTS
import com.remax.visualnovel.entity.response.Album import com.remax.visualnovel.entity.response.Album
import com.remax.visualnovel.entity.response.Character import com.remax.visualnovel.entity.response.Character
import com.remax.visualnovel.entity.response.ChatBackground import com.remax.visualnovel.entity.response.ChatBackgroundBase
import com.remax.visualnovel.entity.response.ChatModel import com.remax.visualnovel.entity.response.ChatModel
import com.remax.visualnovel.entity.response.ChatSet import com.remax.visualnovel.entity.response.ChatSet
import com.remax.visualnovel.entity.response.ChatSound import com.remax.visualnovel.entity.response.ChatSound
@ -87,7 +87,7 @@ interface ChatService {
* 获取聊天背景列表 * 获取聊天背景列表
*/ */
@POST("/web/chat-background/list") @POST("/web/chat-background/list")
suspend fun getChatBackgroundList(@Body request: AIIDRequest): Response<List<ChatBackground>> suspend fun getChatBackgroundList(@Body request: AIIDRequest): Response<List<ChatBackgroundBase.ChatBackground>>
/** /**
* 获取聊天设置 * 获取聊天设置

View File

@ -2,23 +2,23 @@ package com.remax.visualnovel.entity.response
data class ActorBean( data class ActorBean(
val id: Int, val id: Int = 0,
val roleName: String, val roleName: String = "",
val description: String, val description: String = "",
var coverImage: String = "", var coverImage: String = "",
val sourceId: Int, //来源ID;所属书籍/漫剧 val sourceId: Int = 0, //来源ID;所属书籍/漫剧
val sourceType: Int, //来源分类 val sourceType: Int = 0, //来源分类
val commonCount: Int, //评论数 val commonCount: Int = 0, //评论数
val createTime: String, val createTime: String = "",
val status: String, val status: String = "",
// other needed // other needed
val avatarRes: Int, val avatarRes: Int = 0,
val from: String = "from", val from: String = "from",
val rating: Float, val rating: Float = 0F,
val characterName: String, val characterName: String = "",
val age: Int, val age: Int = 0,
val tags: List<String>, val tags: List<String> = emptyList(),
val workTitle: String, val workTitle: String = "",
val imageRes: Int val imageRes: Int = 0
) )

View File

@ -1,15 +1,23 @@
package com.remax.visualnovel.entity.response package com.remax.visualnovel.entity.response
import android.net.Uri import android.net.Uri
import com.remax.visualnovel.entity.model.base.BasePhoto
data class ChatBackground( sealed class ChatBackgroundBase(val itemType: Int) {
var imageId: Long? = 0L, data class ChatBackground(
var imageUrl: String? = "", var imageId: Long? = 0L,
var imageUrl: String? = "",
var localUri: Uri? = null,
var isDefault: Boolean = false,
var isSelected: Boolean = false,
var isCustomBg: Boolean = false,
) : ChatBackgroundBase(ITEM_TYPE_BACKGROUND)
object ChatBackgroundUpload : ChatBackgroundBase(ITEM_TYPE_UPLOAD)
}
const val ITEM_TYPE_BACKGROUND = 1
const val ITEM_TYPE_UPLOAD = 2
var localUri: Uri? = null,
var isDefault: Boolean = false,
var isSelected: Boolean = false,
var isCustomBg: Boolean = false,
) : ChatBackgroundBase()

View File

@ -1,9 +0,0 @@
package com.remax.visualnovel.entity.response
import android.net.Uri
import com.remax.visualnovel.entity.model.base.BasePhoto
abstract class ChatBackgroundBase(
)

View File

@ -1,10 +0,0 @@
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()

View File

@ -10,8 +10,7 @@ import android.widget.LinearLayout
import androidx.core.graphics.toColorInt 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.ChatBackgroundBase
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,31 +290,29 @@ class ChatSettingView @JvmOverloads constructor(
fun initBackgroundSelectView() { fun initBackgroundSelectView() {
val items = listOf( val items = listOf(
ChatBackground( ChatBackgroundBase.ChatBackground(
imageId = 1, imageId = 1,
imageUrl = "https://vsn.s3.cn-north-1.amazonaws.com.cn/coverImage/fe8e3c7b-5b22-40f4-bacc-0183888c5149_test.png" imageUrl = "https://vsn.s3.cn-north-1.amazonaws.com.cn/coverImage/fe8e3c7b-5b22-40f4-bacc-0183888c5149_test.png"
), ),
ChatBackground( ChatBackgroundBase.ChatBackground(
imageId = 1,
imageUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png"
),
ChatBackground(
imageId = 1, imageId = 1,
imageUrl = "https://vsn.s3.cn-north-1.amazonaws.com.cn/coverImage/fe8e3c7b-5b22-40f4-bacc-0183888c5149_test.png" imageUrl = "https://vsn.s3.cn-north-1.amazonaws.com.cn/coverImage/fe8e3c7b-5b22-40f4-bacc-0183888c5149_test.png"
), ),
ChatBackground( ChatBackgroundBase.ChatBackground(
imageId = 1,
imageUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png"
),
ChatBackground(
imageId = 1, imageId = 1,
imageUrl = "https://vsn.s3.cn-north-1.amazonaws.com.cn/coverImage/fe8e3c7b-5b22-40f4-bacc-0183888c5149_test.png" imageUrl = "https://vsn.s3.cn-north-1.amazonaws.com.cn/coverImage/fe8e3c7b-5b22-40f4-bacc-0183888c5149_test.png"
), ),
ChatBackground( ChatBackgroundBase.ChatBackground(
imageId = 1, imageId = 1,
imageUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png" imageUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png"
), ),
ChatBackgroundUpload( ChatBackgroundBase.ChatBackground(
imageId = 1,
imageUrl = "https://vsn.s3.cn-north-1.amazonaws.com.cn/coverImage/fe8e3c7b-5b22-40f4-bacc-0183888c5149_test.png"
),
ChatBackgroundBase.ChatBackground(
imageId = 1,
imageUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png"
) )
) )

View File

@ -17,9 +17,7 @@ import com.drake.brv.utils.setup
import com.remax.visualnovel.R 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.ChatBackgroundBase 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.glide.load
import com.remax.visualnovel.extension.toast import com.remax.visualnovel.extension.toast
import com.remax.visualnovel.utils.imagepick.EpalPickerPresenter import com.remax.visualnovel.utils.imagepick.EpalPickerPresenter
@ -39,7 +37,7 @@ class ExpandBackgroundSubView @JvmOverloads constructor(
defStyleAttr: Int = 0 defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) { ) : LinearLayout(context, attrs, defStyleAttr) {
private lateinit var items: List<ChatBackgroundBase> private var items = mutableListOf<ChatBackgroundBase>()
private var mBinding: LayoutSettingBgSubViewBinding private var mBinding: LayoutSettingBgSubViewBinding
@ -57,41 +55,47 @@ class ExpandBackgroundSubView @JvmOverloads constructor(
setDivider(10, true) setDivider(10, true)
orientation = DividerOrientation.VERTICAL orientation = DividerOrientation.VERTICAL
}.setup { }.setup {
addType<ChatBackground>(R.layout.layout_item_setting_background) addType<ChatBackgroundBase.ChatBackground>(R.layout.layout_item_setting_background)
addType<ChatBackgroundUpload>(R.layout.layout_item_setting_background_upload) addType<ChatBackgroundBase.ChatBackgroundUpload>(R.layout.layout_item_setting_background_upload)
onClick(R.id.root) { onClick(R.id.root) {
when (val item = getModel<Any>(it)) { /*when (val item = getModel<Any>(it)) {
is ChatBackground -> { is ChatBackgroundBase.ChatBackground -> {
val chatBackground = getModel<ChatBackground>() val chatBackground = getModel<ChatBackgroundBase.ChatBackground>()
if (!chatBackground.isSelected) { if (!chatBackground.isSelected) {
itemsRv.bindingAdapter.models?.filterIsInstance<ChatBackground>()?.forEach { item -> itemsRv.bindingAdapter.models?.filterIsInstance<ChatBackgroundBase.ChatBackground>()?.forEach { item ->
item.isSelected = item == chatBackground item.isSelected = item == chatBackground
} }
itemsRv.bindingAdapter.notifyDataSetChanged() itemsRv.bindingAdapter.notifyDataSetChanged()
} }
} }
is ChatBackgroundUpload -> { is ChatBackgroundBase.ChatBackgroundUpload -> {
selectCustomBg() selectCustomBg()
} }
} }*/
/*when (itemViewType) { when (itemViewType) {
R.layout.layout_item_setting_background -> { R.layout.layout_item_setting_background -> {
val chatBackground = getModel<ChatBackgroundBase.ChatBackground>()
if (!chatBackground.isSelected) {
itemsRv.bindingAdapter.models?.filterIsInstance<ChatBackgroundBase.ChatBackground>()?.forEach { item ->
item.isSelected = item == chatBackground
}
itemsRv.bindingAdapter.notifyDataSetChanged()
}
} }
R.layout.layout_item_setting_background_upload -> { R.layout.layout_item_setting_background_upload -> {
selectCustomBg() selectCustomBg()
} }
}*/ }
} }
onBind { onBind {
when (itemViewType) { when (itemViewType) {
R.layout.layout_item_setting_background -> { R.layout.layout_item_setting_background -> {
val item = getModel<ChatBackground>() val item = getModel<ChatBackgroundBase.ChatBackground>()
with(getBinding<LayoutItemSettingBackgroundBinding>()) { with(getBinding<LayoutItemSettingBackgroundBinding>()) {
if (!item.imageUrl.isNullOrEmpty()) { if (!item.imageUrl.isNullOrEmpty()) {
ivBackgroundSrc.load(item.imageUrl) ivBackgroundSrc.load(item.imageUrl)
@ -99,13 +103,13 @@ class ExpandBackgroundSubView @JvmOverloads constructor(
ivBackgroundSrc.load(item.localUri!!) ivBackgroundSrc.load(item.localUri!!)
} }
ivDel.visibility = if (item.isCustomBg) VISIBLE else GONE ivDel.isVisible = item.isCustomBg
ivBackgroundSrc.isVisible = item.isSelected selectBg.isVisible = item.isSelected
} }
} }
R.layout.layout_item_setting_background_upload -> { R.layout.layout_item_setting_background_upload -> {
val item = getModel<ChatBackgroundUpload>() val item = getModel<ChatBackgroundBase.ChatBackgroundUpload>()
} }
} }
} }
@ -113,7 +117,9 @@ class ExpandBackgroundSubView @JvmOverloads constructor(
} }
fun setItems(newItems: List<ChatBackgroundBase>) { fun setItems(newItems: List<ChatBackgroundBase>) {
items = newItems items.clear()
items.addAll(newItems)
items.add(ChatBackgroundBase.ChatBackgroundUpload)
mBinding.itemsRv.models = items mBinding.itemsRv.models = items
} }
@ -141,15 +147,22 @@ class ExpandBackgroundSubView @JvmOverloads constructor(
}) })
} }
private fun appendCustomBg(items: ArrayList<ImageItem>?) { private fun appendCustomBg(uploadedItems: ArrayList<ImageItem>?) {
val customBgList = items?.map { imageItem -> val customBgList = uploadedItems?.map { imageItem ->
ChatBackground( ChatBackgroundBase.ChatBackground(
imageId = imageItem.id, imageId = imageItem.id,
imageUrl = imageItem.path, imageUrl = imageItem.path,
localUri = imageItem.uri localUri = imageItem.uri,
isCustomBg = true
) )
} }
mBinding.itemsRv.addModels(customBgList)
if (!customBgList.isNullOrEmpty()) {
items.add(if (items.isNotEmpty()) items.size - 1 else 0, customBgList!!.get(0))
mBinding.itemsRv.models = items
}
//items.add((items.size - 1).takeIf { items.isNotEmpty() } ?: 0, customBgList!!.first())
} }
private fun uploadImageAndRequest(items: ArrayList<ImageItem>?) { private fun uploadImageAndRequest(items: ArrayList<ImageItem>?) {

View File

@ -28,7 +28,7 @@ import kotlin.math.max
@Route(path = Routers.ROUTE_FRAG_ACTORLIST) @Route(path = Routers.ROUTE_FRAG_ACTORLIST)
class ActorListFragment : BaseBindingFragment<FragmentMainActorBinding>() { class ActorListFragment : BaseBindingFragment<FragmentMainActorBinding>() {
private lateinit var mActorAdapter: ActorsAdapter private lateinit var mRvAdapter: ActorsAdapter
private val mActorsModel by viewModels<ActorsViewModel>() private val mActorsModel by viewModels<ActorsViewModel>()
private var mLoadedPageIndex = 0 private var mLoadedPageIndex = 0
private val mRequestParam by lazy { ParamActorList() } private val mRequestParam by lazy { ParamActorList() }
@ -67,11 +67,10 @@ class ActorListFragment : BaseBindingFragment<FragmentMainActorBinding>() {
mActorsRv.setHasFixedSize(true) mActorsRv.setHasFixedSize(true)
mActorsRv.itemAnimator = DefaultItemAnimator() mActorsRv.itemAnimator = DefaultItemAnimator()
mActorAdapter = ActorsAdapter() mRvAdapter = ActorsAdapter()
mActorsRv.adapter = mActorAdapter mActorsRv.adapter = mRvAdapter
val characterList = createSampleData()
with(mActorAdapter) { with(mRvAdapter) {
setList(characterList)
loadMoreModule.setOnLoadMoreListener { loadMoreModule.setOnLoadMoreListener {
getActorList(false, showLoading = false) getActorList(false, showLoading = false)
} }
@ -116,20 +115,20 @@ class ActorListFragment : BaseBindingFragment<FragmentMainActorBinding>() {
mActorsModel.getActorList(mRequestParam) mActorsModel.getActorList(mRequestParam)
}, showLoading = showLoading) { }, showLoading = showLoading) {
onSuccess = { onSuccess = {
val data = it ?: emptyList() var datas = it ?: emptyList()
with(mActorAdapter) { with(mRvAdapter) {
if (isRefresh) { if (isRefresh) {
setList(data) setList(datas)
setMyEmptyView(R.string.no_character_yet, topMargin = 60) setMyEmptyView(R.string.no_character_yet, topMargin = 60)
} else { } else {
addData(data) addData(datas)
loadMoreModule.loadMoreComplete() loadMoreModule.loadMoreComplete()
} }
if (data.size < mRequestParam.limit) { if (datas.size < mRequestParam.limit) {
loadMoreModule.loadMoreEnd() loadMoreModule.loadMoreEnd()
} }
} }
if (data.isNotEmpty()) { if (datas.isNotEmpty()) {
mLoadedPageIndex++ mLoadedPageIndex++
} }
} }
@ -139,6 +138,13 @@ class ActorListFragment : BaseBindingFragment<FragmentMainActorBinding>() {
binding.refreshLayout.finishRefresh() binding.refreshLayout.finishRefresh()
} }
} }
onFailed = { code, msg ->
// TODO - remove temp datas
with(mRvAdapter) {
setList(createSampleData())
}
}
} }
} }
@ -160,7 +166,14 @@ class ActorListFragment : BaseBindingFragment<FragmentMainActorBinding>() {
private fun createSampleData(): List<ActorBean> { private fun createSampleData(): List<ActorBean> {
return listOf() return listOf(
ActorBean(characterName = "testName-1", description = "Des-xxxxxxxxxxxxx"),
ActorBean(characterName = "testName-1", description = "Des-xxxxxxxxxxxxx"),
ActorBean(characterName = "testName-1", description = "Des-xxxxxxxxxxxxx"),
ActorBean(characterName = "testName-1", description = "Des-xxxxxxxxxxxxx"),
ActorBean(characterName = "testName-1", description = "Des-xxxxxxxxxxxxx"),
ActorBean(characterName = "testName-1", description = "Des-xxxxxxxxxxxxx"),
)
} }

View File

@ -24,7 +24,7 @@ import com.remax.visualnovel.entity.imbean.raw.CustomAlbumData
import com.remax.visualnovel.entity.model.MyImgData import com.remax.visualnovel.entity.model.MyImgData
import com.remax.visualnovel.entity.response.Album import com.remax.visualnovel.entity.response.Album
import com.remax.visualnovel.entity.response.AppearanceImage import com.remax.visualnovel.entity.response.AppearanceImage
import com.remax.visualnovel.entity.response.ChatBackground import com.remax.visualnovel.entity.response.ChatBackgroundBase
import com.remax.visualnovel.extension.setOnClick import com.remax.visualnovel.extension.setOnClick
import com.remax.visualnovel.widget.dialoglib.ScreenUtils import com.remax.visualnovel.widget.dialoglib.ScreenUtils
import com.remax.visualnovel.widget.imageviewer.core.ImageLoader import com.remax.visualnovel.widget.imageviewer.core.ImageLoader
@ -50,7 +50,7 @@ class MyImageLoader : ImageLoader {
data.imageUrl data.imageUrl
} }
is ChatBackground -> { is ChatBackgroundBase.ChatBackground -> {
data.imageUrl data.imageUrl
} }

View File

@ -9,28 +9,36 @@
<com.remax.visualnovel.widget.roundedimageview.RoundedImageView <com.remax.visualnovel.widget.roundedimageview.RoundedImageView
android:id="@+id/iv_background_src" android:id="@+id/iv_background_src"
android:layout_width="0dp" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:src="@mipmap/img_1" android:src="@mipmap/img_1"
android:scaleType="centerCrop" android:scaleType="centerCrop"
app:layout_constraintDimensionRatio="h,87:116"
app:riv_corner_radius="@dimen/dp_10" app:riv_corner_radius="@dimen/dp_10"
app:layout_constraintBottom_toBottomOf="@+id/selectBg" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/selectBg" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/selectBg" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/selectBg" /> app:layout_constraintTop_toTopOf="parent" />
<com.remax.visualnovel.widget.uitoken.view.UITokenFrameLayout <com.remax.visualnovel.widget.uitoken.view.UITokenFrameLayout
android:id="@+id/selectBg" android:id="@+id/selectBg"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
app:backgroundColorToken="@string/color_surface_element_normal"
app:layout_constraintDimensionRatio="h,87:116" app:layout_constraintDimensionRatio="h,87:116"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:radiusToken="@string/radius_l" app:radiusToken="@string/radius_l"
app:advStrokeWidth="@dimen/dp_5" app:advStrokeWidth="@dimen/dp_5"
app:advStrokeColor="@color/blue_6f" app:advStrokeColor="@color/blue_6f"
app:advRadius="@dimen/dp_10" app:advBgColor="@color/transparent"
/> app:advRadius="@dimen/dp_10">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/setting_bg_selected_indi"
android:layout_gravity="right|bottom"
/>
</com.remax.visualnovel.widget.uitoken.view.UITokenFrameLayout>
<com.remax.visualnovel.widget.uitoken.view.UITokenImageView <com.remax.visualnovel.widget.uitoken.view.UITokenImageView
android:id="@+id/iv_del" android:id="@+id/iv_del"
@ -46,14 +54,7 @@
/> />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_selected_indi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/setting_bg_selected_indi"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>