mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-22 07:57:39 +00:00
Improve flash console screen
This commit is contained in:
parent
40f971d18a
commit
8453282fa6
@ -1,6 +1,5 @@
|
|||||||
package com.topjohnwu.magisk.di
|
package com.topjohnwu.magisk.di
|
||||||
|
|
||||||
import android.net.Uri
|
|
||||||
import com.topjohnwu.magisk.legacy.flash.FlashViewModel
|
import com.topjohnwu.magisk.legacy.flash.FlashViewModel
|
||||||
import com.topjohnwu.magisk.legacy.surequest.SuRequestViewModel
|
import com.topjohnwu.magisk.legacy.surequest.SuRequestViewModel
|
||||||
import com.topjohnwu.magisk.ui.MainViewModel
|
import com.topjohnwu.magisk.ui.MainViewModel
|
||||||
@ -31,8 +30,6 @@ val viewModelModules = module {
|
|||||||
viewModel { MainViewModel() }
|
viewModel { MainViewModel() }
|
||||||
|
|
||||||
// Legacy
|
// Legacy
|
||||||
viewModel { (action: String, file: Uri, additional: Uri) ->
|
viewModel { FlashViewModel(get()) }
|
||||||
FlashViewModel(action, file, additional, get())
|
|
||||||
}
|
|
||||||
viewModel { SuRequestViewModel(get(), get(), get(SUTimeout), get()) }
|
viewModel { SuRequestViewModel(get(), get(), get(SUTimeout), get()) }
|
||||||
}
|
}
|
||||||
|
@ -18,18 +18,12 @@ import com.topjohnwu.magisk.model.events.ViewEvent
|
|||||||
import com.topjohnwu.magisk.ui.base.BaseUIActivity
|
import com.topjohnwu.magisk.ui.base.BaseUIActivity
|
||||||
import com.topjohnwu.magisk.ui.base.CompatNavigationDelegate
|
import com.topjohnwu.magisk.ui.base.CompatNavigationDelegate
|
||||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
import org.koin.core.parameter.parametersOf
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
open class FlashActivity : BaseUIActivity<FlashViewModel, ActivityFlashBinding>() {
|
open class FlashActivity : BaseUIActivity<FlashViewModel, ActivityFlashBinding>() {
|
||||||
|
|
||||||
override val layoutRes: Int = R.layout.activity_flash
|
override val layoutRes: Int = R.layout.activity_flash
|
||||||
override val viewModel: FlashViewModel by viewModel {
|
override val viewModel: FlashViewModel by viewModel()
|
||||||
val uri = intent.data ?: let { finish(); Uri.EMPTY }
|
|
||||||
val additionalUri = intent.getParcelableExtra(Const.Key.FLASH_DATA) ?: uri
|
|
||||||
val action = intent.getStringExtra(Const.Key.FLASH_ACTION) ?: let { finish();"" }
|
|
||||||
parametersOf(action, uri, additionalUri)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val navigation: CompatNavigationDelegate<BaseUIActivity<FlashViewModel, ActivityFlashBinding>>? =
|
override val navigation: CompatNavigationDelegate<BaseUIActivity<FlashViewModel, ActivityFlashBinding>>? =
|
||||||
null
|
null
|
||||||
@ -40,6 +34,7 @@ open class FlashActivity : BaseUIActivity<FlashViewModel, ActivityFlashBinding>(
|
|||||||
val id = intent.getIntExtra(Const.Key.DISMISS_ID, -1)
|
val id = intent.getIntExtra(Const.Key.DISMISS_ID, -1)
|
||||||
if (id != -1)
|
if (id != -1)
|
||||||
Notifications.mgr.cancel(id)
|
Notifications.mgr.cancel(id)
|
||||||
|
viewModel.startFlashing(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBackPressed() {
|
override fun onBackPressed() {
|
||||||
|
@ -2,35 +2,32 @@ package com.topjohnwu.magisk.legacy.flash
|
|||||||
|
|
||||||
import android.Manifest.permission.READ_EXTERNAL_STORAGE
|
import android.Manifest.permission.READ_EXTERNAL_STORAGE
|
||||||
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||||
|
import android.content.Intent
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import androidx.core.os.postDelayed
|
import androidx.core.os.postDelayed
|
||||||
import androidx.databinding.ObservableArrayList
|
import androidx.databinding.ObservableArrayList
|
||||||
import com.topjohnwu.magisk.BR
|
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.core.Config
|
import com.topjohnwu.magisk.core.Config
|
||||||
import com.topjohnwu.magisk.core.Const
|
import com.topjohnwu.magisk.core.Const
|
||||||
import com.topjohnwu.magisk.databinding.ComparableRvItem
|
|
||||||
import com.topjohnwu.magisk.extensions.*
|
import com.topjohnwu.magisk.extensions.*
|
||||||
|
import com.topjohnwu.magisk.model.binding.BindingAdapter
|
||||||
import com.topjohnwu.magisk.model.entity.recycler.ConsoleItem
|
import com.topjohnwu.magisk.model.entity.recycler.ConsoleItem
|
||||||
import com.topjohnwu.magisk.model.events.SnackbarEvent
|
import com.topjohnwu.magisk.model.events.SnackbarEvent
|
||||||
import com.topjohnwu.magisk.model.flash.FlashResultListener
|
import com.topjohnwu.magisk.model.flash.FlashResultListener
|
||||||
import com.topjohnwu.magisk.model.flash.Flashing
|
import com.topjohnwu.magisk.model.flash.Flashing
|
||||||
import com.topjohnwu.magisk.model.flash.Patching
|
import com.topjohnwu.magisk.model.flash.Patching
|
||||||
import com.topjohnwu.magisk.ui.base.BaseViewModel
|
import com.topjohnwu.magisk.ui.base.BaseViewModel
|
||||||
import com.topjohnwu.magisk.utils.DiffObservableList
|
import com.topjohnwu.magisk.ui.base.diffListOf
|
||||||
|
import com.topjohnwu.magisk.ui.base.itemBindingOf
|
||||||
import com.topjohnwu.magisk.utils.KObservableField
|
import com.topjohnwu.magisk.utils.KObservableField
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
import me.tatarka.bindingcollectionadapter2.ItemBinding
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class FlashViewModel(
|
class FlashViewModel(
|
||||||
action: String,
|
|
||||||
installer: Uri,
|
|
||||||
uri: Uri,
|
|
||||||
private val resources: Resources
|
private val resources: Resources
|
||||||
) : BaseViewModel(), FlashResultListener {
|
) : BaseViewModel(), FlashResultListener {
|
||||||
|
|
||||||
@ -39,11 +36,9 @@ class FlashViewModel(
|
|||||||
|
|
||||||
val behaviorText = KObservableField(resources.getString(R.string.flashing))
|
val behaviorText = KObservableField(resources.getString(R.string.flashing))
|
||||||
|
|
||||||
val items = DiffObservableList(ComparableRvItem.callback)
|
val adapter = BindingAdapter<ConsoleItem>()
|
||||||
val itemBinding = ItemBinding.of<ComparableRvItem<*>> { itemBinding, _, item ->
|
val items = diffListOf<ConsoleItem>()
|
||||||
item.bind(itemBinding)
|
val itemBinding = itemBindingOf<ConsoleItem>()
|
||||||
itemBinding.bindExtra(BR.viewModel, this@FlashViewModel)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val outItems = ObservableArrayList<String>()
|
private val outItems = ObservableArrayList<String>()
|
||||||
private val logItems = Collections.synchronizedList(mutableListOf<String>())
|
private val logItems = Collections.synchronizedList(mutableListOf<String>())
|
||||||
@ -51,8 +46,12 @@ class FlashViewModel(
|
|||||||
init {
|
init {
|
||||||
outItems.sendUpdatesTo(items) { it.map { ConsoleItem(it) } }
|
outItems.sendUpdatesTo(items) { it.map { ConsoleItem(it) } }
|
||||||
outItems.copyNewInputInto(logItems)
|
outItems.copyNewInputInto(logItems)
|
||||||
|
}
|
||||||
|
|
||||||
state = State.LOADING
|
fun startFlashing(intent: Intent) {
|
||||||
|
val installer = intent.data ?: return
|
||||||
|
val uri: Uri? = intent.getParcelableExtra(Const.Key.FLASH_DATA)
|
||||||
|
val action = intent.getStringExtra(Const.Key.FLASH_ACTION) ?: return
|
||||||
|
|
||||||
when (action) {
|
when (action) {
|
||||||
Const.Value.FLASH_ZIP -> Flashing
|
Const.Value.FLASH_ZIP -> Flashing
|
||||||
@ -68,7 +67,7 @@ class FlashViewModel(
|
|||||||
.SecondSlot(installer, outItems, logItems, this)
|
.SecondSlot(installer, outItems, logItems, this)
|
||||||
.exec()
|
.exec()
|
||||||
Const.Value.PATCH_FILE -> Patching
|
Const.Value.PATCH_FILE -> Patching
|
||||||
.File(installer, uri, outItems, logItems, this)
|
.File(installer, uri ?: return, outItems, logItems, this)
|
||||||
.exec()
|
.exec()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import com.topjohnwu.magisk.databinding.ComparableRvItem
|
|||||||
import com.topjohnwu.magisk.model.entity.recycler.LenientRvItem
|
import com.topjohnwu.magisk.model.entity.recycler.LenientRvItem
|
||||||
import me.tatarka.bindingcollectionadapter2.BindingRecyclerViewAdapter
|
import me.tatarka.bindingcollectionadapter2.BindingRecyclerViewAdapter
|
||||||
|
|
||||||
class BindingAdapter : BindingRecyclerViewAdapter<ComparableRvItem<*>>() {
|
class BindingAdapter <T : ComparableRvItem<*>> : BindingRecyclerViewAdapter<T>() {
|
||||||
|
|
||||||
private var recyclerView: RecyclerView? = null
|
private var recyclerView: RecyclerView? = null
|
||||||
|
|
||||||
@ -15,12 +15,12 @@ class BindingAdapter : BindingRecyclerViewAdapter<ComparableRvItem<*>>() {
|
|||||||
variableId: Int,
|
variableId: Int,
|
||||||
layoutRes: Int,
|
layoutRes: Int,
|
||||||
position: Int,
|
position: Int,
|
||||||
item: ComparableRvItem<*>
|
item: T
|
||||||
) {
|
) {
|
||||||
super.onBindBinding(binding, variableId, layoutRes, position, item)
|
super.onBindBinding(binding, variableId, layoutRes, position, item)
|
||||||
|
|
||||||
when (item) {
|
when (item) {
|
||||||
is LenientRvItem -> {
|
is LenientRvItem<*> -> {
|
||||||
val recycler = recyclerView ?: return
|
val recycler = recyclerView ?: return
|
||||||
item.onBindingBound(binding)
|
item.onBindingBound(binding)
|
||||||
item.onBindingBound(binding, recycler)
|
item.onBindingBound(binding, recycler)
|
||||||
@ -34,4 +34,4 @@ class BindingAdapter : BindingRecyclerViewAdapter<ComparableRvItem<*>>() {
|
|||||||
this.recyclerView = recyclerView
|
this.recyclerView = recyclerView
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,27 @@
|
|||||||
package com.topjohnwu.magisk.model.entity.recycler
|
package com.topjohnwu.magisk.model.entity.recycler
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.core.view.updateLayoutParams
|
import androidx.core.view.updateLayoutParams
|
||||||
import androidx.databinding.ViewDataBinding
|
import androidx.databinding.ViewDataBinding
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
class ConsoleItem(val item: String) : LenientRvItem<ConsoleItem>() {
|
class ConsoleItem(val item: String) : LenientRvItem<ConsoleItem>() {
|
||||||
override val layoutRes = R.layout.item_console_md2
|
override val layoutRes = R.layout.item_console_md2
|
||||||
|
|
||||||
|
private var parentWidth = -1
|
||||||
|
|
||||||
override fun onBindingBound(binding: ViewDataBinding, recyclerView: RecyclerView) {
|
override fun onBindingBound(binding: ViewDataBinding, recyclerView: RecyclerView) {
|
||||||
|
if (parentWidth < 0)
|
||||||
|
parentWidth = (recyclerView.parent as View).width
|
||||||
|
|
||||||
val view = binding.root as TextView
|
val view = binding.root as TextView
|
||||||
view.measure(0, 0)
|
view.measure(0, 0)
|
||||||
val desiredWidth = view.measuredWidth
|
|
||||||
|
// We want our recyclerView at least as wide as screen
|
||||||
|
val desiredWidth = max(view.measuredWidth, parentWidth)
|
||||||
|
|
||||||
view.updateLayoutParams { width = desiredWidth }
|
view.updateLayoutParams { width = desiredWidth }
|
||||||
|
|
||||||
@ -23,4 +32,4 @@ class ConsoleItem(val item: String) : LenientRvItem<ConsoleItem>() {
|
|||||||
|
|
||||||
override fun contentSameAs(other: ConsoleItem) = itemSameAs(other)
|
override fun contentSameAs(other: ConsoleItem) = itemSameAs(other)
|
||||||
override fun itemSameAs(other: ConsoleItem) = item == other.item
|
override fun itemSameAs(other: ConsoleItem) = item == other.item
|
||||||
}
|
}
|
@ -5,7 +5,6 @@ import com.topjohnwu.magisk.R
|
|||||||
import com.topjohnwu.magisk.core.Config
|
import com.topjohnwu.magisk.core.Config
|
||||||
import com.topjohnwu.magisk.core.Const
|
import com.topjohnwu.magisk.core.Const
|
||||||
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.binding.BindingAdapter
|
||||||
import com.topjohnwu.magisk.model.entity.recycler.ConsoleItem
|
import com.topjohnwu.magisk.model.entity.recycler.ConsoleItem
|
||||||
@ -42,9 +41,9 @@ class LogViewModel(
|
|||||||
|
|
||||||
// --- console
|
// --- console
|
||||||
|
|
||||||
val consoleAdapter = BindingAdapter()
|
val consoleAdapter = BindingAdapter<ConsoleItem>()
|
||||||
val itemsConsole = diffListOf<ComparableRvItem<*>>()
|
val itemsConsole = diffListOf<ConsoleItem>()
|
||||||
val itemConsoleBinding = itemBindingOf<ComparableRvItem<*>> {}
|
val itemConsoleBinding = itemBindingOf<ConsoleItem>()
|
||||||
|
|
||||||
override fun refresh(): Disposable {
|
override fun refresh(): Disposable {
|
||||||
val logs = repo.fetchLogs()
|
val logs = repo.fetchLogs()
|
||||||
|
@ -23,6 +23,7 @@ import com.google.android.material.textfield.TextInputLayout
|
|||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.extensions.replaceRandomWithSpecial
|
import com.topjohnwu.magisk.extensions.replaceRandomWithSpecial
|
||||||
import com.topjohnwu.magisk.extensions.subscribeK
|
import com.topjohnwu.magisk.extensions.subscribeK
|
||||||
|
import com.topjohnwu.superuser.internal.UiThreadHandler
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
import io.reactivex.disposables.Disposable
|
import io.reactivex.disposables.Disposable
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
@ -62,12 +63,12 @@ fun setOnTouchListener(view: View, listener: View.OnTouchListener) {
|
|||||||
@BindingAdapter("scrollToLast")
|
@BindingAdapter("scrollToLast")
|
||||||
fun setScrollToLast(view: RecyclerView, shouldScrollToLast: Boolean) {
|
fun setScrollToLast(view: RecyclerView, shouldScrollToLast: Boolean) {
|
||||||
|
|
||||||
fun scrollToLast() = view.post {
|
fun scrollToLast() = UiThreadHandler.handler.postDelayed({
|
||||||
view.scrollToPosition(view.adapter?.itemCount?.minus(1) ?: 0)
|
view.scrollToPosition(view.adapter?.itemCount?.minus(1) ?: 0)
|
||||||
}
|
}, 30)
|
||||||
|
|
||||||
fun wait(callback: () -> Unit) {
|
fun wait(callback: () -> Unit) {
|
||||||
Observable.timer(1, TimeUnit.SECONDS).subscribeK { callback() }
|
UiThreadHandler.handler.postDelayed(callback, 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun RecyclerView.Adapter<*>.setListener() {
|
fun RecyclerView.Adapter<*>.setListener() {
|
||||||
@ -241,4 +242,4 @@ fun RecyclerView.setSpanCount(count: Int) {
|
|||||||
is GridLayoutManager -> lama.spanCount = count
|
is GridLayoutManager -> lama.spanCount = count
|
||||||
is StaggeredGridLayoutManager -> lama.spanCount = count
|
is StaggeredGridLayoutManager -> lama.spanCount = count
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,21 +56,30 @@
|
|||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<HorizontalScrollView
|
||||||
android:id="@+id/flash_content"
|
|
||||||
itemBinding="@{viewModel.itemBinding}"
|
|
||||||
items="@{viewModel.items}"
|
|
||||||
scrollToLast="@{true}"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:clipToPadding="false"
|
android:layout_marginTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size}"
|
||||||
android:orientation="vertical"
|
tools:layout_marginTop="@dimen/internal_action_bar_size">
|
||||||
android:paddingLeft="@{viewModel.insets.left}"
|
|
||||||
android:paddingRight="@{viewModel.insets.right}"
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:paddingBottom="@{viewModel.insets.bottom}"
|
android:id="@+id/flash_content"
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
adapter="@{viewModel.adapter}"
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
itemBinding="@{viewModel.itemBinding}"
|
||||||
tools:listitem="@layout/item_console_md2" />
|
items="@{viewModel.items}"
|
||||||
|
scrollToLast="@{true}"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingLeft="@{viewModel.insets.left}"
|
||||||
|
android:paddingRight="@{viewModel.insets.right}"
|
||||||
|
android:paddingBottom="@{viewModel.insets.bottom}"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
|
tools:listitem="@layout/item_console_md2" />
|
||||||
|
|
||||||
|
</HorizontalScrollView>
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||||
gone="@{!viewModel.loaded || !viewModel.canShowReboot}"
|
gone="@{!viewModel.loaded || !viewModel.canShowReboot}"
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size}"
|
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size}"
|
||||||
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_console"
|
tools:listitem="@layout/item_console_md2"
|
||||||
tools:paddingTop="24dp" />
|
tools:paddingTop="24dp" />
|
||||||
|
|
||||||
</HorizontalScrollView>
|
</HorizontalScrollView>
|
||||||
|
@ -8,11 +8,6 @@
|
|||||||
name="item"
|
name="item"
|
||||||
type="com.topjohnwu.magisk.model.entity.recycler.ConsoleItem" />
|
type="com.topjohnwu.magisk.model.entity.recycler.ConsoleItem" />
|
||||||
|
|
||||||
<!--no actions are required-->
|
|
||||||
<variable
|
|
||||||
name="viewModel"
|
|
||||||
type="Object" />
|
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -16,7 +16,7 @@ buildscript {
|
|||||||
maven { url 'https://kotlin.bintray.com/kotlinx' }
|
maven { url 'https://kotlin.bintray.com/kotlinx' }
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.6.0-rc02'
|
classpath 'com.android.tools.build:gradle:3.6.0-rc03'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${vKotlin}"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${vKotlin}"
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user