From 5946ffae6e95681aade3041282da136ecf77bbd2 Mon Sep 17 00:00:00 2001 From: Eugene Date: Wed, 24 Jun 2026 20:25:05 +0300 Subject: [PATCH] piggy feature --- .../androidApp/src/main/AndroidManifest.xml | 47 +++++++++- .../videobox/multiplatform/MainActivity.kt | 12 ++- .../multiplatform/SecretCodeReceiver.kt | 31 +++++++ .../videobox/multiplatform/piggy/Color.kt | 75 ++++++++++++++++ .../videobox/multiplatform/piggy/Theme.kt | 89 +++++++++++++++++++ .../preview/SearchScreenPreview.kt | 1 - .../res/drawable/pig_launcher_foreground.xml | 14 +++ .../res/drawable/pig_launcher_monochrome.xml | 14 +++ .../res/mipmap-anydpi-v26/pig_launcher.xml | 6 ++ .../res/values/pig_launcher_background.xml | 4 + .../src/main/res/values/strings.xml | 2 + .../vbox/shared/presentation/BaseScreen.kt | 5 +- .../presentation/search/SearchScreen.kt | 9 +- 13 files changed, 295 insertions(+), 14 deletions(-) create mode 100644 apps/vbox/client/androidApp/src/main/kotlin/ru/shadowsparky/videobox/multiplatform/SecretCodeReceiver.kt create mode 100644 apps/vbox/client/androidApp/src/main/kotlin/ru/shadowsparky/videobox/multiplatform/piggy/Color.kt create mode 100644 apps/vbox/client/androidApp/src/main/kotlin/ru/shadowsparky/videobox/multiplatform/piggy/Theme.kt create mode 100644 apps/vbox/client/androidApp/src/main/res/drawable/pig_launcher_foreground.xml create mode 100644 apps/vbox/client/androidApp/src/main/res/drawable/pig_launcher_monochrome.xml create mode 100644 apps/vbox/client/androidApp/src/main/res/mipmap-anydpi-v26/pig_launcher.xml create mode 100644 apps/vbox/client/androidApp/src/main/res/values/pig_launcher_background.xml diff --git a/apps/vbox/client/androidApp/src/main/AndroidManifest.xml b/apps/vbox/client/androidApp/src/main/AndroidManifest.xml index c7c272e..c3711a2 100644 --- a/apps/vbox/client/androidApp/src/main/AndroidManifest.xml +++ b/apps/vbox/client/androidApp/src/main/AndroidManifest.xml @@ -19,7 +19,6 @@ android:enableOnBackInvokedCallback="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" - android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.Videobox" tools:ignore="UnusedAttribute"> @@ -51,14 +50,54 @@ + android:host="box.shadowsparky.ru" + android:scheme="https" /> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/vbox/client/androidApp/src/main/kotlin/ru/shadowsparky/videobox/multiplatform/MainActivity.kt b/apps/vbox/client/androidApp/src/main/kotlin/ru/shadowsparky/videobox/multiplatform/MainActivity.kt index 14d2b8f..18a8d66 100644 --- a/apps/vbox/client/androidApp/src/main/kotlin/ru/shadowsparky/videobox/multiplatform/MainActivity.kt +++ b/apps/vbox/client/androidApp/src/main/kotlin/ru/shadowsparky/videobox/multiplatform/MainActivity.kt @@ -9,15 +9,18 @@ import androidx.activity.SystemBarStyle import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.runtime.CompositionLocalProvider import androidx.lifecycle.lifecycleScope import com.arkivanov.decompose.retainedComponent import kotlinx.coroutines.launch import ru.shadowsparky.koin +import ru.shadowsparky.vbox.shared.presentation.LocalColorSchemeProvider import ru.shadowsparky.vbox.shared.presentation.Nav import ru.shadowsparky.vbox.shared.presentation.RootComponent import ru.shadowsparky.vbox.shared.presentation.RootFactory import ru.shadowsparky.vbox.shared.presentation.UrlRoutes import ru.shadowsparky.vbox.shared.presentation.nav.Route +import ru.shadowsparky.videobox.multiplatform.piggy.getPiggyColorScheme class MainActivity : ComponentActivity() { private lateinit var root: RootComponent @@ -39,8 +42,15 @@ class MainActivity : ComponentActivity() { .setData(null) .setAction(null) } + val isPiggyActivity = componentName?.className == SecretCodeReceiver.PIGGY_CLS setContent { - Nav(rootComponent = root) + if (isPiggyActivity) { + CompositionLocalProvider(LocalColorSchemeProvider provides getPiggyColorScheme()) { + Nav(rootComponent = root) + } + } else { + Nav(rootComponent = root) + } edgeToEdge(isSystemInDarkTheme()) } lifecycleScope.launch { diff --git a/apps/vbox/client/androidApp/src/main/kotlin/ru/shadowsparky/videobox/multiplatform/SecretCodeReceiver.kt b/apps/vbox/client/androidApp/src/main/kotlin/ru/shadowsparky/videobox/multiplatform/SecretCodeReceiver.kt new file mode 100644 index 0000000..44d6987 --- /dev/null +++ b/apps/vbox/client/androidApp/src/main/kotlin/ru/shadowsparky/videobox/multiplatform/SecretCodeReceiver.kt @@ -0,0 +1,31 @@ +package ru.shadowsparky.videobox.multiplatform + +import android.content.BroadcastReceiver +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager + +class SecretCodeReceiver : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + if (context == null || intent?.action != "android.provider.Telephony.SECRET_CODE") return + val pm = context.packageManager + val mainActivity = ComponentName(context, MainActivity::class.java) + val piggyActivityAlias = ComponentName(context, PIGGY_CLS) + val isMainEnabled = pm.getComponentEnabledSetting(mainActivity) == PackageManager.COMPONENT_ENABLED_STATE_ENABLED + pm.setState(piggyActivityAlias, isMainEnabled) + pm.setState(mainActivity, !isMainEnabled) + } + + private fun PackageManager.setState(cn: ComponentName, isEnabled: Boolean) { + setComponentEnabledSetting( + cn, + if (isEnabled) PackageManager.COMPONENT_ENABLED_STATE_ENABLED else PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP + ) + } + + companion object { + const val PIGGY_CLS = "ru.shadowsparky.videobox.multiplatform.PiggyActivity" + } +} diff --git a/apps/vbox/client/androidApp/src/main/kotlin/ru/shadowsparky/videobox/multiplatform/piggy/Color.kt b/apps/vbox/client/androidApp/src/main/kotlin/ru/shadowsparky/videobox/multiplatform/piggy/Color.kt new file mode 100644 index 0000000..5df75ff --- /dev/null +++ b/apps/vbox/client/androidApp/src/main/kotlin/ru/shadowsparky/videobox/multiplatform/piggy/Color.kt @@ -0,0 +1,75 @@ +package ru.shadowsparky.videobox.multiplatform.piggy + +import androidx.compose.ui.graphics.Color + +val primaryLight = Color(0xFF8F4A4D) +val onPrimaryLight = Color(0xFFFFFFFF) +val primaryContainerLight = Color(0xFFFFDADA) +val onPrimaryContainerLight = Color(0xFF733337) +val secondaryLight = Color(0xFF765657) +val onSecondaryLight = Color(0xFFFFFFFF) +val secondaryContainerLight = Color(0xFFFFDADA) +val onSecondaryContainerLight = Color(0xFF5D3F40) +val tertiaryLight = Color(0xFF755A2F) +val onTertiaryLight = Color(0xFFFFFFFF) +val tertiaryContainerLight = Color(0xFFFFDDB0) +val onTertiaryContainerLight = Color(0xFF5B421A) +val errorLight = Color(0xFFBA1A1A) +val onErrorLight = Color(0xFFFFFFFF) +val errorContainerLight = Color(0xFFFFDAD6) +val onErrorContainerLight = Color(0xFF93000A) +val backgroundLight = Color(0xFFFFF8F7) +val onBackgroundLight = Color(0xFF221919) +val surfaceLight = Color(0xFFFFF8F7) +val onSurfaceLight = Color(0xFF221919) +val surfaceVariantLight = Color(0xFFF4DDDD) +val onSurfaceVariantLight = Color(0xFF524343) +val outlineLight = Color(0xFF857373) +val outlineVariantLight = Color(0xFFD7C1C1) +val scrimLight = Color(0xFF000000) +val inverseSurfaceLight = Color(0xFF382E2E) +val inverseOnSurfaceLight = Color(0xFFFFEDEC) +val inversePrimaryLight = Color(0xFFFFB3B4) +val surfaceDimLight = Color(0xFFE8D6D6) +val surfaceBrightLight = Color(0xFFFFF8F7) +val surfaceContainerLowestLight = Color(0xFFFFFFFF) +val surfaceContainerLowLight = Color(0xFFFFF0F0) +val surfaceContainerLight = Color(0xFFFCEAE9) +val surfaceContainerHighLight = Color(0xFFF6E4E4) +val surfaceContainerHighestLight = Color(0xFFF0DEDE) + +val primaryDark = Color(0xFFFFB3B4) +val onPrimaryDark = Color(0xFF561D22) +val primaryContainerDark = Color(0xFF733337) +val onPrimaryContainerDark = Color(0xFFFFDADA) +val secondaryDark = Color(0xFFE6BDBD) +val onSecondaryDark = Color(0xFF44292A) +val secondaryContainerDark = Color(0xFF5D3F40) +val onSecondaryContainerDark = Color(0xFFFFDADA) +val tertiaryDark = Color(0xFFE6C18D) +val onTertiaryDark = Color(0xFF422C05) +val tertiaryContainerDark = Color(0xFF5B421A) +val onTertiaryContainerDark = Color(0xFFFFDDB0) +val errorDark = Color(0xFFFFB4AB) +val onErrorDark = Color(0xFF690005) +val errorContainerDark = Color(0xFF93000A) +val onErrorContainerDark = Color(0xFFFFDAD6) +val backgroundDark = Color(0xFF1A1111) +val onBackgroundDark = Color(0xFFF0DEDE) +val surfaceDark = Color(0xFF1A1111) +val onSurfaceDark = Color(0xFFF0DEDE) +val surfaceVariantDark = Color(0xFF524343) +val onSurfaceVariantDark = Color(0xFFD7C1C1) +val outlineDark = Color(0xFF9F8C8C) +val outlineVariantDark = Color(0xFF524343) +val scrimDark = Color(0xFF000000) +val inverseSurfaceDark = Color(0xFFF0DEDE) +val inverseOnSurfaceDark = Color(0xFF382E2E) +val inversePrimaryDark = Color(0xFF8F4A4D) +val surfaceDimDark = Color(0xFF1A1111) +val surfaceBrightDark = Color(0xFF413737) +val surfaceContainerLowestDark = Color(0xFF140C0C) +val surfaceContainerLowDark = Color(0xFF221919) +val surfaceContainerDark = Color(0xFF271D1D) +val surfaceContainerHighDark = Color(0xFF322828) +val surfaceContainerHighestDark = Color(0xFF3D3232) diff --git a/apps/vbox/client/androidApp/src/main/kotlin/ru/shadowsparky/videobox/multiplatform/piggy/Theme.kt b/apps/vbox/client/androidApp/src/main/kotlin/ru/shadowsparky/videobox/multiplatform/piggy/Theme.kt new file mode 100644 index 0000000..cc7c7ff --- /dev/null +++ b/apps/vbox/client/androidApp/src/main/kotlin/ru/shadowsparky/videobox/multiplatform/piggy/Theme.kt @@ -0,0 +1,89 @@ +package ru.shadowsparky.videobox.multiplatform.piggy + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.ColorScheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable + +private val lightScheme = lightColorScheme( + primary = primaryLight, + onPrimary = onPrimaryLight, + primaryContainer = primaryContainerLight, + onPrimaryContainer = onPrimaryContainerLight, + secondary = secondaryLight, + onSecondary = onSecondaryLight, + secondaryContainer = secondaryContainerLight, + onSecondaryContainer = onSecondaryContainerLight, + tertiary = tertiaryLight, + onTertiary = onTertiaryLight, + tertiaryContainer = tertiaryContainerLight, + onTertiaryContainer = onTertiaryContainerLight, + error = errorLight, + onError = onErrorLight, + errorContainer = errorContainerLight, + onErrorContainer = onErrorContainerLight, + background = backgroundLight, + onBackground = onBackgroundLight, + surface = surfaceLight, + onSurface = onSurfaceLight, + surfaceVariant = surfaceVariantLight, + onSurfaceVariant = onSurfaceVariantLight, + outline = outlineLight, + outlineVariant = outlineVariantLight, + scrim = scrimLight, + inverseSurface = inverseSurfaceLight, + inverseOnSurface = inverseOnSurfaceLight, + inversePrimary = inversePrimaryLight, + surfaceDim = surfaceDimLight, + surfaceBright = surfaceBrightLight, + surfaceContainerLowest = surfaceContainerLowestLight, + surfaceContainerLow = surfaceContainerLowLight, + surfaceContainer = surfaceContainerLight, + surfaceContainerHigh = surfaceContainerHighLight, + surfaceContainerHighest = surfaceContainerHighestLight, +) + +private val darkScheme = darkColorScheme( + primary = primaryDark, + onPrimary = onPrimaryDark, + primaryContainer = primaryContainerDark, + onPrimaryContainer = onPrimaryContainerDark, + secondary = secondaryDark, + onSecondary = onSecondaryDark, + secondaryContainer = secondaryContainerDark, + onSecondaryContainer = onSecondaryContainerDark, + tertiary = tertiaryDark, + onTertiary = onTertiaryDark, + tertiaryContainer = tertiaryContainerDark, + onTertiaryContainer = onTertiaryContainerDark, + error = errorDark, + onError = onErrorDark, + errorContainer = errorContainerDark, + onErrorContainer = onErrorContainerDark, + background = backgroundDark, + onBackground = onBackgroundDark, + surface = surfaceDark, + onSurface = onSurfaceDark, + surfaceVariant = surfaceVariantDark, + onSurfaceVariant = onSurfaceVariantDark, + outline = outlineDark, + outlineVariant = outlineVariantDark, + scrim = scrimDark, + inverseSurface = inverseSurfaceDark, + inverseOnSurface = inverseOnSurfaceDark, + inversePrimary = inversePrimaryDark, + surfaceDim = surfaceDimDark, + surfaceBright = surfaceBrightDark, + surfaceContainerLowest = surfaceContainerLowestDark, + surfaceContainerLow = surfaceContainerLowDark, + surfaceContainer = surfaceContainerDark, + surfaceContainerHigh = surfaceContainerHighDark, + surfaceContainerHighest = surfaceContainerHighestDark, +) + +@Composable +fun getPiggyColorScheme(): ColorScheme { + return if (isSystemInDarkTheme()) darkScheme else lightScheme +} + diff --git a/apps/vbox/client/androidApp/src/main/kotlin/ru/shadowsparky/videobox/multiplatform/preview/SearchScreenPreview.kt b/apps/vbox/client/androidApp/src/main/kotlin/ru/shadowsparky/videobox/multiplatform/preview/SearchScreenPreview.kt index e3bdbc3..c1d319d 100644 --- a/apps/vbox/client/androidApp/src/main/kotlin/ru/shadowsparky/videobox/multiplatform/preview/SearchScreenPreview.kt +++ b/apps/vbox/client/androidApp/src/main/kotlin/ru/shadowsparky/videobox/multiplatform/preview/SearchScreenPreview.kt @@ -39,7 +39,6 @@ fun AppBarWithSearchWithBackPreview() { @Composable fun InternalAppBarPreview() { SearchAppBar( - Modifier, TextFieldValue(""), FocusRequester(), {}, diff --git a/apps/vbox/client/androidApp/src/main/res/drawable/pig_launcher_foreground.xml b/apps/vbox/client/androidApp/src/main/res/drawable/pig_launcher_foreground.xml new file mode 100644 index 0000000..aaa26c7 --- /dev/null +++ b/apps/vbox/client/androidApp/src/main/res/drawable/pig_launcher_foreground.xml @@ -0,0 +1,14 @@ + + + + + diff --git a/apps/vbox/client/androidApp/src/main/res/drawable/pig_launcher_monochrome.xml b/apps/vbox/client/androidApp/src/main/res/drawable/pig_launcher_monochrome.xml new file mode 100644 index 0000000..aaa26c7 --- /dev/null +++ b/apps/vbox/client/androidApp/src/main/res/drawable/pig_launcher_monochrome.xml @@ -0,0 +1,14 @@ + + + + + diff --git a/apps/vbox/client/androidApp/src/main/res/mipmap-anydpi-v26/pig_launcher.xml b/apps/vbox/client/androidApp/src/main/res/mipmap-anydpi-v26/pig_launcher.xml new file mode 100644 index 0000000..8dc430c --- /dev/null +++ b/apps/vbox/client/androidApp/src/main/res/mipmap-anydpi-v26/pig_launcher.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/apps/vbox/client/androidApp/src/main/res/values/pig_launcher_background.xml b/apps/vbox/client/androidApp/src/main/res/values/pig_launcher_background.xml new file mode 100644 index 0000000..28f502c --- /dev/null +++ b/apps/vbox/client/androidApp/src/main/res/values/pig_launcher_background.xml @@ -0,0 +1,4 @@ + + + #FDD5D5 + diff --git a/apps/vbox/client/androidApp/src/main/res/values/strings.xml b/apps/vbox/client/androidApp/src/main/res/values/strings.xml index 1083d06..a11ef76 100644 --- a/apps/vbox/client/androidApp/src/main/res/values/strings.xml +++ b/apps/vbox/client/androidApp/src/main/res/values/strings.xml @@ -1,5 +1,7 @@ Videobox + Свиное Рыло + Сохранённые фильмы Просмотр списка ранее сохранённых фильмов diff --git a/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/presentation/BaseScreen.kt b/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/presentation/BaseScreen.kt index 873494d..50d09c5 100644 --- a/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/presentation/BaseScreen.kt +++ b/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/presentation/BaseScreen.kt @@ -9,6 +9,7 @@ import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.compositionLocalOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import com.seiko.imageloader.LocalImageLoader @@ -30,9 +31,11 @@ import ru.shadowsparky.vbox.shared.presentation.settings.register.RegisterScreen import ru.shadowsparky.vbox.shared.presentation.settings.serv.EditServScreen import ru.shadowsparky.vbox.shared.presentation.settings.tag.TagScreen +val LocalColorSchemeProvider = compositionLocalOf { null } + @Composable fun getColorScheme(): ColorScheme { - return ru.shadowsparky.ui.theme.getColorScheme() + return LocalColorSchemeProvider.current ?: ru.shadowsparky.ui.theme.getColorScheme() } @Composable diff --git a/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/presentation/search/SearchScreen.kt b/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/presentation/search/SearchScreen.kt index a71f87c..1d8380d 100644 --- a/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/presentation/search/SearchScreen.kt +++ b/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/presentation/search/SearchScreen.kt @@ -92,7 +92,6 @@ fun SearchScreen( BaseMainScreen( appBar = { SearchAppBar( - modifier = Modifier.fillMaxWidth(), textFieldValue = textFieldValue, onDone = { component.done(textFieldValue.text) }, onValueChange = { textFieldValue = it }, @@ -214,7 +213,6 @@ expect fun Modifier.requestFocusOnDownEvent(focusRequester: FocusRequester): Mod @Composable @OptIn(ExperimentalMaterial3Api::class) fun SearchAppBar( - modifier: Modifier, textFieldValue: TextFieldValue, focusRequester: FocusRequester, onDone: () -> Unit, @@ -230,7 +228,7 @@ fun SearchAppBar( } val blur = LocalBlurState.current AppBarWithSearch( - modifier = modifier.applyBlurEffect(blur), + modifier = Modifier.applyBlurEffect(blur), state = rememberSearchBarState(), colors = ComponentDefaults.appBarWithSearchDefaults(), inputField = { @@ -316,10 +314,7 @@ fun AppBarWithSearch( BackButton { onBack() } Spacer(Modifier.width(12.dp)) } - Text( - text = title, - maxLines = 1 - ) + Text(text = title, maxLines = 1) } } }