mirror of
https://codeberg.org/mi6e4ka/openstore.git
synced 2026-07-09 15:59:50 +00:00
Compare commits
9 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eda5bf6c9d | ||
|
|
823fb11546 | ||
|
|
74c0e35c76 | ||
|
|
0cc3da6949 | ||
|
|
1ee5d87aeb | ||
|
|
f4320992c8 | ||
|
|
f4ee755783 | ||
|
|
f09226ef3a | ||
|
|
a6509993a3 |
14 changed files with 133 additions and 49 deletions
|
|
@ -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">
|
||||
<activity
|
||||
|
|
@ -35,11 +34,12 @@
|
|||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="http" />
|
||||
<data android:host="rustore.ru" />
|
||||
<data android:host="www.rustore.ru" />
|
||||
<data android:host="apps.rustore.ru" />
|
||||
<data android:scheme="https" />
|
||||
<data android:scheme="https" android:host="www.rustore.ru" android:pathPrefix="/catalog/app/" />
|
||||
<data android:scheme="https" android:host="apps.rustore.ru" android:pathPrefix="/app/" />
|
||||
<data android:scheme="https" android:host="www.rustore.ru" android:pathPrefix="/instruction" />
|
||||
<data android:scheme="http" android:host="www.rustore.ru" android:pathPrefix="/catalog/app/" />
|
||||
<data android:scheme="http" android:host="apps.rustore.ru" android:pathPrefix="/app/" />
|
||||
<data android:scheme="http" android:host="www.rustore.ru" android:pathPrefix="/instruction" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
|
@ -76,4 +76,4 @@
|
|||
android:name=".internal.installer.PackageInstallerStatusReceiver"
|
||||
android:exported="false" />
|
||||
</application>
|
||||
</manifest>
|
||||
</manifest>
|
||||
|
|
|
|||
|
|
@ -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 ->
|
||||
|
|
|
|||
|
|
@ -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<Files>) {
|
|||
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) }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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}")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
)
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -73,4 +73,6 @@
|
|||
<string name="theme_auto_label">Auto</string>
|
||||
<string name="theme_dark_label">Dark</string>
|
||||
<string name="theme_light_label">Light</string>
|
||||
<string name="back_button_desc">Back</string>
|
||||
<string name="tts_current_platform">Apps for platfom</string>
|
||||
</resources>
|
||||
|
|
@ -1,6 +1,3 @@
|
|||
<resources>
|
||||
<style name="AppTheme" parent="android:Theme.Material.NoActionBar">
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
</style>
|
||||
<style name="AppTheme" parent="android:Theme.Material.NoActionBar" />
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -73,4 +73,20 @@
|
|||
<string name="theme_dark_label">Тёмная</string>
|
||||
<string name="theme_light_label">Светлая</string>
|
||||
<string name="settings_updates_sources_description">Обновления будут проверяться для приложений из выбранных источников</string>
|
||||
<string name="back_button_desc">Назад</string>
|
||||
<string name="tts_current_platform">Приложения для платформы</string>
|
||||
<string name="copy_link_desc">Скопировать ссылку на apk</string>
|
||||
<string name="download_apk_desc">Скачать apk без установки</string>
|
||||
<string name="open_in_browser_desc">Открыть страницу приложения в браузере</string>
|
||||
<string name="app_size_desc">Вес приложения</string>
|
||||
<string name="latest_version_desc">Текущая версия</string>
|
||||
<string name="last_update_desc">Последнее обновление</string>
|
||||
<string name="min_api_desc">Минимальная версия android</string>
|
||||
<string name="installer_type_desc">Тип установочного файла</string>
|
||||
<string name="downloads_desc">Количество установок</string>
|
||||
<string name="age_legal_desc">Возрастная категория</string>
|
||||
<string name="reviews_desc">Рейтинг и отзывы\nСредняя оценка: %1$.2f\nВсего оценок: %2$d</string>
|
||||
<string name="review_rating_desc">оценка: %1$d</string>
|
||||
<string name="likes_desc">Лайки</string>
|
||||
<string name="dislikes_desc">Дизлайки</string>
|
||||
</resources>
|
||||
|
|
@ -1,6 +1,3 @@
|
|||
<resources>
|
||||
<style name="AppTheme" parent="android:Theme.Material.Light.NoActionBar">
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
<item name="android:statusBarColor">#33000000</item>
|
||||
</style>
|
||||
<style name="AppTheme" parent="android:Theme.Material.Light.NoActionBar" />
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<network-security-config>
|
||||
<domain-config cleartextTrafficPermitted="false">
|
||||
<domain includeSubdomains="true">rustore.ru</domain>
|
||||
<pin-set expiration="2028-11-21">
|
||||
<pin digest="SHA-256">hETpgVvaLC0bvcGG3t0cuqiHvr4XyP2MTwCiqhgRWwU=</pin>
|
||||
</pin-set>
|
||||
</domain-config>
|
||||
</network-security-config>
|
||||
Loading…
Add table
Add a link
Reference in a new issue