mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-12-31 00:47:50 +00:00
Added magisk log screen
This commit is contained in:
@@ -164,4 +164,9 @@ open class MainActivity : CompatActivity<MainViewModel, ActivityMainMd2Binding>(
|
||||
.start()
|
||||
}
|
||||
|
||||
fun invalidateToolbar() {
|
||||
//binding.mainToolbar.startAnimations()
|
||||
binding.mainToolbar.invalidate()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +1,17 @@
|
||||
package com.topjohnwu.magisk.redesign.log
|
||||
|
||||
import android.graphics.Insets
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.core.view.isVisible
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.databinding.FragmentLogMd2Binding
|
||||
import com.topjohnwu.magisk.redesign.MainActivity
|
||||
import com.topjohnwu.magisk.redesign.compat.CompatFragment
|
||||
import com.topjohnwu.magisk.redesign.hide.MotionRevealHelper
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
|
||||
class LogFragment : CompatFragment<LogViewModel, FragmentLogMd2Binding>() {
|
||||
@@ -11,14 +19,58 @@ class LogFragment : CompatFragment<LogViewModel, FragmentLogMd2Binding>() {
|
||||
override val layoutRes = R.layout.fragment_log_md2
|
||||
override val viewModel by viewModel<LogViewModel>()
|
||||
|
||||
private var actionSave: MenuItem? = null
|
||||
private var isMagiskLogVisible
|
||||
get() = binding.logFilter.isVisible
|
||||
set(value) {
|
||||
MotionRevealHelper.withViews(binding.logFilter, binding.logFilterToggle, value)
|
||||
actionSave?.isVisible = value
|
||||
(activity as MainActivity).invalidateToolbar()
|
||||
}
|
||||
|
||||
override fun consumeSystemWindowInsets(insets: Insets) = insets
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
|
||||
setHasOptionsMenu(true)
|
||||
activity.title = resources.getString(R.string.section_log)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding.logFilterToggle.setOnClickListener {
|
||||
isMagiskLogVisible = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
inflater.inflate(R.menu.menu_log_md2, menu)
|
||||
actionSave = menu.findItem(R.id.action_save)?.also {
|
||||
it.isVisible = isMagiskLogVisible
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.action_save -> viewModel.saveMagiskLog()
|
||||
R.id.action_clear ->
|
||||
if (isMagiskLogVisible) viewModel.clearMagiskLog()
|
||||
else viewModel.clearLog()
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
|
||||
override fun onPreBind(binding: FragmentLogMd2Binding) = Unit
|
||||
|
||||
override fun onBackPressed(): Boolean {
|
||||
if (binding.logFilter.isVisible) {
|
||||
isMagiskLogVisible = false
|
||||
return true
|
||||
}
|
||||
return super.onBackPressed()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,33 +1,107 @@
|
||||
package com.topjohnwu.magisk.redesign.log
|
||||
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.data.repository.LogRepository
|
||||
import com.topjohnwu.magisk.databinding.ComparableRvItem
|
||||
import com.topjohnwu.magisk.extensions.subscribeK
|
||||
import com.topjohnwu.magisk.model.binding.BindingAdapter
|
||||
import com.topjohnwu.magisk.model.entity.recycler.ConsoleRvItem
|
||||
import com.topjohnwu.magisk.model.entity.recycler.LogItem
|
||||
import com.topjohnwu.magisk.model.events.SnackbarEvent
|
||||
import com.topjohnwu.magisk.redesign.compat.CompatViewModel
|
||||
import com.topjohnwu.magisk.redesign.home.itemBindingOf
|
||||
import com.topjohnwu.magisk.redesign.superuser.diffListOf
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
class LogViewModel(
|
||||
private val repo: LogRepository
|
||||
) : CompatViewModel() {
|
||||
|
||||
// --- main view
|
||||
|
||||
val items = diffListOf<LogItem>()
|
||||
val itemBinding = itemBindingOf<LogItem> {
|
||||
it.bindExtra(BR.viewModel, this)
|
||||
}
|
||||
|
||||
override fun refresh() = repo.fetchLogsNowrap()
|
||||
.map { it.map { LogItem(it) } }
|
||||
.map { it to items.calculateDiff(it) }
|
||||
.subscribeK {
|
||||
items.firstOrNull()?.isTop = false
|
||||
items.lastOrNull()?.isBottom = false
|
||||
// --- console
|
||||
|
||||
items.update(it.first, it.second)
|
||||
val consoleAdapter = BindingAdapter()
|
||||
val itemsConsole = diffListOf<ComparableRvItem<*>>()
|
||||
val itemConsoleBinding = itemBindingOf<ComparableRvItem<*>> {}
|
||||
|
||||
items.firstOrNull()?.isTop = true
|
||||
items.lastOrNull()?.isBottom = true
|
||||
override fun refresh(): Disposable {
|
||||
val logs = repo.fetchLogsNowrap()
|
||||
.map { it.map { LogItem(it) } }
|
||||
.observeOn(Schedulers.computation())
|
||||
.map { it to items.calculateDiff(it) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnSuccess {
|
||||
items.firstOrNull()?.isTop = false
|
||||
items.lastOrNull()?.isBottom = false
|
||||
|
||||
items.update(it.first, it.second)
|
||||
|
||||
items.firstOrNull()?.isTop = true
|
||||
items.lastOrNull()?.isBottom = true
|
||||
}
|
||||
.ignoreElement()
|
||||
|
||||
val console = repo.fetchMagiskLogs()
|
||||
.map { it.map { ConsoleRvItem(it) } }
|
||||
.observeOn(Schedulers.computation())
|
||||
.map { it to itemsConsole.calculateDiff(it) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnSuccess { itemsConsole.update(it.first, it.second) }
|
||||
.ignoreElement()
|
||||
|
||||
return Completable.merge(listOf(logs, console)).subscribeK()
|
||||
}
|
||||
|
||||
fun saveMagiskLog() {
|
||||
val now = Calendar.getInstance()
|
||||
val filename = "magisk_log_%04d%02d%02d_%02d%02d%02d.log".format(
|
||||
now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1,
|
||||
now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY),
|
||||
now.get(Calendar.MINUTE), now.get(Calendar.SECOND)
|
||||
)
|
||||
|
||||
val logFile = File(Config.downloadDirectory, filename)
|
||||
runCatching {
|
||||
logFile.createNewFile()
|
||||
}.onFailure {
|
||||
Timber.e(it)
|
||||
return
|
||||
}
|
||||
|
||||
Shell.su("cat ${Const.MAGISK_LOG} > $logFile").submit {
|
||||
SnackbarEvent(logFile.path).publish()
|
||||
}
|
||||
}
|
||||
|
||||
fun clearMagiskLog() = repo.clearMagiskLogs()
|
||||
.ignoreElement()
|
||||
.subscribeK {
|
||||
SnackbarEvent(R.string.logs_cleared).publish()
|
||||
requestRefresh()
|
||||
}
|
||||
.add()
|
||||
|
||||
fun clearLog() = repo.clearLogs()
|
||||
.subscribeK {
|
||||
SnackbarEvent(R.string.logs_cleared).publish()
|
||||
requestRefresh()
|
||||
}
|
||||
.add()
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user