This commit is contained in:
topjohnwu 2019-05-30 01:05:48 -07:00
parent b31d3802eb
commit c0d1ce96d1
10 changed files with 8 additions and 223 deletions

View File

@ -1,27 +0,0 @@
package com.topjohnwu.magisk.data.network
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.model.entity.GithubRepo
import io.reactivex.Single
import retrofit2.http.GET
import retrofit2.http.Query
interface GithubApiServices {
@GET("users/Magisk-Modules-Repo/repos")
fun fetchRepos(
@Query("page") page: Int,
@Query("per_page") count: Int = REPOS_PER_PAGE,
@Query("sort") sortOrder: String = when (Config.get<Int>(Config.Key.REPO_ORDER)) {
Config.Value.ORDER_DATE -> "updated"
Config.Value.ORDER_NAME -> "full_name"
else -> "updated"
}
): Single<List<GithubRepo>>
companion object {
const val REPOS_PER_PAGE = 100
}
}

View File

@ -40,22 +40,6 @@ interface GithubRawApiServices {
//endregion //endregion
//region topjohnwu/Magisk/master
@GET("$MAGISK_MASTER/scripts/module_installer.sh")
@Streaming
fun fetchModuleInstaller(): Single<ResponseBody>
//endregion
//region Magisk-Modules-Repo
@GET("$MAGISK_MODULES/{$MODULE}/master/{$FILE}")
@Streaming
fun fetchFile(@Path(MODULE) id: String, @Path(FILE) file: String): Single<ResponseBody>
//endregion
/** /**
* This method shall be used exclusively for fetching files from urls from previous requests. * This method shall be used exclusively for fetching files from urls from previous requests.
* Him, who uses it in a wrong way, shall die in an eternal flame. * Him, who uses it in a wrong way, shall die in an eternal flame.

View File

@ -1,21 +0,0 @@
package com.topjohnwu.magisk.data.network
import io.reactivex.Single
import okhttp3.ResponseBody
import retrofit2.http.GET
import retrofit2.http.Path
import retrofit2.http.Streaming
interface GithubServices {
@GET("Magisk-Modules-Repo/{$MODULE}/archive/master.zip")
@Streaming
fun fetchModuleZip(@Path(MODULE) module: String): Single<ResponseBody>
companion object {
private const val MODULE = "module"
}
}

View File

@ -1,98 +0,0 @@
package com.topjohnwu.magisk.data.repository
import android.content.Context
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.data.database.RepositoryDao
import com.topjohnwu.magisk.data.network.GithubApiServices
import com.topjohnwu.magisk.data.network.GithubRawApiServices
import com.topjohnwu.magisk.data.network.GithubServices
import com.topjohnwu.magisk.model.entity.GithubRepo
import com.topjohnwu.magisk.model.entity.toRepository
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.utils.toSingle
import com.topjohnwu.magisk.utils.writeToFile
import com.topjohnwu.magisk.utils.writeToString
import io.reactivex.Completable
import io.reactivex.Single
class ModuleRepository(
private val context: Context,
private val apiRaw: GithubRawApiServices,
private val api: GithubApiServices,
private val apiWeb: GithubServices,
private val repoDao: RepositoryDao
) {
fun fetchModules(force: Boolean = false) =
if (force) fetchRemoteRepos() else fetchCachedOrdered()
.flatMap { if (it.isEmpty()) fetchRemoteRepos() else it.toSingle() }
private fun fetchRemoteRepos() = fetchAllRepos()
.map {
it.mapNotNull {
runCatching {
fetchProperties(it.name, it.updatedAtMillis).blockingGet()
}.getOrNull()
}
}
//either github apparently returns repos incorrectly or ...
//either ways this fixes duplicates
.map { it.distinctBy { it.id } }
.doOnSuccess { repoDao.insert(it) }
private fun fetchCachedOrdered() = Single.fromCallable {
when (Config.get<Int>(Config.Key.REPO_ORDER)) {
Config.Value.ORDER_DATE -> repoDao.fetchAll()
Config.Value.ORDER_NAME -> repoDao.fetchAllOrderByName()
else -> repoDao.fetchAll()
}
}
fun fetchInstalledModules() = Single.fromCallable { Utils.loadModulesLeanback() }
.map { it.values.toList() }
fun fetchInstallFile(module: String) = apiRaw
.fetchFile(module, FILE_INSTALL_SH)
.map { it.writeToFile(context, FILE_INSTALL_SH) }
fun fetchReadme(module: String) = apiRaw
.fetchFile(module, FILE_README_MD)
.map { it.writeToString() }
fun fetchConfig(module: String) = apiRaw
.fetchFile(module, FILE_CONFIG_SH)
.map { it.writeToFile(context, FILE_CONFIG_SH) }
fun fetchInstallZip(module: String) = apiWeb
.fetchModuleZip(module)
.map { it.writeToFile(context, FILE_INSTALL_ZIP) }
fun fetchInstaller() = apiRaw
.fetchModuleInstaller()
.map { it.writeToFile(context, FILE_MODULE_INSTALLER_SH) }
fun deleteAllCached() = Completable.fromCallable { repoDao.deleteAll() }
private fun fetchProperties(module: String, lastChanged: Long) = apiRaw
.fetchFile(module, "module.prop")
.map { it.toRepository(lastChanged) }
private fun fetchAllRepos(page: Int = 0): Single<List<GithubRepo>> = api.fetchRepos(page)
.flatMap {
if (it.size == GithubApiServices.REPOS_PER_PAGE) {
fetchAllRepos(page + 1).map { newList -> it + newList }
} else {
Single.just(it)
}
}
companion object {
const val FILE_INSTALL_SH = "install.sh"
const val FILE_README_MD = "README.md"
const val FILE_CONFIG_SH = "config.sh"
const val FILE_INSTALL_ZIP = "install.zip"
const val FILE_MODULE_INSTALLER_SH = "module_installer.sh"
}
}

View File

@ -3,9 +3,7 @@ package com.topjohnwu.magisk.di
import com.squareup.moshi.Moshi import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import com.topjohnwu.magisk.Constants import com.topjohnwu.magisk.Constants
import com.topjohnwu.magisk.data.network.GithubApiServices
import com.topjohnwu.magisk.data.network.GithubRawApiServices import com.topjohnwu.magisk.data.network.GithubRawApiServices
import com.topjohnwu.magisk.data.network.GithubServices
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor import okhttp3.logging.HttpLoggingInterceptor
import org.koin.dsl.module import org.koin.dsl.module
@ -23,8 +21,6 @@ val networkingModule = module {
single { createRetrofit(get(), get(), get()) } single { createRetrofit(get(), get(), get()) }
single { createApiService<GithubServices>(get(), Constants.GITHUB_URL) }
single { createApiService<GithubApiServices>(get(), Constants.GITHUB_API_URL) }
single { createApiService<GithubRawApiServices>(get(), Constants.GITHUB_RAW_API_URL) } single { createApiService<GithubRawApiServices>(get(), Constants.GITHUB_RAW_API_URL) }
} }

View File

@ -6,7 +6,6 @@ import org.koin.dsl.module
val repositoryModule = module { val repositoryModule = module {
single { MagiskRepository(get(), get(), get()) } single { MagiskRepository(get(), get(), get()) }
single { ModuleRepository(get(), get(), get(), get(), get()) }
single { LogRepository(get()) } single { LogRepository(get()) }
single { AppRepository(get()) } single { AppRepository(get()) }
single { SettingRepository(get()) } single { SettingRepository(get()) }

View File

@ -18,7 +18,7 @@ val viewModelModules = module {
viewModel { HomeViewModel(get()) } viewModel { HomeViewModel(get()) }
viewModel { SuperuserViewModel(get(), get(), get(), get()) } viewModel { SuperuserViewModel(get(), get(), get(), get()) }
viewModel { HideViewModel(get(), get()) } viewModel { HideViewModel(get(), get()) }
viewModel { ModuleViewModel(get(), get(), get(), get()) } viewModel { ModuleViewModel(get(), get(), get()) }
viewModel { LogViewModel(get(), get()) } viewModel { LogViewModel(get(), get()) }
viewModel { (action: String, uri: Uri?) -> FlashViewModel(action, uri, get()) } viewModel { (action: String, uri: Uri?) -> FlashViewModel(action, uri, get()) }
viewModel { SuRequestViewModel(get(), get(), get(SUTimeout), get()) } viewModel { SuRequestViewModel(get(), get(), get(SUTimeout), get()) }

View File

@ -1,18 +0,0 @@
package com.topjohnwu.magisk.model.entity
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import com.topjohnwu.magisk.utils.timeFormatStandard
import com.topjohnwu.magisk.utils.toTime
import timber.log.Timber
@JsonClass(generateAdapter = true)
data class GithubRepo(
@Json(name = "name") val name: String,
@Json(name = "updated_at") val updatedAt: String
) {
val updatedAtMillis by lazy {
updatedAt.toTime(timeFormatStandard)
.apply { Timber.i("$name updated @ $this ($updatedAt)") }
}
}

View File

@ -16,7 +16,6 @@ import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.KConfig import com.topjohnwu.magisk.KConfig
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.data.database.RepoDatabaseHelper import com.topjohnwu.magisk.data.database.RepoDatabaseHelper
import com.topjohnwu.magisk.data.repository.ModuleRepository
import com.topjohnwu.magisk.data.repository.SettingRepository import com.topjohnwu.magisk.data.repository.SettingRepository
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
@ -27,7 +26,6 @@ abstract class BasePreferenceFragment : PreferenceFragmentCompat(),
protected val prefs: SharedPreferences by inject() protected val prefs: SharedPreferences by inject()
protected val app: App by inject() protected val app: App by inject()
protected val settingRepo: SettingRepository by inject() protected val settingRepo: SettingRepository by inject()
protected val moduleRepo: ModuleRepository by inject()
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,

View File

@ -11,7 +11,6 @@ import com.skoumal.teanity.util.KObservableField
import com.topjohnwu.magisk.BR import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.data.database.RepoDatabaseHelper import com.topjohnwu.magisk.data.database.RepoDatabaseHelper
import com.topjohnwu.magisk.data.repository.ModuleRepository
import com.topjohnwu.magisk.model.entity.Repo import com.topjohnwu.magisk.model.entity.Repo
import com.topjohnwu.magisk.model.entity.recycler.ModuleRvItem import com.topjohnwu.magisk.model.entity.recycler.ModuleRvItem
import com.topjohnwu.magisk.model.entity.recycler.RepoRvItem import com.topjohnwu.magisk.model.entity.recycler.RepoRvItem
@ -21,18 +20,15 @@ import com.topjohnwu.magisk.model.events.OpenChangelogEvent
import com.topjohnwu.magisk.model.events.OpenFilePickerEvent import com.topjohnwu.magisk.model.events.OpenFilePickerEvent
import com.topjohnwu.magisk.tasks.UpdateRepos import com.topjohnwu.magisk.tasks.UpdateRepos
import com.topjohnwu.magisk.ui.base.MagiskViewModel import com.topjohnwu.magisk.ui.base.MagiskViewModel
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.utils.toSingle import com.topjohnwu.magisk.utils.toSingle
import com.topjohnwu.magisk.utils.update import com.topjohnwu.magisk.utils.update
import com.topjohnwu.magisk.utils.zip
import io.reactivex.Single import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import me.tatarka.bindingcollectionadapter2.OnItemBind import me.tatarka.bindingcollectionadapter2.OnItemBind
class ModuleViewModel( class ModuleViewModel(
private val resources: Resources, private val resources: Resources,
private val moduleRepo: ModuleRepository,
private val repoDatabase: RepoDatabaseHelper, private val repoDatabase: RepoDatabaseHelper,
private val repoUpdater: UpdateRepos private val repoUpdater: UpdateRepos
) : MagiskViewModel() { ) : MagiskViewModel() {
@ -62,33 +58,9 @@ class ModuleViewModel(
fun repoPressed(item: RepoRvItem) = OpenChangelogEvent(item.item).publish() fun repoPressed(item: RepoRvItem) = OpenChangelogEvent(item.item).publish()
fun downloadPressed(item: RepoRvItem) = InstallModuleEvent(item.item).publish() fun downloadPressed(item: RepoRvItem) = InstallModuleEvent(item.item).publish()
fun refreshNew(forceReload: Boolean) { fun refresh(force: Boolean) {
val updateInstalled = moduleRepo.fetchInstalledModules() Single.fromCallable { Utils.loadModulesLeanback() }
.flattenAsFlowable { it } .map { it.values.toList() }
.map { ModuleRvItem(it) }
.toList()
.map { it to itemsInstalled.calculateDiff(it) }
val updateRemote = moduleRepo.fetchModules(forceReload)
zip(updateInstalled, updateRemote) { installed, remote -> installed to remote }
.observeOn(AndroidSchedulers.mainThread())
.map {
itemsInstalled.update(it.first.first, it.first.second)
it.second
}
.observeOn(Schedulers.computation())
.flattenAsFlowable { it }
.map { RepoRvItem(it) }
.toList()
.doOnSuccess { allItems.update(it) }
.flatMap { queryRaw() }
.applyViewModel(this)
.subscribeK { itemsRemote.update(it.first, it.second) }
}
fun refresh/*Old*/(force: Boolean) {
moduleRepo.fetchInstalledModules()
.flattenAsFlowable { it } .flattenAsFlowable { it }
.map { ModuleRvItem(it) } .map { ModuleRvItem(it) }
.toList() .toList()