feat(ui): add custom theme color support and share app functionality

Introduce a new custom theme feature that allows users to personalize the application background color using RGB sliders, hex input, or a set of predefined palettes.

Key changes include:
* **Custom Theme Engine**: Added `CustomThemeFragment` and `ThemeHelper` to manage color selection and application. The UI dynamically updates the background color across the `MainActivity` and `PlayerFragment` when preferences change.
* **Android TV Support**: Provided a specialized layout for television devices (`fragment_custom_theme.xml` in `layout-television`) with optimized focus handling for D-pad navigation.
* **Share Feature**: Implemented a "Share App" preference in `SettingsFragment` that triggers a standard Android share intent and displays a thank-you notification upon use.
* **Localization**: Added Ukrainian language support and updated string resources for multiple locales (DE, DA, EL, FR, JA, NL, PL, RU) to include the new theme and share options.
* **Persistence**: Updated `PreferencesHelper` and `Keys` to store theme-related settings, including the enabled state, selected color, and predefined color index.
This commit is contained in:
2026-06-01 19:32:46 +02:00
parent 4429ed4057
commit 181ebd47df
29 changed files with 947 additions and 3 deletions
@@ -2,6 +2,7 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/colorBackground"
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_margin="4dp"
android:focusable="true"
android:clickable="true"
android:background="@drawable/selector_color_circle">
<View
android:id="@+id/color_circle"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center"
android:background="@drawable/shape_color_circle" />
</FrameLayout>
@@ -0,0 +1,132 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
android:padding="16dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/predefined_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/theme_predefined_colors"
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toTopOf="@id/color_recycler_view"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/color_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="@id/predefined_label"
tools:listitem="@layout/element_color_circle" />
<TextView
android:id="@+id/custom_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="@string/theme_custom_rgb"
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/color_recycler_view" />
<LinearLayout
android:id="@+id/rgb_controls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="@drawable/shape_rgb_controls_border"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="@id/custom_label">
<TextView
android:id="@+id/red_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/theme_red" />
<SeekBar
android:id="@+id/seek_red"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="255"
android:focusable="true" />
<TextView
android:id="@+id/green_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/theme_green" />
<SeekBar
android:id="@+id/seek_green"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="255"
android:focusable="true" />
<TextView
android:id="@+id/blue_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/theme_blue" />
<SeekBar
android:id="@+id/seek_blue"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="255"
android:focusable="true" />
</LinearLayout>
<FrameLayout
android:id="@+id/color_preview_border"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:background="@drawable/shape_rgb_controls_border"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/rgb_controls">
<View
android:id="@+id/color_preview"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@android:color/black" />
</FrameLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/hex_input_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/color_preview_border">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/hex_code"
android:layout_width="140dp"
android:layout_height="wrap_content"
android:gravity="center"
android:inputType="textCapCharacters"
android:maxLength="9"
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
tools:text="#FF000000" />
</com.google.android.material.textfield.TextInputLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>