Tidy up ViewEvents
This commit is contained in:
parent
a86d5b3e61
commit
d7a26dbf27
@ -8,6 +8,8 @@ import androidx.navigation.NavDirections
|
||||
import com.topjohnwu.magisk.MainDirections
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.ui.base.ActivityExecutor
|
||||
import com.topjohnwu.magisk.ui.base.ViewEvent
|
||||
|
||||
class InstallExternalModuleEvent : ViewEvent(), ActivityExecutor {
|
||||
|
||||
|
@ -7,6 +7,8 @@ import androidx.annotation.AttrRes
|
||||
import androidx.browser.customtabs.CustomTabsIntent
|
||||
import androidx.core.net.toUri
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.ui.base.ContextExecutor
|
||||
import com.topjohnwu.magisk.ui.base.ViewEvent
|
||||
|
||||
data class OpenInappLinkEvent(
|
||||
private val link: String
|
||||
|
@ -5,7 +5,9 @@ import androidx.annotation.StringRes
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.ktx.snackbar
|
||||
import com.topjohnwu.magisk.ui.base.ActivityExecutor
|
||||
import com.topjohnwu.magisk.ui.base.BaseUIActivity
|
||||
import com.topjohnwu.magisk.ui.base.ViewEvent
|
||||
|
||||
class SnackbarEvent private constructor(
|
||||
@StringRes private val messageRes: Int,
|
||||
|
@ -1,17 +0,0 @@
|
||||
package com.topjohnwu.magisk.model.events
|
||||
|
||||
import androidx.lifecycle.Observer
|
||||
|
||||
/**
|
||||
* Observer for [ViewEvent]s, which automatically checks if event was handled
|
||||
*/
|
||||
class ViewEventObserver(private val onEventUnhandled: (ViewEvent) -> Unit) : Observer<ViewEvent> {
|
||||
override fun onChanged(event: ViewEvent?) {
|
||||
event?.let {
|
||||
if (!it.handled) {
|
||||
it.handled = true
|
||||
onEventUnhandled(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -3,7 +3,6 @@ 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
|
||||
@ -12,12 +11,19 @@ import com.topjohnwu.magisk.core.utils.SafetyNetHelper
|
||||
import com.topjohnwu.magisk.data.network.GithubRawServices
|
||||
import com.topjohnwu.magisk.ktx.DynamicClassLoader
|
||||
import com.topjohnwu.magisk.ktx.writeTo
|
||||
import com.topjohnwu.magisk.ui.base.ActivityExecutor
|
||||
import com.topjohnwu.magisk.ui.base.ContextExecutor
|
||||
import com.topjohnwu.magisk.ui.base.ViewEvent
|
||||
import com.topjohnwu.magisk.ui.base.ViewEventWithScope
|
||||
import com.topjohnwu.magisk.ui.safetynet.SafetyNetResult
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
import com.topjohnwu.magisk.view.MarkDownWindow
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import dalvik.system.DexFile
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.json.JSONObject
|
||||
import org.koin.core.KoinComponent
|
||||
import org.koin.core.inject
|
||||
@ -26,35 +32,9 @@ import java.io.File
|
||||
import java.io.IOException
|
||||
import java.lang.reflect.InvocationHandler
|
||||
|
||||
/**
|
||||
* Class for passing events from ViewModels to Activities/Fragments
|
||||
* Variable [handled] used so each event is handled only once
|
||||
* (see https://medium.com/google-developers/livedata-with-snackbar-navigation-and-other-events-the-singleliveevent-case-ac2622673150)
|
||||
* Use [ViewEventObserver] for observing these events
|
||||
*/
|
||||
abstract class ViewEvent {
|
||||
var handled = false
|
||||
}
|
||||
|
||||
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 {
|
||||
) : ViewEventWithScope(), ContextExecutor, KoinComponent, SafetyNetHelper.Callback {
|
||||
|
||||
private val svc by inject<GithubRawServices>()
|
||||
|
||||
@ -161,7 +141,7 @@ class ViewActionEvent(val action: BaseActivity.() -> Unit) : ViewEvent(), Activi
|
||||
override fun invoke(activity: BaseActivity) = action(activity)
|
||||
}
|
||||
|
||||
class OpenChangelogEvent(val item: Repo) : ViewEventsWithScope(), ContextExecutor {
|
||||
class OpenChangelogEvent(val item: Repo) : ViewEventWithScope(), ContextExecutor {
|
||||
override fun invoke(context: Context) {
|
||||
scope.launch {
|
||||
MarkDownWindow.show(context, null, item::readme)
|
||||
|
@ -2,8 +2,8 @@ package com.topjohnwu.magisk.model.events.dialog
|
||||
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.core.utils.BiometricHelper
|
||||
import com.topjohnwu.magisk.model.events.ActivityExecutor
|
||||
import com.topjohnwu.magisk.model.events.ViewEvent
|
||||
import com.topjohnwu.magisk.ui.base.ActivityExecutor
|
||||
import com.topjohnwu.magisk.ui.base.ViewEvent
|
||||
|
||||
class BiometricDialog(
|
||||
builder: Builder.() -> Unit
|
||||
|
@ -5,7 +5,7 @@ import androidx.appcompat.app.AppCompatDelegate
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.model.events.ActivityExecutor
|
||||
import com.topjohnwu.magisk.ui.base.ActivityExecutor
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.topjohnwu.magisk.model.events.dialog
|
||||
|
||||
import android.content.Context
|
||||
import com.topjohnwu.magisk.model.events.ContextExecutor
|
||||
import com.topjohnwu.magisk.model.events.ViewEvent
|
||||
import com.topjohnwu.magisk.ui.base.ContextExecutor
|
||||
import com.topjohnwu.magisk.ui.base.ViewEvent
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
|
||||
abstract class DialogEvent : ViewEvent(), ContextExecutor {
|
||||
|
@ -2,9 +2,9 @@ package com.topjohnwu.magisk.model.navigation
|
||||
|
||||
import androidx.navigation.NavDirections
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.model.events.ActivityExecutor
|
||||
import com.topjohnwu.magisk.model.events.ViewEvent
|
||||
import com.topjohnwu.magisk.ui.base.ActivityExecutor
|
||||
import com.topjohnwu.magisk.ui.base.BaseUIActivity
|
||||
import com.topjohnwu.magisk.ui.base.ViewEvent
|
||||
|
||||
class NavigationWrapper(
|
||||
private val directions: NavDirections
|
||||
|
@ -17,9 +17,6 @@ import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.ktx.startAnimations
|
||||
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<VM : BaseViewModel, Binding : ViewDataBinding> :
|
||||
@ -94,9 +91,10 @@ abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> :
|
||||
return currentFragment?.onKeyEvent(event) == true || super.dispatchKeyEvent(event)
|
||||
}
|
||||
|
||||
override fun onEventDispatched(event: ViewEvent) {
|
||||
(event as? ContextExecutor)?.invoke(this)
|
||||
(event as? ActivityExecutor)?.invoke(this)
|
||||
override fun onEventDispatched(event: ViewEvent) = when(event) {
|
||||
is ContextExecutor -> event(this)
|
||||
is ActivityExecutor -> event(this)
|
||||
else -> Unit
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
|
@ -5,7 +5,6 @@ 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 {
|
||||
|
||||
|
@ -13,10 +13,6 @@ 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.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<VM : BaseViewModel, Binding : ViewDataBinding> :
|
||||
Fragment(), BaseUIComponent<VM> {
|
||||
@ -47,10 +43,11 @@ abstract class BaseUIFragment<VM : BaseViewModel, Binding : ViewDataBinding> :
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onEventDispatched(event: ViewEvent) {
|
||||
(event as? ContextExecutor)?.invoke(requireContext())
|
||||
(event as? FragmentExecutor)?.invoke(this)
|
||||
(event as? ActivityExecutor)?.invoke(activity)
|
||||
override fun onEventDispatched(event: ViewEvent) = when(event) {
|
||||
is ContextExecutor -> event(requireContext())
|
||||
is ActivityExecutor -> event(activity)
|
||||
is FragmentExecutor -> event(this)
|
||||
else -> Unit
|
||||
}
|
||||
|
||||
open fun onKeyEvent(event: KeyEvent): Boolean {
|
||||
|
@ -15,7 +15,10 @@ import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.model.events.*
|
||||
import com.topjohnwu.magisk.model.events.BackPressEvent
|
||||
import com.topjohnwu.magisk.model.events.PermissionEvent
|
||||
import com.topjohnwu.magisk.model.events.SnackbarEvent
|
||||
import com.topjohnwu.magisk.model.events.ViewActionEvent
|
||||
import com.topjohnwu.magisk.model.navigation.NavigationWrapper
|
||||
import com.topjohnwu.magisk.utils.ObservableHost
|
||||
import com.topjohnwu.magisk.utils.set
|
||||
@ -102,7 +105,7 @@ abstract class BaseViewModel(
|
||||
_viewEvents.postValue(this)
|
||||
}
|
||||
|
||||
fun <Event : ViewEventsWithScope> Event.publish() {
|
||||
fun <Event : ViewEventWithScope> Event.publish() {
|
||||
scope = viewModelScope
|
||||
_viewEvents.postValue(this)
|
||||
}
|
||||
|
28
app/src/main/java/com/topjohnwu/magisk/ui/base/ViewEvent.kt
Normal file
28
app/src/main/java/com/topjohnwu/magisk/ui/base/ViewEvent.kt
Normal file
@ -0,0 +1,28 @@
|
||||
package com.topjohnwu.magisk.ui.base
|
||||
|
||||
import android.content.Context
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
/**
|
||||
* Class for passing events from ViewModels to Activities/Fragments
|
||||
* (see https://medium.com/google-developers/livedata-with-snackbar-navigation-and-other-events-the-singleliveevent-case-ac2622673150)
|
||||
*/
|
||||
abstract class ViewEvent
|
||||
|
||||
abstract class ViewEventWithScope: 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)
|
||||
}
|
@ -17,13 +17,13 @@ import com.topjohnwu.magisk.ktx.packageName
|
||||
import com.topjohnwu.magisk.ktx.res
|
||||
import com.topjohnwu.magisk.model.entity.IconLink
|
||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.Manager
|
||||
import com.topjohnwu.magisk.model.events.ActivityExecutor
|
||||
import com.topjohnwu.magisk.model.events.OpenInappLinkEvent
|
||||
import com.topjohnwu.magisk.model.events.ViewEvent
|
||||
import com.topjohnwu.magisk.model.events.dialog.EnvFixDialog
|
||||
import com.topjohnwu.magisk.model.events.dialog.ManagerInstallDialog
|
||||
import com.topjohnwu.magisk.model.events.dialog.UninstallDialog
|
||||
import com.topjohnwu.magisk.ui.base.ActivityExecutor
|
||||
import com.topjohnwu.magisk.ui.base.BaseViewModel
|
||||
import com.topjohnwu.magisk.ui.base.ViewEvent
|
||||
import com.topjohnwu.magisk.ui.base.itemBindingOf
|
||||
import com.topjohnwu.magisk.utils.set
|
||||
import com.topjohnwu.superuser.Shell
|
||||
|
@ -12,10 +12,10 @@ import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.databinding.FragmentModuleMd2Binding
|
||||
import com.topjohnwu.magisk.ktx.hideKeyboard
|
||||
import com.topjohnwu.magisk.model.events.InstallExternalModuleEvent
|
||||
import com.topjohnwu.magisk.model.events.ViewEvent
|
||||
import com.topjohnwu.magisk.ui.MainActivity
|
||||
import com.topjohnwu.magisk.ui.base.BaseUIFragment
|
||||
import com.topjohnwu.magisk.ui.base.ReselectionTarget
|
||||
import com.topjohnwu.magisk.ui.base.ViewEvent
|
||||
import com.topjohnwu.magisk.utils.EndlessRecyclerScrollListener
|
||||
import com.topjohnwu.magisk.utils.MotionRevealHelper
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
|
@ -4,7 +4,7 @@ import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
import com.topjohnwu.magisk.model.events.ViewEvent
|
||||
import com.topjohnwu.magisk.ui.base.ViewEvent
|
||||
|
||||
class EndlessRecyclerScrollListener(
|
||||
private val layoutManager: RecyclerView.LayoutManager,
|
||||
|
Loading…
Reference in New Issue
Block a user