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.* { *; } -keep class a.* { *; }
# Snet # Snet
-keepclassmembers class com.topjohnwu.magisk.core.utils.SafetyNetHelper { *; } -keepclassmembers class com.topjohnwu.magisk.ui.safetynet.SafetyNetHelper { *; }
-keep,allowobfuscation interface com.topjohnwu.magisk.core.utils.SafetyNetHelper$Callback -keep,allowobfuscation interface com.topjohnwu.magisk.ui.safetynet.SafetyNetHelper$Callback
-keepclassmembers class * implements com.topjohnwu.magisk.core.utils.SafetyNetHelper$Callback { -keepclassmembers class * implements com.topjohnwu.magisk.ui.safetynet.SafetyNetHelper$Callback {
void onResponse(int); void onResponse(int);
} }

View File

@ -15,10 +15,10 @@ import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Info import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.base.BaseActivity import com.topjohnwu.magisk.core.base.BaseActivity
import com.topjohnwu.magisk.model.events.BackPressEvent import com.topjohnwu.magisk.events.BackPressEvent
import com.topjohnwu.magisk.model.events.PermissionEvent import com.topjohnwu.magisk.events.PermissionEvent
import com.topjohnwu.magisk.model.events.SnackbarEvent import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.model.events.ViewActionEvent import com.topjohnwu.magisk.events.ViewActionEvent
import com.topjohnwu.magisk.model.navigation.NavigationWrapper import com.topjohnwu.magisk.model.navigation.NavigationWrapper
import com.topjohnwu.magisk.utils.ObservableHost import com.topjohnwu.magisk.utils.ObservableHost
import com.topjohnwu.magisk.utils.set 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.model.ManagerJson
import com.topjohnwu.magisk.core.su.SuCallbackHandler import com.topjohnwu.magisk.core.su.SuCallbackHandler
import com.topjohnwu.magisk.ktx.reboot import com.topjohnwu.magisk.ktx.reboot
import com.topjohnwu.magisk.model.entity.internal.Configuration import com.topjohnwu.magisk.model.internal.Configuration
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.model.internal.DownloadSubject
import com.topjohnwu.magisk.view.Shortcuts import com.topjohnwu.magisk.view.Shortcuts
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.GlobalScope 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.chooser
import com.topjohnwu.magisk.ktx.exists import com.topjohnwu.magisk.ktx.exists
import com.topjohnwu.magisk.ktx.provide import com.topjohnwu.magisk.ktx.provide
import com.topjohnwu.magisk.model.entity.internal.Configuration.* import com.topjohnwu.magisk.model.internal.Configuration.*
import com.topjohnwu.magisk.model.entity.internal.Configuration.Flash.Secondary import com.topjohnwu.magisk.model.internal.Configuration.Flash.Secondary
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.model.internal.DownloadSubject
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.* import com.topjohnwu.magisk.model.internal.DownloadSubject.*
import com.topjohnwu.magisk.ui.flash.FlashFragment import com.topjohnwu.magisk.ui.flash.FlashFragment
import com.topjohnwu.magisk.utils.APKInstall import com.topjohnwu.magisk.utils.APKInstall
import org.koin.core.get 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.isRunningAsStub
import com.topjohnwu.magisk.core.utils.PatchAPK import com.topjohnwu.magisk.core.utils.PatchAPK
import com.topjohnwu.magisk.ktx.writeTo import com.topjohnwu.magisk.ktx.writeTo
import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Restore import com.topjohnwu.magisk.model.internal.Configuration.APK.Restore
import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Upgrade import com.topjohnwu.magisk.model.internal.Configuration.APK.Upgrade
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.model.internal.DownloadSubject
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import java.io.File 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.data.network.GithubRawServices
import com.topjohnwu.magisk.ktx.checkSum import com.topjohnwu.magisk.ktx.checkSum
import com.topjohnwu.magisk.ktx.writeTo import com.topjohnwu.magisk.ktx.writeTo
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.model.internal.DownloadSubject
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.Magisk import com.topjohnwu.magisk.model.internal.DownloadSubject.Magisk
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.Module import com.topjohnwu.magisk.model.internal.DownloadSubject.Module
import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.magisk.view.Notifications
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import okhttp3.ResponseBody import okhttp3.ResponseBody

View File

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

View File

@ -59,6 +59,6 @@ data class Repo(
class IllegalRepoException(message: String) : Exception(message) class IllegalRepoException(message: String) : Exception(message)
companion object { 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.Entity
import androidx.room.Ignore import androidx.room.Ignore
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import com.topjohnwu.magisk.core.model.MagiskPolicy import com.topjohnwu.magisk.core.model.su.SuPolicy.Companion.ALLOW
import com.topjohnwu.magisk.core.model.MagiskPolicy.Companion.ALLOW
import com.topjohnwu.magisk.ktx.now import com.topjohnwu.magisk.ktx.now
import com.topjohnwu.magisk.ktx.timeFormatTime import com.topjohnwu.magisk.ktx.timeFormatTime
import com.topjohnwu.magisk.ktx.toTime import com.topjohnwu.magisk.ktx.toTime
@Entity(tableName = "logs") @Entity(tableName = "logs")
data class MagiskLog( data class SuLog(
val fromUid: Int, val fromUid: Int,
val toUid: Int, val toUid: Int,
val fromPid: Int, val fromPid: Int,
@ -24,8 +23,8 @@ data class MagiskLog(
@Ignore val timeString = time.toTime(timeFormatTime) @Ignore val timeString = time.toTime(timeFormatTime)
} }
fun MagiskPolicy.toLog( fun SuPolicy.toLog(
toUid: Int, toUid: Int,
fromPid: Int, fromPid: Int,
command: String 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.ApplicationInfo
import android.content.pm.PackageManager 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 import com.topjohnwu.magisk.ktx.getLabel
data class MagiskPolicy( data class SuPolicy(
var uid: Int, var uid: Int,
val packageName: String, val packageName: String,
val appName: String, val appName: String,
@ -25,7 +25,7 @@ data class MagiskPolicy(
} }
fun MagiskPolicy.toMap() = mapOf( fun SuPolicy.toMap() = mapOf(
"uid" to uid, "uid" to uid,
"package_name" to packageName, "package_name" to packageName,
"policy" to policy, "policy" to policy,
@ -35,7 +35,7 @@ fun MagiskPolicy.toMap() = mapOf(
) )
@Throws(PackageManager.NameNotFoundException::class) @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 uid = get("uid")?.toIntOrNull() ?: -1
val packageName = get("package_name").orEmpty() val packageName = get("package_name").orEmpty()
val info = pm.getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES) 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) if (info.uid != uid)
throw PackageManager.NameNotFoundException() throw PackageManager.NameNotFoundException()
return MagiskPolicy( return SuPolicy(
uid = uid, uid = uid,
packageName = packageName, packageName = packageName,
policy = get("policy")?.toIntOrNull() ?: INTERACTIVE, policy = get("policy")?.toIntOrNull() ?: INTERACTIVE,
@ -56,11 +56,11 @@ fun Map<String, String>.toPolicy(pm: PackageManager): MagiskPolicy {
} }
@Throws(PackageManager.NameNotFoundException::class) @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() val pkg = pm.getPackagesForUid(this)?.firstOrNull()
?: throw PackageManager.NameNotFoundException() ?: throw PackageManager.NameNotFoundException()
val info = pm.getApplicationInfo(pkg, PackageManager.GET_UNINSTALLED_PACKAGES) val info = pm.getApplicationInfo(pkg, PackageManager.GET_UNINSTALLED_PACKAGES)
return MagiskPolicy( return SuPolicy(
uid = info.uid, uid = info.uid,
packageName = pkg, packageName = pkg,
policy = policy, policy = policy,

View File

@ -11,14 +11,14 @@ import com.topjohnwu.magisk.ProviderCallHandler
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Config import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.intent import com.topjohnwu.magisk.core.intent
import com.topjohnwu.magisk.core.model.MagiskPolicy import com.topjohnwu.magisk.core.model.su.SuPolicy
import com.topjohnwu.magisk.core.model.toPolicy 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.core.wrap
import com.topjohnwu.magisk.data.repository.LogRepository import com.topjohnwu.magisk.data.repository.LogRepository
import com.topjohnwu.magisk.ktx.get import com.topjohnwu.magisk.ktx.get
import com.topjohnwu.magisk.ktx.startActivity import com.topjohnwu.magisk.ktx.startActivity
import com.topjohnwu.magisk.ktx.startActivityWithRoot import com.topjohnwu.magisk.ktx.startActivityWithRoot
import com.topjohnwu.magisk.model.entity.toLog
import com.topjohnwu.magisk.ui.surequest.SuRequestActivity import com.topjohnwu.magisk.ui.surequest.SuRequestActivity
import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.superuser.Shell 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) { 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 R.string.su_allow_toast
else else
R.string.su_deny_toast 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.Config
import com.topjohnwu.magisk.core.Const import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.magiskdb.PolicyDao 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.model.toPolicy import com.topjohnwu.magisk.core.model.su.toPolicy
import com.topjohnwu.magisk.ktx.now import com.topjohnwu.magisk.ktx.now
import kotlinx.coroutines.* import kotlinx.coroutines.*
import timber.log.Timber import timber.log.Timber
@ -27,7 +27,7 @@ abstract class SuRequestHandler(
private lateinit var output: DataOutputStream private lateinit var output: DataOutputStream
private lateinit var input: DataInputStream private lateinit var input: DataInputStream
protected lateinit var policy: MagiskPolicy protected lateinit var policy: SuPolicy
private set private set
abstract fun onStart() abstract fun onStart()
@ -44,11 +44,11 @@ abstract class SuRequestHandler(
when (Config.suAutoReponse) { when (Config.suAutoReponse) {
Config.Value.SU_AUTO_DENY -> { Config.Value.SU_AUTO_DENY -> {
respond(MagiskPolicy.DENY, 0) respond(SuPolicy.DENY, 0)
return true return true
} }
Config.Value.SU_AUTO_ALLOW -> { Config.Value.SU_AUTO_ALLOW -> {
respond(MagiskPolicy.ALLOW, 0) respond(SuPolicy.ALLOW, 0)
return true return true
} }
} }

View File

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

View File

@ -1,12 +1,12 @@
package com.topjohnwu.magisk.data.database package com.topjohnwu.magisk.data.database
import androidx.room.* 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.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.util.* import java.util.*
@Database(version = 1, entities = [MagiskLog::class], exportSchema = false) @Database(version = 1, entities = [SuLog::class], exportSchema = false)
abstract class SuLogDatabase : RoomDatabase() { abstract class SuLogDatabase : RoomDatabase() {
abstract fun suLogDao(): SuLogDao 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 deleteAll() = withContext(Dispatchers.IO) { db.clearAllTables() }
suspend fun fetchAll(): MutableList<MagiskLog> { suspend fun fetchAll(): MutableList<SuLog> {
deleteOutdated() deleteOutdated()
return fetch() return fetch()
} }
@Query("SELECT * FROM logs ORDER BY time DESC") @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") @Query("DELETE FROM logs WHERE time < :timeout")
protected abstract suspend fun deleteOutdated(timeout: Long = twoWeeksAgo) protected abstract suspend fun deleteOutdated(timeout: Long = twoWeeksAgo)
@Insert @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 package com.topjohnwu.magisk.data.repository
import com.topjohnwu.magisk.core.Const 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.data.database.SuLogDao
import com.topjohnwu.magisk.ktx.await import com.topjohnwu.magisk.ktx.await
import com.topjohnwu.magisk.model.entity.MagiskLog
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
@ -36,6 +36,6 @@ class LogRepository(
fun clearMagiskLogs(cb: (Shell.Result) -> Unit) = fun clearMagiskLogs(cb: (Shell.Result) -> Unit) =
Shell.su("echo -n > ${Const.MAGISK_LOG}").submit(cb) 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.await
import com.topjohnwu.magisk.ktx.getLabel import com.topjohnwu.magisk.ktx.getLabel
import com.topjohnwu.magisk.ktx.packageName import com.topjohnwu.magisk.ktx.packageName
import com.topjohnwu.magisk.model.entity.HideAppInfo import com.topjohnwu.magisk.ui.hide.HideAppInfo
import com.topjohnwu.magisk.model.entity.HideTarget import com.topjohnwu.magisk.ui.hide.HideTarget
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext

View File

@ -3,6 +3,7 @@ package com.topjohnwu.magisk.databinding
import androidx.annotation.CallSuper import androidx.annotation.CallSuper
import androidx.databinding.PropertyChangeRegistry import androidx.databinding.PropertyChangeRegistry
import androidx.databinding.ViewDataBinding import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.RecyclerView
import com.topjohnwu.magisk.BR import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.utils.DiffObservableList import com.topjohnwu.magisk.utils.DiffObservableList
import com.topjohnwu.magisk.utils.ObservableHost import com.topjohnwu.magisk.utils.ObservableHost
@ -52,3 +53,13 @@ abstract class ComparableRvItem<in T> : RvItem() {
abstract class ObservableItem<T> : ComparableRvItem<T>(), ObservableHost { abstract class ObservableItem<T> : ComparableRvItem<T>(), ObservableHost {
override var callbacks: PropertyChangeRegistry? = null 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.databinding.ViewDataBinding
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.topjohnwu.magisk.model.entity.recycler.LenientRvItem
import me.tatarka.bindingcollectionadapter2.BindingRecyclerViewAdapter import me.tatarka.bindingcollectionadapter2.BindingRecyclerViewAdapter
class RvBindingAdapter<T : RvItem> : BindingRecyclerViewAdapter<T>() { class RvBindingAdapter<T : RvItem> : BindingRecyclerViewAdapter<T>() {
@ -19,7 +18,7 @@ class RvBindingAdapter<T : RvItem> : BindingRecyclerViewAdapter<T>() {
super.onBindBinding(binding, variableId, layoutRes, position, item) super.onBindBinding(binding, variableId, layoutRes, position, item)
when (item) { when (item) {
is LenientRvItem<*> -> { is LenientRvItem -> {
val recycler = recyclerView ?: return val recycler = recyclerView ?: return
item.onBindingBound(binding) item.onBindingBound(binding)
item.onBindingBound(binding, recycler) item.onBindingBound(binding, recycler)

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.events package com.topjohnwu.magisk.events
import android.Manifest import android.Manifest
import android.app.Activity 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.Context
import android.content.res.Resources 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.ContextThemeWrapper
import android.view.MenuItem 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.ActivityExecutor
import com.topjohnwu.magisk.arch.ViewEvent 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 android.app.Activity
import androidx.appcompat.app.AppCompatDelegate 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 android.content.Context
import com.topjohnwu.magisk.arch.ContextExecutor 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.BroadcastReceiver
import android.content.Context import android.content.Context
@ -7,8 +7,8 @@ import android.content.IntentFilter
import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.download.DownloadService import com.topjohnwu.magisk.core.download.DownloadService
import com.topjohnwu.magisk.model.entity.internal.Configuration.EnvFix import com.topjohnwu.magisk.model.internal.Configuration.EnvFix
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.Magisk import com.topjohnwu.magisk.model.internal.DownloadSubject.Magisk
import com.topjohnwu.magisk.view.MagiskDialog import com.topjohnwu.magisk.view.MagiskDialog
class EnvFixDialog : DialogEvent() { 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.R
import com.topjohnwu.magisk.core.Info import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.download.DownloadService import com.topjohnwu.magisk.core.download.DownloadService
import com.topjohnwu.magisk.ktx.res import com.topjohnwu.magisk.ktx.res
import com.topjohnwu.magisk.model.entity.internal.Configuration import com.topjohnwu.magisk.model.internal.Configuration
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.model.internal.DownloadSubject
import com.topjohnwu.magisk.view.MagiskDialog import com.topjohnwu.magisk.view.MagiskDialog
import com.topjohnwu.magisk.view.MarkDownWindow import com.topjohnwu.magisk.view.MarkDownWindow
import kotlinx.coroutines.Dispatchers 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.R
import com.topjohnwu.magisk.core.download.DownloadService import com.topjohnwu.magisk.core.download.DownloadService
import com.topjohnwu.magisk.core.model.module.Repo import com.topjohnwu.magisk.core.model.module.Repo
import com.topjohnwu.magisk.model.entity.internal.Configuration import com.topjohnwu.magisk.model.internal.Configuration
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.model.internal.DownloadSubject
import com.topjohnwu.magisk.view.MagiskDialog import com.topjohnwu.magisk.view.MagiskDialog
class ModuleInstallDialog(private val item: Repo) : DialogEvent() { 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.R
import com.topjohnwu.magisk.view.MagiskDialog 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.R
import com.topjohnwu.magisk.view.MagiskDialog import com.topjohnwu.magisk.view.MagiskDialog

View File

@ -1,11 +1,11 @@
package com.topjohnwu.magisk.model.events.dialog package com.topjohnwu.magisk.events.dialog
import android.widget.Toast import android.widget.Toast
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Info import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.download.DownloadService import com.topjohnwu.magisk.core.download.DownloadService
import com.topjohnwu.magisk.model.entity.internal.Configuration import com.topjohnwu.magisk.model.internal.Configuration
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.model.internal.DownloadSubject
import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.view.MagiskDialog import com.topjohnwu.magisk.view.MagiskDialog
import com.topjohnwu.superuser.Shell 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.net.Uri
import android.os.Parcelable 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.content.Context
import android.os.Parcelable 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.view.View
import android.widget.TextView import android.widget.TextView
@ -6,9 +6,11 @@ import androidx.core.view.updateLayoutParams
import androidx.databinding.ViewDataBinding import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.ComparableRvItem
import com.topjohnwu.magisk.databinding.LenientRvItem
import kotlin.math.max 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 override val layoutRes = R.layout.item_console_md2
private var parentWidth = -1 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.FlashZip
import com.topjohnwu.magisk.core.tasks.MagiskInstaller import com.topjohnwu.magisk.core.tasks.MagiskInstaller
import com.topjohnwu.magisk.databinding.RvBindingAdapter import com.topjohnwu.magisk.databinding.RvBindingAdapter
import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.ktx.* 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.utils.set
import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.superuser.CallbackList 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.content.pm.ApplicationInfo
import android.graphics.drawable.Drawable 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.View
import android.view.ViewGroup import android.view.ViewGroup
@ -7,9 +7,6 @@ import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.ObservableItem import com.topjohnwu.magisk.databinding.ObservableItem
import com.topjohnwu.magisk.ktx.startAnimations 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.addOnPropertyChangedCallback
import com.topjohnwu.magisk.utils.set import com.topjohnwu.magisk.utils.set
import kotlin.math.roundToInt 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) { 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.Config
import com.topjohnwu.magisk.core.utils.currentLocale import com.topjohnwu.magisk.core.utils.currentLocale
import com.topjohnwu.magisk.data.repository.MagiskRepository 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 com.topjohnwu.magisk.utils.set
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch 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.R
import com.topjohnwu.magisk.core.Const import com.topjohnwu.magisk.core.Const

View File

@ -5,7 +5,7 @@ import android.view.*
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseUIFragment import com.topjohnwu.magisk.arch.BaseUIFragment
import com.topjohnwu.magisk.databinding.FragmentHomeMd2Binding 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 com.topjohnwu.superuser.Shell
import org.koin.androidx.viewmodel.ext.android.viewModel 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.MagiskJson
import com.topjohnwu.magisk.core.model.ManagerJson import com.topjohnwu.magisk.core.model.ManagerJson
import com.topjohnwu.magisk.data.repository.MagiskRepository 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.await
import com.topjohnwu.magisk.ktx.packageName import com.topjohnwu.magisk.ktx.packageName
import com.topjohnwu.magisk.ktx.res import com.topjohnwu.magisk.ktx.res
import com.topjohnwu.magisk.model.entity.IconLink import com.topjohnwu.magisk.model.internal.DownloadSubject.Manager
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.utils.set import com.topjohnwu.magisk.utils.set
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.launch import kotlinx.coroutines.launch

View File

@ -5,7 +5,7 @@ import androidx.lifecycle.viewModelScope
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseUIFragment import com.topjohnwu.magisk.arch.BaseUIFragment
import com.topjohnwu.magisk.databinding.FragmentInstallMd2Binding 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 import org.koin.androidx.viewmodel.ext.android.viewModel
class InstallFragment : BaseUIFragment<InstallViewModel, FragmentInstallMd2Binding>() { 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.DownloadService
import com.topjohnwu.magisk.core.download.RemoteFileService import com.topjohnwu.magisk.core.download.RemoteFileService
import com.topjohnwu.magisk.data.repository.StringRepository import com.topjohnwu.magisk.data.repository.StringRepository
import com.topjohnwu.magisk.model.entity.internal.Configuration import com.topjohnwu.magisk.events.RequestFileEvent
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.events.dialog.SecondSlotWarningDialog
import com.topjohnwu.magisk.model.events.RequestFileEvent import com.topjohnwu.magisk.model.internal.Configuration
import com.topjohnwu.magisk.model.events.dialog.SecondSlotWarningDialog import com.topjohnwu.magisk.model.internal.DownloadSubject
import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.utils.set import com.topjohnwu.magisk.utils.set
import com.topjohnwu.superuser.Shell 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 androidx.databinding.Bindable
import com.topjohnwu.magisk.BR import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.model.su.SuLog
import com.topjohnwu.magisk.databinding.ObservableItem import com.topjohnwu.magisk.databinding.ObservableItem
import com.topjohnwu.magisk.ktx.timeDateFormat import com.topjohnwu.magisk.ktx.timeDateFormat
import com.topjohnwu.magisk.ktx.toTime import com.topjohnwu.magisk.ktx.toTime
import com.topjohnwu.magisk.model.entity.MagiskLog
import com.topjohnwu.magisk.utils.set 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 override val layoutRes = R.layout.item_log_access_md2
@ -23,9 +23,9 @@ class LogItem(val item: MagiskLog) : ObservableItem<LogItem>() {
var isBottom = false var isBottom = false
set(value) = set(value, field, { field = it }, BR.bottom) 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.toUid == other.item.toUid &&
item.fromPid == other.item.fromPid && item.fromPid == other.item.fromPid &&
item.packageName == other.item.packageName && 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.Config
import com.topjohnwu.magisk.core.Const import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.data.repository.LogRepository import com.topjohnwu.magisk.data.repository.LogRepository
import com.topjohnwu.magisk.model.entity.recycler.LogItem import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.model.entity.recycler.TextItem
import com.topjohnwu.magisk.model.events.SnackbarEvent
import com.topjohnwu.magisk.utils.set import com.topjohnwu.magisk.utils.set
import com.topjohnwu.magisk.view.TextItem
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -34,8 +33,8 @@ class LogViewModel(
// --- su log // --- su log
val items = diffListOf<LogItem>() val items = diffListOf<LogRvItem>()
val itemBinding = itemBindingOf<LogItem> { val itemBinding = itemBindingOf<LogRvItem> {
it.bindExtra(BR.viewModel, this) it.bindExtra(BR.viewModel, this)
} }
@ -47,7 +46,7 @@ class LogViewModel(
override fun refresh() = viewModelScope.launch { override fun refresh() = viewModelScope.launch {
consoleText = repo.fetchMagiskLogs() consoleText = repo.fetchMagiskLogs()
val (suLogs, diff) = withContext(Dispatchers.Default) { 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) suLogs to items.calculateDiff(suLogs)
} }
items.firstOrNull()?.isTop = false 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.ReselectionTarget
import com.topjohnwu.magisk.arch.ViewEvent import com.topjohnwu.magisk.arch.ViewEvent
import com.topjohnwu.magisk.databinding.FragmentModuleMd2Binding import com.topjohnwu.magisk.databinding.FragmentModuleMd2Binding
import com.topjohnwu.magisk.events.InstallExternalModuleEvent
import com.topjohnwu.magisk.ktx.hideKeyboard import com.topjohnwu.magisk.ktx.hideKeyboard
import com.topjohnwu.magisk.model.events.InstallExternalModuleEvent
import com.topjohnwu.magisk.ui.MainActivity import com.topjohnwu.magisk.ui.MainActivity
import com.topjohnwu.magisk.utils.EndlessRecyclerScrollListener import com.topjohnwu.magisk.utils.EndlessRecyclerScrollListener
import com.topjohnwu.magisk.utils.MotionRevealHelper 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 androidx.databinding.Bindable
import com.topjohnwu.magisk.BR 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.core.model.module.Repo
import com.topjohnwu.magisk.databinding.ComparableRvItem import com.topjohnwu.magisk.databinding.ComparableRvItem
import com.topjohnwu.magisk.databinding.ObservableItem import com.topjohnwu.magisk.databinding.ObservableItem
import com.topjohnwu.magisk.ui.module.ModuleViewModel
import com.topjohnwu.magisk.utils.set import com.topjohnwu.magisk.utils.set
object InstallModule : ComparableRvItem<InstallModule>() { 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.RepoByNameDao
import com.topjohnwu.magisk.data.database.RepoByUpdatedDao import com.topjohnwu.magisk.data.database.RepoByUpdatedDao
import com.topjohnwu.magisk.databinding.RvItem 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.addOnListChangedCallback
import com.topjohnwu.magisk.ktx.reboot import com.topjohnwu.magisk.ktx.reboot
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.model.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.utils.EndlessRecyclerScrollListener import com.topjohnwu.magisk.utils.EndlessRecyclerScrollListener
import com.topjohnwu.magisk.utils.set import com.topjohnwu.magisk.utils.set
import kotlinx.coroutines.Dispatchers 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.Context
import android.content.Intent
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.ActivityExecutor
import com.topjohnwu.magisk.arch.ContextExecutor import com.topjohnwu.magisk.arch.ContextExecutor
import com.topjohnwu.magisk.arch.ViewEvent
import com.topjohnwu.magisk.arch.ViewEventWithScope import com.topjohnwu.magisk.arch.ViewEventWithScope
import com.topjohnwu.magisk.core.Const 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.data.network.GithubRawServices
import com.topjohnwu.magisk.ktx.DynamicClassLoader import com.topjohnwu.magisk.ktx.DynamicClassLoader
import com.topjohnwu.magisk.ktx.writeTo import com.topjohnwu.magisk.ktx.writeTo
import com.topjohnwu.magisk.ui.safetynet.SafetyNetResult
import com.topjohnwu.magisk.view.MagiskDialog import com.topjohnwu.magisk.view.MagiskDialog
import com.topjohnwu.magisk.view.MarkDownWindow
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import dalvik.system.DexFile import dalvik.system.DexFile
import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CancellationException
@ -32,6 +23,7 @@ import java.io.File
import java.io.IOException import java.io.IOException
import java.lang.reflect.InvocationHandler import java.lang.reflect.InvocationHandler
@Suppress("DEPRECATION")
class CheckSafetyNetEvent( class CheckSafetyNetEvent(
private val callback: (SafetyNetResult) -> Unit = {} private val callback: (SafetyNetResult) -> Unit = {}
) : ViewEventWithScope(), ContextExecutor, KoinComponent, SafetyNetHelper.Callback { ) : ViewEventWithScope(), ContextExecutor, KoinComponent, SafetyNetHelper.Callback {
@ -78,8 +70,10 @@ class CheckSafetyNetEvent(
val helper = helperClass val helper = helperClass
.getMethod("get", Class::class.java, Context::class.java, Any::class.java) .getMethod("get", Class::class.java, Context::class.java, Any::class.java)
.invoke(null, SafetyNetHelper::class.java, .invoke(
context, this@CheckSafetyNetEvent) as SafetyNetHelper null, SafetyNetHelper::class.java,
context, this@CheckSafetyNetEvent
) as SafetyNetHelper
if (helper.version < Const.SNET_EXT_VER) if (helper.version < Const.SNET_EXT_VER)
throw Exception() throw Exception()
@ -136,66 +130,3 @@ class CheckSafetyNetEvent(
callback(SafetyNetResult(response)) 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 import org.json.JSONObject

View File

@ -4,7 +4,6 @@ import androidx.databinding.Bindable
import com.topjohnwu.magisk.BR import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseViewModel import com.topjohnwu.magisk.arch.BaseViewModel
import com.topjohnwu.magisk.model.events.CheckSafetyNetEvent
import com.topjohnwu.magisk.ui.safetynet.SafetyNetState.* import com.topjohnwu.magisk.ui.safetynet.SafetyNetState.*
import com.topjohnwu.magisk.utils.set import com.topjohnwu.magisk.utils.set
import org.json.JSONObject import org.json.JSONObject
@ -54,7 +53,7 @@ class SafetynetViewModel : BaseViewModel() {
private fun attest() { private fun attest() {
currentState = LOADING currentState = LOADING
CheckSafetyNetEvent() { CheckSafetyNetEvent {
resolveResponse(it) resolveResponse(it)
}.publish() }.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.Context
import android.content.res.Resources import android.content.res.Resources
@ -16,7 +16,7 @@ import com.topjohnwu.magisk.view.MagiskDialog
import org.koin.core.KoinComponent import org.koin.core.KoinComponent
import org.koin.core.get import org.koin.core.get
sealed class SettingsItem : ObservableItem<SettingsItem>() { sealed class BaseSettingsItem : ObservableItem<BaseSettingsItem>() {
override val layoutRes get() = R.layout.item_settings override val layoutRes get() = R.layout.item_settings
@ -46,19 +46,19 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
open fun refresh() {} open fun refresh() {}
override fun itemSameAs(other: SettingsItem) = this === other override fun itemSameAs(other: BaseSettingsItem) = this === other
override fun contentSameAs(other: SettingsItem) = itemSameAs(other) override fun contentSameAs(other: BaseSettingsItem) = itemSameAs(other)
// --- // ---
interface Callback { interface Callback {
fun onItemPressed(view: View, item: SettingsItem, callback: () -> Unit = {}) fun onItemPressed(view: View, item: BaseSettingsItem, callback: () -> Unit = {})
fun onItemChanged(view: View, item: SettingsItem) 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 * 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 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.DialogSettingsDownloadPathBinding
import com.topjohnwu.magisk.databinding.DialogSettingsUpdateChannelBinding import com.topjohnwu.magisk.databinding.DialogSettingsUpdateChannelBinding
import com.topjohnwu.magisk.ktx.get 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.Utils
import com.topjohnwu.magisk.utils.asTransitive import com.topjohnwu.magisk.utils.asTransitive
import com.topjohnwu.magisk.utils.set import com.topjohnwu.magisk.utils.set
@ -30,11 +29,11 @@ import java.io.File
// --- Customization // --- Customization
object Customization : SettingsItem.Section() { object Customization : BaseSettingsItem.Section() {
override val title = R.string.settings_customization.asTransitive() override val title = R.string.settings_customization.asTransitive()
} }
object Language : SettingsItem.Selector() { object Language : BaseSettingsItem.Selector() {
override var value = -1 override var value = -1
set(value) = setV(value, field, { field = it }) { set(value) = setV(value, field, { field = it }) {
Config.locale = entryValues[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 icon = R.drawable.ic_paint
override val title = R.string.section_theme.asTransitive() override val title = R.string.section_theme.asTransitive()
} }
// --- Manager // --- Manager
object Manager : SettingsItem.Section() { object Manager : BaseSettingsItem.Section() {
override val title = R.string.manager.asTransitive() 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 title = R.string.settings_clear_cache_title.asTransitive()
override val description = R.string.settings_clear_cache_summary.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 title = R.string.settings_hide_manager_title.asTransitive()
override val description = R.string.settings_hide_manager_summary.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 title = R.string.settings_restore_manager_title.asTransitive()
override val description = R.string.settings_restore_manager_summary.asTransitive() override val description = R.string.settings_restore_manager_summary.asTransitive()
} }
@ -108,7 +107,7 @@ object Restore : SettingsItem.Blank() {
fun HideOrRestore() = fun HideOrRestore() =
if (get<Context>().packageName == BuildConfig.APPLICATION_ID) Hide else Restore if (get<Context>().packageName == BuildConfig.APPLICATION_ID) Hide else Restore
object DownloadPath : SettingsItem.Input() { object DownloadPath : BaseSettingsItem.Input() {
override var value = Config.downloadPath override var value = Config.downloadPath
set(value) = setV(value, field, { field = it }) { Config.downloadPath = it } 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 .inflate(LayoutInflater.from(context)).also { it.data = this }.root
} }
object UpdateChannel : SettingsItem.Selector() { object UpdateChannel : BaseSettingsItem.Selector() {
override var value = Config.updateChannel override var value = Config.updateChannel
set(value) = setV(value, field, { field = it }) { Config.updateChannel = it } 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 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 val title = R.string.settings_update_custom.asTransitive()
override var value = Config.customChannelUrl override var value = Config.customChannelUrl
set(value) = setV(value, field, { field = it }) { Config.customChannelUrl = it } 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 .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 title = R.string.settings_check_update_title.asTransitive()
override val description = R.string.settings_check_update_summary.asTransitive() override val description = R.string.settings_check_update_summary.asTransitive()
override var value = Config.checkUpdate override var value = Config.checkUpdate
@ -173,12 +172,12 @@ object UpdateChecker : SettingsItem.Toggle() {
} }
// check whether is module already installed beforehand? // 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 title = R.string.settings_hosts_title.asTransitive()
override val description = R.string.settings_hosts_summary.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 val title = R.string.settings_su_biometric_title.asTransitive()
override var value = Config.suBiometric override var value = Config.suBiometric
set(value) = setV(value, field, { field = it }) { Config.suBiometric = it } 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 title = R.string.settings_su_reauth_title.asTransitive()
override val description = R.string.settings_su_reauth_summary.asTransitive() override val description = R.string.settings_su_reauth_summary.asTransitive()
override var value = Config.suReAuth override var value = Config.suReAuth
@ -206,11 +205,11 @@ object Reauthenticate : SettingsItem.Toggle() {
// --- Magisk // --- Magisk
object Magisk : SettingsItem.Section() { object Magisk : BaseSettingsItem.Section() {
override val title = R.string.magisk.asTransitive() override val title = R.string.magisk.asTransitive()
} }
object MagiskHide : SettingsItem.Toggle() { object MagiskHide : BaseSettingsItem.Toggle() {
override val title = R.string.magiskhide.asTransitive() override val title = R.string.magiskhide.asTransitive()
override val description = R.string.settings_magiskhide_summary.asTransitive() override val description = R.string.settings_magiskhide_summary.asTransitive()
override var value = Config.magiskHide override var value = Config.magiskHide
@ -225,11 +224,11 @@ object MagiskHide : SettingsItem.Toggle() {
// --- Superuser // --- Superuser
object Superuser : SettingsItem.Section() { object Superuser : BaseSettingsItem.Section() {
override val title = R.string.superuser.asTransitive() 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 title = R.string.superuser_access.asTransitive()
override val entryRes = R.array.su_access override val entryRes = R.array.su_access
override val entryValRes = R.array.value_array 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 title = R.string.multiuser_mode.asTransitive()
override val entryRes = R.array.multiuser_mode override val entryRes = R.array.multiuser_mode
override val entryValRes = R.array.value_array 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 title = R.string.mount_namespace_mode.asTransitive()
override val entryRes = R.array.namespace override val entryRes = R.array.namespace
override val entryValRes = R.array.value_array override val entryValRes = R.array.value_array
@ -272,7 +271,7 @@ object MountNamespaceMode : SettingsItem.Selector() {
get() = resources.getStringArray(R.array.namespace_summary)[value].asTransitive() 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 title = R.string.auto_response.asTransitive()
override val entryRes = R.array.auto_response override val entryRes = R.array.auto_response
override val entryValRes = R.array.value_array 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 title = R.string.request_timeout.asTransitive()
override val entryRes = R.array.request_timeout override val entryRes = R.array.request_timeout
override val entryValRes = R.array.request_timeout_value override val entryValRes = R.array.request_timeout_value
@ -297,7 +296,7 @@ object RequestTimeout : SettingsItem.Selector() {
get() = entryValues.indexOfFirst { it.toInt() == Config.suDefaultTimeout } 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 title = R.string.superuser_notification.asTransitive()
override val entryRes = R.array.su_notification override val entryRes = R.array.su_notification
override val entryValRes = R.array.value_array 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.download.DownloadService
import com.topjohnwu.magisk.core.utils.PatchAPK import com.topjohnwu.magisk.core.utils.PatchAPK
import com.topjohnwu.magisk.data.database.RepoDao import com.topjohnwu.magisk.data.database.RepoDao
import com.topjohnwu.magisk.model.entity.internal.Configuration import com.topjohnwu.magisk.events.RecreateEvent
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.events.dialog.BiometricDialog
import com.topjohnwu.magisk.model.entity.recycler.SettingsItem import com.topjohnwu.magisk.model.internal.Configuration
import com.topjohnwu.magisk.model.events.RecreateEvent import com.topjohnwu.magisk.model.internal.DownloadSubject
import com.topjohnwu.magisk.model.events.dialog.BiometricDialog
import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -27,10 +26,10 @@ import org.koin.core.get
class SettingsViewModel( class SettingsViewModel(
private val repositoryDao: RepoDao private val repositoryDao: RepoDao
) : BaseViewModel(), SettingsItem.Callback { ) : BaseViewModel(), BaseSettingsItem.Callback {
val adapter = adapterOf<SettingsItem>() val adapter = adapterOf<BaseSettingsItem>()
val itemBinding = itemBindingOf<SettingsItem> { it.bindExtra(BR.callback, this) } val itemBinding = itemBindingOf<BaseSettingsItem> { it.bindExtra(BR.callback, this) }
val items = diffListOf(createItems()) val items = diffListOf(createItems())
init { init {
@ -39,7 +38,7 @@ class SettingsViewModel(
} }
} }
private fun createItems(): List<SettingsItem> { private fun createItems(): List<BaseSettingsItem> {
// Customization // Customization
val list = mutableListOf( val list = mutableListOf(
Customization, Customization,
@ -90,7 +89,7 @@ class SettingsViewModel(
return list 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 DownloadPath -> withExternalRW(callback)
is Biometrics -> authenticate(callback) is Biometrics -> authenticate(callback)
is Theme -> SettingsFragmentDirections.actionSettingsFragmentToThemeFragment().publish() is Theme -> SettingsFragmentDirections.actionSettingsFragmentToThemeFragment().publish()
@ -100,7 +99,7 @@ class SettingsViewModel(
else -> callback() 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 Language -> RecreateEvent().publish()
is UpdateChannel -> openUrlIfNecessary(view) is UpdateChannel -> openUrlIfNecessary(view)
is Hide -> PatchAPK.hideManager(view.context, item.value) 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 android.graphics.drawable.Drawable
import androidx.databinding.Bindable import androidx.databinding.Bindable
import com.topjohnwu.magisk.BR import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R 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.databinding.ObservableItem
import com.topjohnwu.magisk.ui.superuser.SuperuserViewModel
import com.topjohnwu.magisk.utils.set import com.topjohnwu.magisk.utils.set
class PolicyItem( class PolicyRvItem(
val item: MagiskPolicy, val item: SuPolicy,
val icon: Drawable, val icon: Drawable,
val viewModel: SuperuserViewModel val viewModel: SuperuserViewModel
) : ObservableItem<PolicyItem>() { ) : ObservableItem<PolicyRvItem>() {
override val layoutRes = R.layout.item_policy_md2 override val layoutRes = R.layout.item_policy_md2
@get:Bindable @get:Bindable
@ -21,7 +20,7 @@ class PolicyItem(
set(value) = set(value, field, { field = it }, BR.expanded) set(value) = set(value, field, { field = it }, BR.expanded)
// This property hosts the policy state // 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) set(value) = set(value, field, { field = it }, BR.enabled)
// This property binds with the UI state // This property binds with the UI state
@ -44,7 +43,7 @@ class PolicyItem(
private val updatedPolicy private val updatedPolicy
get() = item.copy( get() = item.copy(
policy = if (policyState) MagiskPolicy.ALLOW else MagiskPolicy.DENY, policy = if (policyState) SuPolicy.ALLOW else SuPolicy.DENY,
notification = shouldNotify, notification = shouldNotify,
logging = shouldLog logging = shouldLog
) )
@ -65,7 +64,7 @@ class PolicyItem(
viewModel.deletePressed(this) viewModel.deletePressed(this)
} }
override fun contentSameAs(other: PolicyItem) = itemSameAs(other) override fun contentSameAs(other: PolicyRvItem) = itemSameAs(other)
override fun itemSameAs(other: PolicyItem) = item.uid == other.item.uid 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.R
import com.topjohnwu.magisk.databinding.ComparableRvItem import com.topjohnwu.magisk.databinding.ComparableRvItem

View File

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

View File

@ -1,9 +1,9 @@
package com.topjohnwu.magisk.ui.theme package com.topjohnwu.magisk.ui.theme
import com.topjohnwu.magisk.arch.BaseViewModel import com.topjohnwu.magisk.arch.BaseViewModel
import com.topjohnwu.magisk.model.entity.recycler.TappableHeadlineItem import com.topjohnwu.magisk.events.RecreateEvent
import com.topjohnwu.magisk.model.events.RecreateEvent import com.topjohnwu.magisk.events.dialog.DarkThemeDialog
import com.topjohnwu.magisk.model.events.dialog.DarkThemeDialog import com.topjohnwu.magisk.view.TappableHeadlineItem
class ThemeViewModel : BaseViewModel(), TappableHeadlineItem.Listener { 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.R
import com.topjohnwu.magisk.databinding.ComparableRvItem 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.R
import com.topjohnwu.magisk.databinding.ComparableRvItem 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.ui.home.MagiskState" />
<import type="com.topjohnwu.magisk.model.entity.DeveloperItem"/> <import type="com.topjohnwu.magisk.ui.home.DeveloperItem"/>
<variable <variable
name="viewModel" name="viewModel"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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