Redesign is now the new norm

This commit is contained in:
topjohnwu
2020-01-13 00:43:09 +08:00
parent 1449486958
commit 3490ba0a56
90 changed files with 313 additions and 313 deletions
@@ -0,0 +1,76 @@
package com.topjohnwu.magisk.ui.log
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.core.graphics.Insets
import androidx.core.view.isVisible
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.FragmentLogMd2Binding
import com.topjohnwu.magisk.ui.MainActivity
import com.topjohnwu.magisk.ui.compat.CompatFragment
import com.topjohnwu.magisk.utils.MotionRevealHelper
import org.koin.androidx.viewmodel.ext.android.viewModel
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()
}
}
@@ -0,0 +1,113 @@
package com.topjohnwu.magisk.ui.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.ConsoleItem
import com.topjohnwu.magisk.model.entity.recycler.LogItem
import com.topjohnwu.magisk.model.entity.recycler.TextItem
import com.topjohnwu.magisk.model.events.SnackbarEvent
import com.topjohnwu.magisk.ui.compat.CompatViewModel
import com.topjohnwu.magisk.ui.compat.diffListOf
import com.topjohnwu.magisk.ui.compat.itemBindingOf
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() {
// --- empty view
val itemEmpty = TextItem(R.string.log_data_none)
val itemMagiskEmpty = TextItem(R.string.log_data_magisk_none)
// --- main view
val items = diffListOf<LogItem>()
val itemBinding = itemBindingOf<LogItem> {
it.bindExtra(BR.viewModel, this)
}
// --- console
val consoleAdapter = BindingAdapter()
val itemsConsole = diffListOf<ComparableRvItem<*>>()
val itemConsoleBinding = itemBindingOf<ComparableRvItem<*>> {}
override fun refresh(): Disposable {
val logs = repo.fetchLogs()
.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 { ConsoleItem(it) }
.toList()
.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()
.subscribeK {
SnackbarEvent(R.string.logs_cleared).publish()
requestRefresh()
}
.add()
fun clearLog() = repo.clearLogs()
.subscribeK {
SnackbarEvent(R.string.logs_cleared).publish()
requestRefresh()
}
.add()
}