mirror of
https://github.com/null2264/yokai.git
synced 2025-06-21 10:44:42 +00:00
Add debug info screens
Nice and freshly converted from compose 😃
This commit is contained in:
parent
0b37080e47
commit
8ae9b09d68
17 changed files with 497 additions and 59 deletions
|
@ -140,9 +140,9 @@ class MangaDetailsAdapter(
|
|||
fun showFloatingActionMode(view: TextView, content: String? = null, isTag: Boolean = false)
|
||||
fun showChapterFilter()
|
||||
fun favoriteManga(longPress: Boolean)
|
||||
fun copyToClipboard(content: String, label: Int, useToast: Boolean = false)
|
||||
fun copyContentToClipboard(content: String, label: Int, useToast: Boolean = false)
|
||||
fun customActionMode(view: TextView): ActionMode.Callback
|
||||
fun copyToClipboard(content: String, label: String?, useToast: Boolean = false)
|
||||
fun copyContentToClipboard(content: String, label: String?, useToast: Boolean = false)
|
||||
fun zoomImageFromThumb(thumbView: View)
|
||||
fun showTrackingSheet()
|
||||
fun updateScroll()
|
||||
|
|
|
@ -4,7 +4,6 @@ import android.animation.ValueAnimator
|
|||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
|
@ -109,6 +108,7 @@ import eu.kanade.tachiyomi.util.system.setCustomTitleAndMessage
|
|||
import eu.kanade.tachiyomi.util.system.timeSpanFromNow
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import eu.kanade.tachiyomi.util.view.activityBinding
|
||||
import eu.kanade.tachiyomi.util.view.copyToClipboard
|
||||
import eu.kanade.tachiyomi.util.view.findChild
|
||||
import eu.kanade.tachiyomi.util.view.getText
|
||||
import eu.kanade.tachiyomi.util.view.isControllerVisible
|
||||
|
@ -1639,10 +1639,10 @@ class MangaDetailsController :
|
|||
* @param content the actual text to copy to the board
|
||||
* @param label Label to show to the user describing the content
|
||||
*/
|
||||
override fun copyToClipboard(content: String, label: Int, useToast: Boolean) {
|
||||
override fun copyContentToClipboard(content: String, label: Int, useToast: Boolean) {
|
||||
val view = view ?: return
|
||||
val contentType = if (label != 0) view.context.getString(label) else null
|
||||
copyToClipboard(content, contentType, useToast)
|
||||
copyContentToClipboard(content, contentType, useToast)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1651,22 +1651,8 @@ class MangaDetailsController :
|
|||
* @param content the actual text to copy to the board
|
||||
* @param label Label to show to the user describing the content
|
||||
*/
|
||||
override fun copyToClipboard(content: String, label: String?, useToast: Boolean) {
|
||||
if (content.isBlank()) return
|
||||
|
||||
val activity = activity ?: return
|
||||
val view = view ?: return
|
||||
|
||||
val clipboard = activity.getSystemService(ClipboardManager::class.java)
|
||||
clipboard.setPrimaryClip(ClipData.newPlainText(label, content))
|
||||
|
||||
label ?: return
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) return
|
||||
if (useToast) {
|
||||
activity.toast(view.context.getString(R.string._copied_to_clipboard, label))
|
||||
} else {
|
||||
snack = view.snack(view.context.getString(R.string._copied_to_clipboard, label))
|
||||
}
|
||||
override fun copyContentToClipboard(content: String, label: String?, useToast: Boolean) {
|
||||
snack = copyToClipboard(content, label, useToast)
|
||||
}
|
||||
|
||||
override fun showTrackingSheet() {
|
||||
|
@ -1897,7 +1883,7 @@ class MangaDetailsController :
|
|||
item: MenuItem?,
|
||||
): Boolean {
|
||||
when (item?.itemId) {
|
||||
R.id.action_copy -> copyToClipboard(text, null)
|
||||
R.id.action_copy -> copyContentToClipboard(text, null)
|
||||
R.id.action_source_search -> sourceSearch(text)
|
||||
R.id.action_global_search, R.id.action_local_search -> {
|
||||
if (authorText != null) {
|
||||
|
|
|
@ -139,7 +139,7 @@ class MangaHeaderHolder(
|
|||
}
|
||||
title.setOnLongClickListener {
|
||||
title.text?.toString()?.toNormalized()?.let {
|
||||
adapter.delegate.copyToClipboard(it, R.string.title)
|
||||
adapter.delegate.copyContentToClipboard(it, R.string.title)
|
||||
}
|
||||
true
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ class MangaHeaderHolder(
|
|||
}
|
||||
mangaAuthor.setOnLongClickListener {
|
||||
mangaAuthor.text?.toString()?.let {
|
||||
adapter.delegate.copyToClipboard(it, R.string.author)
|
||||
adapter.delegate.copyContentToClipboard(it, R.string.author)
|
||||
}
|
||||
true
|
||||
}
|
||||
|
@ -523,7 +523,7 @@ class MangaHeaderHolder(
|
|||
adapter.delegate.showFloatingActionMode(chip, isTag = true)
|
||||
}
|
||||
chip.setOnLongClickListener {
|
||||
adapter.delegate.copyToClipboard(genreText, genreText)
|
||||
adapter.delegate.copyContentToClipboard(genreText, genreText)
|
||||
true
|
||||
}
|
||||
this.addView(chip)
|
||||
|
|
|
@ -241,7 +241,7 @@ class TrackingBottomSheet(private val controller: MangaDetailsController) :
|
|||
|
||||
override fun onTitleLongClick(position: Int) {
|
||||
val title = adapter?.getItem(position)?.track?.title ?: return
|
||||
controller.copyToClipboard(title, R.string.title, true)
|
||||
controller.copyContentToClipboard(title, R.string.title, true)
|
||||
}
|
||||
|
||||
private fun startTransition(duration: Long = 100) {
|
||||
|
|
|
@ -114,7 +114,7 @@ class AboutController : SettingsController() {
|
|||
preference {
|
||||
key = "pref_build_time"
|
||||
titleRes = R.string.build_time
|
||||
summary = getFormattedBuildTime()
|
||||
summary = getFormattedBuildTime(dateFormat)
|
||||
}
|
||||
|
||||
preferenceCategory {
|
||||
|
@ -234,15 +234,18 @@ class AboutController : SettingsController() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun getFormattedBuildTime(): String {
|
||||
try {
|
||||
val inputDf = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.getDefault())
|
||||
inputDf.timeZone = TimeZone.getTimeZone("UTC")
|
||||
val buildTime = inputDf.parse(BuildConfig.BUILD_TIME) ?: return BuildConfig.BUILD_TIME
|
||||
companion object {
|
||||
fun getFormattedBuildTime(dateFormat: DateFormat): String {
|
||||
try {
|
||||
val inputDf = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.getDefault())
|
||||
inputDf.timeZone = TimeZone.getTimeZone("UTC")
|
||||
val buildTime =
|
||||
inputDf.parse(BuildConfig.BUILD_TIME) ?: return BuildConfig.BUILD_TIME
|
||||
|
||||
return buildTime.toTimestampString(dateFormat)
|
||||
} catch (e: ParseException) {
|
||||
return BuildConfig.BUILD_TIME
|
||||
return buildTime.toTimestampString(dateFormat)
|
||||
} catch (e: ParseException) {
|
||||
return BuildConfig.BUILD_TIME
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ import eu.kanade.tachiyomi.network.PREF_DOH_QUAD101
|
|||
import eu.kanade.tachiyomi.network.PREF_DOH_QUAD9
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.ui.setting.database.ClearDatabaseController
|
||||
import eu.kanade.tachiyomi.ui.setting.debug.DebugController
|
||||
import eu.kanade.tachiyomi.util.CrashLogUtil
|
||||
import eu.kanade.tachiyomi.util.system.disableItems
|
||||
import eu.kanade.tachiyomi.util.system.isPackageInstalled
|
||||
|
@ -107,35 +108,47 @@ class SettingsAdvancedController : SettingsController() {
|
|||
}
|
||||
}
|
||||
|
||||
val pm = context.getSystemService(Context.POWER_SERVICE) as? PowerManager?
|
||||
if (pm != null) {
|
||||
preference {
|
||||
key = "disable_batt_opt"
|
||||
titleRes = R.string.disable_battery_optimization
|
||||
summaryRes = R.string.disable_if_issues_with_updating
|
||||
preference {
|
||||
key = "debug_info"
|
||||
titleRes = R.string.pref_debug_info
|
||||
|
||||
onClick {
|
||||
val packageName: String = context.packageName
|
||||
if (!pm.isIgnoringBatteryOptimizations(packageName)) {
|
||||
val intent = Intent().apply {
|
||||
action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
|
||||
data = "package:$packageName".toUri()
|
||||
}
|
||||
startActivity(intent)
|
||||
} else {
|
||||
context.toast(R.string.battery_optimization_disabled)
|
||||
}
|
||||
}
|
||||
onClick {
|
||||
router.pushController(DebugController().withFadeTransaction())
|
||||
}
|
||||
}
|
||||
|
||||
preference {
|
||||
key = "pref_dont_kill_my_app"
|
||||
title = "Don't kill my app!"
|
||||
summaryRes = R.string.about_dont_kill_my_app
|
||||
preferenceCategory {
|
||||
titleRes = R.string.label_background_activity
|
||||
val pm = context.getSystemService(Context.POWER_SERVICE) as? PowerManager?
|
||||
if (pm != null) {
|
||||
preference {
|
||||
key = "disable_batt_opt"
|
||||
titleRes = R.string.disable_battery_optimization
|
||||
summaryRes = R.string.disable_if_issues_with_updating
|
||||
|
||||
onClick {
|
||||
openInBrowser("https://dontkillmyapp.com/")
|
||||
onClick {
|
||||
val packageName: String = context.packageName
|
||||
if (!pm.isIgnoringBatteryOptimizations(packageName)) {
|
||||
val intent = Intent().apply {
|
||||
action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
|
||||
data = "package:$packageName".toUri()
|
||||
}
|
||||
startActivity(intent)
|
||||
} else {
|
||||
context.toast(R.string.battery_optimization_disabled)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
preference {
|
||||
key = "pref_dont_kill_my_app"
|
||||
title = "Don't kill my app!"
|
||||
summaryRes = R.string.about_dont_kill_my_app
|
||||
|
||||
onClick {
|
||||
openInBrowser("https://dontkillmyapp.com/")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
package eu.kanade.tachiyomi.ui.setting.debug
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.mikepenz.fastadapter.FastAdapter
|
||||
import com.mikepenz.fastadapter.adapters.ItemAdapter
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.backup.models.Backup
|
||||
import eu.kanade.tachiyomi.databinding.SubDebugControllerBinding
|
||||
import eu.kanade.tachiyomi.ui.base.controller.BaseController
|
||||
import eu.kanade.tachiyomi.util.view.copyToClipboard
|
||||
import eu.kanade.tachiyomi.util.view.scrollViewWith
|
||||
import kotlinx.serialization.protobuf.schema.ProtoBufSchemaGenerator
|
||||
|
||||
class BackupSchemaController : BaseController<SubDebugControllerBinding>() {
|
||||
|
||||
companion object {
|
||||
const val title = "Backup file schema"
|
||||
}
|
||||
|
||||
private val itemAdapter = ItemAdapter<DebugInfoItem>()
|
||||
private val fastAdapter = FastAdapter.with(itemAdapter)
|
||||
private val schema = ProtoBufSchemaGenerator.generateSchemaText(Backup.serializer().descriptor)
|
||||
|
||||
override fun getTitle() = title
|
||||
override fun createBinding(inflater: LayoutInflater) =
|
||||
SubDebugControllerBinding.inflate(inflater)
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
scrollViewWith(binding.recycler, padBottom = true)
|
||||
fastAdapter.setHasStableIds(true)
|
||||
binding.recycler.layoutManager = LinearLayoutManager(view.context)
|
||||
binding.recycler.adapter = fastAdapter
|
||||
itemAdapter.add(DebugInfoItem(schema, false))
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.sub_debug_info, menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.action_copy -> copyToClipboard(schema, "Backup file schema", true)
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
package eu.kanade.tachiyomi.ui.setting.debug
|
||||
|
||||
import android.os.Build
|
||||
import androidx.preference.PreferenceScreen
|
||||
import androidx.webkit.WebViewCompat
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.more.AboutController
|
||||
import eu.kanade.tachiyomi.ui.setting.SettingsController
|
||||
import eu.kanade.tachiyomi.ui.setting.onClick
|
||||
import eu.kanade.tachiyomi.ui.setting.preference
|
||||
import eu.kanade.tachiyomi.ui.setting.preferenceCategory
|
||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||
import eu.kanade.tachiyomi.util.view.withFadeTransaction
|
||||
import java.text.DateFormat
|
||||
|
||||
class DebugController : SettingsController() {
|
||||
|
||||
override fun getTitle() = resources?.getString(R.string.pref_debug_info)
|
||||
|
||||
private val dateFormat: DateFormat by lazy {
|
||||
preferences.dateFormat()
|
||||
}
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply {
|
||||
preference {
|
||||
title = WorkerInfoController.title
|
||||
onClick {
|
||||
router.pushController(WorkerInfoController().withFadeTransaction())
|
||||
}
|
||||
}
|
||||
preference {
|
||||
title = BackupSchemaController.title
|
||||
onClick {
|
||||
router.pushController(BackupSchemaController().withFadeTransaction())
|
||||
}
|
||||
}
|
||||
preferenceCategory {
|
||||
title = "App Info"
|
||||
preference {
|
||||
key = "pref_version"
|
||||
title = "Version"
|
||||
summary = if (BuildConfig.DEBUG) {
|
||||
"r" + BuildConfig.COMMIT_COUNT
|
||||
} else {
|
||||
BuildConfig.VERSION_NAME
|
||||
}
|
||||
}
|
||||
preference {
|
||||
key = "pref_build_time"
|
||||
title = "Build Time"
|
||||
summary = AboutController.getFormattedBuildTime(dateFormat)
|
||||
}
|
||||
preference {
|
||||
key = "pref_webview_version"
|
||||
title = "WebView version"
|
||||
summary = getWebViewVersion()
|
||||
}
|
||||
}
|
||||
|
||||
preferenceCategory {
|
||||
title = "Device info"
|
||||
preference {
|
||||
title = "Model"
|
||||
summary = "${Build.MANUFACTURER} ${Build.MODEL} (${Build.DEVICE})"
|
||||
}
|
||||
if (DeviceUtil.oneUiVersion != null) {
|
||||
preference {
|
||||
title = "OneUI version"
|
||||
summary = "${DeviceUtil.oneUiVersion}"
|
||||
}
|
||||
} else if (DeviceUtil.miuiMajorVersion != null) {
|
||||
preference {
|
||||
title = "MIUI version"
|
||||
summary = "${DeviceUtil.miuiMajorVersion}"
|
||||
}
|
||||
}
|
||||
val androidVersion = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
Build.VERSION.RELEASE_OR_PREVIEW_DISPLAY
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
Build.VERSION.RELEASE_OR_CODENAME
|
||||
} else {
|
||||
Build.VERSION.RELEASE
|
||||
}
|
||||
preference {
|
||||
title = "Android version"
|
||||
summary = "$androidVersion (${Build.DISPLAY})"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getWebViewVersion(): String {
|
||||
val activity = activity ?: return "Unknown"
|
||||
val webView =
|
||||
WebViewCompat.getCurrentWebViewPackage(activity) ?: return "how did you get here?"
|
||||
val label = webView.applicationInfo.loadLabel(activity.packageManager)
|
||||
val version = webView.versionName
|
||||
return "$label $version"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package eu.kanade.tachiyomi.ui.setting.debug
|
||||
|
||||
import android.view.View
|
||||
import androidx.core.view.isVisible
|
||||
import com.mikepenz.fastadapter.FastAdapter
|
||||
import com.mikepenz.fastadapter.items.AbstractItem
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.databinding.DebugInfoItemBinding
|
||||
|
||||
class DebugInfoItem(val text: String, val header: Boolean) : AbstractItem<FastAdapter.ViewHolder<DebugInfoItem>>() {
|
||||
|
||||
/** defines the type defining this item. must be unique. preferably an id */
|
||||
override val type: Int = R.id.debug_title
|
||||
|
||||
/** defines the layout which will be used for this item in the list */
|
||||
override val layoutRes: Int = R.layout.debug_info_item
|
||||
|
||||
override var identifier = text.hashCode().toLong()
|
||||
|
||||
override fun getViewHolder(v: View): FastAdapter.ViewHolder<DebugInfoItem> {
|
||||
return ViewHolder(v)
|
||||
}
|
||||
|
||||
class ViewHolder(view: View) : FastAdapter.ViewHolder<DebugInfoItem>(view) {
|
||||
|
||||
val binding = DebugInfoItemBinding.bind(view)
|
||||
|
||||
override fun bindView(item: DebugInfoItem, payloads: List<Any>) {
|
||||
binding.debugTitle.isVisible = item.header
|
||||
binding.debugSummary.isVisible = !item.header
|
||||
if (item.header) {
|
||||
binding.debugTitle.text = item.text
|
||||
} else {
|
||||
binding.debugSummary.text = item.text
|
||||
}
|
||||
}
|
||||
|
||||
override fun unbindView(item: DebugInfoItem) {
|
||||
binding.debugTitle.text = ""
|
||||
binding.debugSummary.text = ""
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package eu.kanade.tachiyomi.ui.setting.debug
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.mikepenz.fastadapter.FastAdapter
|
||||
import com.mikepenz.fastadapter.adapters.ItemAdapter
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.databinding.SubDebugControllerBinding
|
||||
import eu.kanade.tachiyomi.ui.base.controller.BaseCoroutineController
|
||||
import eu.kanade.tachiyomi.util.system.launchUI
|
||||
import eu.kanade.tachiyomi.util.view.copyToClipboard
|
||||
import eu.kanade.tachiyomi.util.view.scrollViewWith
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.merge
|
||||
|
||||
class WorkerInfoController : BaseCoroutineController<SubDebugControllerBinding, WorkerInfoPresenter>() {
|
||||
|
||||
companion object {
|
||||
const val title = "Worker info"
|
||||
}
|
||||
|
||||
override var presenter = WorkerInfoPresenter()
|
||||
|
||||
private val itemAdapter = ItemAdapter<DebugInfoItem>()
|
||||
private val fastAdapter = FastAdapter.with(itemAdapter)
|
||||
|
||||
override fun getTitle() = title
|
||||
override fun createBinding(inflater: LayoutInflater) =
|
||||
SubDebugControllerBinding.inflate(inflater)
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
scrollViewWith(binding.recycler, padBottom = true)
|
||||
|
||||
fastAdapter.setHasStableIds(true)
|
||||
binding.recycler.layoutManager = LinearLayoutManager(view.context)
|
||||
binding.recycler.adapter = fastAdapter
|
||||
binding.recycler.itemAnimator = null
|
||||
viewScope.launchUI {
|
||||
merge(presenter.enqueued, presenter.finished, presenter.running).collectLatest {
|
||||
itemAdapter.clear()
|
||||
itemAdapter.add(DebugInfoItem("Enqueued", true))
|
||||
itemAdapter.add(DebugInfoItem(presenter.enqueued.value, false))
|
||||
itemAdapter.add(DebugInfoItem("Finished", true))
|
||||
itemAdapter.add(DebugInfoItem(presenter.finished.value, false))
|
||||
itemAdapter.add(DebugInfoItem("Running", true))
|
||||
itemAdapter.add(DebugInfoItem(presenter.running.value, false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.sub_debug_info, menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.action_copy -> copyToClipboard(
|
||||
"${presenter.enqueued.value}\n${presenter.finished.value}\n${presenter.running.value}",
|
||||
"Backup file schema",
|
||||
true,
|
||||
)
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package eu.kanade.tachiyomi.ui.setting.debug
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.asFlow
|
||||
import androidx.work.WorkInfo
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.WorkQuery
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BaseCoroutinePresenter
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class WorkerInfoPresenter : BaseCoroutinePresenter<WorkerInfoController>() {
|
||||
private val workManager by lazy { WorkManager.getInstance(Injekt.get<Application>()) }
|
||||
|
||||
val finished by lazy {
|
||||
workManager
|
||||
.getWorkInfosLiveData(
|
||||
WorkQuery.fromStates(
|
||||
WorkInfo.State.SUCCEEDED,
|
||||
WorkInfo.State.FAILED,
|
||||
WorkInfo.State.CANCELLED,
|
||||
),
|
||||
)
|
||||
.asFlow()
|
||||
.map(::constructString)
|
||||
.stateIn(presenterScope, SharingStarted.WhileSubscribed(), "")
|
||||
}
|
||||
|
||||
val running by lazy {
|
||||
workManager
|
||||
.getWorkInfosLiveData(WorkQuery.fromStates(WorkInfo.State.RUNNING))
|
||||
.asFlow()
|
||||
.map(::constructString)
|
||||
.stateIn(presenterScope, SharingStarted.WhileSubscribed(), "")
|
||||
}
|
||||
|
||||
val enqueued by lazy {
|
||||
workManager
|
||||
.getWorkInfosLiveData(WorkQuery.fromStates(WorkInfo.State.ENQUEUED))
|
||||
.asFlow()
|
||||
.map(::constructString)
|
||||
.stateIn(presenterScope, SharingStarted.WhileSubscribed(), "")
|
||||
}
|
||||
|
||||
private fun constructString(list: List<WorkInfo>) = buildString {
|
||||
if (list.isEmpty()) {
|
||||
appendLine("-")
|
||||
} else {
|
||||
val newList = list.toList()
|
||||
newList.forEach { workInfo ->
|
||||
appendLine("Id: ${workInfo.id}")
|
||||
appendLine("Tags:")
|
||||
workInfo.tags.forEach {
|
||||
appendLine(" - $it")
|
||||
}
|
||||
appendLine("State: ${workInfo.state}")
|
||||
appendLine()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,6 +10,20 @@ object DeviceUtil {
|
|||
getSystemProperty("ro.miui.ui.version.name")?.isNotEmpty() ?: false
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the MIUI major version code from a string like "V12.5.3.0.QFGMIXM".
|
||||
*
|
||||
* @return MIUI major version code (e.g., 13) or null if can't be parsed.
|
||||
*/
|
||||
val miuiMajorVersion by lazy {
|
||||
if (!isMiui) return@lazy null
|
||||
|
||||
Build.VERSION.INCREMENTAL
|
||||
.substringBefore('.')
|
||||
.trimStart('V')
|
||||
.toIntOrNull()
|
||||
}
|
||||
|
||||
@SuppressLint("PrivateApi")
|
||||
fun isMiuiOptimizationDisabled(): Boolean {
|
||||
val sysProp = getSystemProperty("persist.sys.miui_optimization")
|
||||
|
@ -30,6 +44,20 @@ object DeviceUtil {
|
|||
Build.MANUFACTURER.equals("samsung", ignoreCase = true)
|
||||
}
|
||||
|
||||
val oneUiVersion by lazy {
|
||||
try {
|
||||
val semPlatformIntField = Build.VERSION::class.java.getDeclaredField("SEM_PLATFORM_INT")
|
||||
val version = semPlatformIntField.getInt(null) - 90000
|
||||
if (version < 0) {
|
||||
1.0
|
||||
} else {
|
||||
((version / 10000).toString() + "." + version % 10000 / 100).toDouble()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
val invalidDefaultBrowsers = listOf(
|
||||
"android",
|
||||
"com.huawei.android.internal.app",
|
||||
|
|
|
@ -4,6 +4,8 @@ import android.Manifest
|
|||
import android.animation.Animator
|
||||
import android.animation.ValueAnimator
|
||||
import android.app.ActivityManager
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
|
@ -50,6 +52,7 @@ import com.bluelinelabs.conductor.ControllerChangeType
|
|||
import com.bluelinelabs.conductor.Router
|
||||
import com.bluelinelabs.conductor.RouterTransaction
|
||||
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreatorJob
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
|
@ -824,6 +827,25 @@ fun Controller.openInBrowser(url: String) {
|
|||
}
|
||||
}
|
||||
|
||||
fun Controller.copyToClipboard(content: String, label: String?, useToast: Boolean): Snackbar? {
|
||||
if (content.isBlank()) return null
|
||||
|
||||
val activity = activity ?: return null
|
||||
val view = view ?: return null
|
||||
|
||||
val clipboard = activity.getSystemService(ClipboardManager::class.java)
|
||||
clipboard.setPrimaryClip(ClipData.newPlainText(label, content))
|
||||
|
||||
label ?: return null
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) return null
|
||||
return if (useToast) {
|
||||
activity.toast(view.context.getString(R.string._copied_to_clipboard, label))
|
||||
null
|
||||
} else {
|
||||
view.snack(view.context.getString(R.string._copied_to_clipboard, label))
|
||||
}
|
||||
}
|
||||
|
||||
val Controller.activityBinding: MainActivityBinding?
|
||||
get() = (activity as? MainActivity)?.binding
|
||||
|
||||
|
|
34
app/src/main/res/layout/debug_info_item.xml
Normal file
34
app/src/main/res/layout/debug_info_item.xml
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/debug_title"
|
||||
style="?textAppearanceTitleMedium"
|
||||
android:padding="8dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/card_view_group"
|
||||
android:layout_width="match_parent"
|
||||
tools:visibility="invisible"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="Enqueued" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/debug_summary"
|
||||
android:typeface="monospace"
|
||||
android:padding="8dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/card_view_group"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="Enqueued" />
|
||||
</FrameLayout>
|
12
app/src/main/res/layout/sub_debug_controller.xml
Normal file
12
app/src/main/res/layout/sub_debug_controller.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/frame_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"/>
|
||||
</FrameLayout>
|
9
app/src/main/res/menu/sub_debug_info.xml
Normal file
9
app/src/main/res/menu/sub_debug_info.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/action_copy"
|
||||
android:icon="@drawable/ic_content_copy_24dp"
|
||||
android:title="@string/copy_value"
|
||||
app:showAsAction="ifRoom" />
|
||||
</menu>
|
|
@ -877,6 +877,8 @@
|
|||
not in your library \nCurrently using: %1$s</string>
|
||||
<string name="most_entries">Most entries</string>
|
||||
<string name="select_uninstalled_sources">Select uninstalled sources</string>
|
||||
<string name="pref_debug_info">Debug info</string>
|
||||
<string name="label_background_activity">Background activity</string>
|
||||
|
||||
<!-- Browse Settings -->
|
||||
<string name="pref_global_search">Global search</string>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue