This commit is contained in:
ΞTΞRNAL
2026-03-26 12:13:52 +05:30
parent dbbc52b67f
commit 95f98221e3
7 changed files with 151 additions and 10 deletions

View File

@@ -126,7 +126,7 @@ class BetterLocationRoot : Routes.Route() {
overflow = TextOverflow.Ellipsis
)
Text(
text = context.translation.format(
text = translation.format(
"spoofed_coordinates_title",
"latitude" to friendLocation.latitude.toFloat().toString(),
"longitude" to friendLocation.longitude.toFloat().toString()

View File

@@ -466,6 +466,10 @@ fun HomeRootSection.AphelionHomeScreen(nav: NavBackStackEntry) {
var changelogLoading by remember { mutableStateOf(false) }
var changelogError by remember { mutableStateOf<String?>(null) }
var changelogVersion by remember { mutableStateOf<String?>(null) }
var showFullChangelogDialog by rememberSaveable { mutableStateOf(false) }
var fullChangelogText by rememberSaveable { mutableStateOf<String?>(null) }
var fullChangelogLoading by remember { mutableStateOf(false) }
var fullChangelogError by remember { mutableStateOf<String?>(null) }
var showAnnouncementsDialog by rememberSaveable { mutableStateOf(false) }
var announcementsText by rememberSaveable { mutableStateOf<String?>(null) }
var announcementsLoading by remember { mutableStateOf(false) }
@@ -531,6 +535,31 @@ fun HomeRootSection.AphelionHomeScreen(nav: NavBackStackEntry) {
}
}
fun loadFullChangelog() {
if (fullChangelogText != null) return
fullChangelogLoading = true
fullChangelogError = null
coroutineScope.launch(Dispatchers.IO) {
val url = if (updateChannel == "prerelease") changelogPrereleaseUrl else changelogStableUrl
runCatching {
OkHttpClient().newCall(Request.Builder().url(url).build()).execute().use { response ->
val body = response.body?.string() ?: throw IllegalStateException("Empty body")
body.trim()
}
}.onSuccess { text ->
withContext(Dispatchers.Main) {
fullChangelogText = text
fullChangelogLoading = false
}
}.onFailure { e ->
withContext(Dispatchers.Main) {
fullChangelogError = e.message ?: "Failed to fetch"
fullChangelogLoading = false
}
}
}
}
val borderPath = remember { Path() }
val uPath = remember { Path() }
@@ -626,7 +655,8 @@ fun HomeRootSection.AphelionHomeScreen(nav: NavBackStackEntry) {
val announcementShift by remember(focusFactor) { derivedStateOf { (-6 * focusFactor).dp } }
Row(
modifier = Modifier.align(Alignment.CenterStart).graphicsLayer { translationX = announcementShift.toPx() },
verticalAlignment = Alignment.CenterVertically
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(10.dp)
) {
AphelionTopBarActionChip(
icon = Icons.Filled.Notifications, label = null,
@@ -634,6 +664,12 @@ fun HomeRootSection.AphelionHomeScreen(nav: NavBackStackEntry) {
contentDescription = translation["announcements_button_description"],
haptic = haptic
) { showAnnouncementsDialog = true; loadAnnouncements() }
AphelionTopBarActionChip(
icon = Icons.Filled.Description, label = null,
shrinkFactor = (1f - focusFactor).coerceIn(0f, 1f),
contentDescription = translation.getOrNull("changelog_button_description") ?: "Open full changelog",
haptic = haptic
) { showFullChangelogDialog = true; loadFullChangelog() }
}
val settingsShift by remember(focusFactor) { derivedStateOf { (6 * focusFactor).dp } }
Row(
@@ -778,6 +814,7 @@ fun HomeRootSection.AphelionHomeScreen(nav: NavBackStackEntry) {
text = "", icon = Icons.Filled.Notifications,
confirmButtonText = translation["announcements_dialog_close_button"] ?: "Close",
onConfirm = { showAnnouncementsDialog = false },
showCloseButton = false,
customContent = {
Column(modifier = Modifier.fillMaxWidth().heightIn(max = 340.dp).verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(10.dp)) {
if (announcementsLoading) CircularProgressIndicator(color = Color.White)
@@ -796,6 +833,7 @@ fun HomeRootSection.AphelionHomeScreen(nav: NavBackStackEntry) {
onConfirm = { haptic.performHapticFeedback(HapticFeedbackType.LongPress); showChangelogDialog = false; handleUpdateAction() },
dismissButtonText = translation["changelog_dialog_cancel_button"] ?: "Cancel",
onDismiss = { showChangelogDialog = false },
showCloseButton = false,
customContent = {
Column(modifier = Modifier.fillMaxWidth().heightIn(max = 340.dp).verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(10.dp)) {
if (changelogLoading) CircularProgressIndicator(color = Color.White)
@@ -806,6 +844,28 @@ fun HomeRootSection.AphelionHomeScreen(nav: NavBackStackEntry) {
)
}
if (showFullChangelogDialog) {
AestheticDialog(
onDismissRequest = { showFullChangelogDialog = false },
title = translation["changelog_dialog_title"] ?: "Changelog",
text = "",
icon = Icons.Filled.Description,
confirmButtonText = translation["announcements_dialog_close_button"] ?: "Close",
onConfirm = { showFullChangelogDialog = false },
showCloseButton = false,
customContent = {
Column(
modifier = Modifier.fillMaxWidth().heightIn(max = 340.dp).verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
if (fullChangelogLoading) CircularProgressIndicator(color = Color.White)
else if (fullChangelogError != null) Text(fullChangelogError!!, color = Color.Red, fontSize = 14.sp)
else Text(fullChangelogText ?: translation["changelog_dialog_empty"] ?: "", color = PurrfectPalette.textPrimary, fontSize = 14.sp)
}
}
)
}
if (showQuickActionsMenu) {
QuickActionsDialog(
quickActions = cards,

View File

@@ -345,6 +345,10 @@ object LegacyTheme : ThemeContract {
var changelogError by remember { mutableStateOf<String?>(null) }
var changelogText by remember { mutableStateOf<String?>(null) }
var changelogVersion by remember { mutableStateOf<String?>(null) }
var showFullChangelogDialog by remember { mutableStateOf(false) }
var fullChangelogLoading by remember { mutableStateOf(false) }
var fullChangelogError by remember { mutableStateOf<String?>(null) }
var fullChangelogText by remember { mutableStateOf<String?>(null) }
var showAnnouncementsDialog by remember { mutableStateOf(false) }
var announcementsLoading by remember { mutableStateOf(false) }
var announcementsError by remember { mutableStateOf<String?>(null) }
@@ -415,6 +419,23 @@ object LegacyTheme : ThemeContract {
}
}
fun loadFullChangelog(url: String) {
if (fullChangelogText != null) return
fullChangelogLoading = true; fullChangelogError = null
coroutineScope.launch(Dispatchers.IO) {
runCatching {
changelogClient.newCall(Request.Builder().url(url).build()).execute().use { response ->
if (!response.isSuccessful) throw IllegalStateException("Failed to fetch changelog (${response.code})")
response.body?.string()?.trim() ?: throw IllegalStateException("Empty changelog body")
}
}.onSuccess { text ->
withContext(Dispatchers.Main) { fullChangelogText = text; fullChangelogLoading = false }
}.onFailure { error ->
withContext(Dispatchers.Main) { fullChangelogError = error.message ?: "Failed to load changelog"; fullChangelogLoading = false }
}
}
}
LaunchedEffect(Unit) {
if (context.sharedPreferences.getBoolean("show_changelog_on_launch", false)) {
val version = context.sharedPreferences.getString("changelog_version_on_launch", null)
@@ -450,6 +471,9 @@ object LegacyTheme : ThemeContract {
LocalTopBarActionChip(icon = Icons.Filled.Notifications, label = null, contentDescription = translation["announcements_button_description"]) {
showAnnouncementsDialog = true; loadAnnouncements()
}
LocalTopBarActionChip(icon = Icons.Filled.Description, label = null, contentDescription = translation.getOrNull("changelog_button_description") ?: "Open full changelog") {
showFullChangelogDialog = true; loadFullChangelog(changelogUrl)
}
}
Row(modifier = Modifier.wrapContentWidth(Alignment.End), horizontalArrangement = Arrangement.spacedBy(10.dp), verticalAlignment = Alignment.CenterVertically) {
LocalHomeActionChips()
@@ -570,6 +594,7 @@ object LegacyTheme : ThemeContract {
onConfirm = { showChangelogDialog = false; handleUpdateAction() },
dismissButtonText = translation["changelog_dialog_cancel_button"] ?: "Cancel",
onDismiss = { showChangelogDialog = false },
showCloseButton = false,
customContent = {
Column(modifier = Modifier.fillMaxWidth().heightIn(max = 340.dp).verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(10.dp)) {
if (changelogLoading) CircularProgressIndicator(color = Color.White)
@@ -587,6 +612,7 @@ object LegacyTheme : ThemeContract {
text = "", icon = Icons.Filled.Notifications,
confirmButtonText = translation["announcements_dialog_close_button"] ?: "Close",
onConfirm = { showAnnouncementsDialog = false },
showCloseButton = false,
customContent = {
Column(modifier = Modifier.fillMaxWidth().heightIn(max = 340.dp).verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(10.dp)) {
if (announcementsLoading) CircularProgressIndicator(color = Color.White)
@@ -597,6 +623,24 @@ object LegacyTheme : ThemeContract {
)
}
if (showFullChangelogDialog) {
AestheticDialog(
onDismissRequest = { showFullChangelogDialog = false },
title = translation["changelog_dialog_title"] ?: "Changelog",
text = "", icon = Icons.Filled.Description,
confirmButtonText = translation["announcements_dialog_close_button"] ?: "Close",
onConfirm = { showFullChangelogDialog = false },
showCloseButton = false,
customContent = {
Column(modifier = Modifier.fillMaxWidth().heightIn(max = 340.dp).verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(10.dp)) {
if (fullChangelogLoading) CircularProgressIndicator(color = Color.White)
else if (fullChangelogError != null) Text(fullChangelogError!!, color = Color.Red, fontSize = 14.sp)
else Text(fullChangelogText ?: translation["changelog_dialog_empty"] ?: "", color = PurrfectPalette.textPrimary, fontSize = 14.sp)
}
}
)
}
if (showQuickActionsMenu) {
QuickActionsDialog(
quickActions = cards,