Refactor class names

This commit is contained in:
topjohnwu 2020-10-10 22:40:57 -07:00
parent 311c1f0dfd
commit 0a14f43f9c
14 changed files with 203 additions and 245 deletions

View File

@ -8,7 +8,7 @@ import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.model.MagiskJson
import com.topjohnwu.magisk.core.model.ManagerJson
import com.topjohnwu.magisk.core.model.StubJson
import com.topjohnwu.magisk.core.model.module.Repo
import com.topjohnwu.magisk.core.model.module.OnlineModule
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
import com.topjohnwu.magisk.ktx.cachedFile
import com.topjohnwu.magisk.ktx.get
@ -26,7 +26,7 @@ sealed class Subject : Parcelable {
@Parcelize
class Module(
val module: Repo,
val module: OnlineModule,
override val action: Action
) : Subject() {
override val url: String get() = module.zip_url

View File

@ -1,41 +0,0 @@
package com.topjohnwu.magisk.core.model.module
abstract class BaseModule : Comparable<BaseModule> {
abstract var id: String
protected set
abstract var name: String
protected set
abstract var author: String
protected set
abstract var version: String
protected set
abstract var versionCode: Int
protected set
abstract var description: String
protected set
@Throws(NumberFormatException::class)
protected fun parseProps(props: List<String>) {
for (line in props) {
val prop = line.split("=".toRegex(), 2).map { it.trim() }
if (prop.size != 2)
continue
val key = prop[0]
val value = prop[1]
if (key.isEmpty() || key[0] == '#')
continue
when (key) {
"id" -> id = value
"name" -> name = value
"version" -> version = value
"versionCode" -> versionCode = value.toInt()
"author" -> author = value
"description" -> description = value
}
}
}
override operator fun compareTo(other: BaseModule) = name.compareTo(other.name, true)
}

View File

@ -0,0 +1,77 @@
package com.topjohnwu.magisk.core.model.module
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.io.SuFile
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
class LocalModule(path: String) : Module() {
override var id: String = ""
override var name: String = ""
override var author: String = ""
override var version: String = ""
override var versionCode: Int = -1
override var description: String = ""
private val removeFile = SuFile(path, "remove")
private val disableFile = SuFile(path, "disable")
private val updateFile = SuFile(path, "update")
private val ruleFile = SuFile(path, "sepolicy.rule")
val updated: Boolean get() = updateFile.exists()
var enable: Boolean
get() = !disableFile.exists()
set(enable) {
val dir = "$PERSIST/$id"
if (enable) {
Shell.su("mkdir -p $dir", "cp -af $ruleFile $dir").submit()
disableFile.delete()
} else {
Shell.su("rm -rf $dir").submit()
!disableFile.createNewFile()
}
}
var remove: Boolean
get() = removeFile.exists()
set(remove) {
if (remove) {
Shell.su("rm -rf $PERSIST/$id").submit()
removeFile.createNewFile()
} else {
Shell.su("cp -af $ruleFile $PERSIST/$id").submit()
!removeFile.delete()
}
}
init {
runCatching {
parseProps(Shell.su("dos2unix < $path/module.prop").exec().out)
}
if (id.isEmpty()) {
val sep = path.lastIndexOf('/')
id = path.substring(sep + 1)
}
if (name.isEmpty()) {
name = id
}
}
companion object {
private val PERSIST get() = "${Const.MAGISKTMP}/mirror/persist/magisk"
suspend fun installed() = withContext(Dispatchers.IO) {
SuFile(Const.MAGISK_PATH)
.listFiles { _, name -> name != "lost+found" && name != ".core" }
.orEmpty()
.filter { !it.isFile }
.map { LocalModule("${Const.MAGISK_PATH}/${it.name}") }
.sortedBy { it.name.toLowerCase() }
}
}
}

View File

@ -1,77 +1,41 @@
package com.topjohnwu.magisk.core.model.module
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.io.SuFile
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
abstract class Module : Comparable<Module> {
abstract var id: String
protected set
abstract var name: String
protected set
abstract var author: String
protected set
abstract var version: String
protected set
abstract var versionCode: Int
protected set
abstract var description: String
protected set
class Module(path: String) : BaseModule() {
override var id: String = ""
override var name: String = ""
override var author: String = ""
override var version: String = ""
override var versionCode: Int = -1
override var description: String = ""
@Throws(NumberFormatException::class)
protected fun parseProps(props: List<String>) {
for (line in props) {
val prop = line.split("=".toRegex(), 2).map { it.trim() }
if (prop.size != 2)
continue
private val removeFile = SuFile(path, "remove")
private val disableFile = SuFile(path, "disable")
private val updateFile = SuFile(path, "update")
private val ruleFile = SuFile(path, "sepolicy.rule")
val key = prop[0]
val value = prop[1]
if (key.isEmpty() || key[0] == '#')
continue
val updated: Boolean get() = updateFile.exists()
var enable: Boolean
get() = !disableFile.exists()
set(enable) {
val dir = "$PERSIST/$id"
if (enable) {
Shell.su("mkdir -p $dir", "cp -af $ruleFile $dir").submit()
disableFile.delete()
} else {
Shell.su("rm -rf $dir").submit()
!disableFile.createNewFile()
when (key) {
"id" -> id = value
"name" -> name = value
"version" -> version = value
"versionCode" -> versionCode = value.toInt()
"author" -> author = value
"description" -> description = value
}
}
var remove: Boolean
get() = removeFile.exists()
set(remove) {
if (remove) {
Shell.su("rm -rf $PERSIST/$id").submit()
removeFile.createNewFile()
} else {
Shell.su("cp -af $ruleFile $PERSIST/$id").submit()
!removeFile.delete()
}
}
init {
runCatching {
parseProps(Shell.su("dos2unix < $path/module.prop").exec().out)
}
if (id.isEmpty()) {
val sep = path.lastIndexOf('/')
id = path.substring(sep + 1)
}
if (name.isEmpty()) {
name = id
}
}
companion object {
private val PERSIST get() = "${Const.MAGISKTMP}/mirror/persist/magisk"
suspend fun installed() = withContext(Dispatchers.IO) {
SuFile(Const.MAGISK_PATH)
.listFiles { _, name -> name != "lost+found" && name != ".core" }
.orEmpty()
.filter { !it.isFile }
.map { Module("${Const.MAGISK_PATH}/${it.name}") }
.sortedBy { it.name.toLowerCase() }
}
}
override operator fun compareTo(other: Module) = name.compareTo(other.name, true)
}

View File

@ -11,9 +11,9 @@ import kotlinx.android.parcel.Parcelize
import java.text.DateFormat
import java.util.*
@Entity(tableName = "repos")
@Entity(tableName = "modules")
@Parcelize
data class Repo(
data class OnlineModule(
@PrimaryKey override var id: String,
override var name: String = "",
override var author: String = "",
@ -24,7 +24,7 @@ data class Repo(
val prop_url: String,
val zip_url: String,
val notes_url: String
) : BaseModule(), Parcelable {
) : Module(), Parcelable {
private val svc: NetworkService get() = get()

View File

@ -1,6 +1,6 @@
package com.topjohnwu.magisk.core.tasks
import com.topjohnwu.magisk.core.model.module.Repo
import com.topjohnwu.magisk.core.model.module.OnlineModule
import com.topjohnwu.magisk.data.database.RepoDao
import com.topjohnwu.magisk.data.repository.NetworkService
import com.topjohnwu.magisk.ktx.synchronized
@ -18,7 +18,7 @@ class RepoUpdater(
suspend fun run(forced: Boolean) = withContext(Dispatchers.IO) {
val cachedMap = HashMap<String, Date>().also { map ->
repoDB.getRepoStubs().forEach { map[it.id] = Date(it.last_update) }
repoDB.getModuleStubs().forEach { map[it.id] = Date(it.last_update) }
}.synchronized()
val info = svc.fetchRepoInfo()
coroutineScope {
@ -27,15 +27,15 @@ class RepoUpdater(
val lastUpdated = cachedMap.remove(it.id)
if (forced || lastUpdated?.before(Date(it.last_update)) != false) {
try {
val repo = Repo(it).apply { load() }
repoDB.addRepo(repo)
} catch (e: Repo.IllegalRepoException) {
val repo = OnlineModule(it).apply { load() }
repoDB.addModule(repo)
} catch (e: OnlineModule.IllegalRepoException) {
Timber.e(e)
}
}
}
}
}
repoDB.removeRepos(cachedMap.keys)
repoDB.removeModules(cachedMap.keys)
}
}

View File

@ -1,67 +0,0 @@
@file:JvmMultifileClass
package com.topjohnwu.magisk.data.database
import androidx.room.Dao
import androidx.room.Query
import com.topjohnwu.magisk.core.model.module.Repo
interface RepoBase {
fun getRepos(offset: Int, limit: Int = LIMIT): List<Repo>
fun searchRepos(query: String, offset: Int, limit: Int = LIMIT): List<Repo>
@Query("SELECT * FROM repos WHERE id = :id AND versionCode > :versionCode LIMIT 1")
fun getUpdatableRepoById(id: String, versionCode: Int): Repo?
@Query("SELECT * FROM repos WHERE id = :id LIMIT 1")
fun getRepoById(id: String): Repo?
companion object {
const val LIMIT = 10
}
}
@Dao
interface RepoByUpdatedDao : RepoBase {
@Query("SELECT * FROM repos ORDER BY last_update DESC LIMIT :limit OFFSET :offset")
override fun getRepos(offset: Int, limit: Int): List<Repo>
@Query(
"""SELECT *
FROM repos
WHERE
(author LIKE '%' || :query || '%') ||
(name LIKE '%' || :query || '%') ||
(description LIKE '%' || :query || '%')
ORDER BY last_update DESC
LIMIT :limit
OFFSET :offset"""
)
override fun searchRepos(query: String, offset: Int, limit: Int): List<Repo>
}
@Dao
interface RepoByNameDao : RepoBase {
@Query("SELECT * FROM repos ORDER BY name COLLATE NOCASE LIMIT :limit OFFSET :offset")
override fun getRepos(offset: Int, limit: Int): List<Repo>
@Query(
"""SELECT *
FROM repos
WHERE
(author LIKE '%' || :query || '%') ||
(name LIKE '%' || :query || '%') ||
(description LIKE '%' || :query || '%')
ORDER BY name COLLATE NOCASE
LIMIT :limit
OFFSET :offset"""
)
override fun searchRepos(query: String, offset: Int, limit: Int): List<Repo>
}

View File

@ -2,54 +2,89 @@ package com.topjohnwu.magisk.data.database
import androidx.room.*
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.model.module.Repo
import com.topjohnwu.magisk.core.model.module.OnlineModule
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@Database(version = 7, entities = [Repo::class], exportSchema = false)
@Database(version = 8, entities = [OnlineModule::class], exportSchema = false)
abstract class RepoDatabase : RoomDatabase() {
abstract fun repoDao() : RepoDao
abstract fun repoByUpdatedDao(): RepoByUpdatedDao
abstract fun repoByNameDao(): RepoByNameDao
}
@Dao
abstract class RepoDao(private val db: RepoDatabase) {
val repos: List<Repo> get() = when (Config.repoOrder) {
Config.Value.ORDER_NAME -> getReposNameOrder()
else -> getReposDateOrder()
}
suspend fun clear() = withContext(Dispatchers.IO) { db.clearAllTables() }
@Query("SELECT * FROM repos ORDER BY last_update DESC")
protected abstract fun getReposDateOrder(): List<Repo>
@Query("SELECT * FROM repos ORDER BY name COLLATE NOCASE")
protected abstract fun getReposNameOrder(): List<Repo>
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun addRepo(repo: Repo)
@Query("SELECT * FROM repos WHERE id = :id")
abstract fun getRepo(id: String): Repo?
@Query("SELECT id, last_update FROM repos")
abstract fun getRepoStubs(): List<RepoStub>
abstract fun addModule(repo: OnlineModule)
@Delete
abstract fun removeRepo(repo: Repo)
abstract fun removeModule(repo: OnlineModule)
@Query("DELETE FROM repos WHERE id = :id")
abstract fun removeRepo(id: String)
@Query("DELETE FROM modules WHERE id = :id")
abstract fun removeModule(id: String)
@Query("DELETE FROM repos WHERE id IN (:idList)")
abstract fun removeRepos(idList: Collection<String>)
@Query("DELETE FROM modules WHERE id IN (:idList)")
abstract fun removeModules(idList: Collection<String>)
@Query("SELECT * FROM modules WHERE id = :id")
abstract fun getModule(id: String): OnlineModule?
@Query("SELECT id, last_update FROM modules")
abstract fun getModuleStubs(): List<ModuleStub>
fun getModules(offset: Int, limit: Int = LIMIT) = when (Config.repoOrder) {
Config.Value.ORDER_NAME -> getNameOrder(offset, limit)
else -> getDateOrder(offset, limit)
}
fun searchModules(query: String, offset: Int, limit: Int = LIMIT) = when (Config.repoOrder) {
Config.Value.ORDER_NAME -> searchNameOrder(query, offset, limit)
else -> searchDateOrder(query, offset, limit)
}
@Query("SELECT * FROM modules WHERE id = :id AND versionCode > :versionCode LIMIT 1")
abstract fun getUpdatableModule(id: String, versionCode: Int): OnlineModule?
@Query("SELECT * FROM modules ORDER BY last_update DESC LIMIT :limit OFFSET :offset")
protected abstract fun getDateOrder(offset: Int, limit: Int): List<OnlineModule>
@Query("SELECT * FROM modules ORDER BY name COLLATE NOCASE LIMIT :limit OFFSET :offset")
protected abstract fun getNameOrder(offset: Int, limit: Int): List<OnlineModule>
@Query(
"""SELECT *
FROM modules
WHERE
(author LIKE '%' || :query || '%') ||
(name LIKE '%' || :query || '%') ||
(description LIKE '%' || :query || '%')
ORDER BY last_update DESC
LIMIT :limit
OFFSET :offset"""
)
protected abstract fun searchDateOrder(query: String, offset: Int, limit: Int): List<OnlineModule>
@Query(
"""SELECT *
FROM modules
WHERE
(author LIKE '%' || :query || '%') ||
(name LIKE '%' || :query || '%') ||
(description LIKE '%' || :query || '%')
ORDER BY name COLLATE NOCASE
LIMIT :limit
OFFSET :offset"""
)
protected abstract fun searchNameOrder(query: String, offset: Int, limit: Int): List<OnlineModule>
companion object {
const val LIMIT = 10
}
}
data class RepoStub(
data class ModuleStub(
@PrimaryKey val id: String,
val last_update: Long
)

View File

@ -17,8 +17,6 @@ val databaseModule = module {
single { StringDao() }
single { createRepoDatabase(get()) }
single { get<RepoDatabase>().repoDao() }
single { get<RepoDatabase>().repoByNameDao() }
single { get<RepoDatabase>().repoByUpdatedDao() }
single { createSuLogDatabase(get(Protected)).suLogDao() }
single { RepoUpdater(get(), get()) }
}

View File

@ -20,7 +20,7 @@ val viewModelModules = module {
viewModel { HideViewModel() }
viewModel { HomeViewModel(get()) }
viewModel { LogViewModel(get()) }
viewModel { ModuleViewModel(get(), get(), get()) }
viewModel { ModuleViewModel(get(), get()) }
viewModel { SafetynetViewModel() }
viewModel { SettingsViewModel(get()) }
viewModel { SuperuserViewModel(get(), get()) }

View File

@ -12,7 +12,7 @@ import com.topjohnwu.magisk.arch.*
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.base.ActivityResultCallback
import com.topjohnwu.magisk.core.base.BaseActivity
import com.topjohnwu.magisk.core.model.module.Repo
import com.topjohnwu.magisk.core.model.module.OnlineModule
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.view.MarkDownWindow
import com.topjohnwu.magisk.view.Shortcuts
@ -22,7 +22,7 @@ class ViewActionEvent(val action: BaseActivity.() -> Unit) : ViewEvent(), Activi
override fun invoke(activity: BaseUIActivity<*, *>) = action(activity)
}
class OpenReadmeEvent(val item: Repo) : ViewEventWithScope(), ContextExecutor {
class OpenReadmeEvent(val item: OnlineModule) : ViewEventWithScope(), ContextExecutor {
override fun invoke(context: Context) {
scope.launch {
MarkDownWindow.show(context, null, item::notes)

View File

@ -5,10 +5,10 @@ import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.download.Action
import com.topjohnwu.magisk.core.download.DownloadService
import com.topjohnwu.magisk.core.download.Subject
import com.topjohnwu.magisk.core.model.module.Repo
import com.topjohnwu.magisk.core.model.module.OnlineModule
import com.topjohnwu.magisk.view.MagiskDialog
class ModuleInstallDialog(private val item: Repo) : DialogEvent() {
class ModuleInstallDialog(private val item: OnlineModule) : DialogEvent() {
override fun build(dialog: MagiskDialog) {
with(dialog) {

View File

@ -3,8 +3,8 @@ package com.topjohnwu.magisk.ui.module
import androidx.databinding.Bindable
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.model.module.Module
import com.topjohnwu.magisk.core.model.module.Repo
import com.topjohnwu.magisk.core.model.module.LocalModule
import com.topjohnwu.magisk.core.model.module.OnlineModule
import com.topjohnwu.magisk.databinding.ComparableRvItem
import com.topjohnwu.magisk.databinding.ObservableItem
import com.topjohnwu.magisk.utils.set
@ -39,7 +39,7 @@ class SectionTitle(
override fun contentSameAs(other: SectionTitle): Boolean = this === other
}
sealed class RepoItem(val item: Repo) : ObservableItem<RepoItem>() {
sealed class RepoItem(val item: OnlineModule) : ObservableItem<RepoItem>() {
override val layoutRes: Int = R.layout.item_repo_md2
@get:Bindable
@ -51,21 +51,21 @@ sealed class RepoItem(val item: Repo) : ObservableItem<RepoItem>() {
override fun contentSameAs(other: RepoItem): Boolean = item == other.item
override fun itemSameAs(other: RepoItem): Boolean = item.id == other.item.id
class Update(item: Repo) : RepoItem(item) {
class Update(item: OnlineModule) : RepoItem(item) {
override val isUpdate get() = true
}
class Remote(item: Repo) : RepoItem(item) {
class Remote(item: OnlineModule) : RepoItem(item) {
override val isUpdate get() = false
}
}
class ModuleItem(val item: Module) : ObservableItem<ModuleItem>() {
class ModuleItem(val item: LocalModule) : ObservableItem<ModuleItem>() {
override val layoutRes = R.layout.item_module_md2
@get:Bindable
var repo: Repo? = null
var repo: OnlineModule? = null
set(value) = set(value, field, { field = it }, BR.repo)
@get:Bindable

View File

@ -9,10 +9,9 @@ import com.topjohnwu.magisk.arch.*
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.download.Subject
import com.topjohnwu.magisk.core.model.module.Module
import com.topjohnwu.magisk.core.model.module.LocalModule
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.data.database.RepoDao
import com.topjohnwu.magisk.databinding.RvItem
import com.topjohnwu.magisk.events.OpenReadmeEvent
import com.topjohnwu.magisk.events.SelectModuleEvent
@ -44,8 +43,7 @@ import kotlin.math.roundToInt
* */
class ModuleViewModel(
private val repoName: RepoByNameDao,
private val repoUpdated: RepoByUpdatedDao,
private val repoDB: RepoDao,
private val repoUpdater: RepoUpdater
) : BaseViewModel(), Queryable {
@ -117,12 +115,6 @@ class ModuleViewModel(
// ---
private var refetch = false
private val dao
get() = when (Config.repoOrder) {
Config.Value.ORDER_DATE -> repoUpdated
Config.Value.ORDER_NAME -> repoName
else -> throw IllegalArgumentException()
}
// ---
@ -186,7 +178,7 @@ class ModuleViewModel(
}
private suspend fun loadInstalled() {
val installed = Module.installed().map { ModuleItem(it) }
val installed = LocalModule.installed().map { ModuleItem(it) }
val diff = withContext(Dispatchers.Default) {
itemsInstalled.calculateDiff(installed)
}
@ -197,11 +189,11 @@ class ModuleViewModel(
val (updates, diff) = withContext(Dispatchers.IO) {
itemsInstalled.forEach {
launch {
it.repo = dao.getRepoById(it.item.id)
it.repo = repoDB.getModule(it.item.id)
}
}
val updates = itemsInstalled
.mapNotNull { dao.getUpdatableRepoById(it.item.id, it.item.versionCode) }
.mapNotNull { repoDB.getUpdatableModule(it.item.id, it.item.versionCode) }
.map { RepoItem.Update(it) }
val diff = itemsUpdatable.calculateDiff(updates)
return@withContext updates to diff
@ -219,7 +211,7 @@ class ModuleViewModel(
remoteJob = viewModelScope.launch {
suspend fun loadRemoteDB(offset: Int) = withContext(Dispatchers.IO) {
dao.getRepos(offset).map { RepoItem.Remote(it) }
repoDB.getModules(offset).map { RepoItem.Remote(it) }
}
isRemoteLoading = true
@ -253,7 +245,7 @@ class ModuleViewModel(
listOf()
} else {
withContext(Dispatchers.IO) {
dao.searchRepos(query, offset).map { RepoItem.Remote(it) }
repoDB.searchModules(query, offset).map { RepoItem.Remote(it) }
}
}
}