Added magisk log screen

This commit is contained in:
Viktor De Pasquale
2019-11-21 17:31:37 +01:00
parent 94f0c61619
commit 67c50d7504
8 changed files with 262 additions and 23 deletions

View File

@@ -164,4 +164,9 @@ open class MainActivity : CompatActivity<MainViewModel, ActivityMainMd2Binding>(
.start()
}
fun invalidateToolbar() {
//binding.mainToolbar.startAnimations()
binding.mainToolbar.invalidate()
}
}

View File

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

View File

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