调整道路属性面板
This commit is contained in:
squallzhjch 2023-05-26 10:06:58 +08:00
parent 4e997b8632
commit b6bbcad634
9 changed files with 219 additions and 168 deletions

View File

@ -121,6 +121,11 @@
"code": 4006, "code": 4006,
"name": "普通交限" "name": "普通交限"
}, },
"4022":{
"table": "OMDB_TRAFFICLIGHT",
"code": 4022,
"name": "交通灯"
},
"5001":{ "5001":{
"table": "OMDB_LANE_LINK_LG", "table": "OMDB_LANE_LINK_LG",
"code": 5001, "code": 5001,

View File

@ -1,10 +1,15 @@
package com.navinfo.omqs.ui.activity.map package com.navinfo.omqs.ui.activity.map
import android.app.Activity
import android.content.Intent
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.PersistableBundle
import android.speech.tts.TextToSpeech
import android.util.Log import android.util.Log
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View import android.view.View
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
@ -29,7 +34,10 @@ import com.navinfo.omqs.util.FlowEventBus
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import com.navinfo.omqs.ui.widget.RecyclerViewSpacesItemDecoration import com.navinfo.omqs.ui.widget.RecyclerViewSpacesItemDecoration
import com.navinfo.omqs.util.SpeakMode
import org.videolan.vlc.Util import org.videolan.vlc.Util
import java.math.BigDecimal
import java.math.RoundingMode
import javax.inject.Inject import javax.inject.Inject
/** /**
@ -43,6 +51,17 @@ class MainActivity : BaseActivity() {
var switchFragment = false var switchFragment = false
private val someActivityResultLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val data: Intent? = result.data
Log.e("jingo", "MainActivity someActivityResultLauncher RESULT_OK")
} else {
Log.e("jingo", "MainActivity someActivityResultLauncher ${result.resultCode}")
}
}
//注入地图控制器 //注入地图控制器
@Inject @Inject
lateinit var mapController: NIMapController lateinit var mapController: NIMapController
@ -88,6 +107,13 @@ class MainActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
WindowCompat.setDecorFitsSystemWindows(window, false) WindowCompat.setDecorFitsSystemWindows(window, false)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val checkIntent = Intent()
checkIntent.action = TextToSpeech.Engine.ACTION_CHECK_TTS_DATA
someActivityResultLauncher.launch(checkIntent)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main) binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
//初始化地图 //初始化地图
@ -98,6 +124,7 @@ class MainActivity : BaseActivity() {
Constant.MAP_PATH, Constant.MAP_PATH,
Constant.USER_DATA_PATH + "/trace.sqlite" Constant.USER_DATA_PATH + "/trace.sqlite"
) )
viewModel.speakMode = SpeakMode(this)
// 在mapController初始化前获取当前OMDB图层显隐 // 在mapController初始化前获取当前OMDB图层显隐
viewModel.refreshOMDBLayer(LayerConfigUtils.getLayerConfigList()) viewModel.refreshOMDBLayer(LayerConfigUtils.getLayerConfigList())
mapController.mMapView.vtmMap.viewport().maxZoomLevel = 25 mapController.mMapView.vtmMap.viewport().maxZoomLevel = 25
@ -144,8 +171,7 @@ class MainActivity : BaseActivity() {
//道路属性面板 //道路属性面板
binding.mainActivityTopSignRecyclerview.layoutManager = LinearLayoutManager( binding.mainActivityTopSignRecyclerview.layoutManager = LinearLayoutManager(
this, this, RecyclerView.HORIZONTAL, false
RecyclerView.HORIZONTAL, false
) )
// binding.mainActivityTopSignRecyclerview.addItemDecoration( // binding.mainActivityTopSignRecyclerview.addItemDecoration(
// RecycleViewDivider(this, LinearLayoutManager.HORIZONTAL) // RecycleViewDivider(this, LinearLayoutManager.HORIZONTAL)
@ -164,19 +190,28 @@ class MainActivity : BaseActivity() {
) )
) )
) )
//监听要素面板变化
viewModel.liveDataSignList.observe(this) { viewModel.liveDataSignList.observe(this) {
signAdapter.refreshData(it) signAdapter.refreshData(it)
} }
//监听道路信息变化
viewModel.liveDataTopSignList.observe(this) { viewModel.liveDataTopSignList.observe(this) {
topSignAdapter.refreshData(it) topSignAdapter.refreshData(it)
} }
//监听地图中点变化
viewModel.liveDataCenterPoint.observe(this) {
binding.mainActivityGeometry.text = "经纬度:${
BigDecimal(it.longitude).setScale(
6,
RoundingMode.HALF_UP
)
},${BigDecimal(it.latitude).setScale(6, RoundingMode.HALF_UP)}"
}
lifecycleScope.launch { lifecycleScope.launch {
// 初始化地图图层控制接收器 // 初始化地图图层控制接收器
FlowEventBus.subscribe<List<ImportConfig>>( FlowEventBus.subscribe<List<ImportConfig>>(
lifecycle, lifecycle, Constant.EVENT_LAYER_MANAGER_CHANGE
Constant.EVENT_LAYER_MANAGER_CHANGE
) { ) {
viewModel.refreshOMDBLayer(it) viewModel.refreshOMDBLayer(it)
} }
@ -201,6 +236,7 @@ class MainActivity : BaseActivity() {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
viewModel.speakMode?.shutdown()
mapController.mMapView.onDestroy() mapController.mMapView.onDestroy()
mapController.locationLayerHandler.stopLocation() mapController.locationLayerHandler.stopLocation()
} }

View File

@ -45,7 +45,10 @@ import io.realm.RealmSet
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.oscim.core.GeoPoint import org.oscim.core.GeoPoint
import org.oscim.core.MapPosition
import org.oscim.map.Map
import org.videolan.libvlc.LibVlcUtil import org.videolan.libvlc.LibVlcUtil
import java.io.File import java.io.File
import java.util.* import java.util.*
@ -59,7 +62,7 @@ import javax.inject.Inject
class MainViewModel @Inject constructor( class MainViewModel @Inject constructor(
private val mapController: NIMapController, private val mapController: NIMapController,
private val traceDataBase: TraceDataBase, private val traceDataBase: TraceDataBase,
private val realmOperateHelper: RealmOperateHelper private val realmOperateHelper: RealmOperateHelper,
) : ViewModel() { ) : ViewModel() {
private var mCameraDialog: CommonDialog? = null private var mCameraDialog: CommonDialog? = null
@ -78,7 +81,7 @@ class MainViewModel @Inject constructor(
//语音窗体 //语音窗体
private var pop: PopupWindow? = null private var pop: PopupWindow? = null
private var mSpeakMode: SpeakMode? = null var speakMode: SpeakMode? = null
//录音图标 //录音图标
var volume: ImageView? = null var volume: ImageView? = null
@ -88,12 +91,28 @@ class MainViewModel @Inject constructor(
val liveDataMenuState = MutableLiveData<Boolean>() val liveDataMenuState = MutableLiveData<Boolean>()
val liveDataCenterPoint = MutableLiveData<MapPosition>()
/** /**
* 是不是线选择模式 * 是不是线选择模式
*/ */
private var bSelectRoad = false private var bSelectRoad = false
init { init {
mapController.mMapView.vtmMap.events.bind(Map.UpdateListener { e, mapPosition ->
when (e) {
Map.SCALE_EVENT, Map.MOVE_EVENT, Map.ROTATE_EVENT ->
if (liveDataCenterPoint.value == null
|| liveDataCenterPoint.value!!.x != mapPosition.x
|| liveDataCenterPoint.value!!.y != mapPosition.y
) {
liveDataCenterPoint.value = mapPosition
}
}
})
//处理质检数据点击事件
mapController.markerHandle.setOnQsRecordItemClickListener(object : mapController.markerHandle.setOnQsRecordItemClickListener(object :
OnQsRecordItemClickListener { OnQsRecordItemClickListener {
override fun onQsRecordList(list: MutableList<String>) { override fun onQsRecordList(list: MutableList<String>) {
@ -101,9 +120,11 @@ class MainViewModel @Inject constructor(
} }
}) })
initLocation() initLocation()
//处理地图点击操作
viewModelScope.launch { viewModelScope.launch {
mapController.onMapClickFlow.collectLatest { mapController.onMapClickFlow.collectLatest {
// testPoint = it // testPoint = it
//线选择状态
if (bSelectRoad) { if (bSelectRoad) {
captureLink(it) captureLink(it)
} }
@ -223,10 +244,10 @@ class MainViewModel @Inject constructor(
) )
when (element.code) { when (element.code) {
2041, 2008, 2010 -> topSignList.add( 2002, 2008, 2010, 2041 -> topSignList.add(
signBean signBean
) )
else -> signList.add( 4002, 4003, 4004, 4006, 4022 -> signList.add(
signBean signBean
) )
} }
@ -237,6 +258,10 @@ class MainViewModel @Inject constructor(
} }
liveDataTopSignList.postValue(topSignList.distinctBy { it.elementCode }) liveDataTopSignList.postValue(topSignList.distinctBy { it.elementCode })
liveDataSignList.postValue(signList.distinctBy { it.elementCode }) liveDataSignList.postValue(signList.distinctBy { it.elementCode })
val speechText = SignUtil.getRoadSpeechText(topSignList)
withContext(Dispatchers.Main) {
speakMode?.speakText(speechText)
}
Log.e("jingo", "自动捕捉数据 共${signList.size}") Log.e("jingo", "自动捕捉数据 共${signList.size}")
} }
} }
@ -303,10 +328,6 @@ class MainViewModel @Inject constructor(
fun startSoundMetter(context: Context, v: View) { fun startSoundMetter(context: Context, v: View) {
if (mSpeakMode == null) {
mSpeakMode = SpeakMode(context as Activity?)
}
//语音识别动画 //语音识别动画
if (pop == null) { if (pop == null) {
pop = PopupWindow() pop = PopupWindow()
@ -340,12 +361,12 @@ class MainViewModel @Inject constructor(
if (!TextUtils.isEmpty(filePath) && File(filePath).exists()) { if (!TextUtils.isEmpty(filePath) && File(filePath).exists()) {
if (File(filePath) == null || File(filePath).length() < 1600) { if (File(filePath) == null || File(filePath).length() < 1600) {
ToastUtils.showLong("语音时间太短,无效!") ToastUtils.showLong("语音时间太短,无效!")
mSpeakMode!!.speakText("语音时间太短,无效") speakMode?.speakText("语音时间太短,无效")
stopSoundMeter() stopSoundMeter()
return return
} }
} }
mSpeakMode!!.speakText("结束录音") speakMode?.speakText("结束录音")
//获取右侧fragment容器 //获取右侧fragment容器
val naviController = val naviController =
(context as Activity).findNavController(R.id.main_activity_right_fragment) (context as Activity).findNavController(R.id.main_activity_right_fragment)
@ -357,14 +378,14 @@ class MainViewModel @Inject constructor(
@RequiresApi(api = Build.VERSION_CODES.Q) @RequiresApi(api = Build.VERSION_CODES.Q)
override fun onfaild(message: String?) { override fun onfaild(message: String?) {
ToastUtils.showLong("录制失败!") ToastUtils.showLong("录制失败!")
mSpeakMode!!.speakText("录制失败") speakMode?.speakText("录制失败")
stopSoundMeter() stopSoundMeter()
} }
}) })
mSoundMeter!!.start(Constant.USER_DATA_ATTACHEMNT_PATH + name) mSoundMeter!!.start(Constant.USER_DATA_ATTACHEMNT_PATH + name)
ToastUtils.showLong("开始录音") ToastUtils.showLong("开始录音")
mSpeakMode!!.speakText("开始录音") speakMode?.speakText("开始录音")
} }
//停止语音录制 //停止语音录制

View File

@ -40,7 +40,6 @@ class LeftAdapter(private var itemListener: ((Int, String) -> Unit?)? = null) :
override fun refreshData(newData: List<String>) { override fun refreshData(newData: List<String>) {
data = newData data = newData
selectTitle = newData[0]
notifyDataSetChanged() notifyDataSetChanged()
} }

View File

@ -83,7 +83,7 @@ class PhenomenonFragment :
} }
//右侧菜单查询数据监听 //右侧菜单查询数据监听
viewModel.liveDataRightTypeList.observe(viewLifecycleOwner) { viewModel.liveDataRightTypeList.observe(viewLifecycleOwner) {
rightAdapter.setSelectTitle(viewModel.liveDataQsRecordBean.value!!.classType) rightAdapter.setSelectTitle(viewModel.liveDataQsRecordBean.value!!.phenomenon)
rightAdapter.refreshData(it) rightAdapter.refreshData(it)
} }

View File

@ -3,6 +3,7 @@ package com.navinfo.omqs.ui.widget
import android.util.Log import android.util.Log
import com.navinfo.collect.library.data.entity.RenderEntity import com.navinfo.collect.library.data.entity.RenderEntity
import com.navinfo.omqs.R import com.navinfo.omqs.R
import com.navinfo.omqs.bean.SignBean
class SignUtil { class SignUtil {
companion object { companion object {
@ -73,6 +74,10 @@ class SignUtil {
4003 -> "条件点限速" 4003 -> "条件点限速"
//可变点限速 //可变点限速
4004 -> "可变点限速" 4004 -> "可变点限速"
//普通交限
4006 -> "普通交限"
//交通灯
4022 -> "交通灯"
else -> "" else -> ""
} }
} }
@ -209,6 +214,8 @@ class SignUtil {
4003 -> getConditionalSpeedLimitIcon(data) 4003 -> getConditionalSpeedLimitIcon(data)
//可变点限速 //可变点限速
4004 -> R.drawable.icon_change_limit 4004 -> R.drawable.icon_change_limit
//交通灯
4022 -> R.drawable.icon_traffic_light
else -> 0 else -> 0
} }
@ -285,5 +292,24 @@ class SignUtil {
} }
return R.drawable.icon_road_direction return R.drawable.icon_road_direction
} }
/**
* 获取道路播报语音文字
*/
fun getRoadSpeechText(topSignList: MutableList<SignBean>): String {
if (topSignList.size == 0)
return ""
val stringBuffer = StringBuffer()
stringBuffer.append("当前道路")
for (item in topSignList) {
when (item.elementCode) {
2002 -> stringBuffer.append("功能等级${item.iconText.substring(2)}级,")
2008 -> stringBuffer.append("种别${item.iconText},")
2010 -> stringBuffer.append("${item.iconText},")
2041 -> stringBuffer.append("${item.iconText.substringBefore("|")}车道")
}
}
return stringBuffer.toString()
}
} }
} }

View File

@ -1,149 +0,0 @@
package com.navinfo.omqs.util;
import android.app.Activity;
import android.app.Dialog;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.view.View;
import com.navinfo.omqs.ui.dialog.FirstDialog;
import java.util.HashMap;
import java.util.Locale;
//语音类
public class SpeakMode extends Activity implements TextToSpeech.OnInitListener{
private Activity mActivity;
private TextToSpeech mTextToSpeech;//TTS对象
private int status;
private int MY_DATA_CHECK_CODE = 0;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0x11:
try {
HashMap<String, String> params = new HashMap<String, String>();
params.put(TextToSpeech.Engine.KEY_PARAM_STREAM, "STREAM_NOTIFICATION");//设置播放类型音频流类型
mTextToSpeech.speak(msg.obj + "", TextToSpeech.QUEUE_ADD, params);//将这个发音任务添加当前任务之后
//BaseToast.makeText(mActivity,msg.obj+"",Toast.LENGTH_LONG).show();
mTextToSpeech.playSilence(100, TextToSpeech.QUEUE_ADD, params);//间隔多长时间
} catch (Exception e) {
}
break;
}
}
};
public SpeakMode(Activity activity) {
mActivity = activity;
if (mActivity != null && !mActivity.isFinishing())
this.mTextToSpeech = new TextToSpeech(this.mActivity, this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent checkIntent = new Intent();
checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
startActivityForResult(checkIntent, MY_DATA_CHECK_CODE);
}
public void setData(String json) {
}
@Override
public void onInit(int status) {
this.status = status;
if (this.mTextToSpeech != null) {
int result = this.mTextToSpeech.setLanguage(Locale.CHINESE);
if (result == TextToSpeech.LANG_MISSING_DATA
|| result == TextToSpeech.LANG_NOT_SUPPORTED) {
if (mActivity != null && !mActivity.isFinishing()) {
FirstDialog firstDialog = new FirstDialog(mActivity);
firstDialog.setTitle("提示");
firstDialog.setMessage("设备不支持语音播报,请先下载语音助手。");
firstDialog.setConfirmListener(new FirstDialog.OnClickListener() {
@Override
public void onClick(Dialog dialog, int which) {
dialog.dismiss();
}
});
firstDialog.setNegativeView(View.GONE);
firstDialog.show();
}
}
}
Log.i("TextToSpeechDemo", String.valueOf(status));
}
//读语音处理
public void speakText(final String message) {
new Thread(new Runnable() {
@Override
public void run() {
if (mTextToSpeech != null) {
int result = mTextToSpeech.setLanguage(Locale.CHINESE);
if (result == TextToSpeech.LANG_MISSING_DATA
|| result == TextToSpeech.LANG_NOT_SUPPORTED) {
} else {
if (mTextToSpeech != null && mTextToSpeech.isSpeaking()) {
while (mTextToSpeech.isSpeaking()) {
try {
//增加播报停止解决不能播报最新内容问题
mTextToSpeech.stop();
Thread.sleep(100);
} catch (Exception e) {
}
}
}
Message msg = new Message();
msg.what = 0x11;
msg.obj = message;
mHandler.sendMessage(msg);
}
}
}
}).start();
}
public void stopSpeek() {
try {
if (this.mTextToSpeech != null && this.mTextToSpeech.isSpeaking()) {
this.mTextToSpeech.stop();
}
} catch (Exception e) {
}
}
}

View File

@ -0,0 +1,110 @@
package com.navinfo.omqs.util
import android.content.Context
import android.os.Handler
import android.os.Message
import android.speech.tts.TextToSpeech
import android.util.Log
import android.view.View
import com.navinfo.omqs.ui.dialog.FirstDialog
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.util.*
import javax.inject.Inject
//语音类
class SpeakMode(private val context: Context) : TextToSpeech.OnInitListener {
private var mTextToSpeech: TextToSpeech = TextToSpeech(context, this)
private var status = 0
private val MY_DATA_CHECK_CODE = 0
private val mHandler: Handler = object : Handler() {
override fun handleMessage(msg: Message) {
when (msg.what) {
0x11 -> try {
val params = HashMap<String, String>()
params[TextToSpeech.Engine.KEY_PARAM_STREAM] =
"STREAM_NOTIFICATION" //设置播放类型(音频流类型)
mTextToSpeech.speak(
msg.obj.toString() + "",
TextToSpeech.QUEUE_ADD,
params
) //将这个发音任务添加当前任务之后
//BaseToast.makeText(mActivity,msg.obj+"",Toast.LENGTH_LONG).show();
mTextToSpeech.playSilence(100, TextToSpeech.QUEUE_ADD, params) //间隔多长时间
} catch (e: Exception) {
}
}
}
}
init {
// if (mActivity != null && !mActivity.isFinishing) mTextToSpeech = TextToSpeech(
// mActivity, this
// )
}
// override fun onCreate(savedInstanceState: Bundle?) {
// super.onCreate(savedInstanceState)
// val checkIntent = Intent()
// checkIntent.action = TextToSpeech.Engine.ACTION_CHECK_TTS_DATA
// startActivityForResult(checkIntent, MY_DATA_CHECK_CODE)
// }
fun setData(json: String?) {}
override fun onInit(status: Int) {
this.status = status
val result = mTextToSpeech.setLanguage(Locale.CHINESE)
if (result == TextToSpeech.LANG_MISSING_DATA
|| result == TextToSpeech.LANG_NOT_SUPPORTED
) {
if (context != null) {
val firstDialog = FirstDialog(context)
firstDialog.setTitle("提示")
firstDialog.setMessage("设备不支持语音播报,请先下载语音助手。")
firstDialog.setConfirmListener { dialog, _ -> dialog.dismiss() }
firstDialog.setNegativeView(View.GONE)
firstDialog.show()
}
}
Log.i("TextToSpeechDemo", status.toString())
}
//读语音处理
fun speakText(message: String) {
mTextToSpeech.speak(message, TextToSpeech.QUEUE_FLUSH, null, "")
// val result = mTextToSpeech.setLanguage(Locale.CHINESE)
// if (result == TextToSpeech.LANG_MISSING_DATA
// || result == TextToSpeech.LANG_NOT_SUPPORTED
// ) {
// } else {
// while (mTextToSpeech.isSpeaking) {
// try {
// //增加播报停止,解决不能播报最新内容问题
// mTextToSpeech.stop()
// } catch (e: Exception) {
//
// }
// }
// val msg = Message()
// msg.what = 0x11
// msg.obj = message
// mHandler.sendMessage(msg)
// }
}
fun stopSpeech() {
try {
if (mTextToSpeech.isSpeaking) {
mTextToSpeech.stop()
}
} catch (e: Exception) {
}
}
fun shutdown() {
stopSpeech()
mTextToSpeech.shutdown()
}
}

View File

@ -42,6 +42,9 @@
<item name="android:gravity">center_vertical</item> <item name="android:gravity">center_vertical</item>
<item name="android:paddingRight">6dp</item> <item name="android:paddingRight">6dp</item>
<item name="android:paddingLeft">10dp</item> <item name="android:paddingLeft">10dp</item>
<item name="autoSizeMaxTextSize">14sp</item>
<item name="autoSizeMinTextSize">8sp</item>
<item name="autoSizeTextType">uniform</item>
<item name="android:drawableRight">@drawable/baseline_keyboard_arrow_down_12</item> <item name="android:drawableRight">@drawable/baseline_keyboard_arrow_down_12</item>
<item name="android:background">@drawable/shape_rect_white_2dp_bg</item> <item name="android:background">@drawable/shape_rect_white_2dp_bg</item>
<item name="android:layout_width">match_parent</item> <item name="android:layout_width">match_parent</item>