More refactoring

Cleanups, move classes to sane locations, etc.
This commit is contained in:
topjohnwu 2020-08-19 02:05:23 -07:00
parent 846bbb4da1
commit 34450cdddd
85 changed files with 365 additions and 522 deletions

View File

@ -29,9 +29,9 @@
-keep class a.* { *; }
# Snet
-keepclassmembers class com.topjohnwu.magisk.core.utils.SafetyNetHelper { *; }
-keep,allowobfuscation interface com.topjohnwu.magisk.core.utils.SafetyNetHelper$Callback
-keepclassmembers class * implements com.topjohnwu.magisk.core.utils.SafetyNetHelper$Callback {
-keepclassmembers class com.topjohnwu.magisk.ui.safetynet.SafetyNetHelper { *; }
-keep,allowobfuscation interface com.topjohnwu.magisk.ui.safetynet.SafetyNetHelper$Callback
-keepclassmembers class * implements com.topjohnwu.magisk.ui.safetynet.SafetyNetHelper$Callback {
void onResponse(int);
}

View File

@ -15,10 +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.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.events.BackPressEvent
import com.topjohnwu.magisk.events.PermissionEvent
import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.events.ViewActionEvent
import com.topjohnwu.magisk.model.navigation.NavigationWrapper
import com.topjohnwu.magisk.utils.ObservableHost
import com.topjohnwu.magisk.utils.set

View File

@ -8,8 +8,8 @@ import com.topjohnwu.magisk.core.magiskdb.PolicyDao
import com.topjohnwu.magisk.core.model.ManagerJson
import com.topjohnwu.magisk.core.su.SuCallbackHandler
import com.topjohnwu.magisk.ktx.reboot
import com.topjohnwu.magisk.model.entity.internal.Configuration
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.model.internal.Configuration
import com.topjohnwu.magisk.model.internal.DownloadSubject
import com.topjohnwu.magisk.view.Shortcuts
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.GlobalScope

View File

@ -13,10 +13,10 @@ import com.topjohnwu.magisk.core.tasks.EnvFixTask
import com.topjohnwu.magisk.ktx.chooser
import com.topjohnwu.magisk.ktx.exists
import com.topjohnwu.magisk.ktx.provide
import com.topjohnwu.magisk.model.entity.internal.Configuration.*
import com.topjohnwu.magisk.model.entity.internal.Configuration.Flash.Secondary
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.*
import com.topjohnwu.magisk.model.internal.Configuration.*
import com.topjohnwu.magisk.model.internal.Configuration.Flash.Secondary
import com.topjohnwu.magisk.model.internal.DownloadSubject
import com.topjohnwu.magisk.model.internal.DownloadSubject.*
import com.topjohnwu.magisk.ui.flash.FlashFragment
import com.topjohnwu.magisk.utils.APKInstall
import org.koin.core.get

View File

@ -10,9 +10,9 @@ import com.topjohnwu.magisk.core.intent
import com.topjohnwu.magisk.core.isRunningAsStub
import com.topjohnwu.magisk.core.utils.PatchAPK
import com.topjohnwu.magisk.ktx.writeTo
import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Restore
import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Upgrade
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.model.internal.Configuration.APK.Restore
import com.topjohnwu.magisk.model.internal.Configuration.APK.Upgrade
import com.topjohnwu.magisk.model.internal.DownloadSubject
import com.topjohnwu.superuser.Shell
import java.io.File

View File

@ -10,9 +10,9 @@ import com.topjohnwu.magisk.core.utils.ProgressInputStream
import com.topjohnwu.magisk.data.network.GithubRawServices
import com.topjohnwu.magisk.ktx.checkSum
import com.topjohnwu.magisk.ktx.writeTo
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.Magisk
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.Module
import com.topjohnwu.magisk.model.internal.DownloadSubject
import com.topjohnwu.magisk.model.internal.DownloadSubject.Magisk
import com.topjohnwu.magisk.model.internal.DownloadSubject.Module
import com.topjohnwu.magisk.view.Notifications
import kotlinx.coroutines.launch
import okhttp3.ResponseBody

View File

@ -3,9 +3,9 @@ package com.topjohnwu.magisk.core.magiskdb
import android.content.Context
import android.content.pm.PackageManager
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.model.MagiskPolicy
import com.topjohnwu.magisk.core.model.toMap
import com.topjohnwu.magisk.core.model.toPolicy
import com.topjohnwu.magisk.core.model.su.SuPolicy
import com.topjohnwu.magisk.core.model.su.toMap
import com.topjohnwu.magisk.core.model.su.toPolicy
import com.topjohnwu.magisk.ktx.now
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
@ -49,11 +49,11 @@ class PolicyDao(
}
}.query().first().toPolicyOrNull()
suspend fun update(policy: MagiskPolicy) = buildQuery<Replace> {
suspend fun update(policy: SuPolicy) = buildQuery<Replace> {
values(policy.toMap())
}.commit()
suspend fun <R: Any> fetchAll(mapper: (MagiskPolicy) -> R) = buildQuery<Select> {
suspend fun <R: Any> fetchAll(mapper: (SuPolicy) -> R) = buildQuery<Select> {
condition {
equals("uid/100000", Const.USER_ID)
}
@ -61,7 +61,7 @@ class PolicyDao(
it.toPolicyOrNull()?.let(mapper)
}
private fun Map<String, String>.toPolicyOrNull(): MagiskPolicy? {
private fun Map<String, String>.toPolicyOrNull(): SuPolicy? {
return runCatching { toPolicy(context.packageManager) }.getOrElse {
Timber.e(it)
if (it is PackageManager.NameNotFoundException) {

View File

@ -59,6 +59,6 @@ data class Repo(
class IllegalRepoException(message: String) : Exception(message)
companion object {
val dateFormat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM)!!
val dateFormat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM)
}
}

View File

@ -1,16 +1,15 @@
package com.topjohnwu.magisk.model.entity
package com.topjohnwu.magisk.core.model.su
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.PrimaryKey
import com.topjohnwu.magisk.core.model.MagiskPolicy
import com.topjohnwu.magisk.core.model.MagiskPolicy.Companion.ALLOW
import com.topjohnwu.magisk.core.model.su.SuPolicy.Companion.ALLOW
import com.topjohnwu.magisk.ktx.now
import com.topjohnwu.magisk.ktx.timeFormatTime
import com.topjohnwu.magisk.ktx.toTime
@Entity(tableName = "logs")
data class MagiskLog(
data class SuLog(
val fromUid: Int,
val toUid: Int,
val fromPid: Int,
@ -24,8 +23,8 @@ data class MagiskLog(
@Ignore val timeString = time.toTime(timeFormatTime)
}
fun MagiskPolicy.toLog(
fun SuPolicy.toLog(
toUid: Int,
fromPid: Int,
command: String
) = MagiskLog(uid, toUid, fromPid, packageName, appName, command, policy == ALLOW, now)
) = SuLog(uid, toUid, fromPid, packageName, appName, command, policy == ALLOW, now)

View File

@ -1,12 +1,12 @@
package com.topjohnwu.magisk.core.model
package com.topjohnwu.magisk.core.model.su
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import com.topjohnwu.magisk.core.model.MagiskPolicy.Companion.INTERACTIVE
import com.topjohnwu.magisk.core.model.su.SuPolicy.Companion.INTERACTIVE
import com.topjohnwu.magisk.ktx.getLabel
data class MagiskPolicy(
data class SuPolicy(
var uid: Int,
val packageName: String,
val appName: String,
@ -25,7 +25,7 @@ data class MagiskPolicy(
}
fun MagiskPolicy.toMap() = mapOf(
fun SuPolicy.toMap() = mapOf(
"uid" to uid,
"package_name" to packageName,
"policy" to policy,
@ -35,7 +35,7 @@ fun MagiskPolicy.toMap() = mapOf(
)
@Throws(PackageManager.NameNotFoundException::class)
fun Map<String, String>.toPolicy(pm: PackageManager): MagiskPolicy {
fun Map<String, String>.toPolicy(pm: PackageManager): SuPolicy {
val uid = get("uid")?.toIntOrNull() ?: -1
val packageName = get("package_name").orEmpty()
val info = pm.getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES)
@ -43,7 +43,7 @@ fun Map<String, String>.toPolicy(pm: PackageManager): MagiskPolicy {
if (info.uid != uid)
throw PackageManager.NameNotFoundException()
return MagiskPolicy(
return SuPolicy(
uid = uid,
packageName = packageName,
policy = get("policy")?.toIntOrNull() ?: INTERACTIVE,
@ -56,11 +56,11 @@ fun Map<String, String>.toPolicy(pm: PackageManager): MagiskPolicy {
}
@Throws(PackageManager.NameNotFoundException::class)
fun Int.toPolicy(pm: PackageManager, policy: Int = INTERACTIVE): MagiskPolicy {
fun Int.toPolicy(pm: PackageManager, policy: Int = INTERACTIVE): SuPolicy {
val pkg = pm.getPackagesForUid(this)?.firstOrNull()
?: throw PackageManager.NameNotFoundException()
val info = pm.getApplicationInfo(pkg, PackageManager.GET_UNINSTALLED_PACKAGES)
return MagiskPolicy(
return SuPolicy(
uid = info.uid,
packageName = pkg,
policy = policy,

View File

@ -11,14 +11,14 @@ import com.topjohnwu.magisk.ProviderCallHandler
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.intent
import com.topjohnwu.magisk.core.model.MagiskPolicy
import com.topjohnwu.magisk.core.model.toPolicy
import com.topjohnwu.magisk.core.model.su.SuPolicy
import com.topjohnwu.magisk.core.model.su.toLog
import com.topjohnwu.magisk.core.model.su.toPolicy
import com.topjohnwu.magisk.core.wrap
import com.topjohnwu.magisk.data.repository.LogRepository
import com.topjohnwu.magisk.ktx.get
import com.topjohnwu.magisk.ktx.startActivity
import com.topjohnwu.magisk.ktx.startActivityWithRoot
import com.topjohnwu.magisk.model.entity.toLog
import com.topjohnwu.magisk.ui.surequest.SuRequestActivity
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.superuser.Shell
@ -132,9 +132,9 @@ object SuCallbackHandler : ProviderCallHandler {
}
}
private fun notify(context: Context, policy: MagiskPolicy) {
private fun notify(context: Context, policy: SuPolicy) {
if (policy.notification && Config.suNotification == Config.Value.NOTIFICATION_TOAST) {
val resId = if (policy.policy == MagiskPolicy.ALLOW)
val resId = if (policy.policy == SuPolicy.ALLOW)
R.string.su_allow_toast
else
R.string.su_deny_toast

View File

@ -10,8 +10,8 @@ import com.topjohnwu.magisk.BuildConfig
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.magiskdb.PolicyDao
import com.topjohnwu.magisk.core.model.MagiskPolicy
import com.topjohnwu.magisk.core.model.toPolicy
import com.topjohnwu.magisk.core.model.su.SuPolicy
import com.topjohnwu.magisk.core.model.su.toPolicy
import com.topjohnwu.magisk.ktx.now
import kotlinx.coroutines.*
import timber.log.Timber
@ -27,7 +27,7 @@ abstract class SuRequestHandler(
private lateinit var output: DataOutputStream
private lateinit var input: DataInputStream
protected lateinit var policy: MagiskPolicy
protected lateinit var policy: SuPolicy
private set
abstract fun onStart()
@ -44,11 +44,11 @@ abstract class SuRequestHandler(
when (Config.suAutoReponse) {
Config.Value.SU_AUTO_DENY -> {
respond(MagiskPolicy.DENY, 0)
respond(SuPolicy.DENY, 0)
return true
}
Config.Value.SU_AUTO_ALLOW -> {
respond(MagiskPolicy.ALLOW, 0)
respond(SuPolicy.ALLOW, 0)
return true
}
}

View File

@ -14,10 +14,10 @@ import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.data.network.GithubRawServices
import com.topjohnwu.magisk.di.Protected
import com.topjohnwu.magisk.events.dialog.EnvFixDialog
import com.topjohnwu.magisk.ktx.readUri
import com.topjohnwu.magisk.ktx.reboot
import com.topjohnwu.magisk.ktx.withStreams
import com.topjohnwu.magisk.model.events.dialog.EnvFixDialog
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.signing.SignBoot
import com.topjohnwu.superuser.Shell
@ -100,6 +100,7 @@ abstract class MagiskInstallImpl : KoinComponent {
return true
}
@Suppress("DEPRECATION")
private fun extractZip(): Boolean {
val arch: String
arch = if (Build.VERSION.SDK_INT >= 21) {
@ -130,14 +131,14 @@ abstract class MagiskInstallImpl : KoinComponent {
}
if (name == null && ze.name.startsWith("chromeos/"))
name = ze.name
if (name == null)
continue
val dest = if (installDir is SuFile)
SuFile(installDir, name)
else
File(installDir, name)
dest.parentFile!!.mkdirs()
SuFileOutputStream(dest).use { zi.copyTo(it) }
name?.also {
val dest = if (installDir is SuFile)
SuFile(installDir, it)
else
File(installDir, it)
dest.parentFile!!.mkdirs()
SuFileOutputStream(dest).use { s -> zi.copyTo(s) }
} ?: continue
}
}
} catch (e: IOException) {

View File

@ -1,12 +1,12 @@
package com.topjohnwu.magisk.data.database
import androidx.room.*
import com.topjohnwu.magisk.model.entity.MagiskLog
import com.topjohnwu.magisk.core.model.su.SuLog
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.util.*
@Database(version = 1, entities = [MagiskLog::class], exportSchema = false)
@Database(version = 1, entities = [SuLog::class], exportSchema = false)
abstract class SuLogDatabase : RoomDatabase() {
abstract fun suLogDao(): SuLogDao
@ -20,18 +20,18 @@ abstract class SuLogDao(private val db: SuLogDatabase) {
suspend fun deleteAll() = withContext(Dispatchers.IO) { db.clearAllTables() }
suspend fun fetchAll(): MutableList<MagiskLog> {
suspend fun fetchAll(): MutableList<SuLog> {
deleteOutdated()
return fetch()
}
@Query("SELECT * FROM logs ORDER BY time DESC")
protected abstract suspend fun fetch(): MutableList<MagiskLog>
protected abstract suspend fun fetch(): MutableList<SuLog>
@Query("DELETE FROM logs WHERE time < :timeout")
protected abstract suspend fun deleteOutdated(timeout: Long = twoWeeksAgo)
@Insert
abstract suspend fun insert(log: MagiskLog)
abstract suspend fun insert(log: SuLog)
}

View File

@ -1,9 +1,9 @@
package com.topjohnwu.magisk.data.repository
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.model.su.SuLog
import com.topjohnwu.magisk.data.database.SuLogDao
import com.topjohnwu.magisk.ktx.await
import com.topjohnwu.magisk.model.entity.MagiskLog
import com.topjohnwu.superuser.Shell
@ -36,6 +36,6 @@ class LogRepository(
fun clearMagiskLogs(cb: (Shell.Result) -> Unit) =
Shell.su("echo -n > ${Const.MAGISK_LOG}").submit(cb)
suspend fun insert(log: MagiskLog) = logDao.insert(log)
suspend fun insert(log: SuLog) = logDao.insert(log)
}

View File

@ -7,8 +7,8 @@ import com.topjohnwu.magisk.data.network.GithubRawServices
import com.topjohnwu.magisk.ktx.await
import com.topjohnwu.magisk.ktx.getLabel
import com.topjohnwu.magisk.ktx.packageName
import com.topjohnwu.magisk.model.entity.HideAppInfo
import com.topjohnwu.magisk.model.entity.HideTarget
import com.topjohnwu.magisk.ui.hide.HideAppInfo
import com.topjohnwu.magisk.ui.hide.HideTarget
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

View File

@ -3,6 +3,7 @@ package com.topjohnwu.magisk.databinding
import androidx.annotation.CallSuper
import androidx.databinding.PropertyChangeRegistry
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.RecyclerView
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.utils.DiffObservableList
import com.topjohnwu.magisk.utils.ObservableHost
@ -52,3 +53,13 @@ abstract class ComparableRvItem<in T> : RvItem() {
abstract class ObservableItem<T> : ComparableRvItem<T>(), ObservableHost {
override var callbacks: PropertyChangeRegistry? = null
}
/**
* This item addresses issues where enclosing recycler has to be invalidated or generally
* manipulated with. This shouldn't be however necessary for 99.9% of use-cases. Refrain from using
* this item as it provides virtually no additional functionality. Stick with ComparableRvItem.
* */
interface LenientRvItem {
fun onBindingBound(binding: ViewDataBinding, recyclerView: RecyclerView)
}

View File

@ -2,7 +2,6 @@ package com.topjohnwu.magisk.databinding
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.RecyclerView
import com.topjohnwu.magisk.model.entity.recycler.LenientRvItem
import me.tatarka.bindingcollectionadapter2.BindingRecyclerViewAdapter
class RvBindingAdapter<T : RvItem> : BindingRecyclerViewAdapter<T>() {
@ -19,7 +18,7 @@ class RvBindingAdapter<T : RvItem> : BindingRecyclerViewAdapter<T>() {
super.onBindBinding(binding, variableId, layoutRes, position, item)
when (item) {
is LenientRvItem<*> -> {
is LenientRvItem -> {
val recycler = recyclerView ?: return
item.onBindingBound(binding)
item.onBindingBound(binding, recycler)

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.events
package com.topjohnwu.magisk.events
import android.Manifest
import android.app.Activity

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.events
package com.topjohnwu.magisk.events
import android.content.Context
import android.content.res.Resources

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.events
package com.topjohnwu.magisk.events
import android.view.ContextThemeWrapper
import android.view.MenuItem

View File

@ -0,0 +1,46 @@
package com.topjohnwu.magisk.events
import android.view.View
import androidx.annotation.StringRes
import com.google.android.material.snackbar.Snackbar
import com.topjohnwu.magisk.arch.ActivityExecutor
import com.topjohnwu.magisk.arch.BaseUIActivity
import com.topjohnwu.magisk.arch.ViewEvent
import com.topjohnwu.magisk.core.base.BaseActivity
import com.topjohnwu.magisk.utils.TransitiveText
class SnackbarEvent private constructor(
private val msg: TransitiveText,
private val length: Int,
private val builder: Snackbar.() -> Unit
) : ViewEvent(), ActivityExecutor {
constructor(
@StringRes res: Int,
length: Int = Snackbar.LENGTH_SHORT,
builder: Snackbar.() -> Unit = {}
) : this(TransitiveText.Res(res), length, builder)
constructor(
message: String,
length: Int = Snackbar.LENGTH_SHORT,
builder: Snackbar.() -> Unit = {}
) : this(TransitiveText.String(message), length, builder)
private fun snackbar(
view: View,
message: String,
length: Int = Snackbar.LENGTH_SHORT,
builder: Snackbar.() -> Unit = {}
) = Snackbar.make(view, message, length).apply(builder).show()
override fun invoke(activity: BaseActivity) {
if (activity is BaseUIActivity<*, *>) {
snackbar(activity.snackbarView,
msg.getText(activity.resources).toString(),
length, builder)
}
}
}

View File

@ -0,0 +1,76 @@
package com.topjohnwu.magisk.events
import android.app.Activity
import android.content.Context
import android.content.Intent
import com.topjohnwu.magisk.arch.ActivityExecutor
import com.topjohnwu.magisk.arch.ContextExecutor
import com.topjohnwu.magisk.arch.ViewEvent
import com.topjohnwu.magisk.arch.ViewEventWithScope
import com.topjohnwu.magisk.core.base.BaseActivity
import com.topjohnwu.magisk.core.model.module.Repo
import com.topjohnwu.magisk.view.MarkDownWindow
import kotlinx.coroutines.launch
class ViewActionEvent(val action: BaseActivity.() -> Unit) : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseActivity) = action(activity)
}
class OpenChangelogEvent(val item: Repo) : ViewEventWithScope(), ContextExecutor {
override fun invoke(context: Context) {
scope.launch {
MarkDownWindow.show(context, null, item::readme)
}
}
}
class PermissionEvent(
private val permissions: List<String>,
private val callback: (Boolean) -> Unit
) : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseActivity) =
activity.withPermissions(*permissions.toTypedArray()) {
onSuccess {
callback(true)
}
onFailure {
callback(false)
}
}
}
class BackPressEvent : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseActivity) {
activity.onBackPressed()
}
}
class DieEvent : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseActivity) {
activity.finish()
}
}
class RecreateEvent : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseActivity) {
activity.recreate()
}
}
class RequestFileEvent : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseActivity) {
Intent(Intent.ACTION_GET_CONTENT)
.setType("*/*")
.addCategory(Intent.CATEGORY_OPENABLE)
.also { activity.startActivityForResult(it, REQUEST_CODE) }
}
companion object {
private const val REQUEST_CODE = 10
fun resolve(requestCode: Int, resultCode: Int, data: Intent?) = data
?.takeIf { resultCode == Activity.RESULT_OK }
?.takeIf { requestCode == REQUEST_CODE }
?.data
}
}

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.events.dialog
package com.topjohnwu.magisk.events.dialog
import com.topjohnwu.magisk.arch.ActivityExecutor
import com.topjohnwu.magisk.arch.ViewEvent

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.events.dialog
package com.topjohnwu.magisk.events.dialog
import android.app.Activity
import androidx.appcompat.app.AppCompatDelegate

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.events.dialog
package com.topjohnwu.magisk.events.dialog
import android.content.Context
import com.topjohnwu.magisk.arch.ContextExecutor

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.events.dialog
package com.topjohnwu.magisk.events.dialog
import android.content.BroadcastReceiver
import android.content.Context
@ -7,8 +7,8 @@ import android.content.IntentFilter
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.download.DownloadService
import com.topjohnwu.magisk.model.entity.internal.Configuration.EnvFix
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.Magisk
import com.topjohnwu.magisk.model.internal.Configuration.EnvFix
import com.topjohnwu.magisk.model.internal.DownloadSubject.Magisk
import com.topjohnwu.magisk.view.MagiskDialog
class EnvFixDialog : DialogEvent() {

View File

@ -1,11 +1,11 @@
package com.topjohnwu.magisk.model.events.dialog
package com.topjohnwu.magisk.events.dialog
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.download.DownloadService
import com.topjohnwu.magisk.ktx.res
import com.topjohnwu.magisk.model.entity.internal.Configuration
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.model.internal.Configuration
import com.topjohnwu.magisk.model.internal.DownloadSubject
import com.topjohnwu.magisk.view.MagiskDialog
import com.topjohnwu.magisk.view.MarkDownWindow
import kotlinx.coroutines.Dispatchers

View File

@ -1,10 +1,10 @@
package com.topjohnwu.magisk.model.events.dialog
package com.topjohnwu.magisk.events.dialog
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.download.DownloadService
import com.topjohnwu.magisk.core.model.module.Repo
import com.topjohnwu.magisk.model.entity.internal.Configuration
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.model.internal.Configuration
import com.topjohnwu.magisk.model.internal.DownloadSubject
import com.topjohnwu.magisk.view.MagiskDialog
class ModuleInstallDialog(private val item: Repo) : DialogEvent() {

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.events.dialog
package com.topjohnwu.magisk.events.dialog
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.view.MagiskDialog

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.events.dialog
package com.topjohnwu.magisk.events.dialog
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.view.MagiskDialog
@ -30,4 +30,4 @@ class SuperuserRevokeDialog(
listenerOnSuccess = listener
}
}
}
}

View File

@ -1,11 +1,11 @@
package com.topjohnwu.magisk.model.events.dialog
package com.topjohnwu.magisk.events.dialog
import android.widget.Toast
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.download.DownloadService
import com.topjohnwu.magisk.model.entity.internal.Configuration
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.model.internal.Configuration
import com.topjohnwu.magisk.model.internal.DownloadSubject
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.view.MagiskDialog
import com.topjohnwu.superuser.Shell

View File

@ -1,126 +0,0 @@
package com.topjohnwu.magisk.ktx
import android.content.Context
import android.content.res.ColorStateList
import android.view.View
import android.widget.TextView
import androidx.annotation.ColorInt
import androidx.annotation.ColorRes
import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.fragment.app.Fragment
import com.google.android.material.snackbar.Snackbar
fun AppCompatActivity.snackbar(
view: View,
@StringRes messageRes: Int,
length: Int = Snackbar.LENGTH_SHORT,
f: Snackbar.() -> Unit = {}
) {
snackbar(view, getString(messageRes), length, f)
}
fun AppCompatActivity.snackbar(
view: View,
message: String,
length: Int = Snackbar.LENGTH_SHORT,
f: Snackbar.() -> Unit = {}
) = Snackbar.make(view, message, length)
.apply(f)
.show()
fun Fragment.snackbar(
view: View,
@StringRes messageRes: Int,
length: Int = Snackbar.LENGTH_SHORT,
f: Snackbar.() -> Unit = {}
) {
snackbar(view, getString(messageRes), length, f)
}
fun Fragment.snackbar(
view: View,
message: String,
length: Int = Snackbar.LENGTH_SHORT,
f: Snackbar.() -> Unit = {}
) = Snackbar.make(view, message, length)
.apply(f)
.show()
fun Snackbar.action(init: KSnackbar.() -> Unit) = apply {
val config = KSnackbar().apply(init)
setAction(config.title(context), config.onClickListener)
when {
config.hasValidColor -> setActionTextColor(config.color(context) ?: return@apply)
config.hasValidColorStateList -> setActionTextColor(config.colorStateList(context) ?: return@apply)
}
}
class KSnackbar {
var colorRes: Int = -1
var colorStateListRes: Int = -1
var title: CharSequence = ""
var titleRes: Int = -1
internal var onClickListener: (View) -> Unit = {}
internal val hasValidColor get() = colorRes != -1
internal val hasValidColorStateList get() = colorStateListRes != -1
fun onClicked(listener: (View) -> Unit) {
onClickListener = listener
}
internal fun title(context: Context) = if (title.isBlank()) context.getString(titleRes) else title
internal fun colorStateList(context: Context) = context.colorStateListCompat(colorStateListRes)
internal fun color(context: Context) = context.colorCompat(colorRes)
}
@Deprecated("Kotlin DSL version is preferred", ReplaceWith("action {}"))
fun Snackbar.action(
@StringRes actionRes: Int,
@ColorRes colorRes: Int? = null,
listener: (View) -> Unit
) {
view.resources.getString(actionRes)
colorRes?.let { ContextCompat.getColor(view.context, colorRes) }
action {}
}
@Deprecated("Kotlin DSL version is preferred", ReplaceWith("action {}"))
fun Snackbar.action(action: String, @ColorInt color: Int? = null, listener: (View) -> Unit) {
setAction(action, listener)
color?.let { setActionTextColor(color) }
}
fun Snackbar.textColorRes(@ColorRes colorRes: Int) {
textColor(context.colorCompat(colorRes) ?: return)
}
fun Snackbar.textColor(@ColorInt color: Int) {
val tv = view.findViewById<TextView>(com.google.android.material.R.id.snackbar_text)
tv.setTextColor(color)
}
fun Snackbar.backgroundColorRes(@ColorRes colorRes: Int) {
backgroundColor(context.colorCompat(colorRes) ?: return)
}
fun Snackbar.backgroundColor(@ColorInt color: Int) {
ViewCompat.setBackgroundTintList(
view,
ColorStateList.valueOf(color)
)
}
fun Snackbar.alert() {
textColor(0xF44336)
}
fun Snackbar.success() {
textColor(0x4CAF50)
}

View File

@ -1,16 +0,0 @@
package com.topjohnwu.magisk.model.entity.recycler
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.RecyclerView
import com.topjohnwu.magisk.databinding.ComparableRvItem
/**
* This item addresses issues where enclosing recycler has to be invalidated or generally
* manipulated with. This shouldn't be however necessary for 99.9% of use-cases. Refrain from using
* this item as it provides virtually no additional functionality. Stick with ComparableRvItem.
* */
abstract class LenientRvItem<in T> : ComparableRvItem<T>() {
open fun onBindingBound(binding: ViewDataBinding, recyclerView: RecyclerView) {}
}

View File

@ -1,14 +0,0 @@
package com.topjohnwu.magisk.model.entity.recycler
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.ComparableRvItem
import com.topjohnwu.magisk.ui.theme.Theme
class ThemeItem(val theme: Theme) : ComparableRvItem<ThemeItem>() {
override val layoutRes = R.layout.item_theme
override fun contentSameAs(other: ThemeItem) = itemSameAs(other)
override fun itemSameAs(other: ThemeItem) = theme == other.theme
}

View File

@ -1,5 +0,0 @@
package com.topjohnwu.magisk.model.entity.state
enum class IndeterminateState {
CHECKED, INDETERMINATE, UNCHECKED
}

View File

@ -1,39 +0,0 @@
package com.topjohnwu.magisk.model.events
import android.content.Context
import androidx.annotation.StringRes
import com.google.android.material.snackbar.Snackbar
import com.topjohnwu.magisk.arch.ActivityExecutor
import com.topjohnwu.magisk.arch.BaseUIActivity
import com.topjohnwu.magisk.arch.ViewEvent
import com.topjohnwu.magisk.core.base.BaseActivity
import com.topjohnwu.magisk.ktx.snackbar
class SnackbarEvent private constructor(
@StringRes private val messageRes: Int,
private val messageString: String?,
val length: Int,
val f: Snackbar.() -> Unit
) : ViewEvent(), ActivityExecutor {
constructor(
@StringRes messageRes: Int,
length: Int = Snackbar.LENGTH_SHORT,
f: Snackbar.() -> Unit = {}
) : this(messageRes, null, length, f)
constructor(
message: String,
length: Int = Snackbar.LENGTH_SHORT,
f: Snackbar.() -> Unit = {}
) : this(-1, message, length, f)
fun message(context: Context): String = messageString ?: context.getString(messageRes)
override fun invoke(activity: BaseActivity) {
if (activity is BaseUIActivity<*, *>) {
activity.snackbar(activity.snackbarView, message(activity), length, f)
}
}
}

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.entity.internal
package com.topjohnwu.magisk.model.internal
import android.net.Uri
import android.os.Parcelable

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.entity.internal
package com.topjohnwu.magisk.model.internal
import android.content.Context
import android.os.Parcelable

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.entity.recycler
package com.topjohnwu.magisk.ui.flash
import android.view.View
import android.widget.TextView
@ -6,9 +6,11 @@ import androidx.core.view.updateLayoutParams
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.RecyclerView
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.ComparableRvItem
import com.topjohnwu.magisk.databinding.LenientRvItem
import kotlin.math.max
class ConsoleItem(val item: String) : LenientRvItem<ConsoleItem>() {
class ConsoleItem(val item: String) : ComparableRvItem<ConsoleItem>(), LenientRvItem {
override val layoutRes = R.layout.item_console_md2
private var parentWidth = -1

View File

@ -15,9 +15,8 @@ import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.tasks.FlashZip
import com.topjohnwu.magisk.core.tasks.MagiskInstaller
import com.topjohnwu.magisk.databinding.RvBindingAdapter
import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.ktx.*
import com.topjohnwu.magisk.model.entity.recycler.ConsoleItem
import com.topjohnwu.magisk.model.events.SnackbarEvent
import com.topjohnwu.magisk.utils.set
import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.superuser.CallbackList

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.entity
package com.topjohnwu.magisk.ui.hide
import android.content.pm.ApplicationInfo
import android.graphics.drawable.Drawable

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.entity.recycler
package com.topjohnwu.magisk.ui.hide
import android.view.View
import android.view.ViewGroup
@ -7,9 +7,6 @@ import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.ObservableItem
import com.topjohnwu.magisk.ktx.startAnimations
import com.topjohnwu.magisk.model.entity.HideAppTarget
import com.topjohnwu.magisk.model.entity.StatefulProcess
import com.topjohnwu.magisk.ui.hide.HideViewModel
import com.topjohnwu.magisk.utils.addOnPropertyChangedCallback
import com.topjohnwu.magisk.utils.set
import kotlin.math.roundToInt

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.entity
package com.topjohnwu.magisk.ui.hide
class HideTarget(line: String) {

View File

@ -11,12 +11,6 @@ import com.topjohnwu.magisk.arch.itemBindingOf
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.utils.currentLocale
import com.topjohnwu.magisk.data.repository.MagiskRepository
import com.topjohnwu.magisk.model.entity.HideAppInfo
import com.topjohnwu.magisk.model.entity.HideAppTarget
import com.topjohnwu.magisk.model.entity.HideTarget
import com.topjohnwu.magisk.model.entity.StatefulProcess
import com.topjohnwu.magisk.model.entity.recycler.HideItem
import com.topjohnwu.magisk.model.entity.recycler.HideProcessItem
import com.topjohnwu.magisk.utils.set
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.entity
package com.topjohnwu.magisk.ui.home
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Const

View File

@ -5,7 +5,7 @@ import android.view.*
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseUIFragment
import com.topjohnwu.magisk.databinding.FragmentHomeMd2Binding
import com.topjohnwu.magisk.model.events.RebootEvent
import com.topjohnwu.magisk.events.RebootEvent
import com.topjohnwu.superuser.Shell
import org.koin.androidx.viewmodel.ext.android.viewModel

View File

@ -16,15 +16,14 @@ import com.topjohnwu.magisk.core.download.RemoteFileService
import com.topjohnwu.magisk.core.model.MagiskJson
import com.topjohnwu.magisk.core.model.ManagerJson
import com.topjohnwu.magisk.data.repository.MagiskRepository
import com.topjohnwu.magisk.events.OpenInappLinkEvent
import com.topjohnwu.magisk.events.dialog.EnvFixDialog
import com.topjohnwu.magisk.events.dialog.ManagerInstallDialog
import com.topjohnwu.magisk.events.dialog.UninstallDialog
import com.topjohnwu.magisk.ktx.await
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.OpenInappLinkEvent
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.model.internal.DownloadSubject.Manager
import com.topjohnwu.magisk.utils.set
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.launch

View File

@ -5,7 +5,7 @@ import androidx.lifecycle.viewModelScope
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseUIFragment
import com.topjohnwu.magisk.databinding.FragmentInstallMd2Binding
import com.topjohnwu.magisk.model.events.RequestFileEvent
import com.topjohnwu.magisk.events.RequestFileEvent
import org.koin.androidx.viewmodel.ext.android.viewModel
class InstallFragment : BaseUIFragment<InstallViewModel, FragmentInstallMd2Binding>() {

View File

@ -11,10 +11,10 @@ import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.download.DownloadService
import com.topjohnwu.magisk.core.download.RemoteFileService
import com.topjohnwu.magisk.data.repository.StringRepository
import com.topjohnwu.magisk.model.entity.internal.Configuration
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.model.events.RequestFileEvent
import com.topjohnwu.magisk.model.events.dialog.SecondSlotWarningDialog
import com.topjohnwu.magisk.events.RequestFileEvent
import com.topjohnwu.magisk.events.dialog.SecondSlotWarningDialog
import com.topjohnwu.magisk.model.internal.Configuration
import com.topjohnwu.magisk.model.internal.DownloadSubject
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.utils.set
import com.topjohnwu.superuser.Shell

View File

@ -1,15 +1,15 @@
package com.topjohnwu.magisk.model.entity.recycler
package com.topjohnwu.magisk.ui.log
import androidx.databinding.Bindable
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.model.su.SuLog
import com.topjohnwu.magisk.databinding.ObservableItem
import com.topjohnwu.magisk.ktx.timeDateFormat
import com.topjohnwu.magisk.ktx.toTime
import com.topjohnwu.magisk.model.entity.MagiskLog
import com.topjohnwu.magisk.utils.set
class LogItem(val item: MagiskLog) : ObservableItem<LogItem>() {
class LogRvItem(val item: SuLog) : ObservableItem<LogRvItem>() {
override val layoutRes = R.layout.item_log_access_md2
@ -23,9 +23,9 @@ class LogItem(val item: MagiskLog) : ObservableItem<LogItem>() {
var isBottom = false
set(value) = set(value, field, { field = it }, BR.bottom)
override fun itemSameAs(other: LogItem) = item.appName == other.item.appName
override fun itemSameAs(other: LogRvItem) = item.appName == other.item.appName
override fun contentSameAs(other: LogItem) = item.fromUid == other.item.fromUid &&
override fun contentSameAs(other: LogRvItem) = item.fromUid == other.item.fromUid &&
item.toUid == other.item.toUid &&
item.fromPid == other.item.fromPid &&
item.packageName == other.item.packageName &&

View File

@ -10,10 +10,9 @@ import com.topjohnwu.magisk.arch.itemBindingOf
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.data.repository.LogRepository
import com.topjohnwu.magisk.model.entity.recycler.LogItem
import com.topjohnwu.magisk.model.entity.recycler.TextItem
import com.topjohnwu.magisk.model.events.SnackbarEvent
import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.utils.set
import com.topjohnwu.magisk.view.TextItem
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@ -34,8 +33,8 @@ class LogViewModel(
// --- su log
val items = diffListOf<LogItem>()
val itemBinding = itemBindingOf<LogItem> {
val items = diffListOf<LogRvItem>()
val itemBinding = itemBindingOf<LogRvItem> {
it.bindExtra(BR.viewModel, this)
}
@ -47,7 +46,7 @@ class LogViewModel(
override fun refresh() = viewModelScope.launch {
consoleText = repo.fetchMagiskLogs()
val (suLogs, diff) = withContext(Dispatchers.Default) {
val suLogs = repo.fetchSuLogs().map { LogItem(it) }
val suLogs = repo.fetchSuLogs().map { LogRvItem(it) }
suLogs to items.calculateDiff(suLogs)
}
items.firstOrNull()?.isTop = false

View File

@ -13,8 +13,8 @@ import com.topjohnwu.magisk.arch.BaseUIFragment
import com.topjohnwu.magisk.arch.ReselectionTarget
import com.topjohnwu.magisk.arch.ViewEvent
import com.topjohnwu.magisk.databinding.FragmentModuleMd2Binding
import com.topjohnwu.magisk.events.InstallExternalModuleEvent
import com.topjohnwu.magisk.ktx.hideKeyboard
import com.topjohnwu.magisk.model.events.InstallExternalModuleEvent
import com.topjohnwu.magisk.ui.MainActivity
import com.topjohnwu.magisk.utils.EndlessRecyclerScrollListener
import com.topjohnwu.magisk.utils.MotionRevealHelper

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.entity.recycler
package com.topjohnwu.magisk.ui.module
import androidx.databinding.Bindable
import com.topjohnwu.magisk.BR
@ -7,7 +7,6 @@ import com.topjohnwu.magisk.core.model.module.Module
import com.topjohnwu.magisk.core.model.module.Repo
import com.topjohnwu.magisk.databinding.ComparableRvItem
import com.topjohnwu.magisk.databinding.ObservableItem
import com.topjohnwu.magisk.ui.module.ModuleViewModel
import com.topjohnwu.magisk.utils.set
object InstallModule : ComparableRvItem<InstallModule>() {

View File

@ -14,16 +14,12 @@ import com.topjohnwu.magisk.core.tasks.RepoUpdater
import com.topjohnwu.magisk.data.database.RepoByNameDao
import com.topjohnwu.magisk.data.database.RepoByUpdatedDao
import com.topjohnwu.magisk.databinding.RvItem
import com.topjohnwu.magisk.events.InstallExternalModuleEvent
import com.topjohnwu.magisk.events.OpenChangelogEvent
import com.topjohnwu.magisk.events.dialog.ModuleInstallDialog
import com.topjohnwu.magisk.ktx.addOnListChangedCallback
import com.topjohnwu.magisk.ktx.reboot
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.model.entity.recycler.InstallModule
import com.topjohnwu.magisk.model.entity.recycler.ModuleItem
import com.topjohnwu.magisk.model.entity.recycler.RepoItem
import com.topjohnwu.magisk.model.entity.recycler.SectionTitle
import com.topjohnwu.magisk.model.events.InstallExternalModuleEvent
import com.topjohnwu.magisk.model.events.OpenChangelogEvent
import com.topjohnwu.magisk.model.events.dialog.ModuleInstallDialog
import com.topjohnwu.magisk.model.internal.DownloadSubject
import com.topjohnwu.magisk.utils.EndlessRecyclerScrollListener
import com.topjohnwu.magisk.utils.set
import kotlinx.coroutines.Dispatchers

View File

@ -1,23 +1,14 @@
package com.topjohnwu.magisk.model.events
package com.topjohnwu.magisk.ui.safetynet
import android.app.Activity
import android.content.Context
import android.content.Intent
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.ActivityExecutor
import com.topjohnwu.magisk.arch.ContextExecutor
import com.topjohnwu.magisk.arch.ViewEvent
import com.topjohnwu.magisk.arch.ViewEventWithScope
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.base.BaseActivity
import com.topjohnwu.magisk.core.model.module.Repo
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.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.CancellationException
@ -32,6 +23,7 @@ import java.io.File
import java.io.IOException
import java.lang.reflect.InvocationHandler
@Suppress("DEPRECATION")
class CheckSafetyNetEvent(
private val callback: (SafetyNetResult) -> Unit = {}
) : ViewEventWithScope(), ContextExecutor, KoinComponent, SafetyNetHelper.Callback {
@ -78,8 +70,10 @@ class CheckSafetyNetEvent(
val helper = helperClass
.getMethod("get", Class::class.java, Context::class.java, Any::class.java)
.invoke(null, SafetyNetHelper::class.java,
context, this@CheckSafetyNetEvent) as SafetyNetHelper
.invoke(
null, SafetyNetHelper::class.java,
context, this@CheckSafetyNetEvent
) as SafetyNetHelper
if (helper.version < Const.SNET_EXT_VER)
throw Exception()
@ -136,66 +130,3 @@ class CheckSafetyNetEvent(
callback(SafetyNetResult(response))
}
}
class ViewActionEvent(val action: BaseActivity.() -> Unit) : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseActivity) = action(activity)
}
class OpenChangelogEvent(val item: Repo) : ViewEventWithScope(), ContextExecutor {
override fun invoke(context: Context) {
scope.launch {
MarkDownWindow.show(context, null, item::readme)
}
}
}
class PermissionEvent(
private val permissions: List<String>,
private val callback: (Boolean) -> Unit
) : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseActivity) =
activity.withPermissions(*permissions.toTypedArray()) {
onSuccess {
callback(true)
}
onFailure {
callback(false)
}
}
}
class BackPressEvent : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseActivity) {
activity.onBackPressed()
}
}
class DieEvent : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseActivity) {
activity.finish()
}
}
class RecreateEvent : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseActivity) {
activity.recreate()
}
}
class RequestFileEvent : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseActivity) {
Intent(Intent.ACTION_GET_CONTENT)
.setType("*/*")
.addCategory(Intent.CATEGORY_OPENABLE)
.also { activity.startActivityForResult(it, REQUEST_CODE) }
}
companion object {
private const val REQUEST_CODE = 10
fun resolve(requestCode: Int, resultCode: Int, data: Intent?) = data
?.takeIf { resultCode == Activity.RESULT_OK }
?.takeIf { requestCode == REQUEST_CODE }
?.data
}
}

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.core.utils
package com.topjohnwu.magisk.ui.safetynet
import org.json.JSONObject

View File

@ -4,7 +4,6 @@ import androidx.databinding.Bindable
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseViewModel
import com.topjohnwu.magisk.model.events.CheckSafetyNetEvent
import com.topjohnwu.magisk.ui.safetynet.SafetyNetState.*
import com.topjohnwu.magisk.utils.set
import org.json.JSONObject
@ -54,7 +53,7 @@ class SafetynetViewModel : BaseViewModel() {
private fun attest() {
currentState = LOADING
CheckSafetyNetEvent() {
CheckSafetyNetEvent {
resolveResponse(it)
}.publish()
}

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.entity.recycler
package com.topjohnwu.magisk.ui.settings
import android.content.Context
import android.content.res.Resources
@ -16,7 +16,7 @@ import com.topjohnwu.magisk.view.MagiskDialog
import org.koin.core.KoinComponent
import org.koin.core.get
sealed class SettingsItem : ObservableItem<SettingsItem>() {
sealed class BaseSettingsItem : ObservableItem<BaseSettingsItem>() {
override val layoutRes get() = R.layout.item_settings
@ -46,19 +46,19 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
open fun refresh() {}
override fun itemSameAs(other: SettingsItem) = this === other
override fun contentSameAs(other: SettingsItem) = itemSameAs(other)
override fun itemSameAs(other: BaseSettingsItem) = this === other
override fun contentSameAs(other: BaseSettingsItem) = itemSameAs(other)
// ---
interface Callback {
fun onItemPressed(view: View, item: SettingsItem, callback: () -> Unit = {})
fun onItemChanged(view: View, item: SettingsItem)
fun onItemPressed(view: View, item: BaseSettingsItem, callback: () -> Unit = {})
fun onItemChanged(view: View, item: BaseSettingsItem)
}
// ---
abstract class Value<T> : SettingsItem() {
abstract class Value<T> : BaseSettingsItem() {
/**
* Represents last agreed-upon value by the validation process and the user for current
@ -176,9 +176,9 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
}
abstract class Blank : SettingsItem()
abstract class Blank : BaseSettingsItem()
abstract class Section : SettingsItem() {
abstract class Section : BaseSettingsItem() {
override val layoutRes = R.layout.item_settings_section
}

View File

@ -19,7 +19,6 @@ import com.topjohnwu.magisk.databinding.DialogSettingsAppNameBinding
import com.topjohnwu.magisk.databinding.DialogSettingsDownloadPathBinding
import com.topjohnwu.magisk.databinding.DialogSettingsUpdateChannelBinding
import com.topjohnwu.magisk.ktx.get
import com.topjohnwu.magisk.model.entity.recycler.SettingsItem
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.utils.asTransitive
import com.topjohnwu.magisk.utils.set
@ -30,11 +29,11 @@ import java.io.File
// --- Customization
object Customization : SettingsItem.Section() {
object Customization : BaseSettingsItem.Section() {
override val title = R.string.settings_customization.asTransitive()
}
object Language : SettingsItem.Selector() {
object Language : BaseSettingsItem.Selector() {
override var value = -1
set(value) = setV(value, field, { field = it }) {
Config.locale = entryValues[it]
@ -56,18 +55,18 @@ object Language : SettingsItem.Selector() {
}
}
object Theme : SettingsItem.Blank() {
object Theme : BaseSettingsItem.Blank() {
override val icon = R.drawable.ic_paint
override val title = R.string.section_theme.asTransitive()
}
// --- Manager
object Manager : SettingsItem.Section() {
object Manager : BaseSettingsItem.Section() {
override val title = R.string.manager.asTransitive()
}
object ClearRepoCache : SettingsItem.Blank() {
object ClearRepoCache : BaseSettingsItem.Blank() {
override val title = R.string.settings_clear_cache_title.asTransitive()
override val description = R.string.settings_clear_cache_summary.asTransitive()
@ -76,7 +75,7 @@ object ClearRepoCache : SettingsItem.Blank() {
}
}
object Hide : SettingsItem.Input() {
object Hide : BaseSettingsItem.Input() {
override val title = R.string.settings_hide_manager_title.asTransitive()
override val description = R.string.settings_hide_manager_summary.asTransitive()
@ -99,7 +98,7 @@ object Hide : SettingsItem.Input() {
}
object Restore : SettingsItem.Blank() {
object Restore : BaseSettingsItem.Blank() {
override val title = R.string.settings_restore_manager_title.asTransitive()
override val description = R.string.settings_restore_manager_summary.asTransitive()
}
@ -108,7 +107,7 @@ object Restore : SettingsItem.Blank() {
fun HideOrRestore() =
if (get<Context>().packageName == BuildConfig.APPLICATION_ID) Hide else Restore
object DownloadPath : SettingsItem.Input() {
object DownloadPath : BaseSettingsItem.Input() {
override var value = Config.downloadPath
set(value) = setV(value, field, { field = it }) { Config.downloadPath = it }
@ -130,7 +129,7 @@ object DownloadPath : SettingsItem.Input() {
.inflate(LayoutInflater.from(context)).also { it.data = this }.root
}
object UpdateChannel : SettingsItem.Selector() {
object UpdateChannel : BaseSettingsItem.Selector() {
override var value = Config.updateChannel
set(value) = setV(value, field, { field = it }) { Config.updateChannel = it }
@ -142,7 +141,7 @@ object UpdateChannel : SettingsItem.Selector() {
override val entryValRes = R.array.value_array
}
object UpdateChannelUrl : SettingsItem.Input() {
object UpdateChannelUrl : BaseSettingsItem.Input() {
override val title = R.string.settings_update_custom.asTransitive()
override var value = Config.customChannelUrl
set(value) = setV(value, field, { field = it }) { Config.customChannelUrl = it }
@ -162,7 +161,7 @@ object UpdateChannelUrl : SettingsItem.Input() {
.inflate(LayoutInflater.from(context)).also { it.data = this }.root
}
object UpdateChecker : SettingsItem.Toggle() {
object UpdateChecker : BaseSettingsItem.Toggle() {
override val title = R.string.settings_check_update_title.asTransitive()
override val description = R.string.settings_check_update_summary.asTransitive()
override var value = Config.checkUpdate
@ -173,12 +172,12 @@ object UpdateChecker : SettingsItem.Toggle() {
}
// check whether is module already installed beforehand?
object SystemlessHosts : SettingsItem.Blank() {
object SystemlessHosts : BaseSettingsItem.Blank() {
override val title = R.string.settings_hosts_title.asTransitive()
override val description = R.string.settings_hosts_summary.asTransitive()
}
object Biometrics : SettingsItem.Toggle() {
object Biometrics : BaseSettingsItem.Toggle() {
override val title = R.string.settings_su_biometric_title.asTransitive()
override var value = Config.suBiometric
set(value) = setV(value, field, { field = it }) { Config.suBiometric = it }
@ -193,7 +192,7 @@ object Biometrics : SettingsItem.Toggle() {
}
}
object Reauthenticate : SettingsItem.Toggle() {
object Reauthenticate : BaseSettingsItem.Toggle() {
override val title = R.string.settings_su_reauth_title.asTransitive()
override val description = R.string.settings_su_reauth_summary.asTransitive()
override var value = Config.suReAuth
@ -206,11 +205,11 @@ object Reauthenticate : SettingsItem.Toggle() {
// --- Magisk
object Magisk : SettingsItem.Section() {
object Magisk : BaseSettingsItem.Section() {
override val title = R.string.magisk.asTransitive()
}
object MagiskHide : SettingsItem.Toggle() {
object MagiskHide : BaseSettingsItem.Toggle() {
override val title = R.string.magiskhide.asTransitive()
override val description = R.string.settings_magiskhide_summary.asTransitive()
override var value = Config.magiskHide
@ -225,11 +224,11 @@ object MagiskHide : SettingsItem.Toggle() {
// --- Superuser
object Superuser : SettingsItem.Section() {
object Superuser : BaseSettingsItem.Section() {
override val title = R.string.superuser.asTransitive()
}
object AccessMode : SettingsItem.Selector() {
object AccessMode : BaseSettingsItem.Selector() {
override val title = R.string.superuser_access.asTransitive()
override val entryRes = R.array.su_access
override val entryValRes = R.array.value_array
@ -240,7 +239,7 @@ object AccessMode : SettingsItem.Selector() {
}
}
object MultiuserMode : SettingsItem.Selector() {
object MultiuserMode : BaseSettingsItem.Selector() {
override val title = R.string.multiuser_mode.asTransitive()
override val entryRes = R.array.multiuser_mode
override val entryValRes = R.array.value_array
@ -258,7 +257,7 @@ object MultiuserMode : SettingsItem.Selector() {
}
}
object MountNamespaceMode : SettingsItem.Selector() {
object MountNamespaceMode : BaseSettingsItem.Selector() {
override val title = R.string.mount_namespace_mode.asTransitive()
override val entryRes = R.array.namespace
override val entryValRes = R.array.value_array
@ -272,7 +271,7 @@ object MountNamespaceMode : SettingsItem.Selector() {
get() = resources.getStringArray(R.array.namespace_summary)[value].asTransitive()
}
object AutomaticResponse : SettingsItem.Selector() {
object AutomaticResponse : BaseSettingsItem.Selector() {
override val title = R.string.auto_response.asTransitive()
override val entryRes = R.array.auto_response
override val entryValRes = R.array.value_array
@ -283,7 +282,7 @@ object AutomaticResponse : SettingsItem.Selector() {
}
}
object RequestTimeout : SettingsItem.Selector() {
object RequestTimeout : BaseSettingsItem.Selector() {
override val title = R.string.request_timeout.asTransitive()
override val entryRes = R.array.request_timeout
override val entryValRes = R.array.request_timeout_value
@ -297,7 +296,7 @@ object RequestTimeout : SettingsItem.Selector() {
get() = entryValues.indexOfFirst { it.toInt() == Config.suDefaultTimeout }
}
object SUNotification : SettingsItem.Selector() {
object SUNotification : BaseSettingsItem.Selector() {
override val title = R.string.superuser_notification.asTransitive()
override val entryRes = R.array.su_notification
override val entryValRes = R.array.value_array

View File

@ -15,11 +15,10 @@ import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.download.DownloadService
import com.topjohnwu.magisk.core.utils.PatchAPK
import com.topjohnwu.magisk.data.database.RepoDao
import com.topjohnwu.magisk.model.entity.internal.Configuration
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.model.entity.recycler.SettingsItem
import com.topjohnwu.magisk.model.events.RecreateEvent
import com.topjohnwu.magisk.model.events.dialog.BiometricDialog
import com.topjohnwu.magisk.events.RecreateEvent
import com.topjohnwu.magisk.events.dialog.BiometricDialog
import com.topjohnwu.magisk.model.internal.Configuration
import com.topjohnwu.magisk.model.internal.DownloadSubject
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.launch
@ -27,10 +26,10 @@ import org.koin.core.get
class SettingsViewModel(
private val repositoryDao: RepoDao
) : BaseViewModel(), SettingsItem.Callback {
) : BaseViewModel(), BaseSettingsItem.Callback {
val adapter = adapterOf<SettingsItem>()
val itemBinding = itemBindingOf<SettingsItem> { it.bindExtra(BR.callback, this) }
val adapter = adapterOf<BaseSettingsItem>()
val itemBinding = itemBindingOf<BaseSettingsItem> { it.bindExtra(BR.callback, this) }
val items = diffListOf(createItems())
init {
@ -39,7 +38,7 @@ class SettingsViewModel(
}
}
private fun createItems(): List<SettingsItem> {
private fun createItems(): List<BaseSettingsItem> {
// Customization
val list = mutableListOf(
Customization,
@ -90,7 +89,7 @@ class SettingsViewModel(
return list
}
override fun onItemPressed(view: View, item: SettingsItem, callback: () -> Unit) = when (item) {
override fun onItemPressed(view: View, item: BaseSettingsItem, callback: () -> Unit) = when (item) {
is DownloadPath -> withExternalRW(callback)
is Biometrics -> authenticate(callback)
is Theme -> SettingsFragmentDirections.actionSettingsFragmentToThemeFragment().publish()
@ -100,7 +99,7 @@ class SettingsViewModel(
else -> callback()
}
override fun onItemChanged(view: View, item: SettingsItem) = when (item) {
override fun onItemChanged(view: View, item: BaseSettingsItem) = when (item) {
is Language -> RecreateEvent().publish()
is UpdateChannel -> openUrlIfNecessary(view)
is Hide -> PatchAPK.hideManager(view.context, item.value)

View File

@ -1,19 +1,18 @@
package com.topjohnwu.magisk.model.entity.recycler
package com.topjohnwu.magisk.ui.superuser
import android.graphics.drawable.Drawable
import androidx.databinding.Bindable
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.model.MagiskPolicy
import com.topjohnwu.magisk.core.model.su.SuPolicy
import com.topjohnwu.magisk.databinding.ObservableItem
import com.topjohnwu.magisk.ui.superuser.SuperuserViewModel
import com.topjohnwu.magisk.utils.set
class PolicyItem(
val item: MagiskPolicy,
class PolicyRvItem(
val item: SuPolicy,
val icon: Drawable,
val viewModel: SuperuserViewModel
) : ObservableItem<PolicyItem>() {
) : ObservableItem<PolicyRvItem>() {
override val layoutRes = R.layout.item_policy_md2
@get:Bindable
@ -21,7 +20,7 @@ class PolicyItem(
set(value) = set(value, field, { field = it }, BR.expanded)
// This property hosts the policy state
var policyState = item.policy == MagiskPolicy.ALLOW
var policyState = item.policy == SuPolicy.ALLOW
set(value) = set(value, field, { field = it }, BR.enabled)
// This property binds with the UI state
@ -44,7 +43,7 @@ class PolicyItem(
private val updatedPolicy
get() = item.copy(
policy = if (policyState) MagiskPolicy.ALLOW else MagiskPolicy.DENY,
policy = if (policyState) SuPolicy.ALLOW else SuPolicy.DENY,
notification = shouldNotify,
logging = shouldLog
)
@ -65,7 +64,7 @@ class PolicyItem(
viewModel.deletePressed(this)
}
override fun contentSameAs(other: PolicyItem) = itemSameAs(other)
override fun itemSameAs(other: PolicyItem) = item.uid == other.item.uid
override fun contentSameAs(other: PolicyRvItem) = itemSameAs(other)
override fun itemSameAs(other: PolicyRvItem) = item.uid == other.item.uid
}

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.entity.recycler
package com.topjohnwu.magisk.ui.superuser
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.ComparableRvItem
@ -10,4 +10,4 @@ class SpinnerRvItem(val item: String) : ComparableRvItem<SpinnerRvItem>() {
override fun contentSameAs(other: SpinnerRvItem) = itemSameAs(other)
override fun itemSameAs(other: SpinnerRvItem) = item == other.item
}
}

View File

@ -11,16 +11,15 @@ import com.topjohnwu.magisk.arch.adapterOf
import com.topjohnwu.magisk.arch.diffListOf
import com.topjohnwu.magisk.arch.itemBindingOf
import com.topjohnwu.magisk.core.magiskdb.PolicyDao
import com.topjohnwu.magisk.core.model.MagiskPolicy
import com.topjohnwu.magisk.core.model.su.SuPolicy
import com.topjohnwu.magisk.core.utils.BiometricHelper
import com.topjohnwu.magisk.core.utils.currentLocale
import com.topjohnwu.magisk.databinding.ComparableRvItem
import com.topjohnwu.magisk.model.entity.recycler.PolicyItem
import com.topjohnwu.magisk.model.entity.recycler.TappableHeadlineItem
import com.topjohnwu.magisk.model.entity.recycler.TextItem
import com.topjohnwu.magisk.model.events.SnackbarEvent
import com.topjohnwu.magisk.model.events.dialog.BiometricDialog
import com.topjohnwu.magisk.model.events.dialog.SuperuserRevokeDialog
import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.events.dialog.BiometricDialog
import com.topjohnwu.magisk.events.dialog.SuperuserRevokeDialog
import com.topjohnwu.magisk.view.TappableHeadlineItem
import com.topjohnwu.magisk.view.TextItem
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -34,7 +33,7 @@ class SuperuserViewModel(
private val itemNoData = TextItem(R.string.superuser_policy_none)
private val itemsPolicies = diffListOf<PolicyItem>()
private val itemsPolicies = diffListOf<PolicyRvItem>()
private val itemsHelpers = ObservableArrayList<TextItem>()
val adapter = adapterOf<ComparableRvItem<*>>()
@ -52,7 +51,7 @@ class SuperuserViewModel(
state = State.LOADING
val (policies, diff) = withContext(Dispatchers.Default) {
val policies = db.fetchAll {
PolicyItem(it, it.applicationInfo.loadIcon(packageManager), this@SuperuserViewModel)
PolicyRvItem(it, it.applicationInfo.loadIcon(packageManager), this@SuperuserViewModel)
}.sortedWith(compareBy(
{ it.item.appName.toLowerCase(currentLocale) },
{ it.item.packageName }
@ -77,7 +76,7 @@ class SuperuserViewModel(
private fun hidePressed() =
SuperuserFragmentDirections.actionSuperuserFragmentToHideFragment().publish()
fun deletePressed(item: PolicyItem) {
fun deletePressed(item: PolicyRvItem) {
fun updateState() = viewModelScope.launch {
db.delete(item.item.uid)
itemsPolicies.removeAll { it.genericItemSameAs(item) }
@ -100,7 +99,7 @@ class SuperuserViewModel(
//---
fun updatePolicy(policy: MagiskPolicy, isLogging: Boolean) = viewModelScope.launch {
fun updatePolicy(policy: SuPolicy, isLogging: Boolean) = viewModelScope.launch {
db.update(policy)
val str = when {
isLogging -> when {
@ -115,16 +114,16 @@ class SuperuserViewModel(
SnackbarEvent(resources.getString(str, policy.appName)).publish()
}
fun togglePolicy(item: PolicyItem, enable: Boolean) {
fun togglePolicy(item: PolicyRvItem, enable: Boolean) {
fun updateState() {
item.policyState = enable
val policy = if (enable) MagiskPolicy.ALLOW else MagiskPolicy.DENY
val policy = if (enable) SuPolicy.ALLOW else SuPolicy.DENY
val app = item.item.copy(policy = policy)
viewModelScope.launch {
db.update(app)
val res = if (app.policy == MagiskPolicy.ALLOW) R.string.su_snack_grant
val res = if (app.policy == SuPolicy.ALLOW) R.string.su_snack_grant
else R.string.su_snack_deny
SnackbarEvent(resources.getString(res).format(item.item.appName)).publish()
}

View File

@ -13,12 +13,12 @@ import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseViewModel
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.magiskdb.PolicyDao
import com.topjohnwu.magisk.core.model.MagiskPolicy.Companion.ALLOW
import com.topjohnwu.magisk.core.model.MagiskPolicy.Companion.DENY
import com.topjohnwu.magisk.core.model.su.SuPolicy.Companion.ALLOW
import com.topjohnwu.magisk.core.model.su.SuPolicy.Companion.DENY
import com.topjohnwu.magisk.core.su.SuRequestHandler
import com.topjohnwu.magisk.core.utils.BiometricHelper
import com.topjohnwu.magisk.model.entity.recycler.SpinnerRvItem
import com.topjohnwu.magisk.model.events.DieEvent
import com.topjohnwu.magisk.events.DieEvent
import com.topjohnwu.magisk.ui.superuser.SpinnerRvItem
import com.topjohnwu.magisk.utils.set
import com.topjohnwu.superuser.internal.UiThreadHandler
import kotlinx.coroutines.launch

View File

@ -1,9 +1,9 @@
package com.topjohnwu.magisk.ui.theme
import com.topjohnwu.magisk.arch.BaseViewModel
import com.topjohnwu.magisk.model.entity.recycler.TappableHeadlineItem
import com.topjohnwu.magisk.model.events.RecreateEvent
import com.topjohnwu.magisk.model.events.dialog.DarkThemeDialog
import com.topjohnwu.magisk.events.RecreateEvent
import com.topjohnwu.magisk.events.dialog.DarkThemeDialog
import com.topjohnwu.magisk.view.TappableHeadlineItem
class ThemeViewModel : BaseViewModel(), TappableHeadlineItem.Listener {

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.entity.recycler
package com.topjohnwu.magisk.view
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.ComparableRvItem

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.entity.recycler
package com.topjohnwu.magisk.view
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.ComparableRvItem

View File

@ -9,7 +9,7 @@
<import type="com.topjohnwu.magisk.ui.home.MagiskState" />
<import type="com.topjohnwu.magisk.model.entity.DeveloperItem"/>
<import type="com.topjohnwu.magisk.ui.home.DeveloperItem"/>
<variable
name="viewModel"

View File

@ -6,7 +6,7 @@
<variable
name="item"
type="com.topjohnwu.magisk.model.entity.recycler.ConsoleItem" />
type="com.topjohnwu.magisk.ui.flash.ConsoleItem" />
</data>

View File

@ -7,7 +7,7 @@
<variable
name="item"
type="com.topjohnwu.magisk.model.entity.DeveloperItem" />
type="com.topjohnwu.magisk.ui.home.DeveloperItem" />
<variable
name="viewModel"

View File

@ -9,7 +9,7 @@
<variable
name="item"
type="com.topjohnwu.magisk.model.entity.recycler.HideItem" />
type="com.topjohnwu.magisk.ui.hide.HideItem" />
<variable
name="viewModel"

View File

@ -7,7 +7,7 @@
<variable
name="item"
type="com.topjohnwu.magisk.model.entity.recycler.HideProcessItem" />
type="com.topjohnwu.magisk.ui.hide.HideProcessItem" />
<variable
name="viewModel"

View File

@ -7,7 +7,7 @@
<variable
name="item"
type="com.topjohnwu.magisk.model.entity.IconLink" />
type="com.topjohnwu.magisk.ui.home.IconLink" />
<variable
name="viewModel"

View File

@ -9,7 +9,7 @@
<variable
name="item"
type="com.topjohnwu.magisk.model.entity.recycler.LogItem" />
type="com.topjohnwu.magisk.ui.log.LogRvItem" />
<variable
name="viewModel"

View File

@ -6,7 +6,7 @@
<variable
name="item"
type="com.topjohnwu.magisk.model.entity.recycler.InstallModule" />
type="com.topjohnwu.magisk.ui.module.InstallModule" />
<variable
name="viewModel"

View File

@ -11,7 +11,7 @@
<variable
name="item"
type="com.topjohnwu.magisk.model.entity.recycler.ModuleItem" />
type="com.topjohnwu.magisk.ui.module.ModuleItem" />
<variable
name="viewModel"

View File

@ -7,7 +7,7 @@
<variable
name="item"
type="com.topjohnwu.magisk.model.entity.recycler.PolicyItem" />
type="com.topjohnwu.magisk.ui.superuser.PolicyRvItem" />
</data>

View File

@ -9,7 +9,7 @@
<variable
name="item"
type="com.topjohnwu.magisk.model.entity.recycler.RepoItem" />
type="com.topjohnwu.magisk.ui.module.RepoItem" />
<variable
name="viewModel"

View File

@ -7,7 +7,7 @@
<variable
name="item"
type="com.topjohnwu.magisk.model.entity.recycler.SectionTitle" />
type="com.topjohnwu.magisk.ui.module.SectionTitle" />
<variable
name="viewModel"

View File

@ -7,11 +7,11 @@
<variable
name="item"
type="com.topjohnwu.magisk.model.entity.recycler.SettingsItem" />
type="com.topjohnwu.magisk.ui.settings.BaseSettingsItem" />
<variable
name="callback"
type="com.topjohnwu.magisk.model.entity.recycler.SettingsItem.Callback" />
type="com.topjohnwu.magisk.ui.settings.BaseSettingsItem.Callback" />
</data>

View File

@ -6,7 +6,7 @@
<variable
name="item"
type="com.topjohnwu.magisk.model.entity.recycler.SettingsItem" />
type="com.topjohnwu.magisk.ui.settings.BaseSettingsItem" />
</data>

View File

@ -6,7 +6,7 @@
<variable
name="item"
type="com.topjohnwu.magisk.model.entity.recycler.SpinnerRvItem" />
type="com.topjohnwu.magisk.ui.superuser.SpinnerRvItem" />
</data>
@ -25,4 +25,4 @@
android:textAlignment="inherit"
tools:text="Forever" />
</layout>
</layout>

View File

@ -7,11 +7,11 @@
<variable
name="item"
type="com.topjohnwu.magisk.model.entity.recycler.TappableHeadlineItem" />
type="com.topjohnwu.magisk.view.TappableHeadlineItem" />
<variable
name="listener"
type="com.topjohnwu.magisk.model.entity.recycler.TappableHeadlineItem.Listener" />
type="com.topjohnwu.magisk.view.TappableHeadlineItem.Listener" />
</data>

View File

@ -6,7 +6,7 @@
<variable
name="item"
type="com.topjohnwu.magisk.model.entity.recycler.TextItem" />
type="com.topjohnwu.magisk.view.TextItem" />
</data>
@ -19,4 +19,4 @@
android:textAppearance="@style/AppearanceFoundation.Tiny.Variant"
tools:text="@tools:sample/lorem/random" />
</layout>
</layout>