From a6509993a353e3b76fdd8032bd811381f527d9c4 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 18 May 2026 20:24:11 +0300 Subject: [PATCH 1/6] chore: add new GS root CA for cert pinning --- app/src/main/res/xml/network_security_config.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml index ad43458..61e9f3d 100644 --- a/app/src/main/res/xml/network_security_config.xml +++ b/app/src/main/res/xml/network_security_config.xml @@ -4,6 +4,9 @@ rustore.ru hETpgVvaLC0bvcGG3t0cuqiHvr4XyP2MTwCiqhgRWwU= + + rn+WLLnmp9v3uDP7GPqbcaiRdd+UnCMrap73yz3yu/w= + 4EoCLOMvTM8sf2BGKHuCijKpCfXnUUR/g/0scfb9gXM= \ No newline at end of file From f09226ef3a6052ed50dd41b8a2c545c0b07466aa Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 19 May 2026 13:59:51 +0300 Subject: [PATCH 2/6] feat: improved accessibility (fixed #22, fixed #21) --- .../openstore/ui/components/Gallery.kt | 6 +- .../ui/screen/details/DetailsScreen.kt | 71 +++++++++++++++---- .../ui/screen/results/ResultsScreen.kt | 20 +++++- .../ui/screen/reviews/ReviewsScreen.kt | 18 +++-- .../ui/screen/search/SearchScreen.kt | 7 +- .../ui/screen/settings/SettingsScreen.kt | 5 +- .../ui/screen/updates/UpdatesScreen.kt | 2 +- app/src/main/res/values-en/strings.xml | 2 + app/src/main/res/values/strings.xml | 16 +++++ 9 files changed, 122 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/dev/mi6e4ka/openstore/ui/components/Gallery.kt b/app/src/main/java/dev/mi6e4ka/openstore/ui/components/Gallery.kt index 0865a21..4fc242d 100644 --- a/app/src/main/java/dev/mi6e4ka/openstore/ui/components/Gallery.kt +++ b/app/src/main/java/dev/mi6e4ka/openstore/ui/components/Gallery.kt @@ -33,6 +33,9 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.semantics.clearAndSetSemantics +import androidx.compose.ui.semantics.hideFromAccessibility +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties @@ -62,7 +65,8 @@ fun GalleryWithPager(images: List) { modifier = Modifier.height(250.dp) ) { LazyRow( - horizontalArrangement = Arrangement.spacedBy(8.dp) + horizontalArrangement = Arrangement.spacedBy(8.dp), + modifier = Modifier.clearAndSetSemantics{} ) { itemsIndexed(images) { i, file -> var isLoading by remember { mutableStateOf(true) } diff --git a/app/src/main/java/dev/mi6e4ka/openstore/ui/screen/details/DetailsScreen.kt b/app/src/main/java/dev/mi6e4ka/openstore/ui/screen/details/DetailsScreen.kt index 8212a32..1601359 100644 --- a/app/src/main/java/dev/mi6e4ka/openstore/ui/screen/details/DetailsScreen.kt +++ b/app/src/main/java/dev/mi6e4ka/openstore/ui/screen/details/DetailsScreen.kt @@ -86,6 +86,9 @@ import kotlinx.datetime.toLocalDateTime import android.Manifest import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.ui.semantics.clearAndSetSemantics +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.semantics import kotlin.time.ExperimentalTime import kotlin.time.Instant @@ -141,7 +144,7 @@ fun DetailsScreen( IconButton(onClick = { navController.popBackStack() }) { Icon( painter = painterResource(R.drawable.ic_arrow_back_24px), - contentDescription = "Back" + contentDescription = stringResource(R.string.back_button_desc) ) } }, @@ -153,7 +156,10 @@ fun DetailsScreen( } } ){ - Icon(painterResource(R.drawable.ic_link_24px), null) + Icon( + painterResource(R.drawable.ic_link_24px), + stringResource(R.string.copy_link_desc) + ) } IconButton( { @@ -175,7 +181,10 @@ fun DetailsScreen( } } ){ - Icon(painterResource(R.drawable.apk_install_24px), null) + Icon( + painterResource(R.drawable.apk_install_24px), + stringResource(R.string.download_apk_desc) + ) } IconButton(onClick = { val intent = Intent(Intent.ACTION_VIEW, "https://www.rustore.ru/catalog/app/${state.item?.packageName ?: ""}".toUri()).apply { @@ -184,7 +193,10 @@ fun DetailsScreen( } context.startActivity(intent) }, enabled = state.item != null) { - Icon(painterResource(R.drawable.ic_captive_portal_24px), null) + Icon( + painterResource(R.drawable.ic_captive_portal_24px), + stringResource(R.string.open_in_browser_desc) + ) } } ) } @@ -332,7 +344,7 @@ fun DetailsScreen( verticalArrangement = Arrangement.spacedBy(4.dp) ) { Text(item.appName, fontSize = 24.sp, fontWeight = FontWeight.Bold, maxLines = 2, overflow = TextOverflow.Ellipsis) - Text(item.aggregatorInfo?.companyName ?: item.companyName, maxLines = 2, overflow = TextOverflow.Ellipsis) + Text(item.aggregatorInfo?.companyName ?: item.companyName, maxLines = 2, overflow = TextOverflow.Ellipsis, modifier = Modifier.clearAndSetSemantics(){contentDescription = "Разработчик: ${item.aggregatorInfo?.companyName ?: item.companyName}"}) } } if (!state.isSupported) { @@ -433,18 +445,30 @@ fun DetailsScreen( (state.appFiles?.sumOf { it.size } ?: 0L) / 1024.0 / 1024.0) ) }, - leadingIcon = {Icon(painterResource(R.drawable.ic_upload_file_24px), contentDescription = null)}, + leadingIcon = { + Icon( + painterResource(R.drawable.ic_upload_file_24px), + stringResource(R.string.app_size_desc) + )}, onClick = {}, ) AssistChip( onClick = {}, label = {Text(item.versionName)}, - leadingIcon = {Icon(painterResource(R.drawable.ic_arrow_circle_up_24px), contentDescription = null)} + leadingIcon = { + Icon( + painterResource(R.drawable.ic_arrow_circle_up_24px), + stringResource(R.string.latest_version_desc) + )} ) AssistChip( onClick = {}, label = {FormattedDateText(item.appVerUpdatedAt)}, - leadingIcon = {Icon(painterResource(R.drawable.ic_update_24px), contentDescription = null)} + leadingIcon = { + Icon( + painterResource(R.drawable.ic_update_24px), + stringResource(R.string.last_update_desc) + )} ) var detailedApiVersion by remember { mutableStateOf(false) } AssistChip( @@ -458,22 +482,38 @@ fun DetailsScreen( Text("API ${item.minSdkVersion} +") } }, - leadingIcon = {Icon(painterResource(R.drawable.ic_android_24px), contentDescription = null)} + leadingIcon = { + Icon( + painterResource(R.drawable.ic_android_24px), + stringResource(R.string.min_api_desc) + )} ) AssistChip( onClick = {}, label = {Text(if ((state.appFiles?.size ?: 1) > 1) "${state.appFiles?.size} Split APKs" else "APK")}, - leadingIcon = {Icon(painterResource(R.drawable.ic_adb_24px), contentDescription = null)} + leadingIcon = { + Icon( + painterResource(R.drawable.ic_adb_24px), + stringResource(R.string.installer_type_desc) + )} ) AssistChip( onClick = {}, label = {Text(item.roundedDownloadsText)}, - leadingIcon = {Icon(painterResource(R.drawable.ic_download_24px), contentDescription = null)} + leadingIcon = { + Icon( + painterResource(R.drawable.ic_download_24px), + stringResource(R.string.downloads_desc) + )} ) AssistChip( onClick = {}, label = {Text(item.ageLegal)}, - leadingIcon = {Icon(painterResource(R.drawable.ic_supervised_user_circle_24px), contentDescription = null)} + leadingIcon = { + Icon( + painterResource(R.drawable.ic_supervised_user_circle_24px), + stringResource(R.string.age_legal_desc) + )} ) } GalleryWithPager(item.fileUrls) @@ -539,6 +579,13 @@ fun DetailsScreen( restoreState = true } }) + .clearAndSetSemantics { + contentDescription = context.getString( + R.string.reviews_desc, + state.rating?.averageUserRating ?: 0, + state.rating?.totalRatings ?: 0 + ) + } ) { Row( Modifier diff --git a/app/src/main/java/dev/mi6e4ka/openstore/ui/screen/results/ResultsScreen.kt b/app/src/main/java/dev/mi6e4ka/openstore/ui/screen/results/ResultsScreen.kt index 9e26e5f..811dd57 100644 --- a/app/src/main/java/dev/mi6e4ka/openstore/ui/screen/results/ResultsScreen.kt +++ b/app/src/main/java/dev/mi6e4ka/openstore/ui/screen/results/ResultsScreen.kt @@ -35,6 +35,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.hideFromAccessibility +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -68,7 +70,7 @@ fun ResultsScreen( IconButton(onClick = { navController.popBackStack() }) { Icon( painterResource(R.drawable.ic_arrow_back_24px), - contentDescription = "Back" + contentDescription = stringResource(R.string.back_button_desc) ) } }, @@ -81,7 +83,10 @@ fun ResultsScreen( } TextButton({platformSelectorExpanded = true}) { - Icon(painterResource(state.selectedPlatform.icon), null) + Icon( + painterResource(state.selectedPlatform.icon), + contentDescription = stringResource(R.string.tts_current_platform) + ) Spacer(Modifier.size(8.dp)) Text(stringResource(state.selectedPlatform.label)) } @@ -125,7 +130,16 @@ fun ResultsScreen( modifier = Modifier.weight(1f).padding(start = 16.dp,end = 4.dp) ) { Text(text = app.appName, maxLines = 1, overflow = TextOverflow.Ellipsis) - Text(text = app.packageName, fontSize = 14.sp, maxLines = 1, overflow = TextOverflow.Ellipsis, color = MaterialTheme.colorScheme.secondary) + Text( + text = app.packageName, + fontSize = 14.sp, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + color = MaterialTheme.colorScheme.secondary, + modifier = Modifier.semantics{ + hideFromAccessibility() + } + ) } } } diff --git a/app/src/main/java/dev/mi6e4ka/openstore/ui/screen/reviews/ReviewsScreen.kt b/app/src/main/java/dev/mi6e4ka/openstore/ui/screen/reviews/ReviewsScreen.kt index 2ac553e..56eea6e 100644 --- a/app/src/main/java/dev/mi6e4ka/openstore/ui/screen/reviews/ReviewsScreen.kt +++ b/app/src/main/java/dev/mi6e4ka/openstore/ui/screen/reviews/ReviewsScreen.kt @@ -35,8 +35,12 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.clearAndSetSemantics +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.navigation.NavController @@ -95,7 +99,7 @@ fun ReviewsScreen(packageName: String, navController: NavController = rememberNa IconButton(onClick = { navController.popBackStack() }) { Icon( painterResource(R.drawable.ic_arrow_back_24px), - contentDescription = "Back" + contentDescription = stringResource(R.string.back_button_desc) ) } }, @@ -135,11 +139,12 @@ fun ReviewsScreen(packageName: String, navController: NavController = rememberNa } items(reviews ?: listOf()) { review -> Card( - Modifier.fillMaxWidth() + Modifier.fillMaxWidth().semantics(mergeDescendants = true){} ) { Column( Modifier.padding(16.dp) ) { + val context = LocalContext.current Row( Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, @@ -155,7 +160,10 @@ fun ReviewsScreen(packageName: String, navController: NavController = rememberNa } Spacer(Modifier.height(8.dp)) Row( - verticalAlignment = Alignment.CenterVertically + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.clearAndSetSemantics{ + contentDescription = context.getString(R.string.review_rating_desc, review.appRating) + } ) { repeat(review.appRating) { Icon(painterResource(R.drawable.ic_star_filled_24px), null, Modifier.size(16.dp), tint = MaterialTheme.colorScheme.primary) @@ -171,12 +179,12 @@ fun ReviewsScreen(packageName: String, navController: NavController = rememberNa horizontalArrangement = Arrangement.spacedBy(16.dp) ) { Row(verticalAlignment = Alignment.CenterVertically) { - Icon(painterResource(R.drawable.ic_thumb_up_24px), contentDescription = null, Modifier.size(20.dp), tint = MaterialTheme.colorScheme.secondary) + Icon(painterResource(R.drawable.ic_thumb_up_24px), contentDescription = stringResource(R.string.likes_desc), Modifier.size(20.dp), tint = MaterialTheme.colorScheme.secondary) Spacer(Modifier.width(4.dp)) Text("${review.likeCounter}") } Row(verticalAlignment = Alignment.CenterVertically) { - Icon(painterResource(R.drawable.ic_thumb_down_24px), contentDescription = null, Modifier.size(20.dp), tint = MaterialTheme.colorScheme.secondary) + Icon(painterResource(R.drawable.ic_thumb_down_24px), contentDescription = stringResource(R.string.dislikes_desc), Modifier.size(20.dp), tint = MaterialTheme.colorScheme.secondary) Spacer(Modifier.width(6.dp)) Text("${review.dislikeCounter}") } diff --git a/app/src/main/java/dev/mi6e4ka/openstore/ui/screen/search/SearchScreen.kt b/app/src/main/java/dev/mi6e4ka/openstore/ui/screen/search/SearchScreen.kt index 0b21410..e5c319b 100644 --- a/app/src/main/java/dev/mi6e4ka/openstore/ui/screen/search/SearchScreen.kt +++ b/app/src/main/java/dev/mi6e4ka/openstore/ui/screen/search/SearchScreen.kt @@ -98,7 +98,10 @@ fun SearchScreen(navController: NavController = rememberNavController()) { ) } IconButton({navController.navigate("settings")}) { - Icon(painterResource(R.drawable.ic_settings_24px), "settings") + Icon( + painterResource(R.drawable.ic_settings_24px), + contentDescription = stringResource(R.string.settings_title) + ) } } ) }, @@ -151,7 +154,7 @@ fun SearchScreen(navController: NavController = rememberNavController()) { onValueChange = {s -> search=s}, leadingIcon = { Icon(painterResource(R.drawable.ic_search_24px), contentDescription = null) }, modifier = Modifier.fillMaxWidth().semantics{ - contentDescription = "Search" + contentDescription = context.getString(R.string.search_title) }, singleLine = true, keyboardOptions = KeyboardOptions( diff --git a/app/src/main/java/dev/mi6e4ka/openstore/ui/screen/settings/SettingsScreen.kt b/app/src/main/java/dev/mi6e4ka/openstore/ui/screen/settings/SettingsScreen.kt index 0a863c7..a5cbd2f 100644 --- a/app/src/main/java/dev/mi6e4ka/openstore/ui/screen/settings/SettingsScreen.kt +++ b/app/src/main/java/dev/mi6e4ka/openstore/ui/screen/settings/SettingsScreen.kt @@ -156,7 +156,10 @@ fun SettingsScreen( } } ) { - Icon(painterResource(R.drawable.ic_arrow_back_24px), "back") + Icon( + painterResource(R.drawable.ic_arrow_back_24px), + stringResource(R.string.back_button_desc) + ) } } ) diff --git a/app/src/main/java/dev/mi6e4ka/openstore/ui/screen/updates/UpdatesScreen.kt b/app/src/main/java/dev/mi6e4ka/openstore/ui/screen/updates/UpdatesScreen.kt index f628c66..ac422c0 100644 --- a/app/src/main/java/dev/mi6e4ka/openstore/ui/screen/updates/UpdatesScreen.kt +++ b/app/src/main/java/dev/mi6e4ka/openstore/ui/screen/updates/UpdatesScreen.kt @@ -114,7 +114,7 @@ fun UpdatesScreen(navController: NavController) { IconButton(onClick = { navController.popBackStack() }) { Icon( painter = painterResource(R.drawable.ic_arrow_back_24px), - contentDescription = "Back" + contentDescription = stringResource(R.string.back_button_desc) ) } }, diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index 16d0b51..43e6f88 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -73,4 +73,6 @@ Auto Dark Light + Back + Apps for platfom \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9224639..cc0eee6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -73,4 +73,20 @@ Тёмная Светлая Обновления будут проверяться для приложений из выбранных источников + Назад + Приложения для платформы + Скопировать ссылку на apk + Скачать apk без установки + Открыть страницу приложения в браузере + Вес приложения + Текущая версия + Последнее обновление + Минимальная версия android + Тип установочного файла + Количество установок + Возрастная категория + Рейтинг и отзывы\nСредняя оценка: %1$.2f\nВсего оценок: %2$d + оценка: %1$d + Лайки + Дизлайки \ No newline at end of file From f4ee755783e72e14fdc6d2798765401d5aebbb80 Mon Sep 17 00:00:00 2001 From: oltine Date: Thu, 4 Jun 2026 21:09:36 +0200 Subject: [PATCH 3/6] =?UTF-8?q?=D0=9F=D1=80=D0=B8=D0=BC=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 90144cc..0b74320 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -35,11 +35,12 @@ - - - - - + + + + + + From 0cc3da6949cbec3fd6b5a65101a93faaa8abc362 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 18 Jun 2026 21:27:39 +0300 Subject: [PATCH 4/6] chore: revert ssl pinning --- app/src/main/res/xml/network_security_config.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml index 61e9f3d..ad43458 100644 --- a/app/src/main/res/xml/network_security_config.xml +++ b/app/src/main/res/xml/network_security_config.xml @@ -4,9 +4,6 @@ rustore.ru hETpgVvaLC0bvcGG3t0cuqiHvr4XyP2MTwCiqhgRWwU= - - rn+WLLnmp9v3uDP7GPqbcaiRdd+UnCMrap73yz3yu/w= - 4EoCLOMvTM8sf2BGKHuCijKpCfXnUUR/g/0scfb9gXM= \ No newline at end of file From 74c0e35c764b1eb1fe7dd411c47967b14f958c8c Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 18 Jun 2026 21:28:45 +0300 Subject: [PATCH 5/6] chore: revert ssl pinning --- app/src/main/AndroidManifest.xml | 3 +-- app/src/main/res/xml/network_security_config.xml | 9 --------- 2 files changed, 1 insertion(+), 11 deletions(-) delete mode 100644 app/src/main/res/xml/network_security_config.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0b74320..7deb6c6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -23,7 +23,6 @@ android:supportsRtl="true" android:theme="@style/AppTheme" android:localeConfig="@xml/locale_config" - android:networkSecurityConfig="@xml/network_security_config" tools:targetApi="36" android:memtagMode="async"> - \ No newline at end of file + diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml deleted file mode 100644 index ad43458..0000000 --- a/app/src/main/res/xml/network_security_config.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - rustore.ru - - hETpgVvaLC0bvcGG3t0cuqiHvr4XyP2MTwCiqhgRWwU= - - - \ No newline at end of file From 823fb1154639862a677b24a41d7c2b1bf99c3323 Mon Sep 17 00:00:00 2001 From: oltnd Date: Thu, 18 Jun 2026 21:41:50 +0300 Subject: [PATCH 6/6] feat: enable edge-to-edge display --- app/src/main/java/dev/mi6e4ka/openstore/MainActivity.kt | 2 ++ app/src/main/res/values-night/themes.xml | 5 +---- app/src/main/res/values/themes.xml | 5 +---- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/dev/mi6e4ka/openstore/MainActivity.kt b/app/src/main/java/dev/mi6e4ka/openstore/MainActivity.kt index df8e860..5df0999 100644 --- a/app/src/main/java/dev/mi6e4ka/openstore/MainActivity.kt +++ b/app/src/main/java/dev/mi6e4ka/openstore/MainActivity.kt @@ -3,6 +3,7 @@ package dev.mi6e4ka.openstore import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge import androidx.compose.animation.AnimatedContentTransitionScope import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.tween @@ -35,6 +36,7 @@ import dev.mi6e4ka.openstore.ui.theme.AppTheme class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { + enableEdgeToEdge() super.onCreate(savedInstanceState) val cacheDir = externalCacheDir ?: cacheDir cacheDir.listFiles()?.forEach { file -> diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml index 8bede2e..45af79c 100644 --- a/app/src/main/res/values-night/themes.xml +++ b/app/src/main/res/values-night/themes.xml @@ -1,6 +1,3 @@ - + +