Initial commit: SVXHomyak - Android client for SVXLink reflectors

This commit is contained in:
ua1zbe
2026-08-13 13:33:17 +03:00
commit f924c4cc4a
29 changed files with 2528 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/surface_light" />
<corners android:radius="18dp" />
</shape>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/surface" />
<stroke android:width="1dp" android:color="@color/surface_light" />
<corners android:radius="10dp" />
</shape>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/accent" />
<corners android:radius="14dp" />
</shape>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<group
android:translateX="30"
android:translateY="30"
android:scaleX="1.5"
android:scaleY="1.5">
<path
android:fillColor="#FFFFFF"
android:pathData="M12,14c1.66,0 2.99,-1.34 2.99,-3L15,5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6c0,1.66 1.34,3 3,3zM17.3,11c0,3 -2.54,5.1 -5.3,5.1S6.7,14 6.7,11L5,11c0,3.41 2.72,6.23 6,6.72L11,21h2v-3.28c3.28,-0.48 6,-3.3 6,-6.72h-1.7z" />
</group>
</vector>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="64dp"
android:height="64dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFF"
android:pathData="M12,14c1.66,0 2.99,-1.34 2.99,-3L15,5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6c0,1.66 1.34,3 3,3zM17.3,11c0,3 -2.54,5.1 -5.3,5.1S6.7,14 6.7,11L5,11c0,3.41 2.72,6.23 6,6.72L11,21h2v-3.28c3.28,-0.48 6,-3.3 6,-6.72h-1.7z" />
</vector>

View 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="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z" />
</vector>

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/bg"
android:padding="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:id="@+id/status_chip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="14dp"
android:paddingVertical="6dp"
android:textColor="@color/text_primary"
android:textSize="14sp"
android:background="@drawable/bg_chip"
android:text="@string/status_disconnected" />
<Space
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1" />
<ImageButton
android:id="@+id/btn_settings"
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_settings"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/settings_title"
android:scaleType="centerInside" />
</LinearLayout>
<TextView
android:id="@+id/lbl_subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:textColor="@color/text_secondary"
android:textSize="13sp"
android:singleLine="true"
android:ellipsize="end"
android:text="@string/settings_not_configured" />
<TextView
android:id="@+id/lbl_talker_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="28dp"
android:textColor="@color/text_secondary"
android:textSize="14sp"
android:text="@string/talker_none" />
<TextView
android:id="@+id/lbl_talker"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textColor="@color/accent"
android:textSize="28sp"
android:textStyle="bold"
android:singleLine="true"
android:ellipsize="end"
android:text="@string/talker_none" />
<Space
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<ru.ua1zbe.svxremote.ui.LevelMeter
android:id="@+id/level_meter"
android:layout_width="match_parent"
android:layout_height="30dp" />
<ru.ua1zbe.svxremote.ui.PttButton
android:id="@+id/ptt_button"
android:layout_width="match_parent"
android:layout_height="220dp"
android:layout_marginTop="24dp"
android:layout_marginBottom="12dp" />
<TextView
android:id="@+id/lbl_ptt_hint"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="@color/text_secondary"
android:textSize="13sp"
android:text="@string/ptt_hint" />
<TextView
android:id="@+id/lbl_tx_state"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="@color/danger"
android:textSize="14sp"
android:textStyle="bold"
android:visibility="gone"
android:text="@string/ptt_talking" />
<Button
android:id="@+id/btn_connect"
android:layout_width="match_parent"
android:layout_height="52dp"
android:layout_marginTop="12dp"
android:text="@string/btn_connect"
android:textColor="#0D1117"
android:background="@drawable/bg_primary_btn"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>

View File

@@ -0,0 +1,132 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/bg"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/settings_hint"
android:textColor="@color/text_secondary"
android:textSize="14sp"
android:layout_marginBottom="20dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/pref_server_host"
android:textColor="@color/text_primary"
android:textSize="15sp" />
<EditText
android:id="@+id/input_host"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:inputType="textUri"
android:textColor="@color/text_primary"
android:textColorHint="@color/text_secondary"
android:textSize="16sp"
android:background="@drawable/bg_input"
android:padding="12dp"
android:hint="reflector.example.org" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/pref_server_port"
android:textColor="@color/text_primary"
android:textSize="15sp" />
<EditText
android:id="@+id/input_port"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:inputType="number"
android:textColor="@color/text_primary"
android:textColorHint="@color/text_secondary"
android:textSize="16sp"
android:background="@drawable/bg_input"
android:padding="12dp"
android:hint="5300" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/pref_callsign"
android:textColor="@color/text_primary"
android:textSize="15sp" />
<EditText
android:id="@+id/input_callsign"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
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="@string/pref_callsign_hint" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/pref_auth_key"
android:textColor="@color/text_primary"
android:textSize="15sp" />
<EditText
android:id="@+id/input_auth_key"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:inputType="textPassword"
android:textColor="@color/text_primary"
android:textColorHint="@color/text_secondary"
android:textSize="16sp"
android:background="@drawable/bg_input"
android:padding="12dp"
android:hint="••••••••" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/pref_tg"
android:textColor="@color/text_primary"
android:textSize="15sp" />
<EditText
android:id="@+id/input_tg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:inputType="number"
android:textColor="@color/text_primary"
android:textColorHint="@color/text_secondary"
android:textSize="16sp"
android:background="@drawable/bg_input"
android:padding="12dp"
android:hint="11" />
<Button
android:id="@+id/btn_save"
android:layout_width="match_parent"
android:layout_height="52dp"
android:text="@string/btn_save"
android:textColor="#0D1117"
android:background="@drawable/bg_primary_btn"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
</ScrollView>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<foreground android:drawable="@drawable/ic_launcher_fg" />
<background android:drawable="@color/bg" />
</adaptive-icon>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="bg">#0D1117</color>
<color name="surface">#161B22</color>
<color name="surface_light">#21262D</color>
<color name="text_primary">#E6EDF3</color>
<color name="text_secondary">#8B949E</color>
<color name="accent">#3FB950</color>
<color name="accent_pressed">#2EA043</color>
<color name="danger">#F85149</color>
<color name="warn">#D29922</color>
<color name="info">#58A6FF</color>
<color name="transparent">#00000000</color>
<color name="ptt_idle">#1F6FEB</color>
<color name="ptt_pressed">#F85149</color>
<color name="meter_background">#21262D</color>
<color name="meter_fill">#58A6FF</color>
<color name="meter_fill_tx">#F85149</color>
</resources>

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">SVXHomyak</string>
<string name="settings_title">Настройки</string>
<string name="settings_hint">Параметры подключения к рефлектору SVXLink</string>
<string name="pref_server_host">Сервер (хост или IP)</string>
<string name="pref_server_port">Порт (по умолчанию 5300)</string>
<string name="pref_callsign">Позывной</string>
<string name="pref_auth_key">Пароль (AUTH_KEY)</string>
<string name="pref_tg">Группа вещания (TG)</string>
<string name="btn_save">Сохранить</string>
<string name="saved">Сохранено</string>
<string name="pref_callsign_hint">например UA1ZBE</string>
<string name="status_disconnected">Отключено</string>
<string name="status_connecting">Подключение…</string>
<string name="status_connecting_ssl">Проверка ключа…</string>
<string name="status_connected">На связи</string>
<string name="status_auth_failed">Ошибка авторизации</string>
<string name="status_error">Ошибка: %1$s</string>
<string name="btn_connect">Подключиться</string>
<string name="btn_disconnect">Отключиться</string>
<string name="talker_none"></string>
<string name="talker_now">Сейчас говорит: %1$s</string>
<string name="talker_on_tg">группа %1$d</string>
<string name="ptt_hint">Удерживайте кнопку, чтобы говорить</string>
<string name="ptt_talking">Передача…</string>
<string name="rx_level">Приём</string>
<string name="tx_level">Передача</string>
<string name="server_subtitle">%1$s:%2$d · TG %3$d</string>
<string name="perm_mic">Для работы PTT нужен доступ к микрофону</string>
<string name="toast_connect_failed">Не удалось подключиться: %1$s</string>
<string name="toast_codec_unsupported">Рефлектор требует кодек %1$s — приложение поддерживает только OPUS</string>
<string name="toast_settings_empty">Заполните настройки подключения</string>
<string name="toast_need_settings">Откройте настройки и укажите сервер и позывной</string>
<string name="settings_not_configured">Настройки не заданы</string>
<string name="ptt_disabled">Нет связи</string>
</resources>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.SvxRemote" parent="android:Theme.Material.NoActionBar">
<item name="android:windowBackground">@color/bg</item>
<item name="android:statusBarColor">@color/bg</item>
<item name="android:navigationBarColor">@color/bg</item>
<item name="android:colorAccent">@color/info</item>
</style>
</resources>