自定义背景上传初步

This commit is contained in:
renhaoting 2025-11-07 11:46:22 +08:00
parent 3c9cdb3854
commit a6ccbfa2ba
10 changed files with 149 additions and 29 deletions

View File

@ -7,7 +7,6 @@ import com.remax.visualnovel.entity.request.AIIsShowDTO
import com.remax.visualnovel.entity.request.ChatAlbum import com.remax.visualnovel.entity.request.ChatAlbum
import com.remax.visualnovel.entity.request.ChatSetting import com.remax.visualnovel.entity.request.ChatSetting
import com.remax.visualnovel.entity.request.HeartbeatBuy import com.remax.visualnovel.entity.request.HeartbeatBuy
import com.remax.visualnovel.entity.request.ParamBgUpload
import com.remax.visualnovel.entity.request.ParamLanguage import com.remax.visualnovel.entity.request.ParamLanguage
import com.remax.visualnovel.entity.request.ParamSoundList import com.remax.visualnovel.entity.request.ParamSoundList
import com.remax.visualnovel.entity.request.ParamUserid import com.remax.visualnovel.entity.request.ParamUserid
@ -19,12 +18,12 @@ 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.ChatAiModule import com.remax.visualnovel.entity.response.ChatAiModule
import com.remax.visualnovel.entity.response.ChatBackgroundBase import com.remax.visualnovel.entity.response.ChatBackgroundBase
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
import com.remax.visualnovel.entity.response.Friends import com.remax.visualnovel.entity.response.Friends
import com.remax.visualnovel.entity.response.HeartbeatLevelOutput import com.remax.visualnovel.entity.response.HeartbeatLevelOutput
import com.remax.visualnovel.entity.response.Pageable import com.remax.visualnovel.entity.response.Pageable
import com.remax.visualnovel.entity.response.RespBgUpload
import com.remax.visualnovel.entity.response.Token import com.remax.visualnovel.entity.response.Token
import com.remax.visualnovel.entity.response.VoiceASR import com.remax.visualnovel.entity.response.VoiceASR
import com.remax.visualnovel.entity.response.base.Response import com.remax.visualnovel.entity.response.base.Response
@ -32,11 +31,11 @@ import com.remax.visualnovel.entity.response.basenew.ResponseNew
import okhttp3.MultipartBody import okhttp3.MultipartBody
import okhttp3.RequestBody import okhttp3.RequestBody
import retrofit2.http.Body import retrofit2.http.Body
import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded
import retrofit2.http.Multipart import retrofit2.http.Multipart
import retrofit2.http.POST import retrofit2.http.POST
import retrofit2.http.Part import retrofit2.http.Part
import retrofit2.http.PartMap
interface ChatService { interface ChatService {
@ -180,22 +179,17 @@ interface ChatService {
@POST(BuildConfig.API_BASE + "/model/config/list") @POST(BuildConfig.API_BASE + "/model/config/list")
suspend fun requestAiModelList(@Body language: ParamLanguage): ResponseNew<List<ChatAiModule>> suspend fun requestAiModelList(@Body language: ParamLanguage): ResponseNew<List<ChatAiModule>>
@POST(BuildConfig.API_BASE + "/file/bgImage/upload")
suspend fun uploadCustomBgPic(@Body param: ParamBgUpload): ResponseNew<Any>
/*@Multipart
@POST(BuildConfig.API_BASE + "/file/bgImage/upload")
suspend fun uploadCustomBgPic(@Part("userId") title: RequestBody,
@Part file: MultipartBody.Part): ResponseNew<Any>*/
@POST(BuildConfig.API_BASE + "/file/bgImage/list") @POST(BuildConfig.API_BASE + "/file/bgImage/list")
suspend fun requestChatBgList(@Body userId: ParamUserid): ResponseNew<List<ChatBackgroundBase.ChatBackground>> suspend fun requestChatBgList(@Body userId: ParamUserid): ResponseNew<List<ChatBackgroundBase.ChatBackground>>
/*@FormUrlEncoded
@POST(BuildConfig.API_BASE + "/file/bgImage/list")
suspend fun requestChatBgList(@Field("userId") userId: Int): ResponseNew<List<ChatBackgroundBase.ChatBackground>>*/ @Multipart
@POST(BuildConfig.API_BASE + "/file/bgImage/upload")
fun uploadCustomBgPic(
@PartMap params: Map<String, RequestBody>,
@Part file: MultipartBody.Part
): ResponseNew<RespBgUpload>

View File

@ -3,5 +3,4 @@ package com.remax.visualnovel.entity.request
data class ParamBgUpload( data class ParamBgUpload(
var userId: String, var userId: String,
var file: String,
) )

View File

@ -0,0 +1,5 @@
package com.remax.visualnovel.entity.response
data class RespBgUpload (
val url: String,
)

View File

@ -1,5 +1,7 @@
package com.remax.visualnovel.repository.api package com.remax.visualnovel.repository.api
import android.net.Uri
import androidx.core.net.toFile
import com.remax.visualnovel.api.service.ChatService import com.remax.visualnovel.api.service.ChatService
import com.remax.visualnovel.entity.request.ChatSetting import com.remax.visualnovel.entity.request.ChatSetting
import com.remax.visualnovel.entity.request.ParamBgUpload import com.remax.visualnovel.entity.request.ParamBgUpload
@ -9,6 +11,10 @@ import com.remax.visualnovel.entity.request.ParamUserid
import com.remax.visualnovel.entity.request.SimpleDataDTO import com.remax.visualnovel.entity.request.SimpleDataDTO
import com.remax.visualnovel.repository.api.base.BaseRepositoryNew import com.remax.visualnovel.repository.api.base.BaseRepositoryNew
import com.remax.visualnovel.ui.wallet.manager.WalletManager import com.remax.visualnovel.ui.wallet.manager.WalletManager
import com.remax.visualnovel.utils.FileUtil
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import javax.inject.Inject import javax.inject.Inject
@ -31,6 +37,8 @@ class ChatRepository @Inject constructor(private val chatService: ChatService) :
// ------------------------ new --------------------------------- // ------------------------ new ---------------------------------
suspend fun getSoundList(param: ParamSoundList) = executeHttp { suspend fun getSoundList(param: ParamSoundList) = executeHttp {
chatService.requestSoundList(param) chatService.requestSoundList(param)
} }
@ -39,14 +47,23 @@ class ChatRepository @Inject constructor(private val chatService: ChatService) :
chatService.requestAiModelList(language) chatService.requestAiModelList(language)
} }
suspend fun getChatBgList(userId: Int) = executeHttp { suspend fun getChatBgList(userId: ParamUserid) = executeHttp {
chatService.requestChatBgList(userId) chatService.requestChatBgList(userId)
} }
suspend fun uploadCustomBgPic(param: ParamBgUpload) = executeHttp {
chatService.uploadCustomBgPic(param) suspend fun uploadCustomBgPic(
fileUri: Uri,
param: ParamBgUpload
) = executeHttp {
/*val file = fileUri.toFile()?:
return ApiFailedResponse(1, message = "File not exist")*/
val params = mutableMapOf<String, RequestBody>()
params["userId"] = param.userId.toRequestBody(("text/plain").toMediaType())
val filePart = FileUtil.createFilePart("file", fileUri.toFile())
chatService.uploadCustomBgPic(params, filePart)
} }
} }

View File

@ -2,6 +2,7 @@ package com.remax.visualnovel.ui.chat
import android.graphics.Point import android.graphics.Point
import android.net.Uri
import android.view.View.GONE import android.view.View.GONE
import android.view.View.VISIBLE import android.view.View.VISIBLE
import androidx.activity.viewModels import androidx.activity.viewModels
@ -97,7 +98,7 @@ class ChatActivity : BaseBindingActivity<ActivityActorChatBinding>() {
private fun loadChantBgDatas() { private fun loadChantBgDatas() {
launchAndCollect2({ launchAndCollect2({
mViewModel.loadChatBgList(1) mViewModel.loadChatBgList(ParamUserid(1))
}) { }) {
onSuccess = { onSuccess = {
val dataList = it?: emptyList() val dataList = it?: emptyList()
@ -129,6 +130,20 @@ class ChatActivity : BaseBindingActivity<ActivityActorChatBinding>() {
} }
} }
private fun uploadCustomBg(file: Uri) {
launchAndCollect2({
mViewModel.uploadCustomBgPic(1, file)
}) {
onSuccess = {
val dataList = it
}
onComplete = {
}
}
}
private val loginObserver = Observer<OnLoginEvent?> { private val loginObserver = Observer<OnLoginEvent?> {
launchWithRequest({ launchWithRequest({
//TODO - business handling for login events //TODO - business handling for login events
@ -174,6 +189,10 @@ class ChatActivity : BaseBindingActivity<ActivityActorChatBinding>() {
override fun onSoundFiltersChanged(sexValue: Int) { override fun onSoundFiltersChanged(sexValue: Int) {
loadSoundDatas(sexValue) loadSoundDatas(sexValue)
} }
override fun onUploadCustomBg(file: Uri) {
uploadCustomBg(file)
}
}) })
} }
} }

View File

@ -1,6 +1,7 @@
package com.remax.visualnovel.ui.chat package com.remax.visualnovel.ui.chat
import android.net.Uri
import com.remax.visualnovel.app.viewmodel.base.OssViewModel import com.remax.visualnovel.app.viewmodel.base.OssViewModel
import com.remax.visualnovel.entity.imbean.raw.CustomRawData import com.remax.visualnovel.entity.imbean.raw.CustomRawData
import com.remax.visualnovel.entity.request.ChatSetting import com.remax.visualnovel.entity.request.ChatSetting
@ -89,8 +90,9 @@ class ChatViewModel @Inject constructor(
//------------------------ new ------------------------ //------------------------ new ------------------------
suspend fun loadSoundList(param: ParamSoundList) = chatRepository.getSoundList(param) suspend fun loadSoundList(param: ParamSoundList) = chatRepository.getSoundList(param)
suspend fun loadAiModelList(language: ParamLanguage) = chatRepository.getAiModelList(language) suspend fun loadAiModelList(language: ParamLanguage) = chatRepository.getAiModelList(language)
suspend fun loadChatBgList(userId: Int) = chatRepository.getChatBgList(userId) suspend fun loadChatBgList(userId: ParamUserid) = chatRepository.getChatBgList(userId)
suspend fun uploadCustomBgPic(param: ParamBgUpload) = chatRepository.uploadCustomBgPic(param) suspend fun uploadCustomBgPic(userId: Int, file: Uri) = chatRepository.uploadCustomBgPic(file, ParamBgUpload(userId.toString()))

View File

@ -3,6 +3,7 @@ package com.remax.visualnovel.ui.chat.setting.customui
import android.content.Context import android.content.Context
import android.graphics.Color import android.graphics.Color
import android.net.Uri
import android.util.AttributeSet import android.util.AttributeSet
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -18,6 +19,7 @@ import com.remax.visualnovel.entity.response.ChatMode
import com.remax.visualnovel.entity.response.ChatSound import com.remax.visualnovel.entity.response.ChatSound
import com.remax.visualnovel.extension.showConfirmDialog import com.remax.visualnovel.extension.showConfirmDialog
import com.remax.visualnovel.ui.chat.setting.customui.expandableSelector.ExpandAiModelSelectView import com.remax.visualnovel.ui.chat.setting.customui.expandableSelector.ExpandAiModelSelectView
import com.remax.visualnovel.ui.chat.setting.customui.expandableSelector.ExpandBackgroundSubView
import com.remax.visualnovel.ui.chat.setting.customui.expandableSelector.ExpandBubbleSelectView import com.remax.visualnovel.ui.chat.setting.customui.expandableSelector.ExpandBubbleSelectView
import com.remax.visualnovel.ui.chat.setting.customui.expandableSelector.ExpandChatModeSelectView import com.remax.visualnovel.ui.chat.setting.customui.expandableSelector.ExpandChatModeSelectView
import com.remax.visualnovel.ui.chat.setting.customui.expandableSelector.ExpandSoundSelectView import com.remax.visualnovel.ui.chat.setting.customui.expandableSelector.ExpandSoundSelectView
@ -34,6 +36,7 @@ class ChatSettingView @JvmOverloads constructor(
private lateinit var mEventListener: IEventListener private lateinit var mEventListener: IEventListener
interface IEventListener { interface IEventListener {
fun onSoundFiltersChanged(sexValue: Int) fun onSoundFiltersChanged(sexValue: Int)
fun onUploadCustomBg(file: Uri)
} }
fun setEventListener(listener: IEventListener) { fun setEventListener(listener: IEventListener) {
mEventListener = listener mEventListener = listener
@ -320,6 +323,11 @@ class ChatSettingView @JvmOverloads constructor(
) )
mBinding.backgroundSelectorView.setItems(items) mBinding.backgroundSelectorView.setItems(items)
mBinding.backgroundSelectorView.setOnEventListener(object: ExpandBackgroundSubView.IEventListener {
override fun onUploadCustomBg(file: Uri) {
mEventListener.onUploadCustomBg(file)
}
})
} }

View File

@ -2,6 +2,7 @@ package com.remax.visualnovel.ui.chat.setting.customui.expandableSelector
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.net.Uri
import android.util.AttributeSet import android.util.AttributeSet
import android.view.LayoutInflater import android.view.LayoutInflater
import android.widget.LinearLayout import android.widget.LinearLayout
@ -17,6 +18,7 @@ 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.ChatBackgroundBase import com.remax.visualnovel.entity.response.ChatBackgroundBase
import com.remax.visualnovel.entity.response.ChatBubble
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,6 +41,15 @@ class ExpandBackgroundSubView @JvmOverloads constructor(
private var items = mutableListOf<ChatBackgroundBase>() private var items = mutableListOf<ChatBackgroundBase>()
private var mBinding: LayoutSettingBgSubViewBinding private var mBinding: LayoutSettingBgSubViewBinding
private var mEventListener: IEventListener? = null
interface IEventListener {
fun onUploadCustomBg(file: Uri)
}
fun setOnEventListener(listener: IEventListener) {
this.mEventListener = listener
}
init { init {
mBinding = LayoutSettingBgSubViewBinding.inflate(LayoutInflater.from(context), this, true) mBinding = LayoutSettingBgSubViewBinding.inflate(LayoutInflater.from(context), this, true)
@ -132,7 +143,7 @@ class ExpandBackgroundSubView @JvmOverloads constructor(
activity?.toast(error?.message) activity?.toast(error?.message)
} }
override fun onImagePickComplete(items: ArrayList<ImageItem>?) { override fun onImagePickComplete(items: ArrayList<ImageItem>) {
appendCustomBg(items) appendCustomBg(items)
uploadImageAndRequest(items) uploadImageAndRequest(items)
} }
@ -160,7 +171,9 @@ class ExpandBackgroundSubView @JvmOverloads constructor(
} }
private fun uploadImageAndRequest(items: ArrayList<ImageItem>?) { private fun uploadImageAndRequest(items: ArrayList<ImageItem>?) {
// TODO if (items != null && items.isNotEmpty()) {
mEventListener?.onUploadCustomBg(items.get(0)!!.uri)
}
} }

View File

@ -25,7 +25,6 @@ class ExpandBubbleSelectView @JvmOverloads constructor(
private var isExpanded = false private var isExpanded = false
private var animationDuration = 300 private var animationDuration = 300
private var mEventListener: IEventListener? = null private var mEventListener: IEventListener? = null
interface IEventListener { interface IEventListener {
fun onItemSelected(position: Int, item: ChatBubble) fun onItemSelected(position: Int, item: ChatBubble)
fun onExpanded(isExpanded: Boolean) fun onExpanded(isExpanded: Boolean)

View File

@ -0,0 +1,64 @@
package com.remax.visualnovel.utils
import android.net.Uri
import com.remax.visualnovel.configs.NovelApplication
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.asRequestBody
import java.io.File
object FileUtil {
private val appContext = NovelApplication.appContext()
private fun getFileFromUri(uri: Uri): File? {
return try {
when (uri.scheme) {
"file" -> File(uri.path!!)
"content" -> {
val inputStream = appContext.contentResolver.openInputStream(uri)
val file = File.createTempFile("upload_", null, appContext.cacheDir)
inputStream?.use { input ->
file.outputStream().use { output ->
input.copyTo(output)
}
}
file
}
else -> null
}
} catch (e: Exception) {
null
}
}
fun createFilePart(partName: String, file: File): MultipartBody.Part {
val mediaType = getMimeType(file)
return MultipartBody.Part.createFormData(
partName,
file.name,
file.asRequestBody(mediaType.toMediaType())
)
}
private fun getMimeType(file: File): String {
return when (file.extension.lowercase()) {
"jpg", "jpeg" -> "image/jpeg"
"png" -> "image/png"
"pdf" -> "application/pdf"
"mp4" -> "video/mp4"
else -> "application/octet-stream"
}
}
//==================== 扩展函数 ====================
val Uri.toFile: File?
get() = FileUtil.getFileFromUri(this)
}