From 6c8d355e5960135e74db075204b05f348f053b46 Mon Sep 17 00:00:00 2001 From: theov Date: Fri, 8 May 2026 19:46:11 -0300 Subject: [PATCH] Getting ready for beta 7 :) --- .../components/BetaInfoBottomSheet.kt | 662 ++++++++++++++---- .../components/ChangelogBottomSheet.kt | 44 +- .../values/strings_presentation_batch_g.xml | 191 +++-- gradle.properties | 4 +- 4 files changed, 593 insertions(+), 308 deletions(-) diff --git a/app/src/main/java/com/theveloper/pixelplay/presentation/components/BetaInfoBottomSheet.kt b/app/src/main/java/com/theveloper/pixelplay/presentation/components/BetaInfoBottomSheet.kt index ee66e4b86..82e51697d 100644 --- a/app/src/main/java/com/theveloper/pixelplay/presentation/components/BetaInfoBottomSheet.kt +++ b/app/src/main/java/com/theveloper/pixelplay/presentation/components/BetaInfoBottomSheet.kt @@ -3,10 +3,12 @@ package com.theveloper.pixelplay.presentation.components import android.content.ActivityNotFoundException import android.content.Context import android.content.Intent +import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -15,26 +17,42 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.rounded.AutoAwesome import androidx.compose.material.icons.rounded.BugReport +import androidx.compose.material.icons.rounded.CheckCircle +import androidx.compose.material.icons.rounded.Cloud +import androidx.compose.material.icons.rounded.ExpandLess +import androidx.compose.material.icons.rounded.ExpandMore +import androidx.compose.material.icons.rounded.Gavel +import androidx.compose.material.icons.rounded.Highlight import androidx.compose.material.icons.rounded.Info +import androidx.compose.material.icons.rounded.NightsStay +import androidx.compose.material.icons.rounded.Search +import androidx.compose.material.icons.rounded.Shield +import androidx.compose.material.icons.rounded.Warning +import androidx.compose.material.icons.rounded.Whatshot import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.FilledTonalButton +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.MediumExtendedFloatingActionButton import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -65,7 +83,7 @@ fun BetaInfoBottomSheet(modifier: Modifier = Modifier) { .padding(horizontal = 24.dp), contentPadding = PaddingValues(top = 4.dp), horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(16.dp) + verticalArrangement = Arrangement.spacedBy(14.dp) ) { item(key = "header") { Column(horizontalAlignment = Alignment.CenterHorizontally) { @@ -105,7 +123,6 @@ fun BetaInfoBottomSheet(modifier: Modifier = Modifier) { smoothnessAsPercentBL = 60, smoothnessAsPercentBR = 60 ), - //tonalElevation = 2.dp, color = MaterialTheme.colorScheme.surfaceContainerHigh ) { Row( @@ -154,171 +171,236 @@ fun BetaInfoBottomSheet(modifier: Modifier = Modifier) { } } - item(key = "what-to-expect") { - Surface( - modifier = Modifier.fillMaxWidth(), - shape = AbsoluteSmoothCornerShape( - cornerRadiusTR = fabCornerRadius, - cornerRadiusTL = fabCornerRadius, - cornerRadiusBL = fabCornerRadius, - cornerRadiusBR = fabCornerRadius, - smoothnessAsPercentTR = 60, - smoothnessAsPercentTL = 60, - smoothnessAsPercentBL = 60, - smoothnessAsPercentBR = 60 - ), - tonalElevation = 2.dp, - color = MaterialTheme.colorScheme.surfaceContainerLow + item(key = "github-shortcut") { + GitHubReportCard( + onOpenIssues = { launchUrl(context, issuesUrl) }, + onReportIssue = { launchUrl(context, reportUrl) } + ) + } + + item(key = "section-expect") { + BetaFaqSection( + title = stringResource(R.string.presentation_batch_g_beta_sheet_expect_title), + summary = stringResource(R.string.presentation_batch_g_beta_sheet_expect_summary), + icon = Icons.Rounded.Whatshot, + iconTint = MaterialTheme.colorScheme.primary, + initiallyExpanded = true ) { - Column( - modifier = Modifier - .fillMaxWidth() - .padding(16.dp), - verticalArrangement = Arrangement.spacedBy(8.dp) - ) { - Row(verticalAlignment = Alignment.CenterVertically) { - Icon( - imageVector = Icons.Rounded.Info, - contentDescription = null, - tint = MaterialTheme.colorScheme.secondary - ) - Spacer(modifier = Modifier.width(8.dp)) - Text( - text = stringResource(R.string.presentation_batch_g_beta_sheet_expect_title), - style = MaterialTheme.typography.titleMedium, - fontWeight = FontWeight.SemiBold - ) - } - Text( - text = stringResource(R.string.presentation_batch_g_beta_sheet_expect_1), - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant + BetaBulletList( + items = listOf( + R.string.presentation_batch_g_beta_sheet_expect_1, + R.string.presentation_batch_g_beta_sheet_expect_2, + R.string.presentation_batch_g_beta_sheet_expect_3, + R.string.presentation_batch_g_beta_sheet_expect_4 ) - Text( - text = stringResource(R.string.presentation_batch_g_beta_sheet_expect_2), - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + + item(key = "section-reporting") { + BetaFaqSection( + title = stringResource(R.string.presentation_batch_g_beta_sheet_report_title), + summary = stringResource(R.string.presentation_batch_g_beta_sheet_report_summary), + icon = Icons.Rounded.Search, + iconTint = MaterialTheme.colorScheme.secondary + ) { + BetaSubsectionHeader( + icon = Icons.Rounded.Search, + title = stringResource(R.string.presentation_batch_g_beta_sheet_before_title) + ) + BetaBulletList( + items = listOf( + R.string.presentation_batch_g_beta_sheet_before_1, + R.string.presentation_batch_g_beta_sheet_before_2, + R.string.presentation_batch_g_beta_sheet_before_3, + R.string.presentation_batch_g_beta_sheet_before_4 ) - Text( - text = stringResource(R.string.presentation_batch_g_beta_sheet_expect_3), - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant + ) + BetaSectionDivider() + BetaSubsectionHeader( + icon = Icons.Rounded.CheckCircle, + title = stringResource(R.string.presentation_batch_g_beta_sheet_issue_type_title) + ) + BetaBulletList( + items = listOf( + R.string.presentation_batch_g_beta_sheet_issue_type_bug, + R.string.presentation_batch_g_beta_sheet_issue_type_feature, + R.string.presentation_batch_g_beta_sheet_issue_type_question + ) + ) + } + } + + item(key = "section-bug-report") { + BetaFaqSection( + title = stringResource(R.string.presentation_batch_g_beta_sheet_bug_title), + summary = stringResource(R.string.presentation_batch_g_beta_sheet_bug_summary_text), + icon = Icons.Rounded.BugReport, + iconTint = MaterialTheme.colorScheme.error, + containerColor = MaterialTheme.colorScheme.surfaceContainerHighest + ) { + BetaSubsectionHeader( + icon = Icons.Rounded.BugReport, + title = stringResource(R.string.presentation_batch_g_beta_sheet_bug_template_title) + ) + BetaFieldList( + items = listOf( + R.string.presentation_batch_g_beta_sheet_bug_summary, + R.string.presentation_batch_g_beta_sheet_bug_expected, + R.string.presentation_batch_g_beta_sheet_bug_actual, + R.string.presentation_batch_g_beta_sheet_bug_steps, + R.string.presentation_batch_g_beta_sheet_bug_frequency, + R.string.presentation_batch_g_beta_sheet_bug_screenshot, + R.string.presentation_batch_g_beta_sheet_bug_logs ) - Text( - text = stringResource(R.string.presentation_batch_g_beta_sheet_expect_4), - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant + ) + BetaSectionDivider() + BetaSubsectionHeader( + icon = Icons.Rounded.Info, + title = stringResource(R.string.presentation_batch_g_beta_sheet_env_title) + ) + BetaFieldList( + items = listOf( + R.string.presentation_batch_g_beta_sheet_env_version, + R.string.presentation_batch_g_beta_sheet_env_source, + R.string.presentation_batch_g_beta_sheet_env_android, + R.string.presentation_batch_g_beta_sheet_env_device, + R.string.presentation_batch_g_beta_sheet_env_extra ) - } + ) } } - item(key = "report-issue") { - Surface( - modifier = Modifier.fillMaxWidth(), - shape = AbsoluteSmoothCornerShape( - cornerRadiusTR = fabCornerRadius, - cornerRadiusTL = fabCornerRadius, - cornerRadiusBL = fabCornerRadius, - cornerRadiusBR = fabCornerRadius, - smoothnessAsPercentTR = 60, - smoothnessAsPercentTL = 60, - smoothnessAsPercentBL = 60, - smoothnessAsPercentBR = 60 - ), - tonalElevation = 2.dp, - color = MaterialTheme.colorScheme.surfaceContainerHighest + item(key = "section-feature") { + BetaFaqSection( + title = stringResource(R.string.presentation_batch_g_beta_sheet_feature_title), + summary = stringResource(R.string.presentation_batch_g_beta_sheet_feature_summary), + icon = Icons.Rounded.Highlight, + iconTint = MaterialTheme.colorScheme.primary ) { - Column( - modifier = Modifier - .fillMaxWidth() - .padding(16.dp), - verticalArrangement = Arrangement.spacedBy(10.dp) - ) { - Row(verticalAlignment = Alignment.CenterVertically) { - Icon( - imageVector = Icons.Rounded.BugReport, - contentDescription = null, - tint = MaterialTheme.colorScheme.error - ) - Spacer(modifier = Modifier.width(8.dp)) - Text( - text = stringResource(R.string.presentation_batch_g_beta_sheet_report_title), - style = MaterialTheme.typography.titleMedium, - fontWeight = FontWeight.SemiBold - ) - } - Text( - text = stringResource(R.string.presentation_batch_g_beta_sheet_report_body), - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant + BetaFieldList( + items = listOf( + R.string.presentation_batch_g_beta_sheet_feature_problem, + R.string.presentation_batch_g_beta_sheet_feature_solution, + R.string.presentation_batch_g_beta_sheet_feature_alternatives, + R.string.presentation_batch_g_beta_sheet_feature_scope, + R.string.presentation_batch_g_beta_sheet_feature_mockup ) - Column( - modifier = Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(10.dp) - ) { - Button( - onClick = { launchUrl(context, issuesUrl) }, - // Eliminamos height fija y usamos contentPadding - modifier = Modifier.fillMaxWidth(), - contentPadding = PaddingValues(vertical = 16.dp), - shape = AbsoluteSmoothCornerShape( - cornerRadiusTR = fabCornerRadius, - cornerRadiusTL = fabCornerRadius, - cornerRadiusBL = fabCornerRadius, - cornerRadiusBR = fabCornerRadius, - smoothnessAsPercentTR = 60, - smoothnessAsPercentTL = 60, - smoothnessAsPercentBL = 60, - smoothnessAsPercentBR = 60 - ), - colors = ButtonDefaults.buttonColors( - containerColor = MaterialTheme.colorScheme.primaryContainer, - contentColor = MaterialTheme.colorScheme.onPrimaryContainer - ) - ) { - Icon( - painter = painterResource(id = R.drawable.github), - contentDescription = null, - modifier = Modifier.size(18.dp) - ) - Spacer(modifier = Modifier.width(8.dp)) - Text(text = stringResource(R.string.presentation_batch_g_beta_sheet_open_issues)) - } - FilledTonalButton( - onClick = { launchUrl(context, reportUrl) }, - // Eliminamos height fija y usamos contentPadding - modifier = Modifier.fillMaxWidth(), - contentPadding = PaddingValues(vertical = 16.dp), - shape = AbsoluteSmoothCornerShape( - cornerRadiusTR = fabCornerRadius, - cornerRadiusTL = fabCornerRadius, - cornerRadiusBL = fabCornerRadius, - cornerRadiusBR = fabCornerRadius, - smoothnessAsPercentTR = 60, - smoothnessAsPercentTL = 60, - smoothnessAsPercentBL = 60, - smoothnessAsPercentBR = 60 - ) - ) { - Icon( - imageVector = Icons.Rounded.AutoAwesome, - contentDescription = null, - tint = MaterialTheme.colorScheme.primary - ) - Spacer(modifier = Modifier.width(6.dp)) - Text(text = stringResource(R.string.presentation_batch_g_beta_sheet_report_bug)) - } - } - } + ) + } + } + + item(key = "section-quality") { + BetaFaqSection( + title = stringResource(R.string.presentation_batch_g_beta_sheet_quality_title), + summary = stringResource(R.string.presentation_batch_g_beta_sheet_quality_summary), + icon = Icons.Rounded.Gavel, + iconTint = MaterialTheme.colorScheme.tertiary, + containerColor = MaterialTheme.colorScheme.tertiaryContainer.copy(alpha = 0.45f) + ) { + BetaSubsectionHeader( + icon = Icons.Rounded.Gavel, + title = stringResource(R.string.presentation_batch_g_beta_sheet_title_examples_title) + ) + BetaBulletList( + items = listOf( + R.string.presentation_batch_g_beta_sheet_title_example_1, + R.string.presentation_batch_g_beta_sheet_title_example_2, + R.string.presentation_batch_g_beta_sheet_title_example_3 + ) + ) + BetaSectionDivider() + BetaSubsectionHeader( + icon = Icons.Rounded.Warning, + title = stringResource(R.string.presentation_batch_g_beta_sheet_avoid_title), + tint = MaterialTheme.colorScheme.error + ) + BetaBulletList( + items = listOf( + R.string.presentation_batch_g_beta_sheet_avoid_1, + R.string.presentation_batch_g_beta_sheet_avoid_2, + R.string.presentation_batch_g_beta_sheet_avoid_3 + ) + ) + BetaSectionDivider() + BetaSubsectionHeader( + icon = Icons.Rounded.Shield, + title = stringResource(R.string.presentation_batch_g_beta_sheet_privacy_title) + ) + Text( + text = stringResource(R.string.presentation_batch_g_beta_sheet_privacy_body), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurface + ) + } + } + + item(key = "section-nightly") { + BetaFaqSection( + title = stringResource(R.string.presentation_batch_g_beta_sheet_nightly_title), + summary = stringResource(R.string.presentation_batch_g_beta_sheet_nightly_summary), + icon = Icons.Rounded.NightsStay, + iconTint = MaterialTheme.colorScheme.secondary, + containerColor = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.42f) + ) { + BetaSubsectionHeader( + icon = Icons.Rounded.NightsStay, + title = stringResource(R.string.presentation_batch_g_beta_sheet_nightly_title) + ) + Text( + text = stringResource(R.string.presentation_batch_g_beta_sheet_nightly_body), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurface + ) + Text( + text = stringResource(R.string.presentation_batch_g_beta_sheet_nightly_access), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurface + ) + BetaSectionDivider() + BetaSubsectionHeader( + icon = Icons.Rounded.Cloud, + title = stringResource(R.string.presentation_batch_g_beta_sheet_nightly_report_title) + ) + Text( + text = stringResource(R.string.presentation_batch_g_beta_sheet_nightly_report_body), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurface + ) } } - item { - Spacer(modifier = Modifier.height(38.dp)) + item(key = "bottom-spacer") { + Spacer(modifier = Modifier.height(104.dp)) } } + MediumExtendedFloatingActionButton( + onClick = { launchUrl(context, reportUrl) }, + shape = AbsoluteSmoothCornerShape( + cornerRadiusTR = fabCornerRadius, + cornerRadiusTL = fabCornerRadius, + cornerRadiusBL = fabCornerRadius, + cornerRadiusBR = fabCornerRadius, + smoothnessAsPercentTR = 60, + smoothnessAsPercentTL = 60, + smoothnessAsPercentBL = 60, + smoothnessAsPercentBR = 60 + ), + containerColor = MaterialTheme.colorScheme.primaryContainer, + contentColor = MaterialTheme.colorScheme.onPrimaryContainer, + icon = { + Icon( + painter = painterResource(id = R.drawable.github), + contentDescription = null + ) + }, + text = { + Text(text = stringResource(R.string.presentation_batch_g_beta_sheet_report_bug)) + }, + modifier = Modifier + .align(Alignment.BottomEnd) + .padding(horizontal = 24.dp, vertical = 24.dp) + ) Box( modifier = Modifier .align(Alignment.BottomCenter) @@ -338,6 +420,277 @@ fun BetaInfoBottomSheet(modifier: Modifier = Modifier) { } } +@Composable +private fun GitHubReportCard( + onOpenIssues: () -> Unit, + onReportIssue: () -> Unit +) { + BetaCardSurface( + color = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.55f) + ) { + Column( + modifier = Modifier.padding(16.dp), + verticalArrangement = Arrangement.spacedBy(14.dp) + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + Box( + modifier = Modifier + .size(42.dp) + .background(MaterialTheme.colorScheme.surface, CircleShape), + contentAlignment = Alignment.Center + ) { + Icon( + painter = painterResource(id = R.drawable.github), + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurface, + modifier = Modifier.size(24.dp) + ) + } + Column(verticalArrangement = Arrangement.spacedBy(2.dp)) { + Text( + text = stringResource(R.string.presentation_batch_g_beta_sheet_github_title), + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.SemiBold, + color = MaterialTheme.colorScheme.onSecondaryContainer + ) + Text( + text = stringResource(R.string.presentation_batch_g_beta_sheet_github_body), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSecondaryContainer.copy(alpha = 0.82f) + ) + } + } + Column( + verticalArrangement = Arrangement.spacedBy(10.dp) + ) { + FilledTonalButton( + onClick = onOpenIssues, + modifier = Modifier.fillMaxWidth(), + shape = AbsoluteSmoothCornerShape( + cornerRadiusTR = 14.dp, + cornerRadiusTL = 14.dp, + cornerRadiusBL = 14.dp, + cornerRadiusBR = 14.dp, + smoothnessAsPercentTR = 60, + smoothnessAsPercentTL = 60, + smoothnessAsPercentBL = 60, + smoothnessAsPercentBR = 60 + ), + colors = ButtonDefaults.filledTonalButtonColors( + containerColor = MaterialTheme.colorScheme.surfaceContainerHigh + ) + ) { + Text(text = stringResource(R.string.presentation_batch_g_beta_sheet_open_issues)) + } + Button( + onClick = onReportIssue, + modifier = Modifier.fillMaxWidth(), + shape = AbsoluteSmoothCornerShape( + cornerRadiusTR = 14.dp, + cornerRadiusTL = 14.dp, + cornerRadiusBL = 14.dp, + cornerRadiusBR = 14.dp, + smoothnessAsPercentTR = 60, + smoothnessAsPercentTL = 60, + smoothnessAsPercentBL = 60, + smoothnessAsPercentBR = 60 + ) + ) { + Text(text = stringResource(R.string.presentation_batch_g_beta_sheet_report_bug)) + } + } + } + } +} + +@Composable +private fun BetaFaqSection( + title: String, + summary: String, + icon: ImageVector, + iconTint: Color, + modifier: Modifier = Modifier, + initiallyExpanded: Boolean = false, + containerColor: Color = MaterialTheme.colorScheme.surfaceContainerHigh, + content: @Composable ColumnScope.() -> Unit +) { + var expanded by rememberSaveable { mutableStateOf(initiallyExpanded) } + + BetaCardSurface( + modifier = modifier, + color = containerColor, + onClick = { expanded = !expanded } + ) { + Column( + modifier = Modifier.padding(16.dp), + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + Box( + modifier = Modifier + .size(40.dp) + .background(iconTint.copy(alpha = 0.16f), CircleShape), + contentAlignment = Alignment.Center + ) { + Icon( + imageVector = icon, + contentDescription = null, + tint = iconTint, + modifier = Modifier.size(22.dp) + ) + } + Column( + modifier = Modifier.weight(1f), + verticalArrangement = Arrangement.spacedBy(2.dp) + ) { + Text( + text = title, + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.SemiBold, + color = MaterialTheme.colorScheme.onSurface + ) + Text( + text = summary, + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + Icon( + imageVector = if (expanded) Icons.Rounded.ExpandLess else Icons.Rounded.ExpandMore, + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + + AnimatedVisibility(visible = expanded) { + Column( + modifier = Modifier.fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(10.dp), + content = content + ) + } + } + } +} + +@Composable +private fun BetaCardSurface( + modifier: Modifier = Modifier, + color: Color, + onClick: (() -> Unit)? = null, + content: @Composable () -> Unit +) { + val shape = AbsoluteSmoothCornerShape( + cornerRadiusTR = 18.dp, + cornerRadiusTL = 18.dp, + cornerRadiusBL = 18.dp, + cornerRadiusBR = 18.dp, + smoothnessAsPercentTR = 60, + smoothnessAsPercentTL = 60, + smoothnessAsPercentBL = 60, + smoothnessAsPercentBR = 60 + ) + + if (onClick == null) { + Surface( + modifier = modifier.fillMaxWidth(), + shape = shape, + color = color, + content = content + ) + } else { + Surface( + modifier = modifier.fillMaxWidth(), + shape = shape, + color = color, + onClick = onClick, + content = content + ) + } +} + +@Composable +private fun BetaSubsectionHeader( + icon: ImageVector, + title: String, + tint: Color = MaterialTheme.colorScheme.primary +) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + Icon( + imageVector = icon, + contentDescription = null, + tint = tint, + modifier = Modifier.size(20.dp) + ) + Text( + text = title, + style = MaterialTheme.typography.labelLarge, + fontWeight = FontWeight.SemiBold, + color = MaterialTheme.colorScheme.onSurface + ) + } +} + +@Composable +private fun BetaBulletList(items: List) { + Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { + items.forEach { item -> + BetaBulletText(text = stringResource(item)) + } + } +} + +@Composable +private fun BetaFieldList(items: List) { + Column(verticalArrangement = Arrangement.spacedBy(0.dp)) { + items.forEachIndexed { index, item -> + if (index > 0) { + BetaSectionDivider() + } + Text( + text = stringResource(item), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(vertical = 8.dp) + ) + } + } +} + +@Composable +private fun BetaBulletText(text: String) { + Row( + horizontalArrangement = Arrangement.spacedBy(10.dp), + verticalAlignment = Alignment.Top + ) { + Box( + modifier = Modifier + .padding(top = 8.dp) + .size(5.dp) + .background(MaterialTheme.colorScheme.primary, CircleShape) + ) + Text( + text = text, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } +} + +@Composable +private fun BetaSectionDivider() { + HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.35f)) +} + private fun launchUrl(context: Context, url: String) { val intent = Intent(Intent.ACTION_VIEW, url.toUri()).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) @@ -345,6 +698,5 @@ private fun launchUrl(context: Context, url: String) { try { context.startActivity(intent) } catch (_: ActivityNotFoundException) { - // Swallow the error; caller does not need to handle it here. } } diff --git a/app/src/main/java/com/theveloper/pixelplay/presentation/components/ChangelogBottomSheet.kt b/app/src/main/java/com/theveloper/pixelplay/presentation/components/ChangelogBottomSheet.kt index c2cc795bd..85d28c784 100644 --- a/app/src/main/java/com/theveloper/pixelplay/presentation/components/ChangelogBottomSheet.kt +++ b/app/src/main/java/com/theveloper/pixelplay/presentation/components/ChangelogBottomSheet.kt @@ -64,46 +64,12 @@ data class ChangelogVersion( @Composable private fun changelogVersions(): List = listOf( ChangelogVersion( - version = "0.6.0-beta", - date = "2026-03-05", + version = "0.7.0-beta", + date = "2026-05-08", sections = listOf( - ChangelogSection(R.string.presentation_batch_g_changelog_sec_whats_new, R.array.presentation_batch_g_changelog_060_whats_new), - ChangelogSection(R.string.presentation_batch_g_changelog_sec_improvements, R.array.presentation_batch_g_changelog_060_improvements), - ChangelogSection(R.string.presentation_batch_g_changelog_sec_fixes, R.array.presentation_batch_g_changelog_060_fixes) - ) - ), - ChangelogVersion( - version = "0.5.0-beta", - date = "2026-01-14", - sections = listOf( - ChangelogSection(R.string.presentation_batch_g_changelog_sec_highlights, R.array.presentation_batch_g_changelog_050_highlights), - ChangelogSection(R.string.presentation_batch_g_changelog_sec_improvements, R.array.presentation_batch_g_changelog_050_improvements), - ChangelogSection(R.string.presentation_batch_g_changelog_sec_fixes, R.array.presentation_batch_g_changelog_050_fixes) - ) - ), - ChangelogVersion( - version = "0.4.0-beta", - date = "2025-12-15", - sections = listOf( - ChangelogSection(R.string.presentation_batch_g_changelog_sec_highlights, R.array.presentation_batch_g_changelog_040_highlights) - ) - ), - ChangelogVersion( - version = "0.3.0-beta", - date = "2025-10-28", - sections = listOf( - ChangelogSection(R.string.presentation_batch_g_changelog_sec_whats_new_lower, R.array.presentation_batch_g_changelog_030_whats_new), - ChangelogSection(R.string.presentation_batch_g_changelog_sec_improvements, R.array.presentation_batch_g_changelog_030_improvements), - ChangelogSection(R.string.presentation_batch_g_changelog_sec_fixes, R.array.presentation_batch_g_changelog_030_fixes) - ) - ), - ChangelogVersion( - version = "0.2.0-beta", - date = "2024-09-15", - sections = listOf( - ChangelogSection(R.string.presentation_batch_g_changelog_sec_added, R.array.presentation_batch_g_changelog_020_added), - ChangelogSection(R.string.presentation_batch_g_changelog_sec_changed, R.array.presentation_batch_g_changelog_020_changed), - ChangelogSection(R.string.presentation_batch_g_changelog_sec_fixed, R.array.presentation_batch_g_changelog_020_fixed) + ChangelogSection(R.string.presentation_batch_g_changelog_sec_highlights, R.array.presentation_batch_g_changelog_070_highlights), + ChangelogSection(R.string.presentation_batch_g_changelog_sec_improvements, R.array.presentation_batch_g_changelog_070_improvements), + ChangelogSection(R.string.presentation_batch_g_changelog_sec_fixes, R.array.presentation_batch_g_changelog_070_fixes) ) ) ) diff --git a/app/src/main/res/values/strings_presentation_batch_g.xml b/app/src/main/res/values/strings_presentation_batch_g.xml index 3b7bc88b3..ec9295986 100644 --- a/app/src/main/res/values/strings_presentation_batch_g.xml +++ b/app/src/main/res/values/strings_presentation_batch_g.xml @@ -287,18 +287,71 @@ Backslash (\) can be used to escape character delimiters. Pin Rename Delete - Beta 0.6.0 - Welcome to PixelPlayer 0.6.0-beta - This beta is now focused on stability, performance, and cross-device playback while shipping major new integrations. + Beta 0.7.0 + Welcome to PixelPlayer 0.7.0-beta + You\'re using a beta build that may contain bugs, crashes, or experimental features. Help us improve by reporting issues. What to expect - Faster daily use: smoother startup, navigation, and player interactions across the app. - Broader device support: Android Auto, Wear OS upgrades, and stronger Cast reliability. - Expanded cloud ecosystem: Telegram playlists, NetEase sync, QQ Music, and Google Drive streaming updates. - Large reliability pass: queue/shuffle logic, background playback behavior, and many UI fixes. - Report an issue - Share steps to reproduce, expected result, actual result, and your device/OS details. A short screen recording is very helpful. - Open GitHub issues - Report a bug + Bugs, crashes, or incomplete features may occur unexpectedly. + Some features may change or be removed without notice. + Beta builds may be more unstable than release versions. + Always check for updates before reporting a known issue. + What beta builds can change, break, or improve while testing. + GitHub issue shortcut + Search first, then open a focused report for bugs, crashes, requests, or questions. + Open existing issues + Report issue or crash + How to report + A quick checklist before opening a new issue. + Before opening an issue + Search existing open and closed issues to avoid duplicates. + Update to the latest PixelPlayer version and confirm the problem still happens. + Restart the app and confirm the problem persists. + Try to reproduce it and write down the exact steps. + Which issue type? + Bug report: Something behaves incorrectly. + Feature request: Add a new feature or improvement. + Question: Use Discussions if enabled, or open an issue with a question label. + Bug report + Copy these fields when something behaves incorrectly or crashes. + Bug Report + Short summary: + Expected behavior: + Current behavior: + Steps to play/reproduce: 1. 2. 3. + How often does it happen? Always / Sometimes / Rarely. + Screenshot / video: if available. + Logs / stack trace: if available. + Environment + PixelPlayer version: + Install source: GitHub Release, debug build, nightly build, etc. + Android version: + Device model: + Extra context: SD card usage, special settings, permissions, etc. + Feature request + Copy these fields when you want a new feature or improvement. + Problem statement: What problem are you trying to solve? + Proposed solution: How should it work? + Alternatives considered: Any other approaches? + Scope: Which screens or flows are affected? + Mockup or reference image if available. + Titles, privacy, and scope + Make the report easy to triage and safe to share. + Good issue titles + Equalizer: Indicator shifts when switching preset tabs + Search: History list does not appear for empty query + Feature: Add \"Recently Added\" playlist sort option + Please avoid + Generic reports like \"It doesn\'t work\". + Multiple unrelated problems in one issue. + Unredacted logs or screenshots with private data. + Privacy note + Before posting logs, screenshots, or videos, remove personal or private information. + Nightly builds + How nightlies differ from releases, and what to include when they break. + Nightly builds are generated from the latest commit and may contain unfinished changes, temporary bugs, or regressions. They are more experimental than official releases. + Access them from the repository\'s GitHub Actions workflow artifacts if available. + Reporting nightly issues + When reporting an issue from a nightly build, always mention that it happened on a nightly build, not on the official release. Include the build date, workflow run name or number, or commit SHA if possible. Also check if the same problem happens on the latest official release. Beta 0.5.0 upgrade Clean install recommended If you\'re coming from beta 0.5.0, this update may need fresh library data instead of older cached state. @@ -408,114 +461,28 @@ Backslash (\) can be used to escape character delimiters. Disconnect Connecting... - What\'s New + Highlights Improvements Fixes - Highlights What\'s new Added Changed Fixed - - Android Auto support is now available for in-car playback. - Wear OS support is live, including better watch-to-phone playback controls. - Cloud integrations expanded with Telegram, NetEase, QQ Music, and Google Drive improvements. - Recently Played and persistent queue restoration keep your listening session ready. - Backup & Restore v3 and account management tools are now included. - Lyrics got smarter with manual search fallback and storage improvements. - - - Big performance pass across startup, library, queue, and player interactions. - Player, Cast, Lyrics, Artist, and Genre surfaces were redesigned for smoother use. - Navigation and search flows are more reliable, with safer route handling. - Audio playback compatibility improved for more devices and formats. - Multi-selection workflows were expanded across songs, albums, and playlists. - - - Queue and shuffle behavior is now more stable and predictable. - Several background playback and casting edge cases were fixed. - Sleep Timer, Files tab navigation, and album artist crash issues were fixed. - Widget loading and service stability were improved to reduce overheating/memory issues. - General bug fixes and UI polish across the app. - - - Material 3 Expressive UI Update - 10-band Equalizer & Effects - New Library Sync Flow - AI Integration (Gemini Models) - M3U Playlist Import/Export - Deezer Artist Artwork Integration - Custom Playlist Covers - - - Settings Architecture Refactor - Queue & Player Animations - Baseline Profiles & Performance - Better Lyrics System with Sync Offset - - - Casting Stability Improvements - Player Sheet Stability - General Bug Fixes & Cleanup - - - Major navigation redesign - New file explorer for choosing source directories - New Connectivity and casting functionalities - Seamless continuity between remote devices - Gapless transition between songs - Crossfade control - New Custom Transitions feature (only for playlists) - Keep playing after closed the app - UI Optimizations - Improved stats feature - Redesigned Queue control with more features - Improved different filetypes support for playing and metadata editing - Improved permission controller - Minor bug fixes - - - Introduced a richer listening stats hub with deeper insights into your sessions. - Launched a floating quick player to instantly open and preview local files. - Added a folders tab with a tree-style navigator and playlist-ready view. - - - Refined the overall Material 3 UI for a cleaner and more cohesive experience. - Metadata editing now supports cover art change. - Smoothed out animations and transitions across the app for more fluid navigation. - Enhanced the artist screen layout with richer details and polish. - Upgraded DailyMix and YourMix generation with smarter, more diverse selections. - Strengthened the AI playlist generation. - Improved search relevance and presentation for faster discovery. - Expanded support for a broader range of audio file formats. - - - Resolved metadata quirks so song details stay accurate everywhere. - Restored notification shortcuts so they reliably jump back into playback. - - - Chromecast support for casting audio from your device. - In-app changelog to keep you updated on the latest features. - Support for .LRC files, both embedded and external. - Offline lyrics support. - Synchronized lyrics (synced with the song). - New screen to view the full queue. - Reorder and remove songs from the queue. - Mini-player gestures (swipe down to close). - Added more material animations. - New settings to customize the look and feel. - New settings to clear the cache. + + AI integration improvements and smarter playlist generation. + Enhanced listening stats with deeper insights and new visualizations. + Improved library sync flow across all cloud providers. + Better metadata editing with cover art support. - - Complete redesign of the user interface. - Complete redesign of the player. - Performance improvements in the library. - Improved application startup speed. - The AI now provides better results. + + Performance improvements across startup, library, queue, and player interactions. + Refined Material 3 UI for a cleaner and more cohesive experience. + Smoother animations and transitions throughout the app. + Better search relevance and faster discovery. - - Fixed various bugs in the tag editor. - Fixed a bug where the playback notification was not clearing. - Fixed several bugs that caused the app to crash. + + Fixed queue and shuffle behavior for more stable playback. + Resolved background playback and notification issues. + General bug fixes and UI polish. diff --git a/gradle.properties b/gradle.properties index 09e65f76f..62cc2f709 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,8 +6,8 @@ kotlin.code.style=official # thereby reducing the size of the R class for that library android.nonTransitiveRClass=true android.nonFinalResIds=true -APP_VERSION_NAME=0.6.0-beta -APP_VERSION_CODE=7 +APP_VERSION_NAME=0.7.0-beta +APP_VERSION_CODE=8 org.gradle.configuration-cache=true # Adjusted to stay within 3GB limit and avoid thrashing # Increased heap to 2GB and Metaspace to 1024m to prevent memory exhaustion