/
SettingsViewModel.kt
139 lines (124 loc) · 4.62 KB
/
SettingsViewModel.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package com.topjohnwu.magisk.ui.settings
import android.os.Build
import android.view.View
import android.widget.Toast
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.lifecycle.viewModelScope
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.BuildConfig
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseViewModel
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.isRunningAsStub
import com.topjohnwu.magisk.core.tasks.HideAPK
import com.topjohnwu.magisk.databinding.adapterOf
import com.topjohnwu.magisk.databinding.itemBindingOf
import com.topjohnwu.magisk.di.AppContext
import com.topjohnwu.magisk.events.AddHomeIconEvent
import com.topjohnwu.magisk.events.RecreateEvent
import com.topjohnwu.magisk.events.dialog.BiometricEvent
import com.topjohnwu.magisk.ktx.activity
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.launch
class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Callback {
val adapter = adapterOf<BaseSettingsItem>()
val itemBinding = itemBindingOf<BaseSettingsItem> { it.bindExtra(BR.callback, this) }
val items = createItems()
init {
viewModelScope.launch {
Language.loadLanguages(this)
}
}
private fun createItems(): List<BaseSettingsItem> {
val context = AppContext
val hidden = context.packageName != BuildConfig.APPLICATION_ID
// Customization
val list = mutableListOf(
Customization,
Theme, Language
)
if (isRunningAsStub && ShortcutManagerCompat.isRequestPinShortcutSupported(context))
list.add(AddShortcut)
// Manager
list.addAll(listOf(
AppSettings,
UpdateChannel, UpdateChannelUrl, UpdateChecker, DownloadPath
))
if (Info.env.isActive) {
if (Const.USER_ID == 0) {
if (hidden)
list.add(Restore)
else if (Info.isConnected.get())
list.add(Hide)
}
}
// Magisk
if (Info.env.isActive) {
list.addAll(listOf(
Magisk,
SystemlessHosts
))
if (Const.Version.isCanary()) {
list.addAll(listOf(DenyList, DenyListConfig))
}
}
// Superuser
if (Utils.showSuperUser()) {
list.addAll(listOf(
Superuser,
Tapjack, Biometrics, AccessMode, MultiuserMode, MountNamespaceMode,
AutomaticResponse, RequestTimeout, SUNotification
))
if (Build.VERSION.SDK_INT < 23) {
// Biometric is only available on 6.0+
list.remove(Biometrics)
}
if (Build.VERSION.SDK_INT < 26) {
// Re-authenticate is not feasible on 8.0+
list.add(Reauthenticate)
}
if (Build.VERSION.SDK_INT >= 31) {
// Can hide overlay windows on 12.0+
list.remove(Tapjack)
}
}
return list
}
override fun onItemPressed(view: View, item: BaseSettingsItem, callback: () -> Unit) = when (item) {
is DownloadPath -> withExternalRW(callback)
is Biometrics -> authenticate(callback)
is Theme -> SettingsFragmentDirections.actionSettingsFragmentToThemeFragment().navigate()
is DenyListConfig -> SettingsFragmentDirections.actionSettingsFragmentToDenyFragment().navigate()
is SystemlessHosts -> createHosts()
is Restore -> HideAPK.restore(view.activity)
is AddShortcut -> AddHomeIconEvent().publish()
else -> callback()
}
override fun onItemChanged(view: View, item: BaseSettingsItem) {
when (item) {
is Language -> RecreateEvent().publish()
is UpdateChannel -> openUrlIfNecessary(view)
is Hide -> viewModelScope.launch { HideAPK.hide(view.activity, item.value) }
else -> Unit
}
}
private fun openUrlIfNecessary(view: View) {
UpdateChannelUrl.refresh()
if (UpdateChannelUrl.isEnabled && UpdateChannelUrl.value.isBlank()) {
UpdateChannelUrl.onPressed(view, this)
}
}
private fun authenticate(callback: () -> Unit) {
BiometricEvent {
// allow the change on success
onSuccess { callback() }
}.publish()
}
private fun createHosts() {
Shell.su("add_hosts_module").submit {
Utils.toast(R.string.settings_hosts_toast, Toast.LENGTH_SHORT)
}
}
}