Improve flash console screen

This commit is contained in:
topjohnwu 2020-02-16 19:04:26 -08:00
parent 40f971d18a
commit 8453282fa6
11 changed files with 63 additions and 59 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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}"

View File

@ -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>

View File

@ -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

View File

@ -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}"