Remove unnecessary abstractions
This commit is contained in:
parent
b2bece9ef6
commit
a86d5b3e61
@ -66,7 +66,7 @@ abstract class BaseActivity : AppCompatActivity() {
|
||||
}
|
||||
resultCallbacks[requestCode]?.also {
|
||||
resultCallbacks.remove(requestCode)
|
||||
it(this@BaseActivity, if (success) 1 else -1, null)
|
||||
it(this, if (success) 1 else -1, null)
|
||||
}
|
||||
|
||||
}
|
||||
@ -75,7 +75,7 @@ abstract class BaseActivity : AppCompatActivity() {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
resultCallbacks[requestCode]?.also {
|
||||
resultCallbacks.remove(requestCode)
|
||||
it(this@BaseActivity, resultCode, data)
|
||||
it(this, resultCode, data)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,23 +0,0 @@
|
||||
package com.topjohnwu.magisk.model.events
|
||||
|
||||
import android.content.Context
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
|
||||
interface ContextExecutor {
|
||||
|
||||
operator fun invoke(context: Context)
|
||||
|
||||
}
|
||||
|
||||
interface ActivityExecutor {
|
||||
|
||||
operator fun invoke(activity: BaseActivity)
|
||||
|
||||
}
|
||||
|
||||
interface FragmentExecutor {
|
||||
|
||||
operator fun invoke(fragment: Fragment)
|
||||
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package com.topjohnwu.magisk.model.events
|
||||
|
||||
internal interface EventHandler {
|
||||
|
||||
/**
|
||||
* Called for all [ViewEvent]s published by associated viewModel.
|
||||
* For [SimpleViewEvent]s, both this and [onSimpleEventDispatched]
|
||||
* methods are called - you can choose the way how you handle them.
|
||||
*/
|
||||
fun onEventDispatched(event: ViewEvent) {}
|
||||
|
||||
/**
|
||||
* Called for all [SimpleViewEvent]s published by associated viewModel.
|
||||
* Both this and [onEventDispatched] methods are called - you can choose
|
||||
* the way how you handle them.
|
||||
*/
|
||||
fun onSimpleEventDispatched(event: Int) {}
|
||||
|
||||
val viewEventObserver get() = ViewEventObserver {
|
||||
onEventDispatched(it)
|
||||
if (it is SimpleViewEvent) {
|
||||
onSimpleEventDispatched(it.event)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package com.topjohnwu.magisk.model.events
|
||||
|
||||
class SimpleViewEvent(
|
||||
val event: Int
|
||||
) : ViewEvent()
|
@ -3,6 +3,7 @@ package com.topjohnwu.magisk.model.events
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
@ -32,7 +33,6 @@ import java.lang.reflect.InvocationHandler
|
||||
* Use [ViewEventObserver] for observing these events
|
||||
*/
|
||||
abstract class ViewEvent {
|
||||
|
||||
var handled = false
|
||||
}
|
||||
|
||||
@ -40,6 +40,18 @@ abstract class ViewEventsWithScope: ViewEvent() {
|
||||
lateinit var scope: CoroutineScope
|
||||
}
|
||||
|
||||
interface ContextExecutor {
|
||||
operator fun invoke(context: Context)
|
||||
}
|
||||
|
||||
interface ActivityExecutor {
|
||||
operator fun invoke(activity: BaseActivity)
|
||||
}
|
||||
|
||||
interface FragmentExecutor {
|
||||
operator fun invoke(fragment: Fragment)
|
||||
}
|
||||
|
||||
class CheckSafetyNetEvent(
|
||||
private val callback: (SafetyNetResult) -> Unit = {}
|
||||
) : ViewEventsWithScope(), ContextExecutor, KoinComponent, SafetyNetHelper.Callback {
|
||||
@ -146,7 +158,7 @@ class CheckSafetyNetEvent(
|
||||
}
|
||||
|
||||
class ViewActionEvent(val action: BaseActivity.() -> Unit) : ViewEvent(), ActivityExecutor {
|
||||
override fun invoke(activity: BaseActivity) = activity.run(action)
|
||||
override fun invoke(activity: BaseActivity) = action(activity)
|
||||
}
|
||||
|
||||
class OpenChangelogEvent(val item: Repo) : ViewEventsWithScope(), ContextExecutor {
|
||||
|
@ -7,26 +7,23 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.content.res.use
|
||||
import androidx.core.graphics.Insets
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.databinding.OnRebindCallback
|
||||
import androidx.databinding.ViewDataBinding
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.navigation.NavDirections
|
||||
import androidx.navigation.findNavController
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.ktx.snackbar
|
||||
import com.topjohnwu.magisk.ktx.startAnimations
|
||||
import com.topjohnwu.magisk.model.events.EventHandler
|
||||
import com.topjohnwu.magisk.model.events.SnackbarEvent
|
||||
import com.topjohnwu.magisk.model.events.ActivityExecutor
|
||||
import com.topjohnwu.magisk.model.events.ContextExecutor
|
||||
import com.topjohnwu.magisk.model.events.ViewEvent
|
||||
import com.topjohnwu.magisk.ui.theme.Theme
|
||||
|
||||
abstract class BaseUIActivity<ViewModel : BaseViewModel, Binding : ViewDataBinding> :
|
||||
BaseActivity(), CompatView<ViewModel>, EventHandler {
|
||||
abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> :
|
||||
BaseActivity(), BaseUIComponent<VM> {
|
||||
|
||||
protected lateinit var binding: Binding
|
||||
protected abstract val layoutRes: Int
|
||||
@ -37,12 +34,10 @@ abstract class BaseUIActivity<ViewModel : BaseViewModel, Binding : ViewDataBindi
|
||||
protected val currentFragment get() = topFragment as? BaseUIFragment<*, *>
|
||||
|
||||
override val viewRoot: View get() = binding.root
|
||||
override val navigation by lazy {
|
||||
kotlin.runCatching { findNavController(navHost) }.getOrNull()
|
||||
open val navigation by lazy {
|
||||
runCatching { findNavController(navHost) }.getOrNull()
|
||||
}
|
||||
|
||||
private val delegate by lazy { CompatDelegate(this) }
|
||||
|
||||
open val navHost: Int = 0
|
||||
open val snackbarView get() = binding.root
|
||||
|
||||
@ -66,35 +61,33 @@ abstract class BaseUIActivity<ViewModel : BaseViewModel, Binding : ViewDataBindi
|
||||
.also { window.setBackgroundDrawable(it) }
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
startObserveEvents()
|
||||
|
||||
viewModel.viewEvents.observe(this, viewEventObserver)
|
||||
|
||||
binding = DataBindingUtil.setContentView<Binding>(this, layoutRes).apply {
|
||||
setVariable(BR.viewModel, viewModel)
|
||||
lifecycleOwner = this@BaseUIActivity
|
||||
}
|
||||
|
||||
binding.addOnRebindCallback(object : OnRebindCallback<Binding>() {
|
||||
binding = DataBindingUtil.setContentView<Binding>(this, layoutRes).also {
|
||||
it.setVariable(BR.viewModel, viewModel)
|
||||
it.lifecycleOwner = this
|
||||
it.addOnRebindCallback(object : OnRebindCallback<Binding>() {
|
||||
override fun onPreBind(binding: Binding): Boolean {
|
||||
(binding.root as? ViewGroup)?.startAnimations()
|
||||
return super.onPreBind(binding)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
delegate.onCreate()
|
||||
ensureInsets()
|
||||
|
||||
directionsDispatcher.observe(this, Observer {
|
||||
directionsDispatcher.observe(this) {
|
||||
it?.navigate()
|
||||
// we don't want the directions to be re-dispatched, so we preemptively set them to null
|
||||
if (it != null) {
|
||||
directionsDispatcher.value = null
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
delegate.onResume()
|
||||
viewModel.requestRefresh()
|
||||
}
|
||||
|
||||
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
||||
@ -102,10 +95,8 @@ abstract class BaseUIActivity<ViewModel : BaseViewModel, Binding : ViewDataBindi
|
||||
}
|
||||
|
||||
override fun onEventDispatched(event: ViewEvent) {
|
||||
delegate.onEventExecute(event, this)
|
||||
when (event) {
|
||||
is SnackbarEvent -> snackbar(snackbarView, event.message(this), event.length, event.f)
|
||||
}
|
||||
(event as? ContextExecutor)?.invoke(this)
|
||||
(event as? ActivityExecutor)?.invoke(this)
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
@ -114,12 +105,6 @@ abstract class BaseUIActivity<ViewModel : BaseViewModel, Binding : ViewDataBindi
|
||||
}
|
||||
}
|
||||
|
||||
override fun peekSystemWindowInsets(insets: Insets) {
|
||||
viewModel.insets = insets
|
||||
}
|
||||
|
||||
protected fun ViewEvent.dispatchOnSelf() = onEventDispatched(this)
|
||||
|
||||
fun NavDirections.navigate() {
|
||||
navigation?.navigate(this)
|
||||
}
|
||||
|
@ -0,0 +1,64 @@
|
||||
package com.topjohnwu.magisk.ui.base
|
||||
|
||||
import android.view.View
|
||||
import androidx.core.graphics.Insets
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import com.topjohnwu.magisk.model.events.ViewEvent
|
||||
|
||||
interface BaseUIComponent<VM : BaseViewModel>: LifecycleOwner {
|
||||
|
||||
val viewRoot: View
|
||||
val viewModel: VM
|
||||
|
||||
fun startObserveEvents() {
|
||||
viewModel.viewEvents.observe(this) {
|
||||
onEventDispatched(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun consumeSystemWindowInsets(insets: Insets): Insets? = null
|
||||
|
||||
/**
|
||||
* Called for all [ViewEvent]s published by associated viewModel.
|
||||
*/
|
||||
fun onEventDispatched(event: ViewEvent) {}
|
||||
|
||||
fun ensureInsets() {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(viewRoot) { _, insets ->
|
||||
insets.asInsets()
|
||||
.also { viewModel.insets = it }
|
||||
.let { consumeSystemWindowInsets(it) }
|
||||
?.subtractBy(insets) ?: insets
|
||||
}
|
||||
if (ViewCompat.isAttachedToWindow(viewRoot)) {
|
||||
ViewCompat.requestApplyInsets(viewRoot)
|
||||
} else {
|
||||
viewRoot.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
|
||||
override fun onViewDetachedFromWindow(v: View) = Unit
|
||||
override fun onViewAttachedToWindow(v: View) {
|
||||
ViewCompat.requestApplyInsets(v)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun WindowInsetsCompat.asInsets() = Insets.of(
|
||||
systemWindowInsetLeft,
|
||||
systemWindowInsetTop,
|
||||
systemWindowInsetRight,
|
||||
systemWindowInsetBottom
|
||||
)
|
||||
|
||||
private fun Insets.subtractBy(insets: WindowInsetsCompat) =
|
||||
WindowInsetsCompat.Builder(insets).setSystemWindowInsets(
|
||||
Insets.of(
|
||||
insets.systemWindowInsetLeft - left,
|
||||
insets.systemWindowInsetTop - top,
|
||||
insets.systemWindowInsetRight - right,
|
||||
insets.systemWindowInsetBottom - bottom
|
||||
)
|
||||
).build()
|
||||
|
||||
}
|
@ -13,25 +13,26 @@ import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.NavDirections
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.ktx.startAnimations
|
||||
import com.topjohnwu.magisk.model.events.EventHandler
|
||||
import com.topjohnwu.magisk.model.events.ActivityExecutor
|
||||
import com.topjohnwu.magisk.model.events.ContextExecutor
|
||||
import com.topjohnwu.magisk.model.events.FragmentExecutor
|
||||
import com.topjohnwu.magisk.model.events.ViewEvent
|
||||
|
||||
abstract class BaseUIFragment<ViewModel : BaseViewModel, Binding : ViewDataBinding> :
|
||||
Fragment(), CompatView<ViewModel>, EventHandler {
|
||||
abstract class BaseUIFragment<VM : BaseViewModel, Binding : ViewDataBinding> :
|
||||
Fragment(), BaseUIComponent<VM> {
|
||||
|
||||
protected val activity get() = requireActivity() as BaseUIActivity<*, *>
|
||||
protected lateinit var binding: Binding
|
||||
protected abstract val layoutRes: Int
|
||||
|
||||
override val viewRoot: View get() = binding.root
|
||||
override val navigation get() = activity.navigation
|
||||
private val delegate by lazy { CompatDelegate(this) }
|
||||
private val navigation get() = activity.navigation
|
||||
|
||||
override fun consumeSystemWindowInsets(insets: Insets) = insets
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
viewModel.viewEvents.observe(this, viewEventObserver)
|
||||
startObserveEvents()
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
@ -39,17 +40,17 @@ abstract class BaseUIFragment<ViewModel : BaseViewModel, Binding : ViewDataBindi
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
binding = DataBindingUtil.inflate<Binding>(inflater, layoutRes, container, false).apply {
|
||||
setVariable(BR.viewModel, viewModel)
|
||||
lifecycleOwner = this@BaseUIFragment
|
||||
binding = DataBindingUtil.inflate<Binding>(inflater, layoutRes, container, false).also {
|
||||
it.setVariable(BR.viewModel, viewModel)
|
||||
it.lifecycleOwner = this
|
||||
}
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onEventDispatched(event: ViewEvent) {
|
||||
super.onEventDispatched(event)
|
||||
delegate.onEventExecute(event, this)
|
||||
(event as? ContextExecutor)?.invoke(requireContext())
|
||||
(event as? FragmentExecutor)?.invoke(this)
|
||||
(event as? ActivityExecutor)?.invoke(activity)
|
||||
}
|
||||
|
||||
open fun onKeyEvent(event: KeyEvent): Boolean {
|
||||
@ -61,29 +62,24 @@ abstract class BaseUIFragment<ViewModel : BaseViewModel, Binding : ViewDataBindi
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
binding.addOnRebindCallback(object : OnRebindCallback<Binding>() {
|
||||
override fun onPreBind(binding: Binding): Boolean {
|
||||
this@BaseUIFragment.onPreBind(binding)
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
delegate.onCreate()
|
||||
ensureInsets()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
delegate.onResume()
|
||||
viewModel.requestRefresh()
|
||||
}
|
||||
|
||||
protected open fun onPreBind(binding: Binding) {
|
||||
(binding.root as? ViewGroup)?.startAnimations()
|
||||
}
|
||||
|
||||
protected fun ViewEvent.dispatchOnSelf() = delegate.onEventExecute(this, this@BaseUIFragment)
|
||||
|
||||
fun NavDirections.navigate() {
|
||||
navigation?.navigate(this)
|
||||
}
|
||||
|
@ -107,10 +107,6 @@ abstract class BaseViewModel(
|
||||
_viewEvents.postValue(this)
|
||||
}
|
||||
|
||||
fun Int.publish() {
|
||||
_viewEvents.postValue(SimpleViewEvent(this))
|
||||
}
|
||||
|
||||
fun NavDirections.publish() {
|
||||
_viewEvents.postValue(NavigationWrapper(this))
|
||||
}
|
||||
|
@ -1,75 +0,0 @@
|
||||
package com.topjohnwu.magisk.ui.base
|
||||
|
||||
import android.view.View
|
||||
import androidx.core.graphics.Insets
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.topjohnwu.magisk.model.events.ActivityExecutor
|
||||
import com.topjohnwu.magisk.model.events.ContextExecutor
|
||||
import com.topjohnwu.magisk.model.events.FragmentExecutor
|
||||
import com.topjohnwu.magisk.model.events.ViewEvent
|
||||
import timber.log.Timber
|
||||
|
||||
|
||||
class CompatDelegate internal constructor(
|
||||
private val view: CompatView<*>
|
||||
) {
|
||||
|
||||
fun onCreate() {
|
||||
ensureInsets()
|
||||
}
|
||||
|
||||
fun onResume() {
|
||||
view.viewModel.requestRefresh()
|
||||
}
|
||||
|
||||
fun onEventExecute(event: ViewEvent, activity: BaseUIActivity<*, *>) {
|
||||
(event as? ContextExecutor)?.invoke(activity)
|
||||
(event as? ActivityExecutor)?.invoke(activity)
|
||||
(event as? FragmentExecutor)?.let {
|
||||
Timber.e("Cannot run ${FragmentExecutor::class.java.simpleName} in Activity. Consider adding ${ContextExecutor::class.java.simpleName} as fallback.")
|
||||
}
|
||||
}
|
||||
|
||||
fun onEventExecute(event: ViewEvent, fragment: Fragment) {
|
||||
(event as? ContextExecutor)?.invoke(fragment.requireContext())
|
||||
(event as? FragmentExecutor)?.invoke(fragment)
|
||||
(event as? ActivityExecutor)?.invoke(fragment.requireActivity() as BaseUIActivity<*, *>)
|
||||
}
|
||||
|
||||
private fun ensureInsets() {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(view.viewRoot) { _, insets ->
|
||||
insets.asInsets()
|
||||
.also { view.peekSystemWindowInsets(it) }
|
||||
.let { view.consumeSystemWindowInsets(it) }
|
||||
?.also { view.viewModel.insets = it }
|
||||
?.subtractBy(insets) ?: insets
|
||||
}
|
||||
if (ViewCompat.isAttachedToWindow(view.viewRoot)) {
|
||||
ViewCompat.requestApplyInsets(view.viewRoot)
|
||||
} else {
|
||||
view.viewRoot.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
|
||||
override fun onViewDetachedFromWindow(v: View) = Unit
|
||||
override fun onViewAttachedToWindow(v: View) {
|
||||
ViewCompat.requestApplyInsets(v)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun WindowInsetsCompat.asInsets() = Insets.of(
|
||||
systemWindowInsetLeft,
|
||||
systemWindowInsetTop,
|
||||
systemWindowInsetRight,
|
||||
systemWindowInsetBottom
|
||||
)
|
||||
|
||||
private fun Insets.subtractBy(insets: WindowInsetsCompat) = insets.replaceSystemWindowInsets(
|
||||
insets.systemWindowInsetLeft - left,
|
||||
insets.systemWindowInsetTop - top,
|
||||
insets.systemWindowInsetRight - right,
|
||||
insets.systemWindowInsetBottom - bottom
|
||||
)
|
||||
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
package com.topjohnwu.magisk.ui.base
|
||||
|
||||
import android.view.View
|
||||
import androidx.core.graphics.Insets
|
||||
import androidx.navigation.NavController
|
||||
|
||||
internal interface CompatView<ViewModel : BaseViewModel> {
|
||||
|
||||
val viewRoot: View
|
||||
val viewModel: ViewModel
|
||||
val navigation: NavController?
|
||||
|
||||
fun peekSystemWindowInsets(insets: Insets) = Unit
|
||||
fun consumeSystemWindowInsets(insets: Insets): Insets? = null
|
||||
|
||||
}
|
@ -12,9 +12,6 @@ import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.su.SuCallbackHandler
|
||||
import com.topjohnwu.magisk.core.su.SuCallbackHandler.REQUEST
|
||||
import com.topjohnwu.magisk.databinding.ActivityRequestBinding
|
||||
import com.topjohnwu.magisk.model.events.DieEvent
|
||||
import com.topjohnwu.magisk.model.events.ViewActionEvent
|
||||
import com.topjohnwu.magisk.model.events.ViewEvent
|
||||
import com.topjohnwu.magisk.ui.base.BaseUIActivity
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
|
||||
@ -22,7 +19,6 @@ open class SuRequestActivity : BaseUIActivity<SuRequestViewModel, ActivityReques
|
||||
|
||||
override val layoutRes: Int = R.layout.activity_request
|
||||
override val viewModel: SuRequestViewModel by viewModel()
|
||||
|
||||
override val navigation: NavController? = null
|
||||
|
||||
override fun onBackPressed() {
|
||||
@ -65,14 +61,6 @@ open class SuRequestActivity : BaseUIActivity<SuRequestViewModel, ActivityReques
|
||||
return theme
|
||||
}
|
||||
|
||||
override fun onEventDispatched(event: ViewEvent) {
|
||||
super.onEventDispatched(event)
|
||||
when (event) {
|
||||
is ViewActionEvent -> event.action(this)
|
||||
is DieEvent -> finish()
|
||||
}
|
||||
}
|
||||
|
||||
private fun lockOrientation() {
|
||||
requestedOrientation = if (Build.VERSION.SDK_INT < 18)
|
||||
resources.configuration.orientation
|
||||
|
Loading…
Reference in New Issue
Block a user