Talk group switcher on main screen, auto-connect on launch
- Tapping the TG badge opens a group list; picking a group saves it and reconnects to the server with the new group - Groups configured in settings (comma-separated), defaults 9,11,12,13 - Auto-connect at app launch to the default group from settings
This commit is contained in:
@@ -105,38 +105,18 @@ class MainActivity : Activity(), SvxService.Listener {
|
|||||||
startActivity(Intent(this, SettingsActivity::class.java))
|
startActivity(Intent(this, SettingsActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lblTg.setOnClickListener { showGroupsDialog() }
|
||||||
|
|
||||||
connectZone.setOnClickListener {
|
connectZone.setOnClickListener {
|
||||||
val s = svc
|
if (connected) {
|
||||||
if (connected && s != null) {
|
svc?.disconnect()
|
||||||
s.disconnect()
|
|
||||||
} else {
|
} else {
|
||||||
settings = Prefs.load(this)
|
|
||||||
if (settings.host.isBlank() || settings.callsign.isBlank()) {
|
if (settings.host.isBlank() || settings.callsign.isBlank()) {
|
||||||
toast(getString(R.string.toast_need_settings))
|
toast(getString(R.string.toast_need_settings))
|
||||||
return@setOnClickListener
|
return@setOnClickListener
|
||||||
}
|
}
|
||||||
if (checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
|
requestPermissionsIfNeeded()
|
||||||
requestPermissions(arrayOf(Manifest.permission.RECORD_AUDIO), REQ_MIC)
|
connect()
|
||||||
return@setOnClickListener
|
|
||||||
}
|
|
||||||
if (Build.VERSION.SDK_INT >= 33 &&
|
|
||||||
checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED
|
|
||||||
) {
|
|
||||||
requestPermissions(arrayOf(Manifest.permission.POST_NOTIFICATIONS), REQ_NOTIF)
|
|
||||||
}
|
|
||||||
startForegroundService(Intent(this, SvxService::class.java))
|
|
||||||
bindService(Intent(this, SvxService::class.java), svcConn, Context.BIND_AUTO_CREATE)
|
|
||||||
mainHandler.postDelayed({
|
|
||||||
svc?.connect(
|
|
||||||
ReflectorClient.Settings(
|
|
||||||
host = settings.host,
|
|
||||||
port = settings.port,
|
|
||||||
callsign = settings.callsign,
|
|
||||||
authKey = settings.authKey,
|
|
||||||
talkGroup = settings.talkGroup
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}, 300)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,10 +147,23 @@ class MainActivity : Activity(), SvxService.Listener {
|
|||||||
refreshUi()
|
refreshUi()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var autoConnectAttempted = false
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
settings = Prefs.load(this)
|
settings = Prefs.load(this)
|
||||||
refreshUi()
|
refreshUi()
|
||||||
|
if (!autoConnectAttempted &&
|
||||||
|
settings.host.isNotBlank() &&
|
||||||
|
settings.callsign.isNotBlank()
|
||||||
|
) {
|
||||||
|
autoConnectAttempted = true
|
||||||
|
requestPermissionsIfNeeded()
|
||||||
|
connect()
|
||||||
|
}
|
||||||
|
if (pendingUpdate != null && updateDialog == null && canInstall()) {
|
||||||
|
startUpdate()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
@@ -311,6 +304,62 @@ class MainActivity : Activity(), SvxService.Listener {
|
|||||||
pttButton.enabled2 = connected
|
pttButton.enabled2 = connected
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun requestPermissionsIfNeeded() {
|
||||||
|
if (checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
|
||||||
|
requestPermissions(arrayOf(Manifest.permission.RECORD_AUDIO), REQ_MIC)
|
||||||
|
}
|
||||||
|
if (Build.VERSION.SDK_INT >= 33 &&
|
||||||
|
checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED
|
||||||
|
) {
|
||||||
|
requestPermissions(arrayOf(Manifest.permission.POST_NOTIFICATIONS), REQ_NOTIF)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Запустить сервис и подключиться с текущими настройками. */
|
||||||
|
private fun connect() {
|
||||||
|
startForegroundService(Intent(this, SvxService::class.java))
|
||||||
|
bindService(Intent(this, SvxService::class.java), svcConn, Context.BIND_AUTO_CREATE)
|
||||||
|
mainHandler.postDelayed({
|
||||||
|
svc?.connect(
|
||||||
|
ReflectorClient.Settings(
|
||||||
|
host = settings.host,
|
||||||
|
port = settings.port,
|
||||||
|
callsign = settings.callsign,
|
||||||
|
authKey = settings.authKey,
|
||||||
|
talkGroup = settings.talkGroup
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Переключиться на другую группу: пересохранить и переподключиться. */
|
||||||
|
private fun switchGroup(tg: Long) {
|
||||||
|
settings = settings.copy(talkGroup = tg)
|
||||||
|
Prefs.save(this, settings)
|
||||||
|
refreshUi()
|
||||||
|
svc?.disconnect()
|
||||||
|
mainHandler.postDelayed({ connect() }, 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showGroupsDialog() {
|
||||||
|
val groups = (settings.groups + settings.talkGroup).distinct()
|
||||||
|
if (groups.isEmpty()) {
|
||||||
|
toast(getString(R.string.toast_groups_empty))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val current = settings.talkGroup
|
||||||
|
AlertDialog.Builder(this)
|
||||||
|
.setTitle(R.string.select_tg)
|
||||||
|
.setItems(groups.map { tg ->
|
||||||
|
val label = getString(R.string.tg_badge, tg)
|
||||||
|
if (tg == current) "$label ✓" else label
|
||||||
|
}.toTypedArray()) { _, which ->
|
||||||
|
val tg = groups[which]
|
||||||
|
if (tg != current) switchGroup(tg)
|
||||||
|
}
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
private fun checkForUpdates() {
|
private fun checkForUpdates() {
|
||||||
Thread {
|
Thread {
|
||||||
val version = try {
|
val version = try {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ class SettingsActivity : Activity() {
|
|||||||
private lateinit var inputCallsign: EditText
|
private lateinit var inputCallsign: EditText
|
||||||
private lateinit var inputAuthKey: EditText
|
private lateinit var inputAuthKey: EditText
|
||||||
private lateinit var inputTg: EditText
|
private lateinit var inputTg: EditText
|
||||||
|
private lateinit var inputGroups: EditText
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@@ -25,6 +26,7 @@ class SettingsActivity : Activity() {
|
|||||||
inputCallsign = findViewById(R.id.input_callsign)
|
inputCallsign = findViewById(R.id.input_callsign)
|
||||||
inputAuthKey = findViewById(R.id.input_auth_key)
|
inputAuthKey = findViewById(R.id.input_auth_key)
|
||||||
inputTg = findViewById(R.id.input_tg)
|
inputTg = findViewById(R.id.input_tg)
|
||||||
|
inputGroups = findViewById(R.id.input_groups)
|
||||||
|
|
||||||
val s = Prefs.load(this)
|
val s = Prefs.load(this)
|
||||||
inputHost.setText(s.host)
|
inputHost.setText(s.host)
|
||||||
@@ -32,6 +34,7 @@ class SettingsActivity : Activity() {
|
|||||||
inputCallsign.setText(s.callsign)
|
inputCallsign.setText(s.callsign)
|
||||||
inputAuthKey.setText(s.authKey)
|
inputAuthKey.setText(s.authKey)
|
||||||
inputTg.setText(s.talkGroup.toString())
|
inputTg.setText(s.talkGroup.toString())
|
||||||
|
inputGroups.setText(s.groups.joinToString(", "))
|
||||||
|
|
||||||
findViewById<Button>(R.id.btn_save).setOnClickListener {
|
findViewById<Button>(R.id.btn_save).setOnClickListener {
|
||||||
val host = inputHost.text.toString().trim()
|
val host = inputHost.text.toString().trim()
|
||||||
@@ -39,6 +42,10 @@ class SettingsActivity : Activity() {
|
|||||||
val callsign = inputCallsign.text.toString().trim()
|
val callsign = inputCallsign.text.toString().trim()
|
||||||
val authKey = inputAuthKey.text.toString()
|
val authKey = inputAuthKey.text.toString()
|
||||||
val tg = inputTg.text.toString().trim().toLongOrNull() ?: 11
|
val tg = inputTg.text.toString().trim().toLongOrNull() ?: 11
|
||||||
|
val groups = inputGroups.text.toString()
|
||||||
|
.split(',')
|
||||||
|
.mapNotNull { it.trim().toLongOrNull() }
|
||||||
|
.distinct()
|
||||||
|
|
||||||
if (host.isBlank() || callsign.isBlank()) {
|
if (host.isBlank() || callsign.isBlank()) {
|
||||||
toast(getString(R.string.toast_settings_empty))
|
toast(getString(R.string.toast_settings_empty))
|
||||||
@@ -52,7 +59,8 @@ class SettingsActivity : Activity() {
|
|||||||
port = port.coerceIn(1, 65535),
|
port = port.coerceIn(1, 65535),
|
||||||
callsign = callsign,
|
callsign = callsign,
|
||||||
authKey = authKey,
|
authKey = authKey,
|
||||||
talkGroup = tg.coerceAtLeast(0)
|
talkGroup = tg.coerceAtLeast(0),
|
||||||
|
groups = groups
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
toast(getString(R.string.saved))
|
toast(getString(R.string.saved))
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ data class ConnectionSettings(
|
|||||||
val port: Int,
|
val port: Int,
|
||||||
val callsign: String,
|
val callsign: String,
|
||||||
val authKey: String,
|
val authKey: String,
|
||||||
val talkGroup: Long
|
val talkGroup: Long,
|
||||||
|
val groups: List<Long> = emptyList()
|
||||||
)
|
)
|
||||||
|
|
||||||
object Prefs {
|
object Prefs {
|
||||||
@@ -21,7 +22,12 @@ object Prefs {
|
|||||||
port = sp.getInt("port", 5300),
|
port = sp.getInt("port", 5300),
|
||||||
callsign = sp.getString("callsign", "") ?: "",
|
callsign = sp.getString("callsign", "") ?: "",
|
||||||
authKey = sp.getString("auth_key", "") ?: "",
|
authKey = sp.getString("auth_key", "") ?: "",
|
||||||
talkGroup = sp.getLong("tg", 11)
|
talkGroup = sp.getLong("tg", 11),
|
||||||
|
groups = (sp.getString("groups", "") ?: "")
|
||||||
|
.split(',')
|
||||||
|
.mapNotNull { it.trim().toLongOrNull() }
|
||||||
|
.distinct()
|
||||||
|
.ifEmpty { listOf(9L, 11L, 12L, 13L) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,6 +39,7 @@ object Prefs {
|
|||||||
.putString("callsign", s.callsign.trim())
|
.putString("callsign", s.callsign.trim())
|
||||||
.putString("auth_key", s.authKey)
|
.putString("auth_key", s.authKey)
|
||||||
.putLong("tg", s.talkGroup)
|
.putLong("tg", s.talkGroup)
|
||||||
|
.putString("groups", s.groups.distinct().joinToString(","))
|
||||||
.apply()
|
.apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,7 +110,7 @@
|
|||||||
android:id="@+id/input_tg"
|
android:id="@+id/input_tg"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:inputType="number"
|
android:inputType="number"
|
||||||
android:textColor="@color/text_primary"
|
android:textColor="@color/text_primary"
|
||||||
android:textColorHint="@color/text_secondary"
|
android:textColorHint="@color/text_secondary"
|
||||||
@@ -119,6 +119,26 @@
|
|||||||
android:padding="12dp"
|
android:padding="12dp"
|
||||||
android:hint="11" />
|
android:hint="11" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/pref_groups"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:textSize="15sp" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/input_groups"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="24dp"
|
||||||
|
android:inputType="text"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:textColorHint="@color/text_secondary"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:background="@drawable/bg_input"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:hint="9, 11, 12, 13" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/btn_save"
|
android:id="@+id/btn_save"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -9,6 +9,9 @@
|
|||||||
<string name="pref_callsign">Позывной</string>
|
<string name="pref_callsign">Позывной</string>
|
||||||
<string name="pref_auth_key">Пароль (AUTH_KEY)</string>
|
<string name="pref_auth_key">Пароль (AUTH_KEY)</string>
|
||||||
<string name="pref_tg">Группа вещания (TG)</string>
|
<string name="pref_tg">Группа вещания (TG)</string>
|
||||||
|
<string name="pref_groups">Группы для переключения (через запятую)</string>
|
||||||
|
<string name="select_tg">Выбор группы</string>
|
||||||
|
<string name="toast_groups_empty">Добавьте группы в настройках</string>
|
||||||
<string name="btn_save">Сохранить</string>
|
<string name="btn_save">Сохранить</string>
|
||||||
<string name="app_version">SVXhomyak — v1.0.2</string>
|
<string name="app_version">SVXhomyak — v1.0.2</string>
|
||||||
<string name="saved">Сохранено</string>
|
<string name="saved">Сохранено</string>
|
||||||
@@ -26,7 +29,7 @@
|
|||||||
<string name="meter_mic">MIC</string>
|
<string name="meter_mic">MIC</string>
|
||||||
<string name="meter_idle">---</string>
|
<string name="meter_idle">---</string>
|
||||||
<string name="meter_db">-%1$d dB</string>
|
<string name="meter_db">-%1$d dB</string>
|
||||||
<string name="tg_badge">TG%1$d</string>
|
<string name="tg_badge">TG%1$d ▾</string>
|
||||||
<string name="talker_last_none">Последний: —</string>
|
<string name="talker_last_none">Последний: —</string>
|
||||||
<string name="status_connecting">Подключение…</string>
|
<string name="status_connecting">Подключение…</string>
|
||||||
<string name="status_connecting_ssl">Проверка ключа…</string>
|
<string name="status_connecting_ssl">Проверка ключа…</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user