Added magisk log screen
This commit is contained in:
parent
94f0c61619
commit
67c50d7504
@ -164,4 +164,9 @@ open class MainActivity : CompatActivity<MainViewModel, ActivityMainMd2Binding>(
|
|||||||
.start()
|
.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun invalidateToolbar() {
|
||||||
|
//binding.mainToolbar.startAnimations()
|
||||||
|
binding.mainToolbar.invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,9 +1,17 @@
|
|||||||
package com.topjohnwu.magisk.redesign.log
|
package com.topjohnwu.magisk.redesign.log
|
||||||
|
|
||||||
import android.graphics.Insets
|
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.R
|
||||||
import com.topjohnwu.magisk.databinding.FragmentLogMd2Binding
|
import com.topjohnwu.magisk.databinding.FragmentLogMd2Binding
|
||||||
|
import com.topjohnwu.magisk.redesign.MainActivity
|
||||||
import com.topjohnwu.magisk.redesign.compat.CompatFragment
|
import com.topjohnwu.magisk.redesign.compat.CompatFragment
|
||||||
|
import com.topjohnwu.magisk.redesign.hide.MotionRevealHelper
|
||||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
|
|
||||||
class LogFragment : CompatFragment<LogViewModel, FragmentLogMd2Binding>() {
|
class LogFragment : CompatFragment<LogViewModel, FragmentLogMd2Binding>() {
|
||||||
@ -11,14 +19,58 @@ class LogFragment : CompatFragment<LogViewModel, FragmentLogMd2Binding>() {
|
|||||||
override val layoutRes = R.layout.fragment_log_md2
|
override val layoutRes = R.layout.fragment_log_md2
|
||||||
override val viewModel by viewModel<LogViewModel>()
|
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 consumeSystemWindowInsets(insets: Insets) = insets
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
|
setHasOptionsMenu(true)
|
||||||
activity.title = resources.getString(R.string.section_log)
|
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 onPreBind(binding: FragmentLogMd2Binding) = Unit
|
||||||
|
|
||||||
|
override fun onBackPressed(): Boolean {
|
||||||
|
if (binding.logFilter.isVisible) {
|
||||||
|
isMagiskLogVisible = false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return super.onBackPressed()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,26 +1,52 @@
|
|||||||
package com.topjohnwu.magisk.redesign.log
|
package com.topjohnwu.magisk.redesign.log
|
||||||
|
|
||||||
import com.topjohnwu.magisk.BR
|
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.data.repository.LogRepository
|
||||||
|
import com.topjohnwu.magisk.databinding.ComparableRvItem
|
||||||
import com.topjohnwu.magisk.extensions.subscribeK
|
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.entity.recycler.LogItem
|
||||||
|
import com.topjohnwu.magisk.model.events.SnackbarEvent
|
||||||
import com.topjohnwu.magisk.redesign.compat.CompatViewModel
|
import com.topjohnwu.magisk.redesign.compat.CompatViewModel
|
||||||
import com.topjohnwu.magisk.redesign.home.itemBindingOf
|
import com.topjohnwu.magisk.redesign.home.itemBindingOf
|
||||||
import com.topjohnwu.magisk.redesign.superuser.diffListOf
|
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(
|
class LogViewModel(
|
||||||
private val repo: LogRepository
|
private val repo: LogRepository
|
||||||
) : CompatViewModel() {
|
) : CompatViewModel() {
|
||||||
|
|
||||||
|
// --- main view
|
||||||
|
|
||||||
val items = diffListOf<LogItem>()
|
val items = diffListOf<LogItem>()
|
||||||
val itemBinding = itemBindingOf<LogItem> {
|
val itemBinding = itemBindingOf<LogItem> {
|
||||||
it.bindExtra(BR.viewModel, this)
|
it.bindExtra(BR.viewModel, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun refresh() = repo.fetchLogsNowrap()
|
// --- console
|
||||||
|
|
||||||
|
val consoleAdapter = BindingAdapter()
|
||||||
|
val itemsConsole = diffListOf<ComparableRvItem<*>>()
|
||||||
|
val itemConsoleBinding = itemBindingOf<ComparableRvItem<*>> {}
|
||||||
|
|
||||||
|
override fun refresh(): Disposable {
|
||||||
|
val logs = repo.fetchLogsNowrap()
|
||||||
.map { it.map { LogItem(it) } }
|
.map { it.map { LogItem(it) } }
|
||||||
|
.observeOn(Schedulers.computation())
|
||||||
.map { it to items.calculateDiff(it) }
|
.map { it to items.calculateDiff(it) }
|
||||||
.subscribeK {
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.doOnSuccess {
|
||||||
items.firstOrNull()?.isTop = false
|
items.firstOrNull()?.isTop = false
|
||||||
items.lastOrNull()?.isBottom = false
|
items.lastOrNull()?.isBottom = false
|
||||||
|
|
||||||
@ -29,5 +55,53 @@ class LogViewModel(
|
|||||||
items.firstOrNull()?.isTop = true
|
items.firstOrNull()?.isTop = true
|
||||||
items.lastOrNull()?.isBottom = 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()
|
||||||
|
|
||||||
}
|
}
|
10
app/src/main/res/drawable/ic_folder_list.xml
Normal file
10
app/src/main/res/drawable/ic_folder_list.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="?colorOnSurface"
|
||||||
|
android:pathData="M20,18H4V8H20M20,6H12L10,4H4A2,2 0 0,0 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8A2,2 0 0,0 20,6M15,16H6V14H15V16M18,12H6V10H18V12Z" />
|
||||||
|
</vector>
|
10
app/src/main/res/drawable/ic_save_md2.xml
Normal file
10
app/src/main/res/drawable/ic_save_md2.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="?colorOnSurface"
|
||||||
|
android:pathData="M17 3H5C3.89 3 3 3.9 3 5V19C3 20.1 3.89 21 5 21H19C20.1 21 21 20.1 21 19V7L17 3M19 19H5V5H16.17L19 7.83V19M12 12C10.34 12 9 13.34 9 15S10.34 18 12 18 15 16.66 15 15 13.66 12 12 12M6 6H15V10H6V6Z" />
|
||||||
|
</vector>
|
@ -11,6 +11,10 @@
|
|||||||
|
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
itemBinding="@{viewModel.itemBinding}"
|
itemBinding="@{viewModel.itemBinding}"
|
||||||
items="@{viewModel.items}"
|
items="@{viewModel.items}"
|
||||||
@ -24,6 +28,39 @@
|
|||||||
android:paddingBottom="@{viewModel.insets.bottom}"
|
android:paddingBottom="@{viewModel.insets.bottom}"
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
tools:listitem="@layout/item_log_access_md2"
|
tools:listitem="@layout/item_log_access_md2"
|
||||||
tools:paddingTop="40dp" />
|
tools:paddingTop="24dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/log_filter_toggle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:layout_marginStart="@dimen/l1"
|
||||||
|
android:layout_marginEnd="@dimen/l1"
|
||||||
|
android:layout_marginBottom="@{viewModel.insets.bottom + (int) @dimen/l1}"
|
||||||
|
app:backgroundTint="?colorSurfaceSurfaceVariant"
|
||||||
|
app:srcCompat="@drawable/ic_folder_list"
|
||||||
|
app:tint="?colorPrimary"
|
||||||
|
tools:layout_marginBottom="64dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.circularreveal.cardview.CircularRevealCardView
|
||||||
|
android:id="@+id/log_filter"
|
||||||
|
style="?styleCardVariant"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:visibility="invisible"
|
||||||
|
app:cardCornerRadius="0dp">
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/log_filter_include"
|
||||||
|
layout="@layout/include_log_magisk"
|
||||||
|
viewModel="@{viewModel}"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
</com.google.android.material.circularreveal.cardview.CircularRevealCardView>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
</layout>
|
</layout>
|
34
app/src/main/res/layout/include_log_magisk.xml
Normal file
34
app/src/main/res/layout/include_log_magisk.xml
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="viewModel"
|
||||||
|
type="com.topjohnwu.magisk.redesign.log.LogViewModel" />
|
||||||
|
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<HorizontalScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
adapter="@{viewModel.consoleAdapter}"
|
||||||
|
itemBinding="@{viewModel.itemConsoleBinding}"
|
||||||
|
items="@{viewModel.itemsConsole}"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size}"
|
||||||
|
android:paddingBottom="@{viewModel.insets.bottom}"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
tools:listitem="@layout/item_console"
|
||||||
|
tools:paddingTop="24dp" />
|
||||||
|
|
||||||
|
</HorizontalScrollView>
|
||||||
|
|
||||||
|
</layout>
|
17
app/src/main/res/menu/menu_log_md2.xml
Normal file
17
app/src/main/res/menu/menu_log_md2.xml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?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_save"
|
||||||
|
android:icon="@drawable/ic_save_md2"
|
||||||
|
android:title="@string/menuSaveLog"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_clear"
|
||||||
|
android:icon="@drawable/ic_delete_md2"
|
||||||
|
android:title="@string/menuClearLog"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
|
</menu>
|
Loading…
Reference in New Issue
Block a user