[8.0.0]
[fea] [距离目的地500m 提示]
This commit is contained in:
@@ -21,6 +21,7 @@ import com.mogo.och.unmanned.passenger.bean.TaxiPassengerOrdersInServiceQueryRes
|
||||
import com.mogo.och.unmanned.passenger.callback.IOCHTaxiPassengerOrderStatusCallback
|
||||
import com.mogo.och.unmanned.passenger.model.TaxiPassengerModel
|
||||
import com.mogo.och.unmanned.passenger.ui.TaxiPassengerBaseFragment
|
||||
import com.mogo.och.unmanned.passenger.ui.aiview.AIMessageManager
|
||||
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
@@ -129,6 +130,7 @@ class BaseTaxiPassengerPresenter(view: TaxiPassengerBaseFragment?) :
|
||||
|
||||
mView?.showOrHideArrivedEndLayout(false)
|
||||
overMapViewClear()
|
||||
AIMessageManager.clearData()
|
||||
}
|
||||
|
||||
TaxiOrderStatusEnum.Cancel -> {
|
||||
|
||||
@@ -23,6 +23,8 @@ import com.mogo.och.common.module.utils.RxUtils
|
||||
import com.mogo.och.common.module.voice.VoiceNotice
|
||||
import com.mogo.och.unmanned.taxi.passenger.R
|
||||
import com.mogo.och.unmanned.passenger.presenter.BaseTaxiPassengerPresenter
|
||||
import com.mogo.och.unmanned.passenger.ui.aiview.AIMessageManager
|
||||
import com.mogo.och.unmanned.passenger.ui.aiview.bean.AIMessage
|
||||
import com.mogo.och.unmanned.passenger.ui.arrived.ArrivedView
|
||||
import com.mogo.och.unmanned.passenger.ui.bar.LeftBarView
|
||||
import com.mogo.och.unmanned.passenger.ui.bottom.BottomBar
|
||||
@@ -336,7 +338,11 @@ class TaxiPassengerBaseFragment :
|
||||
showOrHide(true,"Debug 按钮")
|
||||
}
|
||||
override fun setEvaluateView(){
|
||||
|
||||
val automaticExploration = AIMessage.EvaluateData(System.currentTimeMillis().toString(),"",true)
|
||||
AIMessageManager.post(automaticExploration)
|
||||
RxUtils.createSubscribe {
|
||||
AIMessageManager.clearData()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,6 +42,12 @@ object AIMessageManager {
|
||||
}
|
||||
}
|
||||
|
||||
fun clearData(){
|
||||
messageListeners.forEach { callback ->
|
||||
callback.clear()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息监听器接口。
|
||||
*/
|
||||
@@ -52,5 +58,7 @@ object AIMessageManager {
|
||||
* @param msg 接收到的消息。
|
||||
*/
|
||||
fun onReceive(msg: AIMessage)
|
||||
|
||||
fun clear()
|
||||
}
|
||||
}
|
||||
@@ -63,9 +63,9 @@ class AIViewModel : ViewModel(), AIMessageManager.AIMessageListener, IWakeUpList
|
||||
"你说",
|
||||
)
|
||||
|
||||
private val orderListener = object : OrderListener{
|
||||
private val orderListener = object : OrderListener {
|
||||
override fun onCurrentOrderStatusChanged(order: BaseOrderBean?) {
|
||||
if(order?.orderStatus== TaxiOrderStatusEnum.ArriveAtEnd.code){
|
||||
if (order?.orderStatus == TaxiOrderStatusEnum.ArriveAtEnd.code) {
|
||||
synchronized(msgList) {
|
||||
msgList.clear()
|
||||
_messagesFlow.value = msgList.toList()
|
||||
@@ -74,16 +74,16 @@ class AIViewModel : ViewModel(), AIMessageManager.AIMessageListener, IWakeUpList
|
||||
}
|
||||
}
|
||||
|
||||
private val locationCallback = object : IMoGoChassisLocationGCJ02Listener{
|
||||
private val locationCallback = object : IMoGoChassisLocationGCJ02Listener {
|
||||
override fun onChassisLocationGCJ02(mogoLocation: MogoLocation?) {
|
||||
mogoLocation?.let {
|
||||
V2XRepository.provideLocation(it,0)
|
||||
V2XRepository.provideLocation(it, 0)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private val wakeUpListener = object :WakeUpListener{
|
||||
private val wakeUpListener = object : WakeUpListener {
|
||||
override fun wakeupSuccess() {
|
||||
onWakeUp()
|
||||
WakeUpManager.stopWakeup()
|
||||
@@ -96,8 +96,8 @@ class AIViewModel : ViewModel(), AIMessageManager.AIMessageListener, IWakeUpList
|
||||
}
|
||||
|
||||
fun setViewCallback(aiView: AiViewCallback) {
|
||||
OrderModel.setOrderStatusCallback(TAG,orderListener)
|
||||
OchLocationManager.addGCJ02Listener(TAG,1,locationCallback)
|
||||
OrderModel.setOrderStatusCallback(TAG, orderListener)
|
||||
OchLocationManager.addGCJ02Listener(TAG, 1, locationCallback)
|
||||
AIMessageManager.registerListener(this)
|
||||
WakeUpManager.setWakeUpListener(wakeUpListener)
|
||||
mgSpeech.weakUpListener = this
|
||||
@@ -137,7 +137,7 @@ class AIViewModel : ViewModel(), AIMessageManager.AIMessageListener, IWakeUpList
|
||||
WakeUpManager.setWakeUpListener(null)
|
||||
mgSpeech.stopWeakUp()
|
||||
llmResultJob?.cancel()
|
||||
OrderModel.setOrderStatusCallback(TAG,null)
|
||||
OrderModel.setOrderStatusCallback(TAG, null)
|
||||
OchLocationManager.removeGCJ02Listener(TAG)
|
||||
super.onCleared()
|
||||
}
|
||||
@@ -154,6 +154,10 @@ class AIViewModel : ViewModel(), AIMessageManager.AIMessageListener, IWakeUpList
|
||||
updateMsg(msg)
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
clearMsg()
|
||||
}
|
||||
|
||||
private fun handleMsg(newMessage: AIMessage) {
|
||||
val existingIndex = findMessageIndex(newMessage.id)
|
||||
if (existingIndex != -1) {
|
||||
@@ -169,14 +173,14 @@ class AIViewModel : ViewModel(), AIMessageManager.AIMessageListener, IWakeUpList
|
||||
|
||||
private fun handleExistingMessage(index: Int, newMessage: AIMessage) {
|
||||
val oldMessage = msgList[index]
|
||||
|
||||
|
||||
if (shouldSkipUpdate(oldMessage, newMessage)) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
newMessage.showTimestamp = oldMessage.showTimestamp
|
||||
msgList[index] = newMessage
|
||||
|
||||
|
||||
speakMessageIfNeeded(newMessage, isLastMessage = msgList.last() == newMessage)
|
||||
}
|
||||
|
||||
@@ -310,6 +314,13 @@ class AIViewModel : ViewModel(), AIMessageManager.AIMessageListener, IWakeUpList
|
||||
}
|
||||
}
|
||||
|
||||
private fun clearMsg() {
|
||||
synchronized(msgList) {
|
||||
msgList.clear()
|
||||
_messagesFlow.value = msgList.toList()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun getQuestionsRandomIndex(): Int {
|
||||
return tipsQuestions.indexOf(tipsQuestions.random())
|
||||
|
||||
@@ -2,12 +2,17 @@ package com.mogo.och.unmanned.passenger.ui.aiview
|
||||
|
||||
import android.os.CountDownTimer
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.mogo.commons.storage.SharedPrefsMgr
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxBean
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxType
|
||||
import com.mogo.eagle.core.data.msgbox.MsgCategory
|
||||
import com.mogo.eagle.core.function.api.datacenter.msgbox.IMsgBoxListener
|
||||
import com.mogo.eagle.core.function.call.msgbox.CallerMsgBoxListenerManager
|
||||
import com.mogo.eagle.core.utilcode.util.StringUtils
|
||||
import com.mogo.eagle.core.utilcode.util.ThreadUtils
|
||||
import com.mogo.eagle.core.utilcode.util.UiThreadHandler
|
||||
import com.mogo.och.bridge.distance.IDistanceListener
|
||||
import com.mogo.och.bridge.distance.TrajectoryAndDistanceManager
|
||||
import com.mogo.och.data.taxi.BaseOrderBean
|
||||
import com.mogo.och.data.taxi.TaxiOrderStatusEnum
|
||||
import com.mogo.och.unmanned.passenger.ui.aiview.bean.AIMessage
|
||||
@@ -17,7 +22,8 @@ import com.mogo.och.unmanned.taxi.utils.order.OrderModel
|
||||
/**
|
||||
* 自动探查
|
||||
*/
|
||||
class AutomaticExplorationViewModel: ViewModel(), OrderListener, IMsgBoxListener {
|
||||
class AutomaticExplorationViewModel: ViewModel(), OrderListener, IMsgBoxListener,
|
||||
IDistanceListener {
|
||||
|
||||
companion object{
|
||||
private const val TAG = "AutomaticExplorationViewModel"
|
||||
@@ -31,6 +37,7 @@ class AutomaticExplorationViewModel: ViewModel(), OrderListener, IMsgBoxListener
|
||||
fun init(){
|
||||
OrderModel.setOrderStatusCallback(TAG,this)
|
||||
CallerMsgBoxListenerManager.addListener(TAG,this)
|
||||
TrajectoryAndDistanceManager.addDistanceListener(TAG, this)
|
||||
}
|
||||
|
||||
override fun onCurrentOrderStatusChanged(order: BaseOrderBean?) {
|
||||
@@ -141,4 +148,20 @@ class AutomaticExplorationViewModel: ViewModel(), OrderListener, IMsgBoxListener
|
||||
AIMessageManager.post(automaticExploration)
|
||||
}
|
||||
|
||||
private val orderShowEvaluate = "SHOWEVALUATE"
|
||||
|
||||
override fun distanceCallback(distance: Float) {
|
||||
if(distance<=500) {
|
||||
OrderModel.orderBean?.orderNo?.let {
|
||||
val string = SharedPrefsMgr.getInstance().getString(orderShowEvaluate)
|
||||
if (StringUtils.isEmpty(string) || !string.equals(it)) {
|
||||
val automaticExploration = AIMessage.EvaluateData(System.currentTimeMillis().toString(),"",true)
|
||||
AIMessageManager.post(automaticExploration)
|
||||
SharedPrefsMgr.getInstance().putString(orderShowEvaluate, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,6 +24,7 @@ class AIMessageAdapter : ListAdapter<AIMessage, MessageViewHolder>(MessageDiffCa
|
||||
AIMessage.TYPE_ROAD_V2N -> RoadV2NEventViewHolder(inflater.inflate(R.layout.item_ai_road_v2n_event,parent,false))
|
||||
AIMessage.TYPE_ROAD_CROSS -> RoadCrossRoamViewHolder(inflater.inflate(R.layout.item_ai_road_cross_roam,parent,false))
|
||||
AIMessage.TYPE_AUTOMATIC_EXPLORATION -> AutomaticExplorationViewHolder(inflater.inflate(R.layout.item_ai_automatic_exploration,parent,false))
|
||||
AIMessage.TYPE_EVALUATE -> EvaluateViewViewHolder(inflater.inflate(R.layout.taxi_p_evaluate,parent,false))
|
||||
else -> throw IllegalArgumentException("Invalid view type")
|
||||
}
|
||||
}
|
||||
@@ -40,6 +41,7 @@ class AIMessageAdapter : ListAdapter<AIMessage, MessageViewHolder>(MessageDiffCa
|
||||
is AIMessage.RoadV2NEvent -> AIMessage.TYPE_ROAD_V2N
|
||||
is AIMessage.RoadCrossRoam -> AIMessage.TYPE_ROAD_CROSS
|
||||
is AIMessage.AutomaticExploration -> AIMessage.TYPE_AUTOMATIC_EXPLORATION
|
||||
is AIMessage.EvaluateData -> AIMessage.TYPE_EVALUATE
|
||||
else -> AIMessage.TYPE_EVENT
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
package com.mogo.och.unmanned.passenger.ui.aiview.adapter
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.animation.ObjectAnimator
|
||||
import android.animation.ValueAnimator
|
||||
import android.content.Context
|
||||
import android.graphics.Rect
|
||||
import android.os.CountDownTimer
|
||||
import android.text.TextUtils
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.LinearInterpolator
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.toColorInt
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
@@ -30,17 +27,19 @@ import com.mogo.eagle.core.function.hmi.ui.notice.exploration.AutomaticExplorati
|
||||
import com.mogo.eagle.core.function.hmi.ui.v2n.RoadV2NEventLivePlayView
|
||||
import com.mogo.eagle.core.function.view.MapRoamView
|
||||
import com.mogo.eagle.core.function.view.RoadCrossRoamListAdapter
|
||||
import com.mogo.eagle.core.utilcode.kotlin.onClick
|
||||
import com.mogo.eagle.core.utilcode.mogo.glide.GlideImageLoader
|
||||
import com.mogo.eagle.core.utilcode.mogo.imageloader.MogoImageView
|
||||
import com.mogo.eagle.core.utilcode.util.DateTimeUtils
|
||||
import com.mogo.eagle.core.utilcode.util.ThreadUtils
|
||||
import com.mogo.eagle.core.widget.RoundConstraintLayout
|
||||
import com.mogo.och.common.module.wigets.OchRoundImageView
|
||||
import com.mogo.och.common.module.utils.FrameAnimatorContainer
|
||||
import com.mogo.och.common.module.voice.VoiceNotice
|
||||
import com.mogo.och.unmanned.passenger.ui.aiview.bean.AIMessage
|
||||
import com.mogo.och.unmanned.taxi.passenger.R
|
||||
import com.youth.banner.Banner
|
||||
import com.youth.banner.indicator.CircleIndicator
|
||||
import com.youth.banner.transformer.ScaleInTransformer
|
||||
import kotlinx.android.synthetic.main.taxi_p_evaluate.view.iv_evaluate_great
|
||||
import kotlinx.android.synthetic.main.taxi_p_evaluate.view.iv_evaluate_low
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
@@ -352,6 +351,67 @@ class AutomaticExplorationViewHolder(binding: View) : MessageViewHolder(binding)
|
||||
|
||||
}
|
||||
|
||||
|
||||
class EvaluateViewViewHolder(binding: View) : MessageViewHolder(binding) {
|
||||
private var ivEvaluateGreat: ImageView = binding.findViewById(R.id.iv_evaluate_great)
|
||||
private var ivEvaluateLow: ImageView = binding.findViewById(R.id.iv_evaluate_low)
|
||||
private var ivEvaluateGreatAni: FrameAnimatorContainer?=null
|
||||
|
||||
init {
|
||||
}
|
||||
|
||||
override fun bind(item: AIMessage, onItemClickListener: OnItemClickListener?) {
|
||||
if(item is AIMessage.EvaluateData){
|
||||
if(item.isFirst){
|
||||
VoiceNotice.showNotice("行程即将结束咯~小智很想知道您的体验如何呢", AIAssist.LEVEL2)
|
||||
ivEvaluateGreat.setImageResource(R.drawable.arrive_dest_great_000)
|
||||
ivEvaluateLow.scaleY = 1f
|
||||
}
|
||||
}
|
||||
ivEvaluateGreat.onClick {
|
||||
if(item is AIMessage.EvaluateData) {
|
||||
if (item.isFirst) {
|
||||
if (ivEvaluateGreatAni == null) {
|
||||
ivEvaluateGreatAni = FrameAnimatorContainer(
|
||||
R.array.taxi_p_arrive_dest_great,
|
||||
31,
|
||||
ivEvaluateGreat,
|
||||
isOnce = true
|
||||
)
|
||||
ivEvaluateGreatAni?.start()
|
||||
|
||||
} else {
|
||||
ivEvaluateGreatAni?.reStart()
|
||||
}
|
||||
ivEvaluateGreatAni?.setOnAnimStopListener(object :
|
||||
FrameAnimatorContainer.OnAnimationStoppedListener {
|
||||
override fun AnimationStopped() {
|
||||
|
||||
}
|
||||
})
|
||||
VoiceNotice.showNotice("感谢您的认可,我们会再接再厉", AIAssist.LEVEL2)
|
||||
item.isFirst = false
|
||||
}
|
||||
}
|
||||
}
|
||||
ivEvaluateLow.onClick {
|
||||
if(item is AIMessage.EvaluateData) {
|
||||
if (item.isFirst) {
|
||||
ivEvaluateLow.pivotX = (ivEvaluateLow.width / 2).toFloat()
|
||||
ivEvaluateLow.pivotY = ivEvaluateLow.height.toFloat()
|
||||
ivEvaluateLow.animate().scaleY(1.2f).scaleX(1.2f).setListener(object :
|
||||
AnimatorListenerAdapter() {
|
||||
override fun onAnimationStart(animation: Animator) {
|
||||
VoiceNotice.showNotice("感谢您的反馈,我们会继续努力!", AIAssist.LEVEL2)
|
||||
}
|
||||
}).duration = 1000
|
||||
item.isFirst = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class NoScrollLayoutManager(context: Context?) : LinearLayoutManager(context) {
|
||||
override fun canScrollVertically(): Boolean {
|
||||
return false
|
||||
|
||||
@@ -25,6 +25,7 @@ sealed class AIMessage(
|
||||
const val TYPE_ROAD_V2N = 7
|
||||
const val TYPE_ROAD_CROSS = 8
|
||||
const val TYPE_AUTOMATIC_EXPLORATION = 9
|
||||
const val TYPE_EVALUATE = 10
|
||||
}
|
||||
|
||||
data class Scan(
|
||||
@@ -160,4 +161,10 @@ sealed class AIMessage(
|
||||
override val title: String
|
||||
): AIMessage(id,title)
|
||||
|
||||
data class EvaluateData(
|
||||
override val id: String,
|
||||
override val title: String,
|
||||
var isFirst:Boolean = true
|
||||
): AIMessage(id,title)
|
||||
|
||||
}
|
||||
@@ -16,7 +16,6 @@ import com.mogo.och.common.module.utils.FrameAnimatorContainer
|
||||
import com.mogo.och.common.module.utils.RxUtils
|
||||
import com.mogo.och.common.module.voice.VoiceNotice
|
||||
import com.mogo.och.unmanned.taxi.passenger.R
|
||||
import kotlinx.android.synthetic.main.taxi_p_evaluate.view.iv_close
|
||||
import kotlinx.android.synthetic.main.taxi_p_evaluate.view.iv_evaluate_great
|
||||
import kotlinx.android.synthetic.main.taxi_p_evaluate.view.iv_evaluate_low
|
||||
|
||||
@@ -94,9 +93,6 @@ class EvaluateView : ConstraintLayout, EvaluateViewModel.EvaluateCallback {
|
||||
isFirat = false
|
||||
}
|
||||
}
|
||||
iv_close.onClick {
|
||||
visibility = GONE
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<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="@dimen/dp_640"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
|
||||
|
||||
@@ -10,10 +10,8 @@
|
||||
|
||||
<com.mogo.eagle.core.widget.RoundCanClickConstraintLayout
|
||||
android:id="@+id/rcccl_con"
|
||||
android:layout_width="@dimen/dp_600"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dp_349"
|
||||
android:layout_marginStart="@dimen/dp_40"
|
||||
android:layout_marginTop="@dimen/dp_40"
|
||||
android:background="#8CF5FAFF"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
@@ -32,19 +30,6 @@
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_great_evaluate"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/dp_105"
|
||||
android:layout_marginBottom="@dimen/dp_40"
|
||||
android:text="新奇有趣"
|
||||
android:textColor="@color/taxi_cp_303C52"
|
||||
android:textSize="@dimen/dp_26"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_low_evaluate"
|
||||
android:layout_width="wrap_content"
|
||||
@@ -70,15 +55,6 @@
|
||||
|
||||
</com.mogo.eagle.core.widget.RoundCanClickConstraintLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_close"
|
||||
android:layout_width="@dimen/dp_81"
|
||||
android:layout_height="@dimen/dp_81"
|
||||
|
||||
android:src="@drawable/taxi_p_evaluate_close"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_evaluate_great"
|
||||
android:layout_width="@dimen/dp_320"
|
||||
@@ -89,4 +65,16 @@
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/rcccl_con" />
|
||||
|
||||
</merge>
|
||||
<TextView
|
||||
android:id="@+id/tv_great_evaluate"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/dp_40"
|
||||
android:text="新奇有趣"
|
||||
android:textColor="@color/taxi_cp_303C52"
|
||||
android:textSize="@dimen/dp_26"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="@+id/iv_evaluate_great"
|
||||
app:layout_constraintStart_toStartOf="@+id/iv_evaluate_great" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
Reference in New Issue
Block a user