From b6bbcad63458d520a78c1e8ac05d1c3df87f393b Mon Sep 17 00:00:00 2001 From: squallzhjch Date: Fri, 26 May 2023 10:06:58 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4UI=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E9=81=93=E8=B7=AF=E5=B1=9E=E6=80=A7=E9=9D=A2=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/assets/omdb_config.json | 5 + .../omqs/ui/activity/map/MainActivity.kt | 46 +++++- .../omqs/ui/activity/map/MainViewModel.kt | 45 ++++-- .../fragment/evaluationresult/LeftAdapter.kt | 1 - .../evaluationresult/PhenomenonFragment.kt | 2 +- .../com/navinfo/omqs/ui/widget/SignUtil.kt | 26 +++ .../java/com/navinfo/omqs/util/SpeakMode.java | 149 ------------------ .../java/com/navinfo/omqs/util/SpeakMode.kt | 110 +++++++++++++ app/src/main/res/values/styles.xml | 3 + 9 files changed, 219 insertions(+), 168 deletions(-) delete mode 100644 app/src/main/java/com/navinfo/omqs/util/SpeakMode.java create mode 100644 app/src/main/java/com/navinfo/omqs/util/SpeakMode.kt diff --git a/app/src/main/assets/omdb_config.json b/app/src/main/assets/omdb_config.json index f4c8a690..1e7d2c80 100644 --- a/app/src/main/assets/omdb_config.json +++ b/app/src/main/assets/omdb_config.json @@ -121,6 +121,11 @@ "code": 4006, "name": "普通交限" }, + "4022":{ + "table": "OMDB_TRAFFICLIGHT", + "code": 4022, + "name": "交通灯" + }, "5001":{ "table": "OMDB_LANE_LINK_LG", "code": 5001, diff --git a/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt b/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt index 8fe8c4f9..e25cf6e9 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt @@ -1,10 +1,15 @@ package com.navinfo.omqs.ui.activity.map +import android.app.Activity +import android.content.Intent import android.os.Build import android.os.Bundle +import android.os.PersistableBundle +import android.speech.tts.TextToSpeech import android.util.Log import android.view.MotionEvent import android.view.View +import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.viewModels import androidx.annotation.RequiresApi import androidx.core.view.WindowCompat @@ -29,7 +34,10 @@ import com.navinfo.omqs.util.FlowEventBus import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch import com.navinfo.omqs.ui.widget.RecyclerViewSpacesItemDecoration +import com.navinfo.omqs.util.SpeakMode import org.videolan.vlc.Util +import java.math.BigDecimal +import java.math.RoundingMode import javax.inject.Inject /** @@ -43,6 +51,17 @@ class MainActivity : BaseActivity() { 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 lateinit var mapController: NIMapController @@ -88,6 +107,13 @@ class MainActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { WindowCompat.setDecorFitsSystemWindows(window, false) 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) //初始化地图 @@ -98,6 +124,7 @@ class MainActivity : BaseActivity() { Constant.MAP_PATH, Constant.USER_DATA_PATH + "/trace.sqlite" ) + viewModel.speakMode = SpeakMode(this) // 在mapController初始化前获取当前OMDB图层显隐 viewModel.refreshOMDBLayer(LayerConfigUtils.getLayerConfigList()) mapController.mMapView.vtmMap.viewport().maxZoomLevel = 25 @@ -144,8 +171,7 @@ class MainActivity : BaseActivity() { //道路属性面板 binding.mainActivityTopSignRecyclerview.layoutManager = LinearLayoutManager( - this, - RecyclerView.HORIZONTAL, false + this, RecyclerView.HORIZONTAL, false ) // binding.mainActivityTopSignRecyclerview.addItemDecoration( // RecycleViewDivider(this, LinearLayoutManager.HORIZONTAL) @@ -164,19 +190,28 @@ class MainActivity : BaseActivity() { ) ) ) + //监听要素面板变化 viewModel.liveDataSignList.observe(this) { signAdapter.refreshData(it) } - + //监听道路信息变化 viewModel.liveDataTopSignList.observe(this) { 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 { // 初始化地图图层控制接收器 FlowEventBus.subscribe>( - lifecycle, - Constant.EVENT_LAYER_MANAGER_CHANGE + lifecycle, Constant.EVENT_LAYER_MANAGER_CHANGE ) { viewModel.refreshOMDBLayer(it) } @@ -201,6 +236,7 @@ class MainActivity : BaseActivity() { override fun onDestroy() { super.onDestroy() + viewModel.speakMode?.shutdown() mapController.mMapView.onDestroy() mapController.locationLayerHandler.stopLocation() } diff --git a/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainViewModel.kt b/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainViewModel.kt index 141cae55..7ca2b97c 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainViewModel.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainViewModel.kt @@ -45,7 +45,10 @@ import io.realm.RealmSet import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.oscim.core.GeoPoint +import org.oscim.core.MapPosition +import org.oscim.map.Map import org.videolan.libvlc.LibVlcUtil import java.io.File import java.util.* @@ -59,7 +62,7 @@ import javax.inject.Inject class MainViewModel @Inject constructor( private val mapController: NIMapController, private val traceDataBase: TraceDataBase, - private val realmOperateHelper: RealmOperateHelper + private val realmOperateHelper: RealmOperateHelper, ) : ViewModel() { private var mCameraDialog: CommonDialog? = null @@ -78,7 +81,7 @@ class MainViewModel @Inject constructor( //语音窗体 private var pop: PopupWindow? = null - private var mSpeakMode: SpeakMode? = null + var speakMode: SpeakMode? = null //录音图标 var volume: ImageView? = null @@ -88,12 +91,28 @@ class MainViewModel @Inject constructor( val liveDataMenuState = MutableLiveData() + val liveDataCenterPoint = MutableLiveData() + /** * 是不是线选择模式 */ private var bSelectRoad = false 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 : OnQsRecordItemClickListener { override fun onQsRecordList(list: MutableList) { @@ -101,9 +120,11 @@ class MainViewModel @Inject constructor( } }) initLocation() + //处理地图点击操作 viewModelScope.launch { mapController.onMapClickFlow.collectLatest { // testPoint = it + //线选择状态 if (bSelectRoad) { captureLink(it) } @@ -223,10 +244,10 @@ class MainViewModel @Inject constructor( ) when (element.code) { - 2041, 2008, 2010 -> topSignList.add( + 2002, 2008, 2010, 2041 -> topSignList.add( signBean ) - else -> signList.add( + 4002, 4003, 4004, 4006, 4022 -> signList.add( signBean ) } @@ -237,6 +258,10 @@ class MainViewModel @Inject constructor( } liveDataTopSignList.postValue(topSignList.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}条") } } @@ -303,10 +328,6 @@ class MainViewModel @Inject constructor( fun startSoundMetter(context: Context, v: View) { - if (mSpeakMode == null) { - mSpeakMode = SpeakMode(context as Activity?) - } - //语音识别动画 if (pop == null) { pop = PopupWindow() @@ -340,12 +361,12 @@ class MainViewModel @Inject constructor( if (!TextUtils.isEmpty(filePath) && File(filePath).exists()) { if (File(filePath) == null || File(filePath).length() < 1600) { ToastUtils.showLong("语音时间太短,无效!") - mSpeakMode!!.speakText("语音时间太短,无效") + speakMode?.speakText("语音时间太短,无效") stopSoundMeter() return } } - mSpeakMode!!.speakText("结束录音") + speakMode?.speakText("结束录音") //获取右侧fragment容器 val naviController = (context as Activity).findNavController(R.id.main_activity_right_fragment) @@ -357,14 +378,14 @@ class MainViewModel @Inject constructor( @RequiresApi(api = Build.VERSION_CODES.Q) override fun onfaild(message: String?) { ToastUtils.showLong("录制失败!") - mSpeakMode!!.speakText("录制失败") + speakMode?.speakText("录制失败") stopSoundMeter() } }) mSoundMeter!!.start(Constant.USER_DATA_ATTACHEMNT_PATH + name) ToastUtils.showLong("开始录音") - mSpeakMode!!.speakText("开始录音") + speakMode?.speakText("开始录音") } //停止语音录制 diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/LeftAdapter.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/LeftAdapter.kt index 9235fb61..c68b7e88 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/LeftAdapter.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/LeftAdapter.kt @@ -40,7 +40,6 @@ class LeftAdapter(private var itemListener: ((Int, String) -> Unit?)? = null) : override fun refreshData(newData: List) { data = newData - selectTitle = newData[0] notifyDataSetChanged() } diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/PhenomenonFragment.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/PhenomenonFragment.kt index 0b5c7206..e0b6f624 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/PhenomenonFragment.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/PhenomenonFragment.kt @@ -83,7 +83,7 @@ class PhenomenonFragment : } //右侧菜单查询数据监听 viewModel.liveDataRightTypeList.observe(viewLifecycleOwner) { - rightAdapter.setSelectTitle(viewModel.liveDataQsRecordBean.value!!.classType) + rightAdapter.setSelectTitle(viewModel.liveDataQsRecordBean.value!!.phenomenon) rightAdapter.refreshData(it) } diff --git a/app/src/main/java/com/navinfo/omqs/ui/widget/SignUtil.kt b/app/src/main/java/com/navinfo/omqs/ui/widget/SignUtil.kt index e27f5868..eff5a96c 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/widget/SignUtil.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/widget/SignUtil.kt @@ -3,6 +3,7 @@ package com.navinfo.omqs.ui.widget import android.util.Log import com.navinfo.collect.library.data.entity.RenderEntity import com.navinfo.omqs.R +import com.navinfo.omqs.bean.SignBean class SignUtil { companion object { @@ -73,6 +74,10 @@ class SignUtil { 4003 -> "条件点限速" //可变点限速 4004 -> "可变点限速" + //普通交限 + 4006 -> "普通交限" + //交通灯 + 4022 -> "交通灯" else -> "" } } @@ -209,6 +214,8 @@ class SignUtil { 4003 -> getConditionalSpeedLimitIcon(data) //可变点限速 4004 -> R.drawable.icon_change_limit + //交通灯 + 4022 -> R.drawable.icon_traffic_light else -> 0 } @@ -285,5 +292,24 @@ class SignUtil { } return R.drawable.icon_road_direction } + + /** + * 获取道路播报语音文字 + */ + fun getRoadSpeechText(topSignList: MutableList): 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() + } } } \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/omqs/util/SpeakMode.java b/app/src/main/java/com/navinfo/omqs/util/SpeakMode.java deleted file mode 100644 index 1930e611..00000000 --- a/app/src/main/java/com/navinfo/omqs/util/SpeakMode.java +++ /dev/null @@ -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 params = new HashMap(); - - 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) { - - } - } - -} diff --git a/app/src/main/java/com/navinfo/omqs/util/SpeakMode.kt b/app/src/main/java/com/navinfo/omqs/util/SpeakMode.kt new file mode 100644 index 00000000..9674b77d --- /dev/null +++ b/app/src/main/java/com/navinfo/omqs/util/SpeakMode.kt @@ -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() + 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() + } +} \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 014fb4ae..ad37daa4 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -42,6 +42,9 @@ center_vertical 6dp 10dp + 14sp + 8sp + uniform @drawable/baseline_keyboard_arrow_down_12 @drawable/shape_rect_white_2dp_bg match_parent