From 48e5038466d809b83e615e8222bdd27243cb8d67 Mon Sep 17 00:00:00 2001 From: LagradOst <11805592+LagradOst@users.noreply.github.com> Date: Tue, 8 Sep 2026 18:58:49 +0200 Subject: [PATCH] Logcat fixes --- .../ui/settings/SettingsUIScreen.kt | 21 +- .../ui/settings/logcat/LogcatDialog.kt | 201 ++++++++++-------- .../lagradost/cloudstream4/compose/Colors.kt | 4 +- .../lagradost/cloudstream4/compose/Dialog.kt | 4 +- 4 files changed, 134 insertions(+), 96 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUIScreen.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUIScreen.kt index 3e67ed15e26..2fce9c58278 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUIScreen.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUIScreen.kt @@ -20,6 +20,7 @@ import com.lagradost.cloudstream3.CommonActivity.activity import com.lagradost.cloudstream3.MainActivity import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.SearchQuality +import com.lagradost.cloudstream3.mvvm.safe import com.lagradost.cloudstream3.ui.clear import com.lagradost.cloudstream3.ui.home.HomeChildItemAdapter import com.lagradost.cloudstream3.ui.home.ParentItemAdapter @@ -104,8 +105,10 @@ object SettingsUIScreen : SearchableSettings { }, onValueChanged = { newValue -> settings.ui.primaryColor.set(newValue) // We need to set before we recreate - activity?.recreate() - return@ListPreference true + safe { + activity?.recreate() + } + return@ListPreference false }), Preference.PreferenceItem.ListPreference( preference = settings.ui.theme, @@ -127,8 +130,10 @@ object SettingsUIScreen : SearchableSettings { }, onValueChanged = { newValue -> settings.ui.theme.set(newValue) // We need to set before we recreate - activity?.recreate() - return@ListPreference true + safe { + activity?.recreate() + } + return@ListPreference false }), Preference.PreferenceItem.ListPreference( preference = settings.ui.layout, @@ -139,9 +144,11 @@ object SettingsUIScreen : SearchableSettings { ).toMap().toPersistentMap(), onValueChanged = { newValue -> settings.ui.layout.set(newValue) // We need to set before we recreate - activity?.updateTv() - activity?.recreate() - return@ListPreference true + safe { + activity?.updateTv() + activity?.recreate() + } + return@ListPreference false }), ) ), diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/logcat/LogcatDialog.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/logcat/LogcatDialog.kt index a157a0cda9c..73dc7ea58ba 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/logcat/LogcatDialog.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/logcat/LogcatDialog.kt @@ -15,14 +15,22 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Button +import androidx.compose.material3.LinearProgressIndicator +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.FocusRequester.Companion.FocusRequesterFactory.component1 +import androidx.compose.ui.focus.FocusRequester.Companion.FocusRequesterFactory.component2 +import androidx.compose.ui.focus.focusProperties +import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource @@ -35,7 +43,8 @@ import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.utils.UIHelper.clipboardHelper import com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager import com.lagradost.cloudstream3.utils.txt -import com.lagradost.cloudstream4.compose.Colors +import com.lagradost.cloudstream4.compose.BlackButton +import com.lagradost.cloudstream4.compose.WhiteButton import com.lagradost.cloudstream4.compose.circle import com.lagradost.cloudstream4.compose.ripple import com.lagradost.cloudstream4.compose.rounded @@ -54,10 +63,12 @@ import java.util.Locale @Composable fun LogcatDialog(dismiss: () -> Unit) { - val list = remember { mutableStateOf(persistentListOf()) } + var isLoading by remember { mutableStateOf(true) } LaunchedEffect(dismiss) { try { + isLoading = true + // https://developer.android.com/studio/command-line/logcat val process = Runtime.getRuntime().exec("logcat --binary -d") val items = arrayListOf() @@ -71,8 +82,11 @@ fun LogcatDialog(dismiss: () -> Unit) { list.value = items.toPersistentList() } catch (e: Exception) { logError(e) // kinda ironic + } finally { + isLoading = false } } + val (dismissFocus, confirmFocus) = remember { FocusRequester.createRefs() } val context = LocalContext.current val scope = rememberCoroutineScope() @@ -83,98 +97,115 @@ fun LogcatDialog(dismiss: () -> Unit) { Text(text = stringResource(R.string.log_cat)) }, text = { - LazyColumn { + if (isLoading) { + LinearProgressIndicator( + modifier = Modifier.fillMaxWidth(), + color = MaterialTheme.colorScheme.onBackground, + trackColor = MaterialTheme.colorScheme.surfaceVariant, + ) + } + LazyColumn( + modifier = Modifier.focusProperties { + start = dismissFocus + end = confirmFocus + } + ) { items(items = list.value) { item -> - LogcatItem(item) + LogcatItem(item, modifier = Modifier.focusProperties { + start = dismissFocus + end = confirmFocus + }) } } }, confirmButton = { - Button( - onClick = { - scope.launch { - withContext(Dispatchers.IO) { - val date = SimpleDateFormat("yyyy_MM_dd_HH_mm", Locale.getDefault()).format(Date(currentTimeMillis())) - var fileStream: OutputStream? - try { - fileStream = VideoDownloadManager.setupStream( - context, - "logcat_${date}", - null, - "txt", - false - ).openNew() - fileStream.bufferedWriter() - .use { writer -> - list.value.forEach { - writer.write(it.toString()) - writer.write("\n\n") - } + WhiteButton( + text = stringResource(R.string.sort_save), + modifier = Modifier.focusRequester(confirmFocus) + ) { + scope.launch { + withContext(Dispatchers.IO) { + val date = SimpleDateFormat("yyyy_MM_dd_HH_mm", Locale.getDefault()).format( + Date(currentTimeMillis()) + ) + var fileStream: OutputStream? + try { + fileStream = VideoDownloadManager.setupStream( + context, + "logcat_${date}", + null, + "txt", + false + ).openNew() + fileStream.bufferedWriter() + .use { writer -> + list.value.forEach { + writer.write(it.toString()) + writer.write("\n\n") } - dismiss() - } catch (t: Throwable) { - logError(t) - showToast(t.message) - } - /*try { - val date = SimpleDateFormat( - "yyyy_MM_dd_HH_mm", - Locale.getDefault() - ).format( - Date(System.currentTimeMillis()) - ) + } + dismiss() + } catch (t: Throwable) { + logError(t) + showToast(t.message) + } + /*try { + val date = SimpleDateFormat( + "yyyy_MM_dd_HH_mm", + Locale.getDefault() + ).format( + Date(System.currentTimeMillis()) + ) - val file = FileHelper.logcat.createFile(context, "logcat_${date}") - ?: throw ErrorLoadingException("Unable to create file") - val stream = file.openOutputStream(append = false) - ?: throw ErrorLoadingException("Unable to create stream") + val file = FileHelper.logcat.createFile(context, "logcat_${date}") + ?: throw ErrorLoadingException("Unable to create file") + val stream = file.openOutputStream(append = false) + ?: throw ErrorLoadingException("Unable to create stream") - stream.bufferedWriter() - .use { writer -> - list.value.forEach { - writer.write(it.toString()) - writer.write("\n\n") - } + stream.bufferedWriter() + .use { writer -> + list.value.forEach { + writer.write(it.toString()) + writer.write("\n\n") } - dismiss() - showToast( - txt( - R.string.logcat_success, - file.absolutePath ?: file.uri.toString() - ), - Toast.LENGTH_LONG - ) - } catch (t: Throwable) { - logError(t) - showToast(t.message) - }*/ - } + } + dismiss() + showToast( + txt( + R.string.logcat_success, + file.absolutePath ?: file.uri.toString() + ), + Toast.LENGTH_LONG + ) + } catch (t: Throwable) { + logError(t) + showToast(t.message) + }*/ } - }, colors = Colors.whiteButton - ) { Text(text = stringResource(R.string.sort_save)) } - Button( - onClick = { - clipboardHelper( - txt("Logcat"), - list.value.joinToString(separator = "\n\n") { it.toString() } - ) - }, colors = Colors.whiteButton - ) { Text(text = stringResource(R.string.sort_copy)) } - Button( - onClick = { - try { - Runtime.getRuntime().exec("logcat -c") - } catch (t: Throwable) { - logError(t) - } - dismiss() - }, colors = Colors.whiteButton - ) { Text(text = stringResource(R.string.sort_clear)) } + } + } + + WhiteButton(text = stringResource(R.string.sort_copy)) { + clipboardHelper( + txt("Logcat"), + list.value.joinToString(separator = "\n\n") { it.toString() } + ) + } + WhiteButton(text = stringResource(R.string.sort_clear)) { + try { + Runtime.getRuntime().exec("logcat -c") + } catch (t: Throwable) { + logError(t) + } + dismiss() + } }, dismissButton = { - Button( - onClick = dismiss, colors = Colors.blackButton - ) { Text(text = stringResource(R.string.sort_close)) } + BlackButton( + text = stringResource(R.string.sort_close), + onClick = dismiss, + modifier = Modifier.focusRequester(dismissFocus) + ) }, properties = DialogProperties(usePlatformDefaultWidth = false) ) @@ -182,7 +213,7 @@ fun LogcatDialog(dismiss: () -> Unit) { @Composable -fun LogcatItem(item: LogcatItem) { +fun LogcatItem(item: LogcatItem, modifier: Modifier = Modifier) { val interactionSource = remember { MutableInteractionSource() } val color = when (item.level) { @@ -227,7 +258,7 @@ fun LogcatItem(item: LogcatItem) { ) } Row( - modifier = Modifier + modifier = modifier .height(IntrinsicSize.Min) .fillMaxWidth() .clickable( diff --git a/shared/src/commonMain/kotlin/com/lagradost/cloudstream4/compose/Colors.kt b/shared/src/commonMain/kotlin/com/lagradost/cloudstream4/compose/Colors.kt index d39bffa6650..2e009e4e73b 100644 --- a/shared/src/commonMain/kotlin/com/lagradost/cloudstream4/compose/Colors.kt +++ b/shared/src/commonMain/kotlin/com/lagradost/cloudstream4/compose/Colors.kt @@ -6,7 +6,7 @@ import androidx.compose.runtime.ReadOnlyComposable import com.lagradost.cloudstream4.theme.CloudStreamTheme.colors object Colors { - val blackButton + internal val blackButton @Composable @ReadOnlyComposable get() = ButtonColors( containerColor = colors.surfaceVariant, contentColor = colors.onBackground, @@ -14,7 +14,7 @@ object Colors { disabledContentColor = colors.onBackground.copy(alpha = 0.9f) ) - val whiteButton + internal val whiteButton @Composable @ReadOnlyComposable get() = ButtonColors( containerColor = colors.onBackground, contentColor = colors.surfaceVariant, diff --git a/shared/src/commonMain/kotlin/com/lagradost/cloudstream4/compose/Dialog.kt b/shared/src/commonMain/kotlin/com/lagradost/cloudstream4/compose/Dialog.kt index 9dbed5f4275..9a6ab32c81a 100644 --- a/shared/src/commonMain/kotlin/com/lagradost/cloudstream4/compose/Dialog.kt +++ b/shared/src/commonMain/kotlin/com/lagradost/cloudstream4/compose/Dialog.kt @@ -87,8 +87,8 @@ fun ActionDialog( @Composable fun WhiteButton( text: String, - onClick: () -> Unit, modifier: Modifier = Modifier, + onClick: () -> Unit, ) { BaseButton( text = text, @@ -101,8 +101,8 @@ fun WhiteButton( @Composable fun BlackButton( text: String, - onClick: () -> Unit, modifier: Modifier = Modifier, + onClick: () -> Unit, ) { BaseButton( text = text,