Explorar el Código

Add worker info screen (#8774)

Mainly for debug purpose, might help with support.
Ivan Iskandar hace 2 años
padre
commit
ab61a65b4a

+ 5 - 0
app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt

@@ -118,6 +118,7 @@ object SettingsAdvancedScreen : SearchableSettings {
     private fun getBackgroundActivityGroup(): Preference.PreferenceGroup {
         val context = LocalContext.current
         val uriHandler = LocalUriHandler.current
+        val navigator = LocalNavigator.currentOrThrow
 
         return Preference.PreferenceGroup(
             title = stringResource(R.string.label_background_activity),
@@ -149,6 +150,10 @@ object SettingsAdvancedScreen : SearchableSettings {
                     subtitle = stringResource(R.string.about_dont_kill_my_app),
                     onClick = { uriHandler.openUri("https://dontkillmyapp.com/") },
                 ),
+                Preference.PreferenceItem.TextPreference(
+                    title = stringResource(R.string.pref_worker_info),
+                    onClick = { navigator.push(WorkerInfoScreen) },
+                ),
             ),
         )
     }

+ 161 - 0
app/src/main/java/eu/kanade/presentation/more/settings/screen/WorkerInfoScreen.kt

@@ -0,0 +1,161 @@
+package eu.kanade.presentation.more.settings.screen
+
+import android.content.Context
+import androidx.compose.foundation.horizontalScroll
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.ArrowBack
+import androidx.compose.material.icons.filled.ContentCopy
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.SnackbarHost
+import androidx.compose.material3.SnackbarHostState
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBar
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalClipboardManager
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.unit.dp
+import androidx.lifecycle.asFlow
+import androidx.work.WorkInfo
+import androidx.work.WorkManager
+import androidx.work.WorkQuery
+import cafe.adriel.voyager.core.model.ScreenModel
+import cafe.adriel.voyager.core.model.coroutineScope
+import cafe.adriel.voyager.core.model.rememberScreenModel
+import cafe.adriel.voyager.core.screen.Screen
+import cafe.adriel.voyager.navigator.LocalNavigator
+import cafe.adriel.voyager.navigator.currentOrThrow
+import eu.kanade.presentation.components.LazyColumn
+import eu.kanade.presentation.components.Scaffold
+import eu.kanade.presentation.util.plus
+import eu.kanade.tachiyomi.R
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
+
+object WorkerInfoScreen : Screen {
+
+    @Composable
+    override fun Content() {
+        val context = LocalContext.current
+        val navigator = LocalNavigator.currentOrThrow
+        val clipboardManager = LocalClipboardManager.current
+
+        val screenModel = rememberScreenModel { Model(context) }
+        val enqueued by screenModel.enqueued.collectAsState()
+        val finished by screenModel.finished.collectAsState()
+        val running by screenModel.running.collectAsState()
+
+        val snackbarHostState = remember { SnackbarHostState() }
+        val scope = rememberCoroutineScope()
+
+        Scaffold(
+            topBar = {
+                TopAppBar(
+                    title = { Text(text = stringResource(R.string.pref_worker_info)) },
+                    navigationIcon = {
+                        IconButton(onClick = navigator::pop) {
+                            Icon(imageVector = Icons.Default.ArrowBack, contentDescription = null)
+                        }
+                    },
+                    actions = {
+                        val copiedString = stringResource(R.string.copied_to_clipboard_plain)
+                        IconButton(
+                            onClick = {
+                                clipboardManager.setText(AnnotatedString(enqueued + finished + running))
+                                scope.launch { snackbarHostState.showSnackbar(copiedString) }
+                            },
+                        ) {
+                            Icon(imageVector = Icons.Default.ContentCopy, contentDescription = null)
+                        }
+                    },
+                    scrollBehavior = it,
+                )
+            },
+            snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
+        ) { contentPadding ->
+            LazyColumn(
+                contentPadding = contentPadding + PaddingValues(horizontal = 16.dp),
+                modifier = Modifier.horizontalScroll(rememberScrollState()),
+            ) {
+                item { SectionTitle(title = "Enqueued") }
+                item { SectionText(text = enqueued) }
+
+                item { SectionTitle(title = "Finished") }
+                item { SectionText(text = finished) }
+
+                item { SectionTitle(title = "Running") }
+                item { SectionText(text = running) }
+            }
+        }
+    }
+
+    @Composable
+    private fun SectionTitle(title: String) {
+        Text(
+            text = title,
+            style = MaterialTheme.typography.titleMedium,
+            modifier = Modifier.padding(vertical = 8.dp),
+        )
+    }
+
+    @Composable
+    private fun SectionText(text: String) {
+        Text(
+            text = text,
+            softWrap = false,
+            fontFamily = FontFamily.Monospace,
+        )
+    }
+
+    private class Model(context: Context) : ScreenModel {
+        private val workManager = WorkManager.getInstance(context)
+
+        val finished = workManager
+            .getWorkInfosLiveData(WorkQuery.fromStates(WorkInfo.State.SUCCEEDED, WorkInfo.State.FAILED, WorkInfo.State.CANCELLED))
+            .asFlow()
+            .map(::constructString)
+            .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), "")
+
+        val running = workManager
+            .getWorkInfosLiveData(WorkQuery.fromStates(WorkInfo.State.RUNNING))
+            .asFlow()
+            .map(::constructString)
+            .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), "")
+
+        val enqueued = workManager
+            .getWorkInfosLiveData(WorkQuery.fromStates(WorkInfo.State.ENQUEUED))
+            .asFlow()
+            .map(::constructString)
+            .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), "")
+
+        private fun constructString(list: List<WorkInfo>) = buildString {
+            if (list.isEmpty()) {
+                appendLine("-")
+            } else {
+                list.forEach { workInfo ->
+                    appendLine("Id: ${workInfo.id}")
+                    appendLine("Tags:")
+                    workInfo.tags.forEach {
+                        appendLine(" - $it")
+                    }
+                    appendLine("State: ${workInfo.state}")
+                    appendLine()
+                }
+            }
+        }
+    }
+}

+ 2 - 0
i18n/src/main/res/values/strings.xml

@@ -538,6 +538,7 @@
     <string name="pref_tablet_ui_mode">Tablet UI</string>
     <string name="pref_verbose_logging">Verbose logging</string>
     <string name="pref_verbose_logging_summary">Print verbose logs to system log (reduces app performance)</string>
+    <string name="pref_worker_info">Worker info</string>
 
       <!-- About section -->
     <string name="website">Website</string>
@@ -634,6 +635,7 @@
         <item quantity="other">%1$s chapters</item>
     </plurals>
     <string name="delete_downloads_for_manga">Delete downloaded chapters?</string>
+    <string name="copied_to_clipboard_plain">Copied to clipboard</string>
     <string name="copied_to_clipboard">Copied to clipboard:\n%1$s</string>
     <string name="clipboard_copy_error">Failed to copy to clipboard</string>
     <string name="source_not_installed">Source not installed: %1$s</string>