mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 14:27:57 +01:00 
			
		
		
		
	Add worker info screen (#8774)
Mainly for debug purpose, might help with support.
This commit is contained in:
		| @@ -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) }, | ||||
|                 ), | ||||
|             ), | ||||
|         ) | ||||
|     } | ||||
|   | ||||
| @@ -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() | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -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> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user