diff --git a/app/src/main/java/com/yizhuan/erban/MainActivity.java b/app/src/main/java/com/yizhuan/erban/MainActivity.java index d108cfb50..121d02855 100644 --- a/app/src/main/java/com/yizhuan/erban/MainActivity.java +++ b/app/src/main/java/com/yizhuan/erban/MainActivity.java @@ -93,6 +93,7 @@ import com.yizhuan.erban.ui.im.chat.MsgViewHolderMatch; import com.yizhuan.erban.ui.im.chat.MsgViewHolderOnline; import com.yizhuan.erban.ui.im.chat.MsgViewHolderRedPackage; import com.yizhuan.erban.ui.im.chat.MsgViewHolderRedPacket; +import com.yizhuan.erban.ui.im.chat.MsgViewHolderSkill; import com.yizhuan.erban.ui.im.chat.MsgViewHolderText; import com.yizhuan.erban.ui.im.chat.SignInNoticeMsgViewHolder; import com.yizhuan.erban.ui.im.chat.SysMsgV2ViewHolder; @@ -147,6 +148,7 @@ import com.yizhuan.xchat_android_core.im.custom.bean.OpenRoomNotiAttachment; import com.yizhuan.xchat_android_core.im.custom.bean.OpenSignInAttachment; import com.yizhuan.xchat_android_core.im.custom.bean.RedPackageAttachment; import com.yizhuan.xchat_android_core.im.custom.bean.RedPacketAttachment; +import com.yizhuan.xchat_android_core.im.custom.bean.SkillMsgAttachment; import com.yizhuan.xchat_android_core.im.custom.bean.SysMsgAttachment; import com.yizhuan.xchat_android_core.im.custom.bean.SysMsgV2Attachment; import com.yizhuan.xchat_android_core.initial.InitialModel; @@ -414,6 +416,9 @@ public class MainActivity extends BaseMvpActivity NimUIKit.registerMsgItemViewHolder(ChatHintAttachment.class, MsgViewHolderChatHint.class); NimUIKit.registerMsgItemViewHolder(MatchAttachment.class, MsgViewHolderMatch.class); + + //技能卡 + NimUIKit.registerMsgItemViewHolder(SkillMsgAttachment.class, MsgViewHolderSkill.class); NimUIKit.setSessionListener(listener); NimUIKit.setContactEventListener(listener1); } diff --git a/app/src/main/java/com/yizhuan/erban/skill/SKillDataParser.kt b/app/src/main/java/com/yizhuan/erban/skill/SKillDataParser.kt new file mode 100644 index 000000000..3eb91e5c3 --- /dev/null +++ b/app/src/main/java/com/yizhuan/erban/skill/SKillDataParser.kt @@ -0,0 +1,103 @@ +package com.yizhuan.erban.skill + +import com.yizhuan.erban.skill.widget.ItemAttribute +import com.yizhuan.erban.skill.widget.ItemEventListener +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, + itemEventListener: ItemEventListener? = null, + item: PropRecordVoEntity, + audioStatus: Int = 0 + ): ItemAttribute { + return ItemAttribute( + cardId, + isSelf, isEdit, + item.state, item.isMust, + item.parentId, item.parentVal, + itemEventListener, + item.refPropVos.toMutableList(), + ).apply { + this.audioStatus = audioStatus + } + } + + + fun parseSkillRecordToAttribute( + item: SkillRecordEntity, + itemEventListener: ItemEventListener? = null, + ): SkillAttribute { + val list: MutableList = ArrayList() + item.propRecordVo.forEach { + val element = parseItemRecordToAttribute( + item.cardId, + item.isSelf, + item.isEdit, + itemEventListener, + it + ).apply { + audioStatus = item.audioStatus + } + list.add(element) + } + return SkillAttribute( + item.id, item.type, item.cardId, + item.icon, item.name, + item.isSelf, item.isEdit, + item.pic, list + ) + } + + fun parseSkillPropertyToAttribute( + item: SkillPropertyEntity, + itemEventListener: ItemEventListener? = null, + ): SkillAttribute { + val list: MutableList = ArrayList() + item.props.forEach { + val element = parseItemRecordToAttribute( + item.cardId, + item.isSelf, + item.isEdit, + itemEventListener, + it.parsePropToRecord() + ) + list.add(element) + } + return SkillAttribute( + -1, item.type, item.cardId, + item.icon, item.name, + item.isSelf, item.isEdit, + item.pic, list + ) + } + + /** + * 转换成服务器数据 + */ + fun parseSkillSelectedValue( + recordId: Int, + cardId: Int, + itemList: List + ): SkillPostServerEntity { + return if (itemList.isEmpty()) { + SkillPostServerEntity(propRecordVo = ArrayList(0)) + } else { + val list = ArrayList() + itemList.forEach { + val item = it.getContentEntity() + list.add( + SKillValueEntity( + item.parentId, + it.getContentEntity().selectedProperties + ) + ) + } + SkillPostServerEntity(recordId, cardId, list) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/yizhuan/erban/skill/SkillDataDelegate.kt b/app/src/main/java/com/yizhuan/erban/skill/SkillDataDelegate.kt new file mode 100644 index 000000000..0536ad290 --- /dev/null +++ b/app/src/main/java/com/yizhuan/erban/skill/SkillDataDelegate.kt @@ -0,0 +1,201 @@ +package com.yizhuan.erban.skill + +import android.annotation.SuppressLint +import com.yizhuan.erban.base.BaseActivity +import com.yizhuan.erban.skill.dialog.SkillSelectionDialog +import com.yizhuan.erban.skill.repository.SkillDataManager +import com.yizhuan.erban.skill.repository.SkillModel +import com.yizhuan.erban.skill.widget.* +import com.yizhuan.xchat_android_core.file.FileModel +import com.yizhuan.xchat_android_core.skill.entity.PropRefEntity +import com.yizhuan.xchat_android_core.skill.entity.PropsEntity +import com.yizhuan.xchat_android_core.skill.entity.SkillPostServerEntity +import com.yizhuan.xchat_android_core.skill.entity.SkillPropertyEntity +import com.yizhuan.xchat_android_core.skill.event.SkillEvent +import com.yizhuan.xchat_android_core.utils.toast +import org.greenrobot.eventbus.EventBus +import java.io.File + +class SkillDataDelegate(private val skillView: SkillCardView, private val activity: BaseActivity) : + ItemEventListener { + @SuppressLint("CheckResult") + override fun onItemClick(item: SkillItem) { + onItemSelection(item) + } + + override fun onRecordSuccess(audioFile: File?, duration: Int) { + onRecordAudioSuccess(audioFile, duration) + } + + override fun onDeleteRecordClick() { + deleteSkill(false) + } + + + /** + * 上传音频文件 + */ + private fun onRecordAudioSuccess(audioFile: File?, duration: Int) { + val sourceItem = + skillView.getItems().find { it.getContentEntity().state == ItemAttribute.STATE_AUDIO }!! + val durationItem = + skillView.getItems() + .find { it.getContentEntity().state == ItemAttribute.STATE_DURATION }!! + + with(durationItem.getContentEntity()) { + if (selectedProperties.isEmpty()) { + val entity = PropRefEntity(parentId, duration.toString()) + selectedProperties.add(entity) + } else { + selectedProperties[0].propVal = duration.toString() + } + } + + audioFile?.absolutePath?.let { + activity.dialogManager.showProgressDialog(activity) + FileModel.get() + .uploadFile(audioFile.absolutePath) + .flatMap { + with(sourceItem.getContentEntity()) { + if (selectedProperties.isEmpty()) { + val entity = PropRefEntity(parentId, it) + selectedProperties.add(entity) + } else { + selectedProperties[0].propVal = it + } + } + SkillModel.instance.saveSkillInfo( + SKillDataParser.parseSkillSelectedValue( + skillView.getAttributes().id, + skillView.getAttributes().cardId, + skillView.getItems() + ) + ) + }.compose(activity.bindToLifecycle()) + .subscribe({ + activity.dialogManager.dismissDialog() + EventBus.getDefault().post(SkillEvent()) + if (skillView.getAttributes().id == -1) { + activity.finish() + } + }, { + activity.dialogManager.dismissDialog() + "上传失败,请重新录制".toast() + (sourceItem as RecordIResourceItem).setItemByState(RecordIResourceItem.RECORD_STATE_READY) + }) + } + } + + /** + * 选项 + */ + @SuppressLint("CheckResult") + private fun onItemSelection(item: SkillItem) { + val propertyEntity = + SkillDataManager.get().getPropertyEntity(item.getContentEntity().cardId) + if (propertyEntity == null) { + SkillModel.instance.getCardInfoById(item.getContentEntity().cardId) + .compose(activity.bindToLifecycle()) + .doOnSubscribe { activity.dialogManager.showProgressDialog(activity) } + .subscribe({ + SkillDataManager.get() + .setSkillPropertyEntity(item.getContentEntity().cardId, it) + showSelectionDialog(item, it) + activity.dialogManager.dismissDialog() + }, { th -> + th.printStackTrace() + activity.toast(th.message) + showSelectionDialog(item, null) + activity.dialogManager.dismissDialog() + }) + } else { + showSelectionDialog(item, propertyEntity) + } + } + + private fun showSelectionValueDialog(item: SkillItem, propertyEntity: PropsEntity?) { + val selectionDialog = SkillSelectionDialog(activity, propertyEntity) { + item.getContentEntity().selectedProperties.clear() + it.forEach { element -> item.getContentEntity().selectedProperties.add(element.parseToRecord()) } + item.invalidate() + } + selectionDialog.openDialog() + } + + /** + * 显示选择对话框 + */ + private fun showSelectionDialog(item: SkillItem, propertyEntity: SkillPropertyEntity?) { + val props = propertyEntity?.props + val propDictVos = props?.find { it.id == item.getContentEntity().parentId }?.apply { + propDictVos?.forEach { prop -> + //清空已选项 + prop.isSelected = false + //设置之前保存的选项,从服务器拉下来的数据 + val hasSelectBefore = + item.getContentEntity().selectedProperties.find { record -> record.propId == prop.id } + if (hasSelectBefore != null) { + //表示这个是上次存在服务器的值 设置为true + prop.isSelected = true + } + } + + } + showSelectionValueDialog(item, propDictVos) + } + + @SuppressLint("CheckResult") + internal fun saveSkill() { + if (!skillView.isValid()) { + activity.toast("请填写或选择带*条目的内容") + return + } + val item = parseSelectedValues() + SkillModel.instance.saveSkillInfo(item).compose(activity.bindToLifecycle()) + .doOnSubscribe { activity.dialogManager.showProgressDialog(activity) } + .subscribe( + { + activity.dialogManager.dismissDialog() + val event = SkillEvent() + event.event = SkillEvent.ADD + EventBus.getDefault().post(event) + activity.finish() + }, + { th -> + th.printStackTrace() + activity.toast(th.message) + activity.dialogManager.dismissDialog() + }) + } + + /** + * 获取SkillView数据转换成提交服务器数据 + */ + private fun parseSelectedValues(): SkillPostServerEntity { + val itemList = skillView.getItems() + val skillAttr = skillView.getAttributes() + return SKillDataParser.parseSkillSelectedValue(skillAttr.id, skillAttr.cardId, itemList) + } + + /** + * 删除技能卡 + */ + @SuppressLint("CheckResult") + fun deleteSkill(needFinishCurrent: Boolean) { + activity.dialogManager.showProgressDialog(activity) + SkillModel.instance.deleteSkill(skillView.getAttributes().id) + .compose(activity.bindToLifecycle()) + .subscribe({ + activity.toast("删除成功") + val event = SkillEvent() + event.event = SkillEvent.REMOVE + EventBus.getDefault().post(event) + activity.dialogManager.dismissDialog() + if (needFinishCurrent) + activity.finish() + }, { th -> + th.printStackTrace() + activity.toast(th.message) + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/yizhuan/erban/skill/activity/AddSkillActivity.kt b/app/src/main/java/com/yizhuan/erban/skill/activity/AddSkillActivity.kt index e0a0b4917..60592ed3f 100644 --- a/app/src/main/java/com/yizhuan/erban/skill/activity/AddSkillActivity.kt +++ b/app/src/main/java/com/yizhuan/erban/skill/activity/AddSkillActivity.kt @@ -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 @@ -8,22 +9,23 @@ import com.netease.nim.uikit.StatusBarUtil import com.yizhuan.erban.R import com.yizhuan.erban.base.BaseBindingActivity import com.yizhuan.erban.databinding.ActivitySkillEditBinding -import com.yizhuan.xchat_android_core.skill.entity.PropRecordVoEntity import com.yizhuan.xchat_android_core.skill.entity.SkillPropertyEntity -import com.yizhuan.xchat_android_core.skill.entity.SkillRecordEntity import com.yizhuan.erban.skill.repository.SkillDataManager import com.yizhuan.erban.skill.repository.SkillModel +import com.yizhuan.erban.skill.widget.CARD_TYPE_AUDIO import com.yizhuan.xchat_android_library.annatation.ActLayoutRes @ActLayoutRes(R.layout.activity_skill_edit) class AddSkillActivity : BaseBindingActivity() { private lateinit var delegate: SkillEditableDelegate + private var cardId = -1 + private var cardType = -1 override fun init() { delegate = SkillEditableDelegate(this) initTitleBar("添加技能") mBinding.click = this mBinding.btnDelete.visibility = View.GONE - val cardId = intent?.getIntExtra(ITEM, -1) ?: -1 + cardId = intent?.getIntExtra(CARD_ID, cardId) ?: cardId if (cardId > 0) { queryCardInfo(cardId) } @@ -33,34 +35,52 @@ class AddSkillActivity : BaseBindingActivity() { private fun queryCardInfo(cardId: Int) { val propertyEntity = SkillDataManager.get().getPropertyEntity(cardId) if (propertyEntity != null) { + if (propertyEntity.type == CARD_TYPE_AUDIO) { + dealAudioView(propertyEntity) + } setSkillViewData(propertyEntity) } else { SkillModel.instance.getCardInfoById(cardId) .compose(bindToLifecycle()) - .subscribe( { + .subscribe({ SkillDataManager.get().setSkillPropertyEntity(cardId, it) - setSkillViewData(it) - }, { th -> th.printStackTrace() + when (it.type) { + CARD_TYPE_AUDIO -> dealAudioView(it) + else -> setSkillViewData(it) + } + }, { th -> + th.printStackTrace() toast(th.message) }) } } + private fun dealAudioView(propertyEntity: SkillPropertyEntity) { + checkPermissionAndDeal(propertyEntity) + mBinding.btnSave.visibility = View.GONE + cardType = propertyEntity.type + } + private fun setSkillViewData(it: SkillPropertyEntity) { - //转换 - val propList = ArrayList() - it.props.forEach { prop -> - propList.add( - PropRecordVoEntity( - prop.id, prop.propVal, -1, null, prop.state, prop.isMust - ) - ) - } - val entity = SkillRecordEntity( - it.cardId, null, it.icon, -1, it.name, - it.pic, propList, it.type, null + it.isSelf = true + it.isEdit = true + delegate.setSkillViewData(it) + } + + @SuppressLint("CheckResult") + private fun checkPermissionAndDeal(it: SkillPropertyEntity) { + checkPermission( + Manifest.permission.RECORD_AUDIO, + Manifest.permission.WRITE_EXTERNAL_STORAGE ) - delegate.setSkillViewData(isSelf = true, isEdit = true, entity = entity) + .subscribe { aBoolean: Boolean -> + if (aBoolean) { + setSkillViewData(it) + } else { + toast("请给予应用必要权限,让程序可正常工作。") + finish() + } + } } @@ -68,28 +88,31 @@ class AddSkillActivity : BaseBindingActivity() { delegate.onLeftClick() } - override fun onClick(v: View?) { super.onClick(v) when (v?.id) { - R.id.btn_save -> delegate.saveSkill(mBinding) + R.id.btn_save -> delegate.saveSkill() } } companion object { - private const val ITEM = "item" - fun start(context: Context, type: Int) { + private const val CARD_ID = "card_id" + fun start(context: Context, cardId: Int) { val intent = Intent(context, AddSkillActivity::class.java) - intent.putExtra(ITEM, type) + intent.putExtra(CARD_ID, cardId) context.startActivity(intent) } } override fun onBackPressed() { + if (cardType == CARD_TYPE_AUDIO) { + super.onBackPressed() + return + } delegate.onLeftClick() } - override fun needSteepStateBar()=true + override fun needSteepStateBar() = true override fun setStatusBar() { super.setStatusBar() StatusBarUtil.transparencyBar(this) diff --git a/app/src/main/java/com/yizhuan/erban/skill/activity/EditSkillActivity.kt b/app/src/main/java/com/yizhuan/erban/skill/activity/EditSkillActivity.kt index e33f424ff..1061d9879 100644 --- a/app/src/main/java/com/yizhuan/erban/skill/activity/EditSkillActivity.kt +++ b/app/src/main/java/com/yizhuan/erban/skill/activity/EditSkillActivity.kt @@ -8,11 +8,9 @@ import com.netease.nim.uikit.StatusBarUtil import com.yizhuan.erban.R import com.yizhuan.erban.base.BaseBindingActivity import com.yizhuan.erban.databinding.ActivitySkillEditBinding -import com.yizhuan.xchat_android_core.skill.event.SkillEvent import com.yizhuan.erban.skill.repository.SkillModel import com.yizhuan.erban.ui.widget.dialog.CommonTipDialog import com.yizhuan.xchat_android_library.annatation.ActLayoutRes -import org.greenrobot.eventbus.EventBus @ActLayoutRes(R.layout.activity_skill_edit) class EditSkillActivity : BaseBindingActivity() { @@ -33,7 +31,7 @@ class EditSkillActivity : BaseBindingActivity() { when (v.id) { R.id.btn_delete -> showDeleteDialog() R.id.btn_save -> { - mDelegate.saveSkill(mBinding) + mDelegate.saveSkill() } } } @@ -48,7 +46,7 @@ class EditSkillActivity : BaseBindingActivity() { deleteTipDialog?.setTipMsg(resources.getString(R.string.tip_delete_skill)) deleteTipDialog?.setOnActionListener(object : CommonTipDialog.OnActionListener { override fun onOk() { - deleteSkill(mBinding.skillView.getSavedValues().id) + mDelegate.deleteSkill() deleteTipDialog?.dismiss() } @@ -63,32 +61,18 @@ class EditSkillActivity : BaseBindingActivity() { deleteTipDialog?.show() } - @SuppressLint("CheckResult") - private fun deleteSkill(id: Int) { - SkillModel.instance.deleteSkill(id) - .compose(bindToLifecycle()) - .subscribe( { - toast("删除成功") - val event = SkillEvent() - event.event = SkillEvent.REMOVE - EventBus.getDefault().post(event) - finish() - }, { th -> - th.printStackTrace() - toast(th.message) - }) - } - @SuppressLint("CheckResult") private fun loadData() { SkillModel.instance.getSkillDetailById(recordId) .compose(bindToLifecycle()) .doOnSubscribe { dialogManager.showProgressDialog(this) } - .subscribe( { - mDelegate.setSkillViewData(isSelf = true, isEdit = true, entity = it) + .subscribe({ + it.isSelf = true + it.isEdit = true + mDelegate.setSkillViewData(it) dialogManager.dismissDialog() - }, { th -> + }, { th -> th.printStackTrace() toast(th.message) dialogManager.dismissDialog() @@ -107,7 +91,8 @@ class EditSkillActivity : BaseBindingActivity() { override fun onBackPressed() { mDelegate.onLeftClick() } - override fun needSteepStateBar()=true + + override fun needSteepStateBar() = true override fun setStatusBar() { super.setStatusBar() StatusBarUtil.transparencyBar(this) diff --git a/app/src/main/java/com/yizhuan/erban/skill/activity/SkillDetailActivity.kt b/app/src/main/java/com/yizhuan/erban/skill/activity/SkillDetailActivity.kt index dea50d8d9..6cc0956b7 100644 --- a/app/src/main/java/com/yizhuan/erban/skill/activity/SkillDetailActivity.kt +++ b/app/src/main/java/com/yizhuan/erban/skill/activity/SkillDetailActivity.kt @@ -34,10 +34,12 @@ class SkillDetailActivity : BaseBindingActivity() { SkillModel.instance.getSkillDetailById(recordId) .compose(bindToLifecycle()) .doOnSubscribe { dialogManager.showProgressDialog(this) } - .subscribe( { - mDelegate.setSkillViewData(isSelf = false, isEdit = false, entity = it) + .subscribe({ + it.isSelf = false + it.isEdit = false + mDelegate.setSkillViewData(it) dialogManager.dismissDialog() - }, { th -> + }, { th -> th.printStackTrace() toast(th.message) dialogManager.dismissDialog() @@ -52,7 +54,8 @@ class SkillDetailActivity : BaseBindingActivity() { context.startActivity(intent) } } - override fun needSteepStateBar()=true + + override fun needSteepStateBar() = true override fun setStatusBar() { super.setStatusBar() StatusBarUtil.transparencyBar(this) diff --git a/app/src/main/java/com/yizhuan/erban/skill/activity/SkillEditableDelegate.kt b/app/src/main/java/com/yizhuan/erban/skill/activity/SkillEditableDelegate.kt index 23b29dff8..0dda92a26 100644 --- a/app/src/main/java/com/yizhuan/erban/skill/activity/SkillEditableDelegate.kt +++ b/app/src/main/java/com/yizhuan/erban/skill/activity/SkillEditableDelegate.kt @@ -1,20 +1,12 @@ package com.yizhuan.erban.skill.activity -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.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.SelectionItem -import com.yizhuan.erban.skill.widget.SkillItem +import com.yizhuan.erban.skill.SKillDataParser +import com.yizhuan.erban.skill.SkillDataDelegate import com.yizhuan.erban.ui.widget.dialog.CommonTipDialog -import org.greenrobot.eventbus.EventBus +import com.yizhuan.xchat_android_core.skill.entity.* /** * 编辑-添加 界面 @@ -52,78 +44,42 @@ class SkillEditableDelegate( saveTipDialog.show() } - private fun showSelectionValueDialog(item: SkillItem, propertyEntity: PropsEntity?) { - val selectionDialog = SkillSelectionDialog(activity, propertyEntity) { - item.getContentEntity().propId = it.id - item.getContentEntity().propVal = it.propVal - item.invalidate() - } - selectionDialog.openDialog() + /** + * 保存 添加 + */ + internal fun saveSkill() { + SkillDataDelegate(activity.mBinding.skillView, activity).saveSkill() } - @SuppressLint("CheckResult") - internal fun saveSkill(binding: ActivitySkillEditBinding) { - if (!binding.skillView.isValid()) { - activity.toast("请填写或选择带*条目的内容") - return - } - val item = binding.skillView.getSavedValues() - SkillModel.instance.saveSkillInfo(item).compose(activity.bindToLifecycle()) - .doOnSubscribe { activity.dialogManager.showProgressDialog(activity) } - .subscribe( - { - activity.dialogManager.dismissDialog() - val event = SkillEvent() - event.event = SkillEvent.ADD - EventBus.getDefault().post(event) - activity.finish() - }, - { th -> - th.printStackTrace() - activity.toast(th.message) - activity.dialogManager.dismissDialog() - }) + /** + * 删除 + */ + internal fun deleteSkill() { + SkillDataDelegate(activity.mBinding.skillView, activity).deleteSkill(true) } - - internal fun setSkillViewData(isSelf: Boolean, isEdit: Boolean, entity: SkillRecordEntity) { - entity.isSelf = isSelf - entity.isEdit = isEdit - val listener = if (isSelf && isEdit) DefaultItemSelectionListenerImp(entity) else null - activity.mBinding.skillView.setItems(entity, listener) + /** + * 记录 + */ + internal fun setSkillViewData(entity: SkillRecordEntity) { + val onItemCall = + if (entity.isEdit && entity.isSelf) + SkillDataDelegate(activity.mBinding.skillView, activity) + else null + val attr = SKillDataParser.parseSkillRecordToAttribute(entity, onItemCall) + activity.mBinding.skillView.initView(attr) } - private fun setSelectionData(item: SkillItem, propertyEntity: SkillPropertyEntity?) { - val props = propertyEntity?.props - val propDictVos = props?.find { - it.id == item.getContentEntity().parentId - } - showSelectionValueDialog(item, propDictVos) - } - - inner class DefaultItemSelectionListenerImp(private val entity: SkillRecordEntity) : - SelectionItem.OnItemSelectionListener { - @SuppressLint("CheckResult") - override fun onItemSelection(item: SkillItem) { - val propertyEntity = SkillDataManager.get().getPropertyEntity(entity.cardId) - if (propertyEntity == null) { - SkillModel.instance.getCardInfoById(entity.cardId) - .compose(activity.bindToLifecycle()) - .doOnSubscribe { activity.dialogManager.showProgressDialog(activity) } - .subscribe( { - SkillDataManager.get().setSkillPropertyEntity(entity.cardId, it) - setSelectionData(item, it) - activity.dialogManager.dismissDialog() - }, { th -> - th.printStackTrace() - activity.toast(th.message) - setSelectionData(item, null) - activity.dialogManager.dismissDialog() - }) - } else { - setSelectionData(item, propertyEntity) - } - } + /** + * 初值属性 + */ + internal fun setSkillViewData(entity: SkillPropertyEntity) { + val onItemCall = if (entity.isEdit && entity.isSelf) SkillDataDelegate( + activity.mBinding.skillView, + activity + ) else null + val attr = SKillDataParser.parseSkillPropertyToAttribute(entity, onItemCall) + activity.mBinding.skillView.initView(attr) } companion object { diff --git a/app/src/main/java/com/yizhuan/erban/skill/activity/SkillHomeActivity.kt b/app/src/main/java/com/yizhuan/erban/skill/activity/SkillHomeActivity.kt index 68eef0b8f..85d8074ee 100644 --- a/app/src/main/java/com/yizhuan/erban/skill/activity/SkillHomeActivity.kt +++ b/app/src/main/java/com/yizhuan/erban/skill/activity/SkillHomeActivity.kt @@ -14,12 +14,15 @@ import com.yizhuan.erban.R import com.yizhuan.erban.base.BaseBindingActivity import com.yizhuan.erban.common.EmptyViewHelper import com.yizhuan.erban.databinding.ActivitySkillHomeBinding +import com.yizhuan.erban.skill.SKillDataParser import com.yizhuan.erban.skill.adapter.MineSkillCardAdapter import com.yizhuan.erban.skill.decoration.SkillLinearVerticalDecoration import com.yizhuan.erban.skill.dialog.AddSkillCardDialog 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.CARD_TYPE_AUDIO +import com.yizhuan.erban.skill.widget.SkillAttribute import com.yizhuan.erban.ui.widget.magicindicator.buildins.UIUtil import com.yizhuan.xchat_android_library.annatation.ActLayoutRes import org.greenrobot.eventbus.EventBus @@ -39,11 +42,13 @@ class SkillHomeActivity : BaseBindingActivity() { userId = intent.getLongExtra(USER_ID, 0) EventBus.getDefault().register(this) mBinding.recyclerView.layoutManager = LinearLayoutManager(this) - adapter = MineSkillCardAdapter(pageType ==PAGE_TYPE_SELF) + adapter = MineSkillCardAdapter(pageType == PAGE_TYPE_SELF, this) mBinding.recyclerView.adapter = adapter mBinding.recyclerView.addItemDecoration(SkillLinearVerticalDecoration(this, 6, 16)) adapter.setOnItemClickListener { _, _, position -> if (pageType != PAGE_TYPE_SELF) return@setOnItemClickListener + val item = adapter.getItem(position) ?: return@setOnItemClickListener + if (item == null || item.type == CARD_TYPE_AUDIO) return@setOnItemClickListener adapter.getItem(position)?.let { EditSkillActivity.start(this, it.id) } @@ -54,6 +59,7 @@ class SkillHomeActivity : BaseBindingActivity() { mBinding.refreshLayout.setOnRefreshListener { loadUserSkillList(userId) } + mBinding.refreshLayout.isEnabled=false//禁用下拉刷新 loadUserSkillList(userId) } @@ -163,7 +169,8 @@ class SkillHomeActivity : BaseBindingActivity() { fun onDataChangedEvent(event: SkillEvent) { loadUserSkillList(userId) } - override fun needSteepStateBar()=true + + override fun needSteepStateBar() = true override fun setStatusBar() { super.setStatusBar() StatusBarUtil.transparencyBar(this) diff --git a/app/src/main/java/com/yizhuan/erban/skill/adapter/MineSkillCardAdapter.kt b/app/src/main/java/com/yizhuan/erban/skill/adapter/MineSkillCardAdapter.kt index 9df605098..81192802c 100644 --- a/app/src/main/java/com/yizhuan/erban/skill/adapter/MineSkillCardAdapter.kt +++ b/app/src/main/java/com/yizhuan/erban/skill/adapter/MineSkillCardAdapter.kt @@ -3,18 +3,36 @@ 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.base.BaseActivity +import com.yizhuan.erban.skill.SKillDataParser +import com.yizhuan.erban.skill.SkillDataDelegate +import com.yizhuan.erban.skill.widget.CARD_TYPE_AUDIO import com.yizhuan.xchat_android_core.skill.entity.SkillRecordEntity import com.yizhuan.erban.skill.widget.SkillCardView /** * 用户所有技能卡 显示 */ -class MineSkillCardAdapter(private val isSelf: Boolean) : +class MineSkillCardAdapter(private val isSelf: Boolean, private val activity: BaseActivity) : BaseQuickAdapter(R.layout.item_mine_skill_card) { override fun convert(helper: BaseViewHolder, item: SkillRecordEntity) { val itemView = helper.itemView as SkillCardView - item.isSelf = isSelf item.isEdit = false - itemView.setItems(item, null) + when (item.type) { + CARD_TYPE_AUDIO -> { + //声音秀没有编辑选项 + item.isSelf = false + itemView.initView( + SKillDataParser.parseSkillRecordToAttribute( + item, + SkillDataDelegate(itemView, activity) + ) + ) + } + else -> { + item.isSelf = isSelf + itemView.initView(SKillDataParser.parseSkillRecordToAttribute(item)) + } + } } } \ No newline at end of file diff --git a/app/src/main/java/com/yizhuan/erban/skill/adapter/SkillSelectionAdapter.kt b/app/src/main/java/com/yizhuan/erban/skill/adapter/SkillSelectionAdapter.kt index 9bc5b8194..9f322e4d9 100644 --- a/app/src/main/java/com/yizhuan/erban/skill/adapter/SkillSelectionAdapter.kt +++ b/app/src/main/java/com/yizhuan/erban/skill/adapter/SkillSelectionAdapter.kt @@ -5,30 +5,99 @@ import android.graphics.Color import com.chad.library.adapter.base.BaseQuickAdapter import com.chad.library.adapter.base.BaseViewHolder import com.yizhuan.erban.R -import com.yizhuan.xchat_android_core.skill.entity.PropDictVosEntity +import com.yizhuan.xchat_android_core.skill.entity.PropDictVo +import com.yizhuan.xchat_android_core.utils.toast -class SkillSelectionAdapter(private val context: Context) : - BaseQuickAdapter(R.layout.item_skill_selection) { - private var selectedPosition = -1 - override fun convert(helper: BaseViewHolder, item: PropDictVosEntity) { +class SkillSelectionAdapter( + private val context: Context, + private val itemState: Int, + private var maxSelectNumber: Int +) : + BaseQuickAdapter(R.layout.item_skill_selection) { + init { + //-1 不限制 + maxSelectNumber = + if (maxSelectNumber == 0 || maxSelectNumber == -1) Int.MAX_VALUE + else maxSelectNumber + } + + private var refreshByUser = false//标志是否是用户选择后刷新Adapter,在用户选择后设置为true + private var selectedCount = 0 + override fun convert(helper: BaseViewHolder, item: PropDictVo) { helper.setText(R.id.tv_item, item.propVal) - val position = helper.adapterPosition helper.setBackgroundRes( R.id.tv_item, - if (selectedPosition == position) R.drawable.bg_round_ffbc51_8 + if (item.isSelected) R.drawable.bg_round_ffbc51_8 else R.drawable.bg_f1f1fa_8 ) helper.setTextColor( R.id.tv_item, - if (selectedPosition == position) context.resources.getColor(R.color.color_333333) - else Color.parseColor("#FFBC51") + if (item.isSelected) Color.parseColor("#FFBC51") + else context.resources.getColor(R.color.color_333333) ) + if (item.isSelected && !refreshByUser) { + selectedCount++ + } } fun select(position: Int) { - if (position == selectedPosition) return - selectedPosition = position + refreshByUser = true + getItem(position)?.let { + when (itemState) { + //0 单选 1 输入 2多选 3 音频 4 音频时长 + 0 -> singleSelect(it) + 2 -> multiSelect(it) + } + } notifyDataSetChanged() } + + fun getSelectedItems(): List { + return data.filter { it.isSelected } + } + + private fun singleSelect(item: PropDictVo) { + data.forEach { it.isSelected = false } + selectedCount = 1 + item.isSelected = true + } + + private fun multiSelect(item: PropDictVo) { + item.isSelected = !item.isSelected + when (item.refIsOnlyCheck) { + 0 -> { + when (item.isSelected) { + false -> { + selectedCount-- + } + true -> { + selectedCount++ + if (selectedCount > maxSelectNumber) { + "最多只能选择${maxSelectNumber}项".toast() + selectedCount-- + item.isSelected = false + return + } else { + data.find { e -> e.refIsOnlyCheck == 1 }?.let { + if (it.isSelected) { + it.isSelected = false + selectedCount-- + } + } + } + } + } + } + 1 -> { + if (item.isSelected) { + data.forEach { that -> that.isSelected = false } + item.isSelected = true + selectedCount = 1 + } else { + selectedCount = 0 + } + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/yizhuan/erban/skill/dialog/AddSkillCardDialog.kt b/app/src/main/java/com/yizhuan/erban/skill/dialog/AddSkillCardDialog.kt index ba07f6bde..cb642d660 100644 --- a/app/src/main/java/com/yizhuan/erban/skill/dialog/AddSkillCardDialog.kt +++ b/app/src/main/java/com/yizhuan/erban/skill/dialog/AddSkillCardDialog.kt @@ -2,6 +2,7 @@ package com.yizhuan.erban.skill.dialog import android.content.Context import android.view.Gravity +import android.view.View import androidx.recyclerview.widget.GridLayoutManager import com.yizhuan.erban.R import com.yizhuan.erban.databinding.DialogAddSkillItemBinding @@ -30,6 +31,7 @@ class AddSkillCardDialog( private lateinit var adapter: AddSkillCardAdapter override fun init() { + binding.btnEnsure.visibility = View.GONE binding.recyclerView.layoutManager = GridLayoutManager(context, 2) binding.recyclerView.addItemDecoration(SkillGridDecoration(context, 26, 15)) adapter = AddSkillCardAdapter() diff --git a/app/src/main/java/com/yizhuan/erban/skill/dialog/SkillSelectionDialog.kt b/app/src/main/java/com/yizhuan/erban/skill/dialog/SkillSelectionDialog.kt index 68fa757df..714187d1d 100644 --- a/app/src/main/java/com/yizhuan/erban/skill/dialog/SkillSelectionDialog.kt +++ b/app/src/main/java/com/yizhuan/erban/skill/dialog/SkillSelectionDialog.kt @@ -8,16 +8,16 @@ import com.yizhuan.erban.R import com.yizhuan.erban.databinding.DialogAddSkillItemBinding import com.yizhuan.erban.skill.adapter.SkillSelectionAdapter import com.yizhuan.erban.skill.decoration.SkillGridDecoration -import com.yizhuan.xchat_android_core.skill.entity.PropDictVosEntity import com.yizhuan.xchat_android_core.skill.entity.PropsEntity import com.yizhuan.erban.treasure_box.widget.dialog.BaseBindingDialog import com.yizhuan.erban.ui.widget.magicindicator.buildins.UIUtil +import com.yizhuan.xchat_android_core.skill.entity.PropDictVo import com.yizhuan.xchat_android_library.annatation.ActLayoutRes @ActLayoutRes(R.layout.dialog_add_skill_item) class SkillSelectionDialog( context: Context, var item: PropsEntity?, - val callback: (value: PropDictVosEntity) -> Unit + val callback: (value: List) -> Unit ) : BaseBindingDialog(context) { private lateinit var adapter: SkillSelectionAdapter @@ -26,16 +26,18 @@ class SkillSelectionDialog( height = UIUtil.dip2px(context, 406.0) gravity = Gravity.BOTTOM binding.tvTitle.visibility = View.VISIBLE - binding.tvTitle.text = item?.propVal?:"" - adapter = SkillSelectionAdapter(context) + binding.tvTitle.text = item?.propVal ?: "" + adapter = SkillSelectionAdapter(context, item?.state ?: 0,item?.checkLimitNum?:-1) adapter.setOnItemClickListener { _, _, position -> adapter.select(position) - callback(adapter.getItem(position)!!) - closeDialog() } binding.recyclerView.layoutManager = GridLayoutManager(context, 2) binding.recyclerView.addItemDecoration(SkillGridDecoration(context, 30, 15)) binding.recyclerView.adapter = adapter adapter.setNewData(item?.propDictVos) + binding.btnEnsure.setOnClickListener { + callback.invoke(adapter.getSelectedItems()) + closeDialog() + } } } \ No newline at end of file diff --git a/app/src/main/java/com/yizhuan/erban/skill/widget/EditItem.kt b/app/src/main/java/com/yizhuan/erban/skill/widget/EditItem.kt index aa72b705d..9a0786fc2 100644 --- a/app/src/main/java/com/yizhuan/erban/skill/widget/EditItem.kt +++ b/app/src/main/java/com/yizhuan/erban/skill/widget/EditItem.kt @@ -1,35 +1,55 @@ package com.yizhuan.erban.skill.widget import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.widget.EditText +import android.widget.TextView import com.yizhuan.erban.R -import com.yizhuan.xchat_android_core.skill.entity.PropRecordVoEntity +import com.yizhuan.xchat_android_core.skill.entity.PropRefEntity import com.yizhuan.xchat_android_core.utils.TextUtils -class EditItem( - private val isSelf: Boolean, - private val isEditable: Boolean, - entity: PropRecordVoEntity, - context: Context -) : - SkillItem(entity, context) { +class EditItem(private val itemAttr: ItemAttribute) : SkillItem { + private lateinit var contentView: EditText + private lateinit var titleVIew: TextView + private fun initItem() { + if (isContentEditable()) { + SkillItemHelper.enableEdit(contentView) + } else { + SkillItemHelper.disableEdit(contentView) + contentView.setCompoundDrawables(null, null, null, null) + } + SkillItemHelper.setTitleText(titleVIew, itemAttr.parentVol, itemAttr.isMust) + itemAttr.selectedProperties.getOrNull(0)?.propVal?.let { contentView.setText(it) } + } - init { + override fun getContentEntity(): ItemAttribute { + itemAttr.selectedProperties.apply { + if (isEmpty()) { + val entity = PropRefEntity(itemAttr.parentId, null) + add(entity) + } + get(0).propVal = contentView.text.toString() + } + return itemAttr + } + + + override fun createItem(context: Context): View { + val view = LayoutInflater.from(context).inflate(R.layout.layout_skill_edit, null, false) + contentView = view.findViewById(R.id.edit_content) + titleVIew = view.findViewById(R.id.title_view) initItem() + return view } - override fun getContentEntity(): PropRecordVoEntity { - entity.propVal = getContentView().text.toString() - entity.propId = entity.parentId - return entity - } + override fun invalidate() {} override fun isValid() = - if (entity.isMust == 0) true else !TextUtils.isEmptyText(getContentView().text.toString()) + if (itemAttr.isMust == 0) true else { + itemAttr.selectedProperties.isNotEmpty() && + !TextUtils.isEmptyText(itemAttr.selectedProperties[0].propVal) + } - override fun getRightRes() = R.drawable.icon_edit_black - override fun isContentEditable(): Boolean { - return isSelf && isEditable - } - - override fun isRightVisitable() = isSelf && isEditable + private fun isContentEditable() = itemAttr.isSelf && itemAttr.editable } \ No newline at end of file diff --git a/app/src/main/java/com/yizhuan/erban/skill/widget/ItemAttribute.kt b/app/src/main/java/com/yizhuan/erban/skill/widget/ItemAttribute.kt new file mode 100644 index 000000000..bf1ca0017 --- /dev/null +++ b/app/src/main/java/com/yizhuan/erban/skill/widget/ItemAttribute.kt @@ -0,0 +1,36 @@ +package com.yizhuan.erban.skill.widget + +import com.yizhuan.xchat_android_core.skill.entity.PropRefEntity +import java.io.File + +data class ItemAttribute( + val cardId: Int, + val isSelf: Boolean = false, + val editable: Boolean = false, + val state: Int = STATE_SINGLE_CHOICE,//0 单选 1 编辑 2 多选 3 音频 + val isMust: Int = 0, + val parentId: Int, + val parentVol: String, + val itemEventListener: ItemEventListener? = null, + var selectedProperties: MutableList + +) { + companion object { + const val STATE_SINGLE_CHOICE = 0 + const val STATE_EDIT = 1 + const val STATE_MULTIPLE_CHOICE = 2 + const val STATE_AUDIO = 3 + const val STATE_DURATION = 4 + } + + var audioDuration: String? = null + var audioStatus: Int = 0//声音秀审核状态 +} + +interface ItemEventListener { + fun onItemClick(item: SkillItem) {} + fun onRecordSuccess(audioFile: File?, duration: Int) {} + fun onDeleteRecordClick() {} +} + + diff --git a/app/src/main/java/com/yizhuan/erban/skill/widget/RecordDurationItem.kt b/app/src/main/java/com/yizhuan/erban/skill/widget/RecordDurationItem.kt new file mode 100644 index 000000000..e377af1f6 --- /dev/null +++ b/app/src/main/java/com/yizhuan/erban/skill/widget/RecordDurationItem.kt @@ -0,0 +1,21 @@ +package com.yizhuan.erban.skill.widget + +import android.content.Context +import android.view.View +import android.view.ViewGroup +import android.widget.Space + +class RecordDurationItem(private val attr: ItemAttribute) : SkillItem { + override fun createItem(context: Context): View { + val view = Space(context) + val layoutParams = ViewGroup.LayoutParams(1, 1) + view.layoutParams = layoutParams + return view + } + + override fun invalidate() {} + + override fun isValid() = true + + override fun getContentEntity() = attr +} \ No newline at end of file diff --git a/app/src/main/java/com/yizhuan/erban/skill/widget/RecordIResourceItem.kt b/app/src/main/java/com/yizhuan/erban/skill/widget/RecordIResourceItem.kt new file mode 100644 index 000000000..7c2c45a54 --- /dev/null +++ b/app/src/main/java/com/yizhuan/erban/skill/widget/RecordIResourceItem.kt @@ -0,0 +1,201 @@ +package com.yizhuan.erban.skill.widget + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import com.netease.nimlib.sdk.media.record.RecordType +import com.yizhuan.erban.R +import com.yizhuan.erban.audio.helper.AudioPlayerHelper +import com.yizhuan.erban.audio.helper.OnPlayListener +import com.yizhuan.erban.databinding.LayoutSkillAudioBinding +import com.yizhuan.erban.ui.widget.dialog.CommonTipDialog +import com.yizhuan.xchat_android_core.utils.TextUtils +import com.yizhuan.xchat_android_core.utils.toast +import java.io.File + +class RecordIResourceItem(private val itemAttribute: ItemAttribute) : SkillItem, + TimerRecorderView.RecordListener, View.OnClickListener { + private lateinit var binding: LayoutSkillAudioBinding + private lateinit var context: Context + private var audioLength = 0 + private var playState = PLAY_STATE_READY + + + //重新录制 + private val reStartTipDialog by lazy { + CommonTipDialog(context).apply { + itemAttribute + setTipMsg( + if (itemAttribute.audioStatus == RECORD_STATE_JUDGE) + "您录制的声音正在审核中,确定要重新录制吗?" + else "确定要重新录制吗?" + ) + setCancelText("否") + setOkText("是") + setBold(true) + setTextSize(ScreenUtil.dip2px(16f)) + setOnActionListener(object : CommonTipDialog.OnActionListener { + override fun onCancel() {} + override fun onOk() { + if (AudioPlayerHelper.get().isPlaying) { + stopAudio() + } + binding.recordState = RECORD_STATE_READY + } + }) + } + } + + //删除录制 + private val deleteTipDialog by lazy { + CommonTipDialog(context).apply { + setTipMsg("确定要删除该声音吗?") + setCancelText("确定") + setBold(true) + setTextSize(ScreenUtil.dip2px(16f)) + setOkText("取消") + setOnActionListener(object : CommonTipDialog.OnActionListener { + override fun onCancel() { + if (AudioPlayerHelper.get().isPlaying) { + stopAudio() + } + itemAttribute.itemEventListener?.onDeleteRecordClick() + } + + override fun onOk() {} + }) + } + } + + 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.recordState = itemAttribute.audioStatus + itemAttribute.audioDuration?.let { binding.duration = it } + binding.btnCancel.text = if (itemAttribute.isSelf) "取消录制" else "取消重新录制" + + binding.click = this + } + + override fun invalidate() {} + + override fun isValid() = true + + override fun getContentEntity() = itemAttribute + + override fun onRecordTimeUpdate(remain: Int) { + audioLength = binding.recordView.recordDuration - remain + } + + override fun onRecordStart(file: File?, recordType: RecordType?) { + binding.recordState = RECORD_STATE_RECORDING + } + + override fun onRecordCancel() { + //审核通过后 重新录制取消 要设置为之前审核通过的状态 + binding.recordState = itemAttribute.audioStatus + } + + override fun onRecordSuccess(file: File?) { + if (audioLength < 3) { + "录制时间不能少于3s哦".toast() + binding.recordState = RECORD_STATE_READY + return + } + itemAttribute.itemEventListener?.onRecordSuccess(file, audioLength) + } + + override fun onRecordFail() { + "录制失败,请重试".toast() + setItemByState(RECORD_STATE_READY) + } + + + /** + * 根据状态设置View + */ + fun setItemByState(state: Int) { + binding.recordState = state + } + + private fun playAudio(url: String?) { + if (playState == PLAY_STATE_PLAYING || TextUtils.isEmptyText(url)) return + playState = PLAY_STATE_PLAYING + binding.palyState = playState + AudioPlayerHelper.get().playInThread(url, object : OnPlayListener { + override fun onError(error: String?) { + "播放出错,请重试".toast() + playState = PLAY_STATE_READY + binding.palyState = playState + } + + override fun onPrepared() {} + + override fun onPlaying(currDuration: Long) {} + + override fun onCompletion() { + playState = PLAY_STATE_READY + binding.palyState = playState + } + }) + } + + private fun stopAudio() { + if (playState == PLAY_STATE_READY) return + AudioPlayerHelper.get().endPlay() + playState = PLAY_STATE_READY + binding.palyState = playState + } + + + companion object { + //录制 + const val MAX_RECORD_DURATION = 15//最大录音时长 + const val RECORD_STATE_READY = 0//初态 即将录制 + const val RECORD_STATE_RECORDING = 5//正在录制 + const val RECORD_STATE_AGREE = 1//上传成功 审核通过 + const val RECORD_STATE_JUDGE = 2//上传成功 正在审核 + const val RECORD_STATE_REFUSE = 3//上传成功 审核不通过 + + //播放 + const val PLAY_STATE_PLAYING = 10 + const val PLAY_STATE_READY = 11//播放出错失败按完成处理,设置为初态 + } + + override fun onClick(v: View) { + when (v.id) { + R.id.btn_cancel -> { + binding.recordView.endAudioRecord(true) + } + R.id.tv_sound, R.id.iv_play -> { + if (playState == PLAY_STATE_READY) { + playAudio(itemAttribute.selectedProperties.getOrNull(0)?.propVal) + } else { + stopAudio() + } + } + R.id.btn_delete -> { + if (deleteTipDialog.isShowing) { + deleteTipDialog.dismiss() + } + deleteTipDialog.show() + } + + R.id.btn_restart -> { + if (reStartTipDialog.isShowing) { + reStartTipDialog.dismiss() + } + reStartTipDialog.show() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/yizhuan/erban/skill/widget/SelectionItem.kt b/app/src/main/java/com/yizhuan/erban/skill/widget/SelectionItem.kt index 5a58c55b7..85e710c36 100644 --- a/app/src/main/java/com/yizhuan/erban/skill/widget/SelectionItem.kt +++ b/app/src/main/java/com/yizhuan/erban/skill/widget/SelectionItem.kt @@ -1,37 +1,59 @@ package com.yizhuan.erban.skill.widget import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.widget.TextView +import androidx.constraintlayout.widget.ConstraintLayout import com.yizhuan.erban.R -import com.yizhuan.xchat_android_core.skill.entity.PropRecordVoEntity +import com.yizhuan.xchat_android_core.utils.TextUtils +import java.lang.StringBuilder -class SelectionItem( - private val isSelf: Boolean, - private val isEditable: Boolean, - private val selectionListener: OnItemSelectionListener?, - entity: PropRecordVoEntity, context: Context -) : - SkillItem(entity, context) { - init { +class SelectionItem(private val itemAttr: ItemAttribute) : SkillItem { + private lateinit var contentView: TextView + private lateinit var titleVIew: TextView + private lateinit var contentFrame: ConstraintLayout + override fun getContentEntity() = itemAttr + override fun createItem(context: Context): View { + val view = + LayoutInflater.from(context).inflate(R.layout.layout_skill_selection, null, false) + contentView = view.findViewById(R.id.edit_content) + titleVIew = view.findViewById(R.id.title_view) + contentFrame = view.findViewById(R.id.fl_content) initItem() + return view } - override fun getContentEntity() = entity + private fun initItem() { + if (!isContentEditable()) { + contentView.setCompoundDrawables(null, null, null, null) + } else { + contentFrame.setOnClickListener { + itemAttr.itemEventListener?.onItemClick(this) + } + } + SkillItemHelper.setTitleText(titleVIew, itemAttr.parentVol, itemAttr.isMust) + setContent() + } + + private fun setContent() { + val builder = StringBuilder() + itemAttr.selectedProperties.forEach { + if (!TextUtils.isEmptyText(it.propVal)) { + builder.append(it.propVal).append("、") + } + } + if (builder.isNotEmpty()) builder.deleteCharAt(builder.length - 1) + contentView.text = builder.toString() + builder.delete(0, builder.length) + } + + override fun invalidate() { + setContent() + } override fun isValid() = - entity.isMust == 0 || entity.propId != -1 + itemAttr.isMust == 0 || itemAttr.selectedProperties.isNotEmpty() - override fun getRightRes() = R.drawable.arrow_right - override fun isContentEditable() = false - override fun isRightVisitable() = isSelf && isEditable//需要优化代码 - - init { - getContentView().setOnClickListener { - selectionListener?.onItemSelection(this) - entity.propVal?.let { getContentView().setText(it) } - } - } - - interface OnItemSelectionListener { - fun onItemSelection(item: SkillItem) - } + private fun isContentEditable() = itemAttr.isSelf && itemAttr.editable } \ No newline at end of file diff --git a/app/src/main/java/com/yizhuan/erban/skill/widget/SkillAttribute.kt b/app/src/main/java/com/yizhuan/erban/skill/widget/SkillAttribute.kt new file mode 100644 index 000000000..e169b91c2 --- /dev/null +++ b/app/src/main/java/com/yizhuan/erban/skill/widget/SkillAttribute.kt @@ -0,0 +1,17 @@ +package com.yizhuan.erban.skill.widget + +const val CARD_TYPE_GAME = 1 +const val CARD_TYPE_ART = 2 +const val CARD_TYPE_AUDIO = 3 + +data class SkillAttribute( + val id: Int, + val type: Int, + val cardId: Int, + val skillRes: String?, + val skillName: String, + val isSelf: Boolean = false, + val isEdit: Boolean = false, + val background: String?, + val itemAttributes: List +) diff --git a/app/src/main/java/com/yizhuan/erban/skill/widget/SkillCardView.kt b/app/src/main/java/com/yizhuan/erban/skill/widget/SkillCardView.kt index 4fc1e1a56..c98caf149 100644 --- a/app/src/main/java/com/yizhuan/erban/skill/widget/SkillCardView.kt +++ b/app/src/main/java/com/yizhuan/erban/skill/widget/SkillCardView.kt @@ -10,10 +10,6 @@ import android.widget.LinearLayout import android.widget.TextView import androidx.annotation.Nullable import com.yizhuan.erban.R -import com.yizhuan.xchat_android_core.skill.entity.PropRecordVoEntity -import com.yizhuan.xchat_android_core.skill.entity.SKillValueEntity -import com.yizhuan.xchat_android_core.skill.entity.SkillPostServerEntity -import com.yizhuan.xchat_android_core.skill.entity.SkillRecordEntity import com.yizhuan.erban.ui.utils.ImageLoadUtils import com.yizhuan.erban.ui.utils.ImageLoadUtilsV2 import com.yizhuan.erban.ui.widget.magicindicator.buildins.UIUtil @@ -30,12 +26,11 @@ class SkillCardView( constructor(context: Context) : this(context, null) constructor(context: Context, @Nullable attrs: AttributeSet?) : this(context, attrs, 0) - private var itemList: ArrayList - private var rootEntity: SkillRecordEntity? = null + private var itemList: MutableList = emptyList().toMutableList() + private lateinit var skillAttr: SkillAttribute init { orientation = VERTICAL - itemList = ArrayList() } //标题 @@ -66,7 +61,7 @@ class SkillCardView( lineParams.leftMargin = lineMargin lineParams.rightMargin = lineMargin for ((index, item) in itemList.withIndex()) { - val itemView = item.createItem() + val itemView = item.createItem(context) addView(itemView, layoutParams) if (index != itemList.size - 1) { val lineView = View(context) @@ -76,18 +71,18 @@ class SkillCardView( } } - private fun createItemView( - isSelf: Boolean, - isEdit: Boolean, - selectionListener: SelectionItem.OnItemSelectionListener?, - entity: PropRecordVoEntity - ): SkillItem { - return when (entity.state) { - 1 -> EditItem(isSelf, isEdit, entity, context) - else -> SelectionItem(isSelf, isEdit,selectionListener, entity, context) + //根据state创建Item视图 + private fun createItemView(item: ItemAttribute): SkillItem { + return when (item.state) { + 1 -> EditItem(item) + 0, 2 -> SelectionItem(item) + 3 -> RecordIResourceItem(item) + else -> RecordDurationItem(item) } } + + //设置SkillView背景 private fun setBackgroundImg(url: String?) { if (TextUtils.isEmpty(url)) { return @@ -95,54 +90,35 @@ class SkillCardView( ImageLoadUtils.loadRoundBackground(context, url, this, 8, R.drawable.bg_corner_shadow_12) } - - fun setItems( - rootEntity: SkillRecordEntity, - selectionListener: SelectionItem.OnItemSelectionListener? - ) { - this.rootEntity = rootEntity - this.itemList.clear() - rootEntity.propRecordVo?.forEach { - this.itemList.add( - createItemView( - rootEntity.isSelf, - rootEntity.isEdit, - selectionListener, - it - ) - ) + fun initView(attr: SkillAttribute) { + this.skillAttr = attr + itemList.clear() + attr.itemAttributes.forEach { + this.itemList.add(createItemView(it)) } - setBackgroundImg(rootEntity.pic) + //暂时处理 + SkillItemHelper.wrapAudio(attr) + setBackgroundImg(attr.background) removeAllViews() - setSkillTitle(rootEntity.icon, rootEntity.name, rootEntity.isSelf, rootEntity.isEdit) + setSkillTitle(attr.skillRes, attr.skillName, attr.isSelf, attr.isEdit) setChildItems() requestLayout() } 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 = itemList - fun getSavedValues(): SkillPostServerEntity { - return if (rootEntity == null) { - SkillPostServerEntity(-1, -1, ArrayList(0)) - } else { - val list = ArrayList() - itemList.forEach { - val item = it.getContentEntity() - list.add(SKillValueEntity(item.parentId, item.propId, item.propVal)) - } - SkillPostServerEntity(rootEntity!!.id, rootEntity!!.cardId, list) - } - - } + fun getAttributes() = skillAttr } \ No newline at end of file diff --git a/app/src/main/java/com/yizhuan/erban/skill/widget/SkillItem.kt b/app/src/main/java/com/yizhuan/erban/skill/widget/SkillItem.kt index 2e4f17fd3..cddd20be0 100644 --- a/app/src/main/java/com/yizhuan/erban/skill/widget/SkillItem.kt +++ b/app/src/main/java/com/yizhuan/erban/skill/widget/SkillItem.kt @@ -1,98 +1,11 @@ package com.yizhuan.erban.skill.widget import android.content.Context -import android.graphics.Color -import android.graphics.drawable.Drawable -import android.text.SpannableStringBuilder -import android.text.style.ForegroundColorSpan -import android.view.LayoutInflater import android.view.View -import android.widget.EditText -import android.widget.TextView -import com.yizhuan.erban.R -import com.yizhuan.xchat_android_core.skill.entity.* -import com.yizhuan.erban.ui.widget.magicindicator.buildins.UIUtil - - abstract class SkillItem( - protected var entity: PropRecordVoEntity, - context: Context -) { - private var titleView: TextView - private var contentView: EditText - private var itemView: View = - LayoutInflater.from(context).inflate(R.layout.layout_skill_item, null, false) - private var rightDrawable: Drawable? = null - - init { - titleView = itemView.findViewById(R.id.title_view) - contentView = itemView.findViewById(R.id.edit_content) - contentView.compoundDrawablePadding = UIUtil.dip2px(context, 10.0) - if (getRightRes() != -1) { - rightDrawable = context.getDrawable(getRightRes()) - } - } - - protected fun initItem() { - if (isContentEditable()) { - enableEdit() - } else { - disableEdit() - } - entity.parentVal?.let { setTitleText(it) } - entity.propVal?.let { contentView.setText(it) } - - if (isContentEditable()) { - contentView.hint = "请输入" - } - if (isRightVisitable()) { - rightDrawable?.let { - it.setBounds(0, 0, it.minimumWidth, it.minimumHeight) - contentView.setCompoundDrawables(null, null, it, null) - } - } - } - - private fun setTitleText(title: String) { - if (entity.isMust == 0) { - titleView.text = title - return - } - val spannableStringBuilder = SpannableStringBuilder(title) - val length = spannableStringBuilder.length - spannableStringBuilder.append("*") - spannableStringBuilder.setSpan( - ForegroundColorSpan(Color.parseColor("#FF2222")), - length, - spannableStringBuilder.length, - SpannableStringBuilder.SPAN_INCLUSIVE_EXCLUSIVE - ) - titleView.text = spannableStringBuilder - } - - internal fun createItem(): View = itemView - internal fun invalidate() { - contentView.setText(getContentEntity().propVal ?: "") - } - - private fun disableEdit() { - contentView.isFocusableInTouchMode = false - contentView.isFocusable = false - contentView.isCursorVisible = false - } - - private fun enableEdit() { - contentView.isFocusableInTouchMode = true - contentView.isFocusable = true - contentView.isCursorVisible = true - } - - - internal abstract fun getContentEntity(): PropRecordVoEntity - internal abstract fun isValid(): Boolean - internal abstract fun getRightRes(): Int - internal abstract fun isContentEditable(): Boolean - internal abstract fun isRightVisitable(): Boolean - - protected fun getContentView(): EditText = contentView +interface SkillItem { + fun createItem(context: Context): View + fun invalidate() + fun isValid(): Boolean + fun getContentEntity(): ItemAttribute } \ No newline at end of file diff --git a/app/src/main/java/com/yizhuan/erban/skill/widget/SkillItemHelper.kt b/app/src/main/java/com/yizhuan/erban/skill/widget/SkillItemHelper.kt new file mode 100644 index 000000000..e1ae450b5 --- /dev/null +++ b/app/src/main/java/com/yizhuan/erban/skill/widget/SkillItemHelper.kt @@ -0,0 +1,58 @@ +package com.yizhuan.erban.skill.widget + +import android.graphics.Color +import android.text.SpannableStringBuilder +import android.text.style.ForegroundColorSpan +import android.widget.EditText +import android.widget.TextView +import com.yizhuan.erban.skill.widget.ItemAttribute.Companion.STATE_AUDIO +import com.yizhuan.erban.skill.widget.ItemAttribute.Companion.STATE_DURATION + +object SkillItemHelper { + /** + * 设置Item标题 + */ + fun setTitleText(titleView: TextView, title: String, isMust: Int) { + if (isMust == 0) { + titleView.text = title + return + } + val spannableStringBuilder = SpannableStringBuilder(title) + val length = spannableStringBuilder.length + spannableStringBuilder.append("*") + spannableStringBuilder.setSpan( + ForegroundColorSpan(Color.parseColor("#FF2222")), + length, + spannableStringBuilder.length, + SpannableStringBuilder.SPAN_INCLUSIVE_EXCLUSIVE + ) + titleView.text = spannableStringBuilder + } + + /** + * 禁用EditText编辑 + */ + + fun disableEdit(contentView: EditText) { + contentView.isFocusableInTouchMode = false + contentView.isFocusable = false + contentView.isCursorVisible = false + } + + /** + * 启用EditText编辑 + */ + fun enableEdit(contentView: EditText) { + contentView.isFocusableInTouchMode = true + contentView.isFocusable = true + contentView.isCursorVisible = true + } + + fun wrapAudio(attr: SkillAttribute) { + if (attr.type == CARD_TYPE_AUDIO) { + val sourceItem = attr.itemAttributes.find { it.state == STATE_AUDIO } + val durationItem = attr.itemAttributes.find { it.state == STATE_DURATION } + sourceItem?.audioDuration = durationItem?.selectedProperties?.getOrNull(0)?.propVal + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/yizhuan/erban/skill/widget/TimerRecorderView.kt b/app/src/main/java/com/yizhuan/erban/skill/widget/TimerRecorderView.kt new file mode 100644 index 000000000..817045aad --- /dev/null +++ b/app/src/main/java/com/yizhuan/erban/skill/widget/TimerRecorderView.kt @@ -0,0 +1,180 @@ +package com.yizhuan.erban.skill.widget + +import android.animation.ValueAnimator +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.RectF +import android.util.AttributeSet +import android.view.animation.LinearInterpolator +import androidx.annotation.Nullable +import androidx.appcompat.widget.AppCompatImageView +import com.netease.nim.uikit.impl.NimUIKitImpl +import com.netease.nimlib.sdk.media.record.AudioRecorder +import com.netease.nimlib.sdk.media.record.IAudioRecordCallback +import com.netease.nimlib.sdk.media.record.RecordType +import com.yizhuan.erban.R +import java.io.File + +private const val STATE_PAUSED = 0 +private const val STATE_PLAYED = 1 + +class TimerRecorderView(context: Context, @Nullable attrs: AttributeSet?, defStyleAttr: Int) : + AppCompatImageView(context, attrs, defStyleAttr), IAudioRecordCallback { + + private var progressWidth = 0 + private var outerWidth = 0 + private var progressColor = 0 + private val progressPaint by lazy { + Paint(Paint.ANTI_ALIAS_FLAG) + } + private var state = STATE_PAUSED + private var animator: ValueAnimator? = null + private var animatedPercent = 0f + internal var recordDuration = 15 + private var audioMessageHelper: AudioRecorder? = null + + var recordListener: RecordListener? = null + + constructor(context: Context) : this(context, null) + + constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) { + val array = context.obtainStyledAttributes(attrs, R.styleable.TimerRecorderView) + progressWidth = array.getDimension(R.styleable.TimerRecorderView_progressWidth, 0f).toInt() + outerWidth = array.getDimension(R.styleable.TimerRecorderView_outerWidth, 0f).toInt() + progressColor = array.getColor(R.styleable.TimerRecorderView_progressColor, 0).toInt() + progressPaint.style = Paint.Style.STROKE + progressPaint.strokeWidth = progressWidth.toFloat() + progressPaint.color = progressColor + array.recycle() + setOnClickListener { + when (state) { + STATE_PAUSED -> { + startRecord() + } + STATE_PLAYED -> { + endAudioRecord(false) + } + } + } + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + val width = MeasureSpec.getSize(widthMeasureSpec) + val height = MeasureSpec.getSize(heightMeasureSpec) + setMeasuredDimension(width, height) + } + + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + if (state == STATE_PLAYED) { + val rectF = RectF() + val swipe = animatedPercent * 360 + rectF.left = outerWidth.toFloat() + rectF.top = outerWidth.toFloat() + rectF.right = measuredWidth.toFloat() - outerWidth + rectF.bottom = measuredHeight.toFloat() - outerWidth + canvas.drawArc(rectF, -90f, swipe, false, progressPaint) + } + } + + + //开始录制 + private fun startRecord() { + if (audioMessageHelper == null) { + val options = NimUIKitImpl.getOptions() + options.audioRecordMaxTime = recordDuration + audioMessageHelper = AudioRecorder( + context, options.audioRecordType, + options.audioRecordMaxTime, this + ) + } + setImageResource(R.drawable.ic_skill_audio_recording) + audioMessageHelper!!.startRecord() + } + + /** + * 结束语音录制 + * + * @param cancel -- true 取消 重新录制 false 录制完成 + */ + fun endAudioRecord(cancel: Boolean) { + state = STATE_PAUSED + audioMessageHelper?.completeRecord(cancel) + setImageResource(R.drawable.ic_skill_audio_ready) + clearRecordAnim() + } + + + private fun playRecordAnim() { + animator = ValueAnimator.ofFloat(0f, 360f) + ?.apply { + duration = (recordDuration * 1000).toLong() + addUpdateListener { + animatedPercent = it.animatedFraction + recordListener?.onRecordTimeUpdate((recordDuration * (1 - animatedPercent)).toInt()) + invalidate() + } + interpolator = LinearInterpolator() + start() + } + } + + + private fun clearRecordAnim() { + animator?.let { + it.removeAllUpdateListeners() + if (it.isRunning) it.end() + } + animator = null + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + clearRecordAnim() + audioMessageHelper?.destroyAudioRecorder() + } + + override fun onRecordReady() {} + + override fun onRecordStart(audioFile: File?, recordType: RecordType?) { + state = STATE_PLAYED + playRecordAnim() + recordListener?.onRecordStart(audioFile, recordType) + } + + override fun onRecordSuccess(audioFile: File?, audioLength: Long, recordType: RecordType?) { + state = STATE_PAUSED + clearRecordAnim() + recordListener?.onRecordSuccess(audioFile) + } + + override fun onRecordFail() { + state = STATE_PAUSED + recordListener?.onRecordFail() + clearRecordAnim() + } + + override fun onRecordCancel() { + state = STATE_PAUSED + recordListener?.onRecordCancel() + clearRecordAnim() + } + + override fun onRecordReachedMaxTime(maxTime: Int) { + state = STATE_PAUSED + clearRecordAnim() + audioMessageHelper?.handleEndRecord(true, maxTime) + } + + interface RecordListener { + fun onRecordTimeUpdate(remain: Int) + fun onRecordStart(file: File?, recordType: RecordType?) + fun onRecordCancel() + fun onRecordSuccess(file: File?) + fun onRecordFail() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/yizhuan/erban/ui/im/chat/MsgViewHolderSkill.java b/app/src/main/java/com/yizhuan/erban/ui/im/chat/MsgViewHolderSkill.java new file mode 100644 index 000000000..63a4b385d --- /dev/null +++ b/app/src/main/java/com/yizhuan/erban/ui/im/chat/MsgViewHolderSkill.java @@ -0,0 +1,53 @@ +package com.yizhuan.erban.ui.im.chat; +import android.widget.TextView; + +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; +import com.netease.nimlib.sdk.msg.attachment.MsgAttachment; +import com.yizhuan.erban.R; +import com.yizhuan.xchat_android_core.im.custom.bean.SkillMsgAttachment; +import com.yizhuan.xchat_android_core.skill.entity.SkillNotifyEntity; + +/** + *

文字消息holder

+ * + * @author jiahui + * @date 2018/1/10 + */ +public class MsgViewHolderSkill extends MsgViewHolderBase { + private TextView mTvTitle; + private TextView mTvContent; + private SkillMsgAttachment matchAttachment; + + public MsgViewHolderSkill(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + + @Override + protected int getContentResId() { + return R.layout.layout_msg_view_holder_skill; + } + + @Override + protected void inflateContentView() { + mTvTitle = findViewById(R.id.tv_title); + mTvContent = findViewById(R.id.tv_content); + } + + @Override + protected void bindContentView() { + CharSequence title = ""; + CharSequence content = ""; + MsgAttachment attachment = message.getAttachment(); + if (attachment instanceof SkillMsgAttachment) { + matchAttachment = (SkillMsgAttachment) attachment; + SkillNotifyEntity entity = matchAttachment.getEntity(); + title = entity.getLayout().getTitle().getContent(); + if (!entity.getLayout().getContents().isEmpty()) { + content = entity.getLayout().getContents().get(0).getContent(); + } + } + mTvTitle.setText(title); + mTvContent.setText(content); + } +} diff --git a/app/src/main/java/com/yizhuan/erban/ui/user/view/UserInfoInfoFragment.kt b/app/src/main/java/com/yizhuan/erban/ui/user/view/UserInfoInfoFragment.kt index 5f3bf2776..c7da8090f 100644 --- a/app/src/main/java/com/yizhuan/erban/ui/user/view/UserInfoInfoFragment.kt +++ b/app/src/main/java/com/yizhuan/erban/ui/user/view/UserInfoInfoFragment.kt @@ -17,6 +17,8 @@ import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView.ItemDecoration import com.netease.nim.uikit.support.glide.GlideApp import com.yizhuan.erban.R +import com.yizhuan.erban.audio.helper.AudioPlayerHelper +import com.yizhuan.erban.audio.helper.OnPlayListener import com.yizhuan.erban.base.BaseViewBindingFragment import com.yizhuan.erban.databinding.FragmentUserinfoUserinfoBinding import com.yizhuan.erban.module_hall.HallDataManager @@ -30,6 +32,7 @@ import com.yizhuan.erban.ui.user.adapter.GiftAdapter import com.yizhuan.erban.ui.user.adapter.SkillCardAdapter import com.yizhuan.erban.ui.user.decorationsend.UserInfoSkillDecoration import com.yizhuan.erban.ui.user.viewmodel.UserInfoViewModel +import com.yizhuan.erban.ui.utils.ImageLoadUtilsV2 import com.yizhuan.erban.ui.widget.magicindicator.buildins.UIUtil import com.yizhuan.xchat_android_core.auth.AuthModel import com.yizhuan.xchat_android_core.module_hall.hall.HallModel @@ -40,6 +43,7 @@ import com.yizhuan.xchat_android_core.user.bean.UserDetailInfo.DataBean.UserGift import com.yizhuan.xchat_android_core.user.bean.UserInfoSkillEntity import com.yizhuan.xchat_android_core.utils.net.BeanObserver import com.yizhuan.xchat_android_core.utils.net.RxHelper +import com.yizhuan.xchat_android_core.utils.toast import com.yizhuan.xchat_android_library.annatation.ActLayoutRes @@ -50,6 +54,7 @@ class UserInfoInfoFragment : BaseViewBindingFragment) { + val audio = list.find { it.cardId == 8 } + var newList: MutableList = list.toMutableList() + if (audio != null) { + binding.llAudio.visibility = View.VISIBLE + ImageLoadUtilsV2.loadImage(binding.ivAudioIcon, audio?.icon) + audio?.name?.let { binding.tvAudioName.text = it } + binding.livUser.stop() + binding.llAudio.setOnClickListener { toggleAudio(audio.propVals) } + newList.remove(audio) + if (newList.isEmpty()) {//只有声音秀 + binding.recyclerSkill.visibility = View.GONE + return + } + } else { + binding.llAudio.visibility = View.GONE + } if (skillAdapter == null) { skillAdapter = SkillCardAdapter(mContext) skillAdapter?.setHeaderAndEmpty(true) @@ -153,12 +174,10 @@ class UserInfoInfoFragment : BaseViewBindingFragment) { + val url = list.find { it.contains("http") } ?: return + if (!audioPlaying) { + playAudio(url) + } else { + stopAudio() + } + } + + private fun playAudio(url: String) { + if (audioPlaying) return + audioPlaying = true + binding.livUser.start() + binding.ivAudioControl.setImageResource(R.drawable.ic_skill_play) + AudioPlayerHelper.get().playInThread(url, object : OnPlayListener { + override fun onError(error: String?) { + "播放出错,请重试".toast() + stopAudio() + } + + override fun onPrepared() {} + + override fun onPlaying(currDuration: Long) {} + + override fun onCompletion() { + stopAudio() + } + }) + } + + private fun stopAudio() { + if (!audioPlaying) return + audioPlaying = false + binding.livUser.stop() + binding.ivAudioControl.setImageResource(R.drawable.ic_skill_pause) + AudioPlayerHelper.get().endPlay() + } } \ No newline at end of file diff --git a/app/src/main/java/com/yizhuan/erban/ui/widget/LivingIconView.java b/app/src/main/java/com/yizhuan/erban/ui/widget/LivingIconView.java index aed5a7414..180b002a5 100644 --- a/app/src/main/java/com/yizhuan/erban/ui/widget/LivingIconView.java +++ b/app/src/main/java/com/yizhuan/erban/ui/widget/LivingIconView.java @@ -26,22 +26,26 @@ public class LivingIconView extends AppCompatImageView { private AnimationDrawable drawable; private int drawableId; + private int dpWidth = 0; + private int dpHeight = 0; public LivingIconView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); + int dp_9 = UIUtil.dip2px(context, 9); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LivingIconView); drawableId = a.getResourceId(R.styleable.LivingIconView_cus_drawable, R.drawable.living_icon_animation); + dpWidth = (int) a.getDimension(R.styleable.LivingIconView_cus_dp_width, dp_9); + dpHeight = (int) a.getDimension(R.styleable.LivingIconView_cus_dp_height, dp_9); a.recycle(); init(context); } - private void init(Context context){ + private void init(Context context) { drawable = (AnimationDrawable) context.getResources().getDrawable(drawableId); drawable.setOneShot(false); setScaleType(ScaleType.FIT_CENTER); setImageDrawable(drawable); - int dp_9 = UIUtil.dip2px(context, 9); - setLayoutParams(new ViewGroup.LayoutParams(dp_9, dp_9)); + setLayoutParams(new ViewGroup.LayoutParams(dpWidth, dpHeight)); } public void setColor(int color) { diff --git a/app/src/main/java/com/yizhuan/erban/ui/widget/dialog/CommonTipDialog.java b/app/src/main/java/com/yizhuan/erban/ui/widget/dialog/CommonTipDialog.java index 87460de64..0359675ac 100644 --- a/app/src/main/java/com/yizhuan/erban/ui/widget/dialog/CommonTipDialog.java +++ b/app/src/main/java/com/yizhuan/erban/ui/widget/dialog/CommonTipDialog.java @@ -1,10 +1,17 @@ package com.yizhuan.erban.ui.widget.dialog; +import static android.graphics.Typeface.BOLD; + import android.content.Context; import android.os.Bundle; -import android.view.Window; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.style.AbsoluteSizeSpan; +import android.text.style.StyleSpan; import android.widget.TextView; +import androidx.annotation.ColorRes; + import com.yizhuan.erban.R; import com.yizhuan.xchat_android_core.utils.TextUtils; @@ -18,6 +25,10 @@ public class CommonTipDialog extends BaseDialog { private String okText = "确定"; private String cancelText = "取消"; + private boolean isBold; + private @ColorRes + int color = -1; + private int textSize = -1; public CommonTipDialog(Context context) { super(context, R.style.dialog); @@ -36,7 +47,19 @@ public class CommonTipDialog extends BaseDialog { TextView tip = findViewById(R.id.message); tip.setText(tipMsg); - + if (color != -1) { + tip.setTextColor(getContext().getResources().getColor(color)); + } + SpannableStringBuilder builder = new SpannableStringBuilder(tipMsg); + if (textSize != -1) { + AbsoluteSizeSpan sizeSpan = new AbsoluteSizeSpan(textSize); + builder.setSpan(sizeSpan, 0, builder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); + } + if (isBold) { + StyleSpan boldSpan = new StyleSpan(BOLD); + builder.setSpan(boldSpan, 0, builder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); + } + tip.setText(builder); TextView ok = findViewById(R.id.btn_ok); ok.setText(okText); ok.setOnClickListener(v -> { @@ -59,6 +82,18 @@ public class CommonTipDialog extends BaseDialog { this.tipMsg = tipMsg; } + public void setBold(boolean isBold) { + this.isBold = isBold; + } + + public void setTextColor(@ColorRes int color) { + this.color = color; + } + + public void setTextSize(int textSize) { + this.textSize = textSize; + } + private OnActionListener l; public void setOkText(String okText) { diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_01.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_01.png new file mode 100644 index 000000000..30b472783 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_01.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_02.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_02.png new file mode 100644 index 000000000..ca0865b67 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_02.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_03.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_03.png new file mode 100644 index 000000000..640fae6be Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_03.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_04.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_04.png new file mode 100644 index 000000000..e346360e0 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_04.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_05.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_05.png new file mode 100644 index 000000000..9ff4da6a4 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_05.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_06.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_06.png new file mode 100644 index 000000000..5357d2f59 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_06.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_07.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_07.png new file mode 100644 index 000000000..04b534e03 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_07.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_08.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_08.png new file mode 100644 index 000000000..9771ec4a7 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_08.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_09.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_09.png new file mode 100644 index 000000000..6f0706308 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_09.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_10.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_10.png new file mode 100644 index 000000000..d1afaf2bd Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_10.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_11.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_11.png new file mode 100644 index 000000000..5e0f5a194 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_11.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_12.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_12.png new file mode 100644 index 000000000..f64b52166 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_12.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_13.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_13.png new file mode 100644 index 000000000..1cbb494fa Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_13.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_14.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_14.png new file mode 100644 index 000000000..673436f8d Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_14.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_15.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_15.png new file mode 100644 index 000000000..b79541013 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_15.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_16.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_16.png new file mode 100644 index 000000000..9f21de4a4 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_16.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_17.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_17.png new file mode 100644 index 000000000..bac0616a7 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_17.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_18.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_18.png new file mode 100644 index 000000000..88b35560d Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_18.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_19.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_19.png new file mode 100644 index 000000000..a97ba2789 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_19.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_20.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_20.png new file mode 100644 index 000000000..38c3a886a Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_20.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_21.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_21.png new file mode 100644 index 000000000..a7b63d355 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_21.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_22.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_22.png new file mode 100644 index 000000000..25009594f Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_22.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_23.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_23.png new file mode 100644 index 000000000..d4a00a17c Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_23.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_24.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_24.png new file mode 100644 index 000000000..4e2107168 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_24.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_25.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_25.png new file mode 100644 index 000000000..5fbdd8cc4 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_25.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_26.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_26.png new file mode 100644 index 000000000..bfc2b9711 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_26.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_27.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_27.png new file mode 100644 index 000000000..c86e69ebc Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_27.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_28.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_28.png new file mode 100644 index 000000000..852ad4abf Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_28.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_29.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_29.png new file mode 100644 index 000000000..45cec89d6 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_29.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_30.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_30.png new file mode 100644 index 000000000..19b669b0a Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_30.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_31.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_31.png new file mode 100644 index 000000000..857cd0de7 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_31.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_32.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_32.png new file mode 100644 index 000000000..f866e3a45 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_32.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_33.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_33.png new file mode 100644 index 000000000..019c0bb27 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_33.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_34.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_34.png new file mode 100644 index 000000000..55d40e013 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_34.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_35.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_35.png new file mode 100644 index 000000000..3061d2505 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_35.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_36.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_36.png new file mode 100644 index 000000000..a3fef5235 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_36.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_37.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_37.png new file mode 100644 index 000000000..f6b7576e2 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_37.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_38.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_38.png new file mode 100644 index 000000000..a2b730cbd Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_38.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_39.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_39.png new file mode 100644 index 000000000..c84698e93 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_39.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_40.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_40.png new file mode 100644 index 000000000..d3ea3b06c Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_anim_40.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_ready.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_ready.png new file mode 100644 index 000000000..c795740ac Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_ready.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_audio_recording.png b/app/src/main/res/drawable-xhdpi/ic_skill_audio_recording.png new file mode 100644 index 000000000..5ceac450f Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_audio_recording.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_pause.png b/app/src/main/res/drawable-xhdpi/ic_skill_pause.png new file mode 100644 index 000000000..ee83e51ed Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_pause.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_skill_play.png b/app/src/main/res/drawable-xhdpi/ic_skill_play.png new file mode 100644 index 000000000..fecd3a5b8 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_skill_play.png differ diff --git a/app/src/main/res/drawable-xhdpi/icon_skill_edit.png b/app/src/main/res/drawable-xhdpi/icon_skill_edit.png new file mode 100644 index 000000000..d0fd08562 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/icon_skill_edit.png differ diff --git a/app/src/main/res/drawable/bg_ffce4e_trans30_20dp.xml b/app/src/main/res/drawable/bg_ffce4e_trans30_20dp.xml new file mode 100644 index 000000000..740b09d61 --- /dev/null +++ b/app/src/main/res/drawable/bg_ffce4e_trans30_20dp.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_round_ffbc51_8.xml b/app/src/main/res/drawable/bg_round_ffbc51_8.xml index 0c603ede1..20ba8ce65 100644 --- a/app/src/main/res/drawable/bg_round_ffbc51_8.xml +++ b/app/src/main/res/drawable/bg_round_ffbc51_8.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_skill_record_sound.xml b/app/src/main/res/drawable/bg_skill_record_sound.xml new file mode 100644 index 000000000..286936091 --- /dev/null +++ b/app/src/main/res/drawable/bg_skill_record_sound.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_userinfo_skill_audio.xml b/app/src/main/res/drawable/bg_userinfo_skill_audio.xml new file mode 100644 index 000000000..01f5f9bec --- /dev/null +++ b/app/src/main/res/drawable/bg_userinfo_skill_audio.xml @@ -0,0 +1,16 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/skill_audio_animation.xml b/app/src/main/res/drawable/skill_audio_animation.xml new file mode 100644 index 000000000..c5a646222 --- /dev/null +++ b/app/src/main/res/drawable/skill_audio_animation.xml @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_add_skill_item.xml b/app/src/main/res/layout/dialog_add_skill_item.xml index 6884bfae4..3457dce18 100644 --- a/app/src/main/res/layout/dialog_add_skill_item.xml +++ b/app/src/main/res/layout/dialog_add_skill_item.xml @@ -20,16 +20,31 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + + - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_userinfo_userinfo.xml b/app/src/main/res/layout/fragment_userinfo_userinfo.xml index 93768fc06..c996138e6 100644 --- a/app/src/main/res/layout/fragment_userinfo_userinfo.xml +++ b/app/src/main/res/layout/fragment_userinfo_userinfo.xml @@ -281,6 +281,52 @@ android:textColor="@color/color_333333" android:textSize="@dimen/sp_14" /> + + + + + + + + + + + + + + app:layout_constraintTop_toBottomOf="@id/ll_skill" + app:layout_constraintVertical_bias="0"> + android:paddingBottom="@dimen/dp_8"> + app:layout_constraintRight_toRightOf="parent" + tools:text="盟手游英雄联盟手游" /> \ No newline at end of file diff --git a/app/src/main/res/layout/layout_msg_view_holder_skill.xml b/app/src/main/res/layout/layout_msg_view_holder_skill.xml new file mode 100644 index 000000000..27610b522 --- /dev/null +++ b/app/src/main/res/layout/layout_msg_view_holder_skill.xml @@ -0,0 +1,29 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_ok_cancel_dialog.xml b/app/src/main/res/layout/layout_ok_cancel_dialog.xml index b9a42deb0..1fc947b62 100644 --- a/app/src/main/res/layout/layout_ok_cancel_dialog.xml +++ b/app/src/main/res/layout/layout_ok_cancel_dialog.xml @@ -5,8 +5,9 @@ android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:background="@drawable/shape_white_20dp_round" - tools:background="@color/black_transparent_10" - android:orientation="vertical"> + android:orientation="vertical" + tools:background="@color/black_transparent_10"> + @@ -15,19 +16,20 @@ android:id="@+id/message" android:layout_width="match_parent" android:layout_height="0dp" + android:layout_marginBottom="@dimen/dp_32" android:layout_weight="1" android:gravity="center" - android:paddingEnd="20dp" + android:lineSpacingMultiplier="1.2" android:paddingStart="20dp" + android:paddingEnd="20dp" android:textColor="@color/color_333333" android:textSize="14sp" - android:layout_marginBottom="@dimen/dp_32" tools:text="购买成功,是否立即驾驶sd水电费水电费?sfasdfasdfasdfasdfasdf" /> @@ -35,21 +37,21 @@ android:id="@+id/btn_cancel" android:layout_width="120dp" android:layout_height="38dp" + android:layout_marginEnd="@dimen/dp_16" + android:background="@drawable/bg_common_cancel" android:gravity="center" android:text="@string/cancel" android:textColor="@color/color_7154EE" - android:layout_marginEnd="@dimen/dp_16" - android:background="@drawable/bg_common_cancel" android:textSize="15sp" /> diff --git a/app/src/main/res/layout/layout_skill_audio.xml b/app/src/main/res/layout/layout_skill_audio.xml new file mode 100644 index 000000000..0ad9cf010 --- /dev/null +++ b/app/src/main/res/layout/layout_skill_audio.xml @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +