Add worker info screen (#8774)

Mainly for debug purpose, might help with support.
This commit is contained in:
Ivan Iskandar 2023-01-03 09:58:11 +07:00 committed by GitHub
parent 01ec26842d
commit ab61a65b4a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 168 additions and 0 deletions

View file

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

View file

@ -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()
}
}
}
}
}

View file

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