Commit 683cfee8 authored by topjohnwu's avatar topjohnwu

Cleanup and move things around

parent 3bcaf0ed
package com.topjohnwu.magisk.arch
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStoreOwner
import com.topjohnwu.magisk.core.di.ServiceLocator
import com.topjohnwu.magisk.ui.home.HomeViewModel
import com.topjohnwu.magisk.ui.install.InstallViewModel
import com.topjohnwu.magisk.ui.log.LogViewModel
import com.topjohnwu.magisk.ui.superuser.SuperuserViewModel
import com.topjohnwu.magisk.ui.surequest.SuRequestViewModel
interface ViewModelHolder : LifecycleOwner {
interface ViewModelHolder : LifecycleOwner, ViewModelStoreOwner {
val viewModel: BaseViewModel
......@@ -17,3 +26,23 @@ interface ViewModelHolder : LifecycleOwner {
*/
fun onEventDispatched(event: ViewEvent) {}
}
object VMFactory : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return when (modelClass) {
HomeViewModel::class.java -> HomeViewModel(ServiceLocator.networkService)
LogViewModel::class.java -> LogViewModel(ServiceLocator.logRepo)
SuperuserViewModel::class.java -> SuperuserViewModel(ServiceLocator.policyDB)
InstallViewModel::class.java -> InstallViewModel(ServiceLocator.networkService)
SuRequestViewModel::class.java ->
SuRequestViewModel(ServiceLocator.policyDB, ServiceLocator.timeoutPrefs)
else -> modelClass.newInstance()
} as T
}
}
inline fun <reified VM : ViewModel> ViewModelHolder.viewModel() =
lazy(LazyThreadSafetyMode.NONE) {
ViewModelProvider(this, VMFactory)[VM::class.java]
}
......@@ -3,9 +3,6 @@ package com.topjohnwu.magisk.core.di
import android.annotation.SuppressLint
import android.content.Context
import android.text.method.LinkMovementMethod
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStoreOwner
import androidx.room.Room
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.data.SuLogDatabase
......@@ -15,11 +12,6 @@ import com.topjohnwu.magisk.core.data.magiskdb.StringDao
import com.topjohnwu.magisk.core.repository.LogRepository
import com.topjohnwu.magisk.core.repository.NetworkService
import com.topjohnwu.magisk.ktx.deviceProtectedContext
import com.topjohnwu.magisk.ui.home.HomeViewModel
import com.topjohnwu.magisk.ui.install.InstallViewModel
import com.topjohnwu.magisk.ui.log.LogViewModel
import com.topjohnwu.magisk.ui.superuser.SuperuserViewModel
import com.topjohnwu.magisk.ui.surequest.SuRequestViewModel
import io.noties.markwon.Markwon
import io.noties.markwon.utils.NoCopySpannableFactory
......@@ -50,27 +42,8 @@ object ServiceLocator {
createApiService(retrofit, Const.Url.GITHUB_API_URL)
)
}
object VMFactory : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return when (modelClass) {
HomeViewModel::class.java -> HomeViewModel(networkService)
LogViewModel::class.java -> LogViewModel(logRepo)
SuperuserViewModel::class.java -> SuperuserViewModel(policyDB)
InstallViewModel::class.java -> InstallViewModel(networkService)
SuRequestViewModel::class.java -> SuRequestViewModel(policyDB, timeoutPrefs)
else -> modelClass.newInstance()
} as T
}
}
}
inline fun <reified VM : ViewModel> ViewModelStoreOwner.viewModel() =
lazy(LazyThreadSafetyMode.NONE) {
ViewModelProvider(this, ServiceLocator.VMFactory)[VM::class.java]
}
private fun createSuLogDatabase(context: Context) =
Room.databaseBuilder(context, SuLogDatabase::class.java, "sulogs.db")
.fallbackToDestructiveMigration()
......
......@@ -30,6 +30,7 @@ import com.google.android.material.chip.Chip
import com.google.android.material.textfield.TextInputLayout
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.di.ServiceLocator
import com.topjohnwu.magisk.utils.TextHolder
import com.topjohnwu.superuser.internal.UiThreadHandler
import com.topjohnwu.widget.IndeterminateCheckBox
import kotlin.math.roundToInt
......@@ -289,3 +290,8 @@ fun TextView.setTextColorAttr(attr: Int) {
context.theme.resolveAttribute(attr, tv, true)
setTextColor(tv.data)
}
@BindingAdapter("android:text")
fun TextView.setText(text: TextHolder) {
this.text = text.getText(context.resources)
}
......@@ -11,7 +11,6 @@ import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.content.res.Configuration
import android.database.Cursor
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.drawable.AdaptiveIconDrawable
......@@ -22,12 +21,10 @@ import android.os.Build.VERSION.SDK_INT
import android.os.Process
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.view.inputmethod.InputMethodManager
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.fragment.app.Fragment
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import androidx.transition.AutoTransition
import androidx.transition.TransitionManager
......@@ -35,7 +32,6 @@ import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.utils.RootUtils
import com.topjohnwu.magisk.core.utils.currentLocale
import com.topjohnwu.magisk.utils.DynamicClassLoader
import com.topjohnwu.superuser.Shell
import java.io.File
import kotlin.Array
......@@ -172,12 +168,6 @@ fun Intent.toCommand(args: MutableList<String> = mutableListOf()): MutableList<S
fun Context.cachedFile(name: String) = File(cacheDir, name)
fun <Result> Cursor.toList(transformer: (Cursor) -> Result): List<Result> {
val out = mutableListOf<Result>()
while (moveToNext()) out.add(transformer(this))
return out
}
fun ApplicationInfo.getLabel(pm: PackageManager): String {
runCatching {
if (labelRes > 0) {
......@@ -192,9 +182,6 @@ fun ApplicationInfo.getLabel(pm: PackageManager): String {
return loadLabel(pm).toString()
}
inline fun <reified T> T.createClassLoader(apk: File) =
DynamicClassLoader(apk, T::class.java.classLoader)
fun Context.unwrap(): Context {
var context = this
while (true) {
......@@ -217,21 +204,6 @@ fun Activity.hideKeyboard() {
view.clearFocus()
}
fun Fragment.hideKeyboard() {
activity?.hideKeyboard()
}
fun View.setOnViewReadyListener(callback: () -> Unit) = addOnGlobalLayoutListener(true, callback)
fun View.addOnGlobalLayoutListener(oneShot: Boolean = false, callback: () -> Unit) =
viewTreeObserver.addOnGlobalLayoutListener(object :
ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
if (oneShot) viewTreeObserver.removeOnGlobalLayoutListener(this)
callback()
}
})
fun ViewGroup.startAnimations() {
val transition = AutoTransition()
.setInterpolator(FastOutSlowInInterpolator())
......
package com.topjohnwu.magisk.ktx
import androidx.databinding.ObservableList
fun <T> ObservableList<T>.addOnListChangedCallback(
onChanged: ((sender: ObservableList<T>) -> Unit)? = null,
onItemRangeRemoved: ((sender: ObservableList<T>, positionStart: Int, itemCount: Int) -> Unit)? = null,
onItemRangeMoved: ((sender: ObservableList<T>, fromPosition: Int, toPosition: Int, itemCount: Int) -> Unit)? = null,
onItemRangeInserted: ((sender: ObservableList<T>, positionStart: Int, itemCount: Int) -> Unit)? = null,
onItemRangeChanged: ((sender: ObservableList<T>, positionStart: Int, itemCount: Int) -> Unit)? = null
) = addOnListChangedCallback(object : ObservableList.OnListChangedCallback<ObservableList<T>>() {
override fun onChanged(sender: ObservableList<T>?) {
onChanged?.invoke(sender ?: return)
}
override fun onItemRangeRemoved(
sender: ObservableList<T>?,
positionStart: Int,
itemCount: Int
) {
onItemRangeRemoved?.invoke(
sender ?: return,
positionStart,
itemCount
)
}
override fun onItemRangeMoved(
sender: ObservableList<T>?,
fromPosition: Int,
toPosition: Int,
itemCount: Int
) {
onItemRangeMoved?.invoke(
sender ?: return,
fromPosition,
toPosition,
itemCount
)
}
override fun onItemRangeInserted(
sender: ObservableList<T>?,
positionStart: Int,
itemCount: Int
) {
onItemRangeInserted?.invoke(
sender ?: return,
positionStart,
itemCount
)
}
override fun onItemRangeChanged(
sender: ObservableList<T>?,
positionStart: Int,
itemCount: Int
) {
onItemRangeChanged?.invoke(
sender ?: return,
positionStart,
itemCount
)
}
})
package com.topjohnwu.magisk.ktx
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flatMapMerge
import kotlinx.coroutines.flow.flow
inline fun <T, R> Flow<T>.concurrentMap(crossinline transform: suspend (T) -> R): Flow<R> {
return flatMapMerge { value ->
flow { emit(transform(value)) }
}
}
package com.topjohnwu.magisk.ktx
import androidx.collection.SparseArrayCompat
import timber.log.Timber
import com.topjohnwu.magisk.core.utils.currentLocale
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flatMapMerge
import kotlinx.coroutines.flow.flow
import java.io.File
import java.io.InputStream
import java.io.OutputStream
import java.lang.reflect.Field
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.*
import java.util.zip.ZipEntry
......@@ -45,8 +49,27 @@ fun <T> MutableSet<T>.synchronized(): MutableSet<T> = Collections.synchronizedSe
fun <K, V> MutableMap<K, V>.synchronized(): MutableMap<K, V> = Collections.synchronizedMap(this)
fun SimpleDateFormat.parseOrNull(date: String) =
runCatching { parse(date) }.onFailure { Timber.e(it) }.getOrNull()
fun Class<*>.reflectField(name: String): Field =
getDeclaredField(name).apply { isAccessible = true }
inline fun <T, R> Flow<T>.concurrentMap(crossinline transform: suspend (T) -> R): Flow<R> {
return flatMapMerge { value ->
flow { emit(transform(value)) }
}
}
fun Long.toTime(format: DateFormat) = format.format(this).orEmpty()
val timeFormatStandard by lazy {
SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ss",
currentLocale
)
}
val timeDateFormat: DateFormat by lazy {
DateFormat.getDateTimeInstance(
DateFormat.DEFAULT,
DateFormat.DEFAULT,
currentLocale
)
}
package com.topjohnwu.magisk.ktx
import com.topjohnwu.magisk.core.utils.currentLocale
import java.text.DateFormat
import java.text.SimpleDateFormat
val now get() = System.currentTimeMillis()
fun Long.toTime(format: DateFormat) = format.format(this).orEmpty()
val timeFormatStandard by lazy { SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss",
currentLocale
) }
val timeDateFormat: DateFormat by lazy {
DateFormat.getDateTimeInstance(
DateFormat.DEFAULT,
DateFormat.DEFAULT,
currentLocale
)
}
......@@ -15,10 +15,10 @@ import com.topjohnwu.magisk.MainDirections
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseMainActivity
import com.topjohnwu.magisk.arch.BaseViewModel
import com.topjohnwu.magisk.arch.viewModel
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.di.viewModel
import com.topjohnwu.magisk.core.isRunningAsStub
import com.topjohnwu.magisk.databinding.ActivityMainMd2Binding
import com.topjohnwu.magisk.ktx.startAnimations
......
......@@ -10,7 +10,7 @@ import androidx.appcompat.widget.SearchView
import androidx.recyclerview.widget.RecyclerView
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseFragment
import com.topjohnwu.magisk.core.di.viewModel
import com.topjohnwu.magisk.arch.viewModel
import com.topjohnwu.magisk.databinding.FragmentDenyMd2Binding
import com.topjohnwu.magisk.ktx.hideKeyboard
import rikka.recyclerview.addEdgeSpacing
......@@ -35,7 +35,7 @@ class DenyListFragment : BaseFragment<FragmentDenyMd2Binding>() {
binding.appList.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
if (newState != RecyclerView.SCROLL_STATE_IDLE) hideKeyboard()
if (newState != RecyclerView.SCROLL_STATE_IDLE) activity?.hideKeyboard()
}
})
......
......@@ -10,9 +10,9 @@ import androidx.navigation.NavDeepLinkBuilder
import com.topjohnwu.magisk.MainDirections
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseFragment
import com.topjohnwu.magisk.arch.viewModel
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.cmp
import com.topjohnwu.magisk.core.di.viewModel
import com.topjohnwu.magisk.databinding.FragmentFlashMd2Binding
import com.topjohnwu.magisk.ui.MainActivity
......
......@@ -19,7 +19,10 @@ import com.topjohnwu.magisk.databinding.diffListOf
import com.topjohnwu.magisk.databinding.itemBindingOf
import com.topjohnwu.magisk.databinding.set
import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.ktx.*
import com.topjohnwu.magisk.ktx.reboot
import com.topjohnwu.magisk.ktx.synchronized
import com.topjohnwu.magisk.ktx.timeFormatStandard
import com.topjohnwu.magisk.ktx.toTime
import com.topjohnwu.superuser.CallbackList
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
......@@ -100,7 +103,8 @@ class FlashViewModel : BaseViewModel() {
private fun savePressed() = withExternalRW {
viewModelScope.launch(Dispatchers.IO) {
val name = "magisk_install_log_%s.log".format(now.toTime(timeFormatStandard))
val name = "magisk_install_log_%s.log".format(
System.currentTimeMillis().toTime(timeFormatStandard))
val file = MediaStoreUtils.getFile(name, true)
file.uri.outputStream().bufferedWriter().use { writer ->
synchronized(logItems) {
......
......@@ -6,8 +6,8 @@ import android.widget.ImageView
import android.widget.TextView
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseFragment
import com.topjohnwu.magisk.arch.viewModel
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.di.viewModel
import com.topjohnwu.magisk.core.download.DownloadService
import com.topjohnwu.magisk.databinding.FragmentHomeMd2Binding
import com.topjohnwu.magisk.events.RebootEvent
......
......@@ -2,7 +2,7 @@ package com.topjohnwu.magisk.ui.install
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseFragment
import com.topjohnwu.magisk.core.di.viewModel
import com.topjohnwu.magisk.arch.viewModel
import com.topjohnwu.magisk.databinding.FragmentInstallMd2Binding
class InstallFragment : BaseFragment<FragmentInstallMd2Binding>() {
......
......@@ -8,7 +8,7 @@ import android.view.View
import androidx.core.view.isVisible
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseFragment
import com.topjohnwu.magisk.core.di.viewModel
import com.topjohnwu.magisk.arch.viewModel
import com.topjohnwu.magisk.databinding.FragmentLogMd2Binding
import com.topjohnwu.magisk.ui.MainActivity
import com.topjohnwu.magisk.utils.MotionRevealHelper
......
......@@ -14,7 +14,6 @@ import com.topjohnwu.magisk.databinding.diffListOf
import com.topjohnwu.magisk.databinding.itemBindingOf
import com.topjohnwu.magisk.databinding.set
import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.ktx.now
import com.topjohnwu.magisk.ktx.timeFormatStandard
import com.topjohnwu.magisk.ktx.toTime
import com.topjohnwu.magisk.view.TextItem
......@@ -59,7 +58,8 @@ class LogViewModel(
fun saveMagiskLog() = withExternalRW {
viewModelScope.launch(Dispatchers.IO) {
val filename = "magisk_log_%s.log".format(now.toTime(timeFormatStandard))
val filename = "magisk_log_%s.log".format(
System.currentTimeMillis().toTime(timeFormatStandard))
val logFile = MediaStoreUtils.getFile(filename, true)
logFile.uri.outputStream().bufferedWriter().use { file ->
file.write("---Detected Device Info---\n\n")
......
......@@ -5,8 +5,8 @@ import android.view.View
import com.topjohnwu.magisk.MainDirections
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseFragment
import com.topjohnwu.magisk.arch.viewModel
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.di.viewModel
import com.topjohnwu.magisk.databinding.FragmentModuleMd2Binding
import com.topjohnwu.magisk.databinding.RvItem
import com.topjohnwu.magisk.databinding.adapterOf
......
......@@ -4,7 +4,7 @@ import android.os.Bundle
import android.view.View
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseFragment
import com.topjohnwu.magisk.core.di.viewModel
import com.topjohnwu.magisk.arch.viewModel
import com.topjohnwu.magisk.databinding.FragmentSettingsMd2Binding
import rikka.recyclerview.addEdgeSpacing
import rikka.recyclerview.addItemSpacing
......
......@@ -4,7 +4,7 @@ import android.os.Bundle
import android.view.View
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseFragment
import com.topjohnwu.magisk.core.di.viewModel
import com.topjohnwu.magisk.arch.viewModel
import com.topjohnwu.magisk.databinding.AnyDiffRvItem
import com.topjohnwu.magisk.databinding.FragmentSuperuserMd2Binding
import com.topjohnwu.magisk.databinding.adapterOf
......
......@@ -10,7 +10,7 @@ import android.view.WindowManager
import androidx.lifecycle.lifecycleScope
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.UIActivity
import com.topjohnwu.magisk.core.di.viewModel
import com.topjohnwu.magisk.arch.viewModel
import com.topjohnwu.magisk.core.su.SuCallbackHandler
import com.topjohnwu.magisk.core.su.SuCallbackHandler.REQUEST
import com.topjohnwu.magisk.databinding.ActivityRequestBinding
......
......@@ -9,7 +9,7 @@ import android.widget.FrameLayout
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseFragment
import com.topjohnwu.magisk.core.di.viewModel
import com.topjohnwu.magisk.arch.viewModel
import com.topjohnwu.magisk.databinding.FragmentThemeMd2Binding
import com.topjohnwu.magisk.databinding.ItemThemeBindingImpl
......
package com.topjohnwu.magisk.utils
import android.content.res.Resources
import android.widget.TextView
import androidx.databinding.BindingAdapter
abstract class TextHolder {
......@@ -46,9 +44,3 @@ abstract class TextHolder {
fun Int.asText(): TextHolder = TextHolder.Resource(this)
fun Int.asText(vararg params: Any): TextHolder = TextHolder.ResourceArgs(this, *params)
fun CharSequence.asText(): TextHolder = TextHolder.String(this)
@BindingAdapter("android:text")
fun TextView.setText(text: TextHolder) {
this.text = text.getText(context.resources)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment