Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11446a92a5 |
@@ -9,6 +9,8 @@ import android.content.Intent
|
||||
import android.content.ServiceConnection
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.graphics.PixelFormat
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
@@ -57,10 +59,12 @@ class MainActivity : Activity(), SvxService.Listener {
|
||||
private lateinit var micDb: TextView
|
||||
private lateinit var pttButton: PttButton
|
||||
private lateinit var btnSettings: ImageButton
|
||||
private lateinit var btnMonitor: ImageButton
|
||||
|
||||
private val mainHandler = Handler(Looper.getMainLooper())
|
||||
|
||||
private var connected = false
|
||||
private var monitoring = false
|
||||
private var settings: ConnectionSettings = ConnectionSettings("", 5300, "", "", 11)
|
||||
|
||||
private var svc: SvxService? = null
|
||||
@@ -101,8 +105,11 @@ class MainActivity : Activity(), SvxService.Listener {
|
||||
micDb = findViewById(R.id.mic_db)
|
||||
pttButton = findViewById(R.id.ptt_button)
|
||||
btnSettings = findViewById(R.id.btn_settings)
|
||||
btnMonitor = findViewById(R.id.btn_monitor)
|
||||
pttButton.enabled2 = false
|
||||
|
||||
btnMonitor.setOnClickListener { toggleMonitoring() }
|
||||
updateMonitorButton()
|
||||
val testText = intent?.getStringExtra("node_toast_test")
|
||||
if (testText != null) {
|
||||
mainHandler.postDelayed({ showNodeOverlay(testText) }, 1500)
|
||||
@@ -239,7 +246,11 @@ class MainActivity : Activity(), SvxService.Listener {
|
||||
ReflectorClient.STATE_READY -> {
|
||||
connected = true
|
||||
updatePttEnabled()
|
||||
statusChip.text = getString(R.string.status_connected)
|
||||
statusChip.text = if (monitoring) {
|
||||
getString(R.string.status_monitoring, monitorTgLabel())
|
||||
} else {
|
||||
getString(R.string.status_connected)
|
||||
}
|
||||
statusChip.setTextColor(getColor(R.color.accent))
|
||||
lblTxState.text = getString(R.string.status_big_connected)
|
||||
lblTxState.setTextColor(getColor(R.color.accent))
|
||||
@@ -280,7 +291,11 @@ class MainActivity : Activity(), SvxService.Listener {
|
||||
|
||||
override fun onTalkerStart(tg: Long, callsign: String) {
|
||||
mainHandler.post {
|
||||
lblTalkerTitle.text = getString(R.string.talker_now, callsign)
|
||||
lblTalkerTitle.text = if (monitoring) {
|
||||
getString(R.string.talker_mon, callsign, tg)
|
||||
} else {
|
||||
getString(R.string.talker_now, callsign)
|
||||
}
|
||||
lblTalker.text = callsign
|
||||
}
|
||||
}
|
||||
@@ -366,7 +381,7 @@ class MainActivity : Activity(), SvxService.Listener {
|
||||
}
|
||||
|
||||
private fun updatePttEnabled() {
|
||||
pttButton.enabled2 = connected
|
||||
pttButton.enabled2 = connected && !monitoring
|
||||
}
|
||||
|
||||
private fun requestPermissionsIfNeeded() {
|
||||
@@ -391,12 +406,36 @@ class MainActivity : Activity(), SvxService.Listener {
|
||||
port = settings.port,
|
||||
callsign = settings.callsign,
|
||||
authKey = settings.authKey,
|
||||
talkGroup = settings.talkGroup
|
||||
talkGroup = settings.talkGroup,
|
||||
monitorTgs = if (monitoring) settings.groups else null
|
||||
)
|
||||
)
|
||||
}, 300)
|
||||
}
|
||||
|
||||
/** Включить/выключить режим мониторинга групп с переподключением. */
|
||||
private fun toggleMonitoring() {
|
||||
monitoring = !monitoring
|
||||
updateMonitorButton()
|
||||
updatePttEnabled()
|
||||
if (connected) {
|
||||
svc?.disconnect()
|
||||
mainHandler.postDelayed({ connect() }, 500)
|
||||
} else {
|
||||
connect()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateMonitorButton() {
|
||||
val active = monitoring
|
||||
btnMonitor.imageTintList = ColorStateList.valueOf(
|
||||
if (active) Color.parseColor("#58A6FF") else Color.parseColor("#8B949E")
|
||||
)
|
||||
btnMonitor.setBackgroundResource(if (active) R.drawable.bg_monitor_on else 0)
|
||||
btnMonitor.contentDescription =
|
||||
getString(if (active) R.string.btn_monitor_on else R.string.btn_monitor)
|
||||
}
|
||||
|
||||
/** Переключиться на другую группу: пересохранить и переподключиться. */
|
||||
private fun switchGroup(tg: Long) {
|
||||
settings = settings.copy(talkGroup = tg)
|
||||
@@ -406,6 +445,9 @@ class MainActivity : Activity(), SvxService.Listener {
|
||||
mainHandler.postDelayed({ connect() }, 500)
|
||||
}
|
||||
|
||||
private fun monitorTgLabel(): String =
|
||||
settings.groups.joinToString(", ") { "TG$it" }
|
||||
|
||||
private fun showNodesDialog() {
|
||||
val nodes = svc?.nodeList().orEmpty()
|
||||
if (nodes.isEmpty()) {
|
||||
|
||||
@@ -58,7 +58,9 @@ class ReflectorClient(
|
||||
val port: Int,
|
||||
val callsign: String,
|
||||
val authKey: String,
|
||||
val talkGroup: Long
|
||||
val talkGroup: Long,
|
||||
/** Список групп для мониторинга; null = обычный режим (своя группа). */
|
||||
val monitorTgs: List<Long>? = null
|
||||
)
|
||||
|
||||
@Volatile
|
||||
@@ -361,8 +363,14 @@ class ReflectorClient(
|
||||
// (иначе сервер не шлёт аудио группы и не показывает
|
||||
// подписку в статусе: monitoredTGs остаётся пустым).
|
||||
sendTcp(socket, MsgBuilder.nodeInfo(CLIENT_SW_INFO, CLIENT_SW_VERSION))
|
||||
val monitor = s.monitorTgs
|
||||
if (monitor.isNullOrEmpty()) {
|
||||
sendTcp(socket, MsgBuilder.selectTg(s.talkGroup))
|
||||
sendTcp(socket, MsgBuilder.tgMonitor(listOf(s.talkGroup)))
|
||||
} else {
|
||||
sendTcp(socket, MsgBuilder.selectTg(0))
|
||||
sendTcp(socket, MsgBuilder.tgMonitor(monitor))
|
||||
}
|
||||
openUdp(s)
|
||||
}
|
||||
|
||||
|
||||
5
app/src/main/res/drawable/bg_monitor_on.xml
Normal file
5
app/src/main/res/drawable/bg_monitor_on.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="#3358A6FF" />
|
||||
</shape>
|
||||
10
app/src/main/res/drawable/ic_headset.xml
Normal file
10
app/src/main/res/drawable/ic_headset.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#8B949E"
|
||||
android:pathData="M12,1c-4.97,0 -9,4.03 -9,9v7c0,1.66 1.34,3 3,3h3v-8L5,12v-2c0,-3.87 3.13,-7 7,-7s7,3.13 7,7v2h-4v8h3c1.66,0 3,-1.34 3,-3v-7c0,-4.97 -4.03,-9 -9,-9z" />
|
||||
</vector>
|
||||
@@ -84,6 +84,15 @@
|
||||
android:ellipsize="end"
|
||||
android:text="@string/settings_not_configured" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btn_monitor"
|
||||
android:layout_width="44dp"
|
||||
android:layout_height="44dp"
|
||||
android:src="@drawable/ic_headset"
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/btn_monitor"
|
||||
android:scaleType="centerInside" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/lbl_tg"
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
@@ -27,6 +27,10 @@
|
||||
<string name="status_disconnected">Отключено</string>
|
||||
<string name="app_title">SVXHomyak</string>
|
||||
<string name="btn_power">Выключить: отключиться и закрыть</string>
|
||||
<string name="btn_monitor">Мониторинг групп (нажмите, чтобы включить)</string>
|
||||
<string name="btn_monitor_on">Мониторинг групп включен (нажмите, чтобы выключить)</string>
|
||||
<string name="status_monitoring">Мониторинг: %1$s</string>
|
||||
<string name="talker_mon">Говорит: %1$s · TG%2$d</string>
|
||||
<string name="status_big_disconnected">DISCONNECTED</string>
|
||||
<string name="status_big_connected">CONNECTED</string>
|
||||
<string name="status_big_talking">ПЕРЕДАЧА</string>
|
||||
|
||||
Reference in New Issue
Block a user