技能卡声音秀完成文件上传

This commit is contained in:
yitao_hello
2022-02-13 23:47:22 +08:00
parent 910a02bc39
commit 6ea53ea819
14 changed files with 465 additions and 121 deletions

View File

@@ -0,0 +1,96 @@
package com.yizhuan.erban.skill
import com.yizhuan.erban.skill.widget.ItemAttribute
import com.yizhuan.erban.skill.widget.SkillAttribute
import com.yizhuan.erban.skill.widget.SkillItem
import com.yizhuan.xchat_android_core.skill.entity.*
object SKillDataParser {
private fun parseItemRecordToAttribute(
cardId: Int,
isSelf: Boolean,
isEdit: Boolean,
itemEventCallBack: ((itemAttr: SkillItem) -> Unit)?,
item: PropRecordVoEntity
): ItemAttribute {
return ItemAttribute(
cardId,
isSelf, isEdit,
item.state, item.isMust,
item.parentId, item.parentVal,
item.refPropVos.toMutableList()
).apply { this.itemEventCallback = itemEventCallBack }
}
fun parseSkillRecordToAttribute(
item: SkillRecordEntity,
itemEventCallBack: ((itemAttr: SkillItem) -> Unit)? = null
): SkillAttribute {
val list: MutableList<ItemAttribute> = ArrayList()
item.propRecordVo.forEach {
val element = parseItemRecordToAttribute(
item.cardId,
item.isSelf,
item.isEdit,
itemEventCallBack,
it
)
list.add(element)
}
return SkillAttribute(
item.id, item.cardId,
item.icon, item.name,
item.isSelf, item.isEdit,
item.pic, list
)
}
fun parseSkillPropertyToAttribute(
item: SkillPropertyEntity,
itemEventCallBack: ((itemAttr: SkillItem) -> Unit)? = null
): SkillAttribute {
val list: MutableList<ItemAttribute> = ArrayList()
item.props.forEach {
val element = parseItemRecordToAttribute(
item.cardId,
item.isSelf,
item.isEdit,
itemEventCallBack,
it.parsePropToRecord()
)
list.add(element)
}
return SkillAttribute(
-1, item.cardId,
item.icon, item.name,
item.isSelf, item.isEdit,
item.pic, list
)
}
/**
* 转换成服务器数据
*/
fun parseSkillSelectedValue(
recordId: Int,
cardId: Int,
itemList: List<SkillItem>
): SkillPostServerEntity {
return if (itemList.isEmpty()) {
SkillPostServerEntity(propRecordVo = ArrayList(0))
} else {
val list = ArrayList<SKillValueEntity>()
itemList.forEach {
val item = it.getContentEntity()
list.add(
SKillValueEntity(
item.parentId,
it.getContentEntity().selectedProperties
)
)
}
SkillPostServerEntity(recordId, cardId, list)
}
}
}

View File

@@ -1,5 +1,6 @@
package com.yizhuan.erban.skill.activity
import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
@@ -12,6 +13,7 @@ import com.yizhuan.xchat_android_core.skill.entity.SkillPropertyEntity
import com.yizhuan.erban.skill.repository.SkillDataManager
import com.yizhuan.erban.skill.repository.SkillModel
import com.yizhuan.xchat_android_library.annatation.ActLayoutRes
import io.reactivex.functions.Consumer
@ActLayoutRes(R.layout.activity_skill_edit)
class AddSkillActivity : BaseBindingActivity<ActivitySkillEditBinding>() {
@@ -37,7 +39,10 @@ class AddSkillActivity : BaseBindingActivity<ActivitySkillEditBinding>() {
.compose(bindToLifecycle())
.subscribe({
SkillDataManager.get().setSkillPropertyEntity(cardId, it)
setSkillViewData(it)
when (it.type) {
3, 4 -> checkPermissionAndDeal(it)
else -> setSkillViewData(it)
}
}, { th ->
th.printStackTrace()
toast(th.message)
@@ -51,6 +56,22 @@ class AddSkillActivity : BaseBindingActivity<ActivitySkillEditBinding>() {
delegate.setSkillViewData(it)
}
@SuppressLint("CheckResult")
private fun checkPermissionAndDeal(it: SkillPropertyEntity) {
checkPermission(
Manifest.permission.RECORD_AUDIO,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
.subscribe { aBoolean: Boolean ->
if (aBoolean) {
setSkillViewData(it)
} else {
toast("请给予应用必要权限,让程序可正常工作。")
finish()
}
}
}
override fun onLeftClickListener() {
delegate.onLeftClick()
@@ -65,9 +86,9 @@ class AddSkillActivity : BaseBindingActivity<ActivitySkillEditBinding>() {
companion object {
private const val ITEM = "item"
fun start(context: Context, type: Int) {
fun start(context: Context, cardId: Int) {
val intent = Intent(context, AddSkillActivity::class.java)
intent.putExtra(ITEM, type)
intent.putExtra(ITEM, cardId)
context.startActivity(intent)
}
}

View File

@@ -48,7 +48,7 @@ class EditSkillActivity : BaseBindingActivity<ActivitySkillEditBinding>() {
deleteTipDialog?.setTipMsg(resources.getString(R.string.tip_delete_skill))
deleteTipDialog?.setOnActionListener(object : CommonTipDialog.OnActionListener {
override fun onOk() {
deleteSkill(mBinding.skillView.getSavedValues().id)
deleteSkill(mBinding.skillView.getAttributes().id)
deleteTipDialog?.dismiss()
}

View File

@@ -4,17 +4,20 @@ import android.annotation.SuppressLint
import com.yizhuan.erban.R
import com.yizhuan.erban.base.BaseBindingActivity
import com.yizhuan.erban.databinding.ActivitySkillEditBinding
import com.yizhuan.erban.skill.SKillDataParser
import com.yizhuan.erban.skill.dialog.SkillSelectionDialog
import com.yizhuan.xchat_android_core.skill.entity.PropsEntity
import com.yizhuan.xchat_android_core.skill.entity.SkillPropertyEntity
import com.yizhuan.xchat_android_core.skill.entity.SkillRecordEntity
import com.yizhuan.xchat_android_core.skill.event.SkillEvent
import com.yizhuan.erban.skill.repository.SkillDataManager
import com.yizhuan.erban.skill.repository.SkillModel
import com.yizhuan.erban.skill.widget.SkillAttribute
import com.yizhuan.erban.skill.widget.SkillItem
import com.yizhuan.erban.skill.widget.TimerRecorderView
import com.yizhuan.erban.ui.widget.dialog.CommonTipDialog
import com.yizhuan.xchat_android_core.file.FileModel
import com.yizhuan.xchat_android_core.skill.entity.*
import com.yizhuan.xchat_android_library.utils.SingleToastUtil
import org.greenrobot.eventbus.EventBus
import java.io.File
/**
* 编辑-添加 界面
@@ -67,7 +70,7 @@ class SkillEditableDelegate(
activity.toast("请填写或选择带*条目的内容")
return
}
val item = binding.skillView.getSavedValues()
val item = parseSelectedValues()
SkillModel.instance.saveSkillInfo(item).compose(activity.bindToLifecycle())
.doOnSubscribe { activity.dialogManager.showProgressDialog(activity) }
.subscribe(
@@ -91,7 +94,7 @@ class SkillEditableDelegate(
*/
internal fun setSkillViewData(entity: SkillRecordEntity) {
val onItemCall = if (entity.isEdit && entity.isSelf) this::onItemCall else null
val attr = SkillAttribute.parseRecordToAttribute(entity, onItemCall)
val attr = SKillDataParser.parseSkillRecordToAttribute(entity, onItemCall)
activity.mBinding.skillView.initView(attr)
}
@@ -100,12 +103,14 @@ class SkillEditableDelegate(
*/
internal fun setSkillViewData(entity: SkillPropertyEntity) {
val onItemCall = if (entity.isEdit && entity.isSelf) this::onItemCall else null
val attr = SkillAttribute.parsePropertyToAttribute(entity, onItemCall)
val attr = SKillDataParser.parseSkillPropertyToAttribute(entity, onItemCall)
activity.mBinding.skillView.initView(attr)
}
private fun setSelectionData(item: SkillItem, propertyEntity: SkillPropertyEntity?) {
/**
* 显示选择对话框
*/
private fun showSelectionDialog(item: SkillItem, propertyEntity: SkillPropertyEntity?) {
val props = propertyEntity?.props
val propDictVos = props?.find {
it.id == item.getContentEntity().parentId
@@ -113,6 +118,15 @@ class SkillEditableDelegate(
showSelectionValueDialog(item, propDictVos)
}
/**
* 获取SkillView数据转换成提交服务器数据
*/
private fun parseSelectedValues(): SkillPostServerEntity {
val itemList = activity.mBinding.skillView.getItems()
val skillAttr = activity.mBinding.skillView.getAttributes()
return SKillDataParser.parseSkillSelectedValue(skillAttr.id, skillAttr.cardId, itemList)
}
@SuppressLint("CheckResult")
private fun onItemCall(item: SkillItem) {
val propertyEntity =
@@ -124,16 +138,16 @@ class SkillEditableDelegate(
.subscribe({
SkillDataManager.get()
.setSkillPropertyEntity(item.getContentEntity().cardId, it)
setSelectionData(item, it)
showSelectionDialog(item, it)
activity.dialogManager.dismissDialog()
}, { th ->
th.printStackTrace()
activity.toast(th.message)
setSelectionData(item, null)
showSelectionDialog(item, null)
activity.dialogManager.dismissDialog()
})
} else {
setSelectionData(item, propertyEntity)
showSelectionDialog(item, propertyEntity)
}
}

View File

@@ -3,8 +3,7 @@ package com.yizhuan.erban.skill.adapter
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.BaseViewHolder
import com.yizhuan.erban.R
import com.yizhuan.erban.skill.widget.ItemAttribute
import com.yizhuan.erban.skill.widget.SkillAttribute
import com.yizhuan.erban.skill.SKillDataParser
import com.yizhuan.xchat_android_core.skill.entity.SkillRecordEntity
import com.yizhuan.erban.skill.widget.SkillCardView
@@ -17,6 +16,6 @@ class MineSkillCardAdapter(private val isSelf: Boolean) :
val itemView = helper.itemView as SkillCardView
item.isSelf = isSelf
item.isEdit = false
itemView.initView(SkillAttribute.parseRecordToAttribute(item))
itemView.initView(SKillDataParser.parseSkillRecordToAttribute(item))
}
}

View File

@@ -1,6 +1,5 @@
package com.yizhuan.erban.skill.widget
import com.yizhuan.xchat_android_core.skill.entity.PropRecordVoEntity
import com.yizhuan.xchat_android_core.skill.entity.PropRefEntity
data class ItemAttribute(
@@ -11,27 +10,10 @@ data class ItemAttribute(
val isMust: Int = 0,
val parentId: Int,
val parentVol: String,
val itemEventCallback: ((item: SkillItem) -> Unit)? = null,
var selectedProperties: MutableList<PropRefEntity>
) {
companion object {
fun parseRecordToAttribute(
cardId: Int,
isSelf: Boolean,
isEdit: Boolean,
itemEventCallBack: ((itemAttr: SkillItem) -> Unit)?,
item: PropRecordVoEntity
): ItemAttribute {
return ItemAttribute(
cardId,
isSelf, isEdit,
item.state, item.isMust,
item.parentId, item.parentVal,
itemEventCallBack,
item.refPropVos.toMutableList()
)
}
}
var recordId: Int = -1
var itemEventCallback: ((item: SkillItem) -> Unit)? = null
}

View File

@@ -0,0 +1,19 @@
package com.yizhuan.erban.skill.widget
import android.content.Context
import android.view.View
import android.view.ViewGroup
class RecordDurationItem(private val attr: ItemAttribute) : SkillItem {
override fun createItem(context: Context): View {
val view = View(context)
view.layoutParams = ViewGroup.LayoutParams(0, 0)
return view
}
override fun invalidate() {}
override fun isValid()=true
override fun getContentEntity()=attr
}

View File

@@ -0,0 +1,145 @@
package com.yizhuan.erban.skill.widget
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import com.yizhuan.erban.common.widget.dialog.DialogManager
import com.yizhuan.erban.databinding.LayoutSkillAudioBinding
import com.yizhuan.erban.skill.SKillDataParser
import com.yizhuan.erban.skill.repository.SkillModel
import com.yizhuan.xchat_android_core.file.FileModel
import com.yizhuan.xchat_android_core.skill.entity.PropRefEntity
import com.yizhuan.xchat_android_core.utils.toast
import io.reactivex.SingleObserver
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import java.io.File
private const val MAX_RECORD_DURATION = 15//最大录音时长
private const val RECORD_STATE_READY = 1//初态 即将录制
private const val RECORD_STATE_COMPLETE = 2//录制完成
private const val RECORD_STATE_JUDGE = 3//上传成功 正在审核
private const val RECORD_STATE_REFUSE = 5//上传成功 审核不通过
private const val RECORD_STATE_AGREE = 6//上传成功 审核通过
private const val RECORD_STATE_LOSS = 7//上传失败 重新录制
class RecordIResourceItem(private val itemAttribute: ItemAttribute) : SkillItem, LifecycleEventObserver,
TimerRecorderView.RecordListener {
private lateinit var binding: LayoutSkillAudioBinding
private lateinit var context: Context
private val compositeDisposable: CompositeDisposable by lazy {
CompositeDisposable()
}
override fun createItem(context: Context): View {
this.context = context
val inflater = LayoutInflater.from(context)
binding = LayoutSkillAudioBinding.inflate(inflater)
initItem()
return binding.root
}
private fun initItem() {
binding.recordView.recordListener = this
binding.recordView.recordDuration = MAX_RECORD_DURATION
binding.btnCancel.setOnClickListener {
}
}
override fun invalidate() {}
override fun isValid() = true
override fun getContentEntity() = itemAttribute
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
if (event.ordinal == Lifecycle.Event.ON_DESTROY.ordinal) {
if (!compositeDisposable.isDisposed) compositeDisposable.dispose()
}
}
override fun onRecordTimeUpdate(remain: Int) {
}
override fun onRecordCancel() {
}
override fun onRecordSuccess(file: File?) {
uploadAudio(file)
}
override fun onRecordFail() {
"录制失败,请重试".toast()
setItemByState(RECORD_STATE_READY)
}
/**
* 上传音频文件
*/
private fun uploadAudio(audioFile: File?) {
audioFile?.absolutePath?.let {
val dialogManager = DialogManager(context)
dialogManager.showProgressDialog(context)
FileModel.get()
.uploadFile(audioFile.absolutePath)
.flatMap {
with(itemAttribute) {
if (selectedProperties.isEmpty()) {
val entity = PropRefEntity(parentId, it)
selectedProperties.add(entity)
} else {
selectedProperties[0].propVal = it
}
}
SkillModel.instance.saveSkillInfo(
SKillDataParser.parseSkillSelectedValue(
itemAttribute.recordId,
itemAttribute.cardId,
arrayListOf(this)
)
)
}
.subscribe(object : SingleObserver<String> {
override fun onSubscribe(d: Disposable) {
compositeDisposable.add(d)
}
override fun onSuccess(url: String) {
dialogManager.dismissDialog()
setItemByState(RECORD_STATE_JUDGE)
}
override fun onError(e: Throwable) {
dialogManager.dismissDialog()
"上传失败".toast()
}
})
}
}
/**
* 根据状态设置View
*/
private fun setItemByState(state: Int) {
when (state) {
RECORD_STATE_READY -> {
binding.groupJudge.visibility = View.GONE
binding.groupReady.visibility = View.VISIBLE
binding.btnCancel.visibility = View.VISIBLE
}
RECORD_STATE_COMPLETE -> {
binding.groupJudge.visibility = View.GONE
binding.groupReady.visibility = View.VISIBLE
binding.btnCancel.visibility = View.GONE
}
RECORD_STATE_JUDGE -> {
binding.groupReady.visibility = View.GONE
binding.groupJudge.visibility = View.VISIBLE
}
}
}
}

View File

@@ -1,8 +1,5 @@
package com.yizhuan.erban.skill.widget
import com.yizhuan.xchat_android_core.skill.entity.SkillPropertyEntity
import com.yizhuan.xchat_android_core.skill.entity.SkillRecordEntity
data class SkillAttribute(
val id: Int,
val cardId: Int,
@@ -12,52 +9,4 @@ data class SkillAttribute(
val isEdit: Boolean = false,
val background: String?,
val itemAttributes: List<ItemAttribute>
) {
companion object {
fun parseRecordToAttribute(
item: SkillRecordEntity,
itemEventCallBack: ((itemAttr: SkillItem) -> Unit)? = null
): SkillAttribute {
val list: MutableList<ItemAttribute> = ArrayList()
item.propRecordVo.forEach {
val element = ItemAttribute.parseRecordToAttribute(
item.cardId,
item.isSelf,
item.isEdit,
itemEventCallBack,
it
)
list.add(element)
}
return SkillAttribute(
item.id, item.cardId,
item.icon, item.name,
item.isSelf, item.isEdit,
item.pic, list
)
}
fun parsePropertyToAttribute(
item: SkillPropertyEntity,
itemEventCallBack: ((itemAttr: SkillItem) -> Unit)? = null
): SkillAttribute {
val list: MutableList<ItemAttribute> = ArrayList()
item.props.forEach {
val element = ItemAttribute.parseRecordToAttribute(
item.cardId,
item.isSelf,
item.isEdit,
itemEventCallBack,
it.parsePropToRecord()
)
list.add(element)
}
return SkillAttribute(
-1, item.cardId,
item.icon, item.name,
item.isSelf, item.isEdit,
item.pic, list
)
}
}
}
)

View File

@@ -9,9 +9,8 @@ import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.annotation.Nullable
import androidx.appcompat.app.AppCompatActivity
import com.yizhuan.erban.R
import com.yizhuan.xchat_android_core.skill.entity.SKillValueEntity
import com.yizhuan.xchat_android_core.skill.entity.SkillPostServerEntity
import com.yizhuan.erban.ui.utils.ImageLoadUtils
import com.yizhuan.erban.ui.utils.ImageLoadUtilsV2
import com.yizhuan.erban.ui.widget.magicindicator.buildins.UIUtil
@@ -73,13 +72,23 @@ class SkillCardView(
}
}
//根据state创建Item视图
private fun createItemView(item: ItemAttribute): SkillItem {
return when (item.state) {
1 -> EditItem(item)
else -> SelectionItem(item)
0, 2 -> SelectionItem(item)
3 -> {
val recordItem = RecordIResourceItem(item)
item.recordId = skillAttr.id
(context as AppCompatActivity).lifecycle.addObserver(recordItem)
recordItem
}
else -> RecordDurationItem(item)
}
}
//设置SkillView背景
private fun setBackgroundImg(url: String?) {
if (TextUtils.isEmpty(url)) {
return
@@ -87,7 +96,6 @@ class SkillCardView(
ImageLoadUtils.loadRoundBackground(context, url, this, 8, R.drawable.bg_corner_shadow_12)
}
fun initView(attr: SkillAttribute) {
this.skillAttr = attr
itemList.clear()
@@ -103,26 +111,18 @@ class SkillCardView(
fun isValid(): Boolean {
var isValid = true
itemList.forEach {
if (!it.isValid()) {
isValid = false
return@forEach
run outer@{
itemList.forEach {
if (!it.isValid()) {
isValid = false
return@outer
}
}
}
return isValid
}
fun getItems(): List<SkillItem> = itemList
fun getSavedValues(): SkillPostServerEntity {
return if (itemList.isEmpty()) {
SkillPostServerEntity(propRecordVo = ArrayList(0))
} else {
val list = ArrayList<SKillValueEntity>()
itemList.forEach {
val item = it.getContentEntity()
list.add(SKillValueEntity(item.parentId, it.getContentEntity().selectedProperties))
}
SkillPostServerEntity(skillAttr.id, skillAttr.cardId, list)
}
}
fun getAttributes() = skillAttr
}

View File

@@ -31,7 +31,7 @@ object SkillItemHelper {
* 禁用EditText编辑
*/
fun disableEdit(contentView: EditText) {
fun disableEdit(contentView: EditText) {
contentView.isFocusableInTouchMode = false
contentView.isFocusable = false
contentView.isCursorVisible = false
@@ -40,7 +40,7 @@ object SkillItemHelper {
/**
* 启用EditText编辑
*/
fun enableEdit(contentView: EditText) {
fun enableEdit(contentView: EditText) {
contentView.isFocusableInTouchMode = true
contentView.isFocusable = true
contentView.isCursorVisible = true
@@ -48,5 +48,7 @@ object SkillItemHelper {
object SkillViewHelper{
}
}

View File

@@ -30,10 +30,10 @@ class TimerRecorderView(context: Context, @Nullable attrs: AttributeSet?, defSty
private var state = STATE_PAUSED
private var animator: ValueAnimator? = null
private var animatedPercent = 0f
private var recordDuration = 15
internal var recordDuration = 15
private var audioMessageHelper: AudioRecorder? = null
private var recordListener:RecordListener?=null
var recordListener: RecordListener? = null
constructor(context: Context) : this(context, null)
@@ -45,8 +45,12 @@ class TimerRecorderView(context: Context, @Nullable attrs: AttributeSet?, defSty
array.recycle()
setOnClickListener {
when (state) {
STATE_PAUSED -> { startRecord() }
STATE_PLAYED -> { onEndAudioRecord(false)}
STATE_PAUSED -> {
startRecord()
}
STATE_PLAYED -> {
endAudioRecord(false)
}
}
}
}
@@ -87,6 +91,7 @@ class TimerRecorderView(context: Context, @Nullable attrs: AttributeSet?, defSty
private fun startRecord() {
if (audioMessageHelper == null) {
val options = NimUIKitImpl.getOptions()
options.audioRecordMaxTime = recordDuration
audioMessageHelper = AudioRecorder(
context, options.audioRecordType,
options.audioRecordMaxTime, this
@@ -100,7 +105,7 @@ class TimerRecorderView(context: Context, @Nullable attrs: AttributeSet?, defSty
*
* @param cancel -- true 取消 重新录制 false 录制完成
*/
private fun onEndAudioRecord(cancel: Boolean) {
fun endAudioRecord(cancel: Boolean) {
state = STATE_PAUSED
audioMessageHelper?.completeRecord(cancel)
clearRecordAnim()
@@ -168,9 +173,9 @@ class TimerRecorderView(context: Context, @Nullable attrs: AttributeSet?, defSty
}
interface RecordListener {
fun onRecordTimeUpdate(remain:Int)
fun onRecordTimeUpdate(remain: Int)
fun onRecordCancel()
fun onRecordSuccess(file:File?)
fun onRecordSuccess(file: File?)
fun onRecordFail()
}
}

View File

@@ -0,0 +1,112 @@
<?xml version="1.0" encoding="utf-8"?>
<layout>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/dp_25"
android:paddingBottom="@dimen/dp_25">
<com.yizhuan.erban.skill.widget.TimerRecorderView
android:id="@+id/record_view"
android:layout_width="@dimen/dp_60"
android:layout_height="@dimen/dp_60"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:src="@drawable/icon_music_pause"
app:progressWidth="@dimen/dp_5" />
<TextView
android:id="@+id/tv_record_tip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_10"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/record_view"
android:text="点击录制语音15S展示才艺技能" />
<Button
android:id="@+id/btn_cancel"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_marginTop="@dimen/dp_10"
android:paddingLeft="@dimen/dp_20"
android:paddingRight="@dimen/dp_20"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_record_tip"
tools:text="取消录制" />
<!--录制完成 审核中-->
<TextView
android:id="@+id/tv_sound"
android:layout_width="200dp"
android:layout_height="@dimen/dp_40"
android:background="#66000000"
android:drawableLeft="@drawable/icon_music_pause"
android:drawablePadding="@dimen/dp_10"
android:gravity="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="10s" />
<TextView
android:id="@+id/tv_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_20"
android:gravity="center"
app:layout_constraintBottom_toBottomOf="@id/tv_sound"
app:layout_constraintStart_toEndOf="@id/tv_sound"
app:layout_constraintTop_toTopOf="@id/tv_sound"
tools:text="审核通过" />
<Button
android:id="@+id/btn_delete"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_marginTop="@dimen/dp_20"
android:paddingLeft="@dimen/dp_20"
android:paddingRight="@dimen/dp_20"
android:visibility="gone"
app:layout_constraintEnd_toStartOf="@id/btn_restart"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_record_tip"
tools:text="删除声音" />
<Button
android:id="@+id/btn_restart"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_marginLeft="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_20"
android:paddingLeft="@dimen/dp_20"
android:paddingRight="@dimen/dp_20"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/btn_delete"
app:layout_constraintTop_toBottomOf="@id/tv_record_tip"
app:layout_goneMarginLeft="0dp"
tools:text="重新录制" />
<androidx.constraintlayout.widget.Group
android:id="@+id/group_ready"
android:layout_width="0dp"
android:layout_height="0dp"
app:constraint_referenced_ids="record_view,tv_record_tip,btn_cancel" />
<androidx.constraintlayout.widget.Group
android:id="@+id/group_judge"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="gone"
app:constraint_referenced_ids="tv_sound,tv_duration,btn_delete,btn_restart" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@@ -23,5 +23,5 @@ only_arm64=false
channel_file=channel.txt
version_name=4.2.0
version_code=420
version_name=4.3.0
version_code=430