Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
M
Magisk
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Magisk
Commits
2c12fe6e
Commit
2c12fe6e
authored
Jul 12, 2020
by
topjohnwu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
More efficient databinding
parent
b41b2283
Hide whitespace changes
Inline
Side-by-side
Showing
26 changed files
with
386 additions
and
276 deletions
+386
-276
RecyclerViewItems.kt
...ava/com/topjohnwu/magisk/databinding/RecyclerViewItems.kt
+4
-1
LogRvItem.kt
...a/com/topjohnwu/magisk/model/entity/recycler/LogRvItem.kt
+3
-2
ModuleRvItem.kt
...om/topjohnwu/magisk/model/entity/recycler/ModuleRvItem.kt
+12
-24
SettingsItem.kt
...om/topjohnwu/magisk/model/entity/recycler/SettingsItem.kt
+4
-3
MainActivity.kt
app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt
+4
-0
MainViewModel.kt
app/src/main/java/com/topjohnwu/magisk/ui/MainViewModel.kt
+0
-5
ReselectionTarget.kt
...rc/main/java/com/topjohnwu/magisk/ui/ReselectionTarget.kt
+0
-7
BaseUIActivity.kt
.../main/java/com/topjohnwu/magisk/ui/base/BaseUIActivity.kt
+1
-2
BaseUIFragment.kt
.../main/java/com/topjohnwu/magisk/ui/base/BaseUIFragment.kt
+6
-0
BaseViewModel.kt
...c/main/java/com/topjohnwu/magisk/ui/base/BaseViewModel.kt
+13
-55
CompatDelegate.kt
.../main/java/com/topjohnwu/magisk/ui/base/CompatDelegate.kt
+1
-2
FlashViewModel.kt
...main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt
+10
-6
HideViewModel.kt
...c/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt
+10
-22
HomeViewModel.kt
...c/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt
+24
-19
InstallFragment.kt
...n/java/com/topjohnwu/magisk/ui/install/InstallFragment.kt
+1
-2
InstallViewModel.kt
.../java/com/topjohnwu/magisk/ui/install/InstallViewModel.kt
+29
-25
LogViewModel.kt
...src/main/java/com/topjohnwu/magisk/ui/log/LogViewModel.kt
+11
-13
ModuleFragment.kt
...ain/java/com/topjohnwu/magisk/ui/module/ModuleFragment.kt
+1
-1
ModuleViewModel.kt
...in/java/com/topjohnwu/magisk/ui/module/ModuleViewModel.kt
+13
-20
SafetynetViewModel.kt
...a/com/topjohnwu/magisk/ui/safetynet/SafetynetViewModel.kt
+29
-33
SettingsItems.kt
...in/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt
+6
-6
SuRequestViewModel.kt
...a/com/topjohnwu/magisk/ui/surequest/SuRequestViewModel.kt
+27
-22
ObservableHost.kt
...rc/main/java/com/topjohnwu/magisk/utils/ObservableHost.kt
+170
-0
include_home_magisk.xml
app/src/main/res/layout/include_home_magisk.xml
+3
-3
include_home_manager.xml
app/src/main/res/layout/include_home_manager.xml
+2
-2
gradle.properties
gradle.properties
+2
-1
No files found.
app/src/main/java/com/topjohnwu/magisk/databinding/RecyclerViewItems.kt
View file @
2c12fe6e
...
@@ -4,6 +4,7 @@ import androidx.annotation.CallSuper
...
@@ -4,6 +4,7 @@ import androidx.annotation.CallSuper
import
androidx.databinding.ViewDataBinding
import
androidx.databinding.ViewDataBinding
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
me.tatarka.bindingcollectionadapter2.ItemBinding
import
me.tatarka.bindingcollectionadapter2.ItemBinding
abstract
class
RvItem
{
abstract
class
RvItem
{
...
@@ -45,4 +46,6 @@ abstract class ComparableRvItem<in T> : RvItem() {
...
@@ -45,4 +46,6 @@ abstract class ComparableRvItem<in T> : RvItem() {
)
=
oldItem
.
genericContentSameAs
(
newItem
)
)
=
oldItem
.
genericContentSameAs
(
newItem
)
}
}
}
}
}
}
\ No newline at end of file
abstract
class
ObservableItem
<
T
>
:
ComparableRvItem
<
T
>(),
ObservableHost
by
ObservableHost
.
impl
app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/LogRvItem.kt
View file @
2c12fe6e
...
@@ -3,6 +3,7 @@ package com.topjohnwu.magisk.model.entity.recycler
...
@@ -3,6 +3,7 @@ package com.topjohnwu.magisk.model.entity.recycler
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.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.model.entity.MagiskLog
...
@@ -16,13 +17,13 @@ class LogItem(val item: MagiskLog) : ObservableItem<LogItem>() {
...
@@ -16,13 +17,13 @@ class LogItem(val item: MagiskLog) : ObservableItem<LogItem>() {
@Bindable
get
@Bindable
get
set
(
value
)
{
set
(
value
)
{
field
=
value
field
=
value
notify
Change
(
BR
.
top
)
notify
PropertyChanged
(
BR
.
top
)
}
}
var
isBottom
=
false
var
isBottom
=
false
@Bindable
get
@Bindable
get
set
(
value
)
{
set
(
value
)
{
field
=
value
field
=
value
notify
Change
(
BR
.
bottom
)
notify
PropertyChanged
(
BR
.
bottom
)
}
}
override
fun
itemSameAs
(
other
:
LogItem
)
=
item
.
appName
==
other
.
item
.
appName
override
fun
itemSameAs
(
other
:
LogItem
)
=
item
.
appName
==
other
.
item
.
appName
...
...
app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/ModuleRvItem.kt
View file @
2c12fe6e
package
com.topjohnwu.magisk.model.entity.recycler
package
com.topjohnwu.magisk.model.entity.recycler
import
androidx.databinding.*
import
androidx.databinding.Bindable
import
androidx.databinding.Observable
import
androidx.databinding.ObservableField
import
androidx.databinding.ViewDataBinding
import
androidx.recyclerview.widget.StaggeredGridLayoutManager
import
androidx.recyclerview.widget.StaggeredGridLayoutManager
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.module.Module
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.ui.module.ModuleViewModel
import
com.topjohnwu.magisk.ui.module.ModuleViewModel
object
InstallModule
:
ComparableRvItem
<
InstallModule
>()
{
object
InstallModule
:
ComparableRvItem
<
InstallModule
>()
{
...
@@ -33,19 +37,19 @@ class SectionTitle(
...
@@ -33,19 +37,19 @@ class SectionTitle(
@Bindable
get
@Bindable
get
set
(
value
)
{
set
(
value
)
{
field
=
value
field
=
value
notify
Change
(
BR
.
button
)
notify
PropertyChanged
(
BR
.
button
)
}
}
var
icon
=
_icon
var
icon
=
_icon
@Bindable
get
@Bindable
get
set
(
value
)
{
set
(
value
)
{
field
=
value
field
=
value
notify
Change
(
BR
.
icon
)
notify
PropertyChanged
(
BR
.
icon
)
}
}
var
hasButton
=
button
!=
0
||
icon
!=
0
var
hasButton
=
button
!=
0
||
icon
!=
0
@Bindable
get
@Bindable
get
set
(
value
)
{
set
(
value
)
{
field
=
value
field
=
value
notify
Change
(
BR
.
hasButton
)
notify
PropertyChanged
(
BR
.
hasButton
)
}
}
override
fun
onBindingBound
(
binding
:
ViewDataBinding
)
{
override
fun
onBindingBound
(
binding
:
ViewDataBinding
)
{
...
@@ -66,7 +70,7 @@ sealed class RepoItem(val item: Repo) : ObservableItem<RepoItem>() {
...
@@ -66,7 +70,7 @@ sealed class RepoItem(val item: Repo) : ObservableItem<RepoItem>() {
@Bindable
get
@Bindable
get
protected
set
(
value
)
{
protected
set
(
value
)
{
field
=
value
field
=
value
notify
Change
(
BR
.
update
)
notify
PropertyChanged
(
BR
.
update
)
}
}
override
fun
contentSameAs
(
other
:
RepoItem
):
Boolean
=
item
==
other
.
item
override
fun
contentSameAs
(
other
:
RepoItem
):
Boolean
=
item
==
other
.
item
...
@@ -89,7 +93,7 @@ class ModuleItem(val item: Module) : ObservableItem<ModuleItem>(), Observable {
...
@@ -89,7 +93,7 @@ class ModuleItem(val item: Module) : ObservableItem<ModuleItem>(), Observable {
var
repo
:
Repo
?
=
null
var
repo
:
Repo
?
=
null
set
(
value
)
{
set
(
value
)
{
field
=
value
field
=
value
notify
Change
(
BR
.
repo
)
notify
PropertyChanged
(
BR
.
repo
)
}
}
@get
:
Bindable
@get
:
Bindable
...
@@ -97,7 +101,7 @@ class ModuleItem(val item: Module) : ObservableItem<ModuleItem>(), Observable {
...
@@ -97,7 +101,7 @@ class ModuleItem(val item: Module) : ObservableItem<ModuleItem>(), Observable {
get
()
=
item
.
enable
get
()
=
item
.
enable
set
(
value
)
{
set
(
value
)
{
item
.
enable
=
value
item
.
enable
=
value
notify
Change
(
BR
.
enabled
)
notify
PropertyChanged
(
BR
.
enabled
)
}
}
@get
:
Bindable
@get
:
Bindable
...
@@ -105,7 +109,7 @@ class ModuleItem(val item: Module) : ObservableItem<ModuleItem>(), Observable {
...
@@ -105,7 +109,7 @@ class ModuleItem(val item: Module) : ObservableItem<ModuleItem>(), Observable {
get
()
=
item
.
remove
get
()
=
item
.
remove
set
(
value
)
{
set
(
value
)
{
item
.
remove
=
value
item
.
remove
=
value
notify
Change
(
BR
.
removed
)
notify
PropertyChanged
(
BR
.
removed
)
}
}
val
isUpdated
get
()
=
item
.
updated
val
isUpdated
get
()
=
item
.
updated
...
@@ -126,21 +130,5 @@ class ModuleItem(val item: Module) : ObservableItem<ModuleItem>(), Observable {
...
@@ -126,21 +130,5 @@ class ModuleItem(val item: Module) : ObservableItem<ModuleItem>(), Observable {
&&
item
.
name
==
other
.
item
.
name
&&
item
.
name
==
other
.
item
.
name
override
fun
itemSameAs
(
other
:
ModuleItem
):
Boolean
=
item
.
id
==
other
.
item
.
id
override
fun
itemSameAs
(
other
:
ModuleItem
):
Boolean
=
item
.
id
==
other
.
item
.
id
}
}
abstract
class
ObservableItem
<
T
>
:
ComparableRvItem
<
T
>(),
Observable
{
private
val
list
=
PropertyChangeRegistry
()
override
fun
removeOnPropertyChangedCallback
(
callback
:
Observable
.
OnPropertyChangedCallback
?)
{
list
.
remove
(
callback
?:
return
)
}
override
fun
addOnPropertyChangedCallback
(
callback
:
Observable
.
OnPropertyChangedCallback
?)
{
list
.
add
(
callback
?:
return
)
}
fun
notifyChange
(
id
:
Int
)
=
list
.
notifyChange
(
this
,
id
)
}
app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/SettingsItem.kt
View file @
2c12fe6e
...
@@ -11,6 +11,7 @@ import androidx.databinding.ViewDataBinding
...
@@ -11,6 +11,7 @@ import androidx.databinding.ViewDataBinding
import
androidx.recyclerview.widget.StaggeredGridLayoutManager
import
androidx.recyclerview.widget.StaggeredGridLayoutManager
import
com.topjohnwu.magisk.BR
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.utils.TransitiveText
import
com.topjohnwu.magisk.utils.TransitiveText
import
com.topjohnwu.magisk.view.MagiskDialog
import
com.topjohnwu.magisk.view.MagiskDialog
import
org.koin.core.KoinComponent
import
org.koin.core.KoinComponent
...
@@ -37,7 +38,7 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
...
@@ -37,7 +38,7 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
// notify only after the callback invocation; callback can invalidate the backing data,
// notify only after the callback invocation; callback can invalidate the backing data,
// which wouldn't be recognized with reverse approach
// which wouldn't be recognized with reverse approach
notify
Change
(
BR
.
description
)
notify
PropertyChanged
(
BR
.
description
)
}
}
open
fun
refresh
()
{}
open
fun
refresh
()
{}
...
@@ -60,7 +61,7 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
...
@@ -60,7 +61,7 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
)
=
object
:
ObservableProperty
<
T
>(
initialValue
)
{
)
=
object
:
ObservableProperty
<
T
>(
initialValue
)
{
override
fun
afterChange
(
property
:
KProperty
<
*
>,
oldValue
:
T
,
newValue
:
T
)
{
override
fun
afterChange
(
property
:
KProperty
<
*
>,
oldValue
:
T
,
newValue
:
T
)
{
setter
(
newValue
)
setter
(
newValue
)
notify
Change
(
fieldId
)
notify
PropertyChanged
(
fieldId
)
}
}
}
}
...
@@ -169,7 +170,7 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
...
@@ -169,7 +170,7 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
}
}
.
applyAdapter
(
entries
)
{
.
applyAdapter
(
entries
)
{
value
=
it
value
=
it
notify
Change
(
BR
.
selectedEntry
)
notify
PropertyChanged
(
BR
.
selectedEntry
)
super
.
onPressed
(
view
,
callback
)
super
.
onPressed
(
view
,
callback
)
}
}
.
reveal
()
.
reveal
()
...
...
app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt
View file @
2c12fe6e
...
@@ -18,6 +18,8 @@ import com.topjohnwu.magisk.core.Info
...
@@ -18,6 +18,8 @@ import com.topjohnwu.magisk.core.Info
import
com.topjohnwu.magisk.databinding.ActivityMainMd2Binding
import
com.topjohnwu.magisk.databinding.ActivityMainMd2Binding
import
com.topjohnwu.magisk.ktx.startAnimations
import
com.topjohnwu.magisk.ktx.startAnimations
import
com.topjohnwu.magisk.ui.base.BaseUIActivity
import
com.topjohnwu.magisk.ui.base.BaseUIActivity
import
com.topjohnwu.magisk.ui.base.BaseViewModel
import
com.topjohnwu.magisk.ui.base.ReselectionTarget
import
com.topjohnwu.magisk.ui.home.HomeFragmentDirections
import
com.topjohnwu.magisk.ui.home.HomeFragmentDirections
import
com.topjohnwu.magisk.utils.HideBottomViewOnScrollBehavior
import
com.topjohnwu.magisk.utils.HideBottomViewOnScrollBehavior
import
com.topjohnwu.magisk.utils.HideTopViewOnScrollBehavior
import
com.topjohnwu.magisk.utils.HideTopViewOnScrollBehavior
...
@@ -26,6 +28,8 @@ import com.topjohnwu.magisk.view.MagiskDialog
...
@@ -26,6 +28,8 @@ import com.topjohnwu.magisk.view.MagiskDialog
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
class
MainViewModel
:
BaseViewModel
()
open
class
MainActivity
:
BaseUIActivity
<
MainViewModel
,
ActivityMainMd2Binding
>()
{
open
class
MainActivity
:
BaseUIActivity
<
MainViewModel
,
ActivityMainMd2Binding
>()
{
override
val
layoutRes
=
R
.
layout
.
activity_main_md2
override
val
layoutRes
=
R
.
layout
.
activity_main_md2
...
...
app/src/main/java/com/topjohnwu/magisk/ui/MainViewModel.kt
deleted
100644 → 0
View file @
b41b2283
package
com.topjohnwu.magisk.ui
import
com.topjohnwu.magisk.ui.base.BaseViewModel
class
MainViewModel
:
BaseViewModel
()
app/src/main/java/com/topjohnwu/magisk/ui/ReselectionTarget.kt
deleted
100644 → 0
View file @
b41b2283
package
com.topjohnwu.magisk.ui
interface
ReselectionTarget
{
fun
onReselected
()
}
app/src/main/java/com/topjohnwu/magisk/ui/base/BaseUIActivity.kt
View file @
2c12fe6e
...
@@ -20,7 +20,6 @@ import com.topjohnwu.magisk.core.Config
...
@@ -20,7 +20,6 @@ import com.topjohnwu.magisk.core.Config
import
com.topjohnwu.magisk.core.base.BaseActivity
import
com.topjohnwu.magisk.core.base.BaseActivity
import
com.topjohnwu.magisk.ktx.snackbar
import
com.topjohnwu.magisk.ktx.snackbar
import
com.topjohnwu.magisk.ktx.startAnimations
import
com.topjohnwu.magisk.ktx.startAnimations
import
com.topjohnwu.magisk.ktx.value
import
com.topjohnwu.magisk.model.events.EventHandler
import
com.topjohnwu.magisk.model.events.EventHandler
import
com.topjohnwu.magisk.model.events.SnackbarEvent
import
com.topjohnwu.magisk.model.events.SnackbarEvent
import
com.topjohnwu.magisk.model.events.ViewEvent
import
com.topjohnwu.magisk.model.events.ViewEvent
...
@@ -116,7 +115,7 @@ abstract class BaseUIActivity<ViewModel : BaseViewModel, Binding : ViewDataBindi
...
@@ -116,7 +115,7 @@ abstract class BaseUIActivity<ViewModel : BaseViewModel, Binding : ViewDataBindi
}
}
override
fun
peekSystemWindowInsets
(
insets
:
Insets
)
{
override
fun
peekSystemWindowInsets
(
insets
:
Insets
)
{
viewModel
.
insets
.
value
=
insets
viewModel
.
insets
=
insets
}
}
protected
fun
ViewEvent
.
dispatchOnSelf
()
=
onEventDispatched
(
this
)
protected
fun
ViewEvent
.
dispatchOnSelf
()
=
onEventDispatched
(
this
)
...
...
app/src/main/java/com/topjohnwu/magisk/ui/base/BaseUIFragment.kt
View file @
2c12fe6e
...
@@ -89,3 +89,9 @@ abstract class BaseUIFragment<ViewModel : BaseViewModel, Binding : ViewDataBindi
...
@@ -89,3 +89,9 @@ abstract class BaseUIFragment<ViewModel : BaseViewModel, Binding : ViewDataBindi
}
}
}
}
interface
ReselectionTarget
{
fun
onReselected
()
}
app/src/main/java/com/topjohnwu/magisk/ui/base/BaseViewModel.kt
View file @
2c12fe6e
...
@@ -5,8 +5,6 @@ import androidx.annotation.CallSuper
...
@@ -5,8 +5,6 @@ import androidx.annotation.CallSuper
import
androidx.core.graphics.Insets
import
androidx.core.graphics.Insets
import
androidx.databinding.Bindable
import
androidx.databinding.Bindable
import
androidx.databinding.Observable
import
androidx.databinding.Observable
import
androidx.databinding.ObservableField
import
androidx.databinding.PropertyChangeRegistry
import
androidx.lifecycle.LiveData
import
androidx.lifecycle.LiveData
import
androidx.lifecycle.MutableLiveData
import
androidx.lifecycle.MutableLiveData
import
androidx.lifecycle.ViewModel
import
androidx.lifecycle.ViewModel
...
@@ -17,30 +15,33 @@ import com.topjohnwu.magisk.core.Info
...
@@ -17,30 +15,33 @@ 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.*
import
com.topjohnwu.magisk.model.events.*
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.observable
import
kotlinx.coroutines.Job
import
kotlinx.coroutines.Job
import
org.koin.core.KoinComponent
import
org.koin.core.KoinComponent
abstract
class
BaseViewModel
(
abstract
class
BaseViewModel
(
initialState
:
State
=
State
.
LOADING
initialState
:
State
=
State
.
LOADING
)
:
ViewModel
(),
Observable
,
KoinComponent
{
)
:
ViewModel
(),
Observable
Host
by
ObservableHost
.
impl
,
KoinComponent
{
enum
class
State
{
enum
class
State
{
LOADED
,
LOADING
,
LOADING_FAILED
LOADED
,
LOADING
,
LOADING_FAILED
}
}
val
loading
@Bindable
get
()
=
state
==
State
.
LOADING
@get
:
Bindable
val
loaded
@Bindable
get
()
=
state
==
State
.
LOADED
val
loading
get
()
=
state
==
State
.
LOADING
val
loadingFailed
@Bindable
get
()
=
state
==
State
.
LOADING_FAILED
@get
:
Bindable
val
loaded
get
()
=
state
==
State
.
LOADED
@get
:
Bindable
val
loadFailed
get
()
=
state
==
State
.
LOADING_FAILED
val
isConnected
get
()
=
Info
.
isConnected
val
isConnected
get
()
=
Info
.
isConnected
val
viewEvents
:
LiveData
<
ViewEvent
>
get
()
=
_viewEvents
val
viewEvents
:
LiveData
<
ViewEvent
>
get
()
=
_viewEvents
val
insets
=
ObservableField
(
Insets
.
NONE
)
var
state
:
State
=
initialState
@get
:
Bindable
set
(
value
)
{
var
insets
by
observable
(
Insets
.
NONE
,
BR
.
insets
)
field
=
value
notifyStateChanged
()
var
state
by
observable
(
initialState
,
BR
.
loading
,
BR
.
loaded
,
BR
.
loadFailed
)
}
private
val
_viewEvents
=
MutableLiveData
<
ViewEvent
>()
private
val
_viewEvents
=
MutableLiveData
<
ViewEvent
>()
private
var
runningJob
:
Job
?
=
null
private
var
runningJob
:
Job
?
=
null
...
@@ -65,12 +66,6 @@ abstract class BaseViewModel(
...
@@ -65,12 +66,6 @@ abstract class BaseViewModel(
protected
open
fun
refresh
():
Job
?
=
null
protected
open
fun
refresh
():
Job
?
=
null
open
fun
notifyStateChanged
()
{
notifyPropertyChanged
(
BR
.
loading
)
notifyPropertyChanged
(
BR
.
loaded
)
notifyPropertyChanged
(
BR
.
loadingFailed
)
}
@CallSuper
@CallSuper
override
fun
onCleared
()
{
override
fun
onCleared
()
{
isConnected
.
removeOnPropertyChangedCallback
(
refreshCallback
)
isConnected
.
removeOnPropertyChangedCallback
(
refreshCallback
)
...
@@ -108,41 +103,4 @@ abstract class BaseViewModel(
...
@@ -108,41 +103,4 @@ abstract class BaseViewModel(
_viewEvents
.
postValue
(
NavigationWrapper
(
this
))
_viewEvents
.
postValue
(
NavigationWrapper
(
this
))
}
}
// The following is copied from androidx.databinding.BaseObservable
@Transient
private
var
callbacks
:
PropertyChangeRegistry
?
=
null
@Synchronized
override
fun
addOnPropertyChangedCallback
(
callback
:
Observable
.
OnPropertyChangedCallback
)
{
if
(
callbacks
==
null
)
{
callbacks
=
PropertyChangeRegistry
()
}
callbacks
?.
add
(
callback
)
}
@Synchronized
override
fun
removeOnPropertyChangedCallback
(
callback
:
Observable
.
OnPropertyChangedCallback
)
{
callbacks
?.
remove
(
callback
)
}
/**
* Notifies listeners that all properties of this instance have changed.
*/
@Synchronized
fun
notifyChange
()
{
callbacks
?.
notifyCallbacks
(
this
,
0
,
null
)
}
/**
* Notifies listeners that a specific property has changed. The getter for the property
* that changes should be marked with [androidx.databinding.Bindable] to generate a field in
* `BR` to be used as `fieldId`.
*
* @param fieldId The generated BR id for the Bindable field.
*/
fun
notifyPropertyChanged
(
fieldId
:
Int
)
{
callbacks
?.
notifyCallbacks
(
this
,
fieldId
,
null
)
}
}
}
app/src/main/java/com/topjohnwu/magisk/ui/base/CompatDelegate.kt
View file @
2c12fe6e
...
@@ -5,7 +5,6 @@ import androidx.core.graphics.Insets
...
@@ -5,7 +5,6 @@ import androidx.core.graphics.Insets
import
androidx.core.view.ViewCompat
import
androidx.core.view.ViewCompat
import
androidx.core.view.WindowInsetsCompat
import
androidx.core.view.WindowInsetsCompat
import
androidx.fragment.app.Fragment
import
androidx.fragment.app.Fragment
import
com.topjohnwu.magisk.ktx.value
import
com.topjohnwu.magisk.model.events.ActivityExecutor
import
com.topjohnwu.magisk.model.events.ActivityExecutor
import
com.topjohnwu.magisk.model.events.ContextExecutor
import
com.topjohnwu.magisk.model.events.ContextExecutor
import
com.topjohnwu.magisk.model.events.FragmentExecutor
import
com.topjohnwu.magisk.model.events.FragmentExecutor
...
@@ -44,7 +43,7 @@ class CompatDelegate internal constructor(
...
@@ -44,7 +43,7 @@ class CompatDelegate internal constructor(
insets
.
asInsets
()
insets
.
asInsets
()
.
also
{
view
.
peekSystemWindowInsets
(
it
)
}
.
also
{
view
.
peekSystemWindowInsets
(
it
)
}
.
let
{
view
.
consumeSystemWindowInsets
(
it
)
}
.
let
{
view
.
consumeSystemWindowInsets
(
it
)
}
?.
also
{
view
.
viewModel
.
insets
.
value
=
it
}
?.
also
{
view
.
viewModel
.
insets
=
it
}
?.
subtractBy
(
insets
)
?:
insets
?.
subtractBy
(
insets
)
?:
insets
}
}
if
(
ViewCompat
.
isAttachedToWindow
(
view
.
viewRoot
))
{
if
(
ViewCompat
.
isAttachedToWindow
(
view
.
viewRoot
))
{
...
...
app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt
View file @
2c12fe6e
...
@@ -3,9 +3,10 @@ package com.topjohnwu.magisk.ui.flash
...
@@ -3,9 +3,10 @@ package com.topjohnwu.magisk.ui.flash
import
android.content.res.Resources
import
android.content.res.Resources
import
android.net.Uri
import
android.net.Uri
import
android.view.MenuItem
import
android.view.MenuItem
import
androidx.databinding.Bindable
import
androidx.databinding.ObservableArrayList
import
androidx.databinding.ObservableArrayList
import
androidx.databinding.ObservableField
import
androidx.lifecycle.viewModelScope
import
androidx.lifecycle.viewModelScope
import
com.topjohnwu.magisk.BR
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.Const
import
com.topjohnwu.magisk.core.Const
...
@@ -19,6 +20,7 @@ import com.topjohnwu.magisk.model.events.SnackbarEvent
...
@@ -19,6 +20,7 @@ import com.topjohnwu.magisk.model.events.SnackbarEvent
import
com.topjohnwu.magisk.ui.base.BaseViewModel
import
com.topjohnwu.magisk.ui.base.BaseViewModel
import
com.topjohnwu.magisk.ui.base.diffListOf
import
com.topjohnwu.magisk.ui.base.diffListOf
import
com.topjohnwu.magisk.ui.base.itemBindingOf
import
com.topjohnwu.magisk.ui.base.itemBindingOf
import
com.topjohnwu.magisk.utils.observable
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
...
@@ -31,8 +33,10 @@ class FlashViewModel(
...
@@ -31,8 +33,10 @@ class FlashViewModel(
private
val
resources
:
Resources
private
val
resources
:
Resources
)
:
BaseViewModel
()
{
)
:
BaseViewModel
()
{
val
showReboot
=
ObservableField
(
Shell
.
rootAccess
())
@get
:
Bindable
val
behaviorText
=
ObservableField
(
resources
.
getString
(
R
.
string
.
flashing
))
var
showReboot
by
observable
(
Shell
.
rootAccess
(),
BR
.
showReboot
)
@get
:
Bindable
var
behaviorText
by
observable
(
resources
.
getString
(
R
.
string
.
flashing
),
BR
.
behaviorText
)
val
adapter
=
BindingAdapter
<
ConsoleItem
>()
val
adapter
=
BindingAdapter
<
ConsoleItem
>()
val
items
=
diffListOf
<
ConsoleItem
>()
val
items
=
diffListOf
<
ConsoleItem
>()
...
@@ -59,7 +63,7 @@ class FlashViewModel(
...
@@ -59,7 +63,7 @@ class FlashViewModel(
FlashZip
(
installer
,
outItems
,
logItems
).
exec
()
FlashZip
(
installer
,
outItems
,
logItems
).
exec
()
}
}
Const
.
Value
.
UNINSTALL
->
{
Const
.
Value
.
UNINSTALL
->
{
showReboot
.
value
=
false
showReboot
=
false
FlashZip
.
Uninstall
(
installer
,
outItems
,
logItems
).
exec
()
FlashZip
.
Uninstall
(
installer
,
outItems
,
logItems
).
exec
()
}
}
Const
.
Value
.
FLASH_MAGISK
->
{
Const
.
Value
.
FLASH_MAGISK
->
{
...
@@ -70,7 +74,7 @@ class FlashViewModel(
...
@@ -70,7 +74,7 @@ class FlashViewModel(
}
}
Const
.
Value
.
PATCH_FILE
->
{
Const
.
Value
.
PATCH_FILE
->
{
uri
?:
return
@launch
uri
?:
return
@launch
showReboot
.
value
=
false
showReboot
=
false
MagiskInstaller
.
Patch
(
installer
,
uri
,
outItems
,
logItems
).
exec
()
MagiskInstaller
.
Patch
(
installer
,
uri
,
outItems
,
logItems
).
exec
()
}
}
else
->
{
else
->
{
...
@@ -84,7 +88,7 @@ class FlashViewModel(
...
@@ -84,7 +88,7 @@ class FlashViewModel(
private
fun
onResult
(
success
:
Boolean
)
{
private
fun
onResult
(
success
:
Boolean
)
{
state
=
if
(
success
)
State
.
LOADED
else
State
.
LOADING_FAILED
state
=
if
(
success
)
State
.
LOADED
else
State
.
LOADING_FAILED
behaviorText
.
value
=
when
{
behaviorText
=
when
{
success
->
resources
.
getString
(
R
.
string
.
done
)
success
->
resources
.
getString
(
R
.
string
.
done
)
else
->
resources
.
getString
(
R
.
string
.
failure
)
else
->
resources
.
getString
(
R
.
string
.
failure
)
}
}
...
...
app/src/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt
View file @
2c12fe6e
...
@@ -2,7 +2,6 @@ package com.topjohnwu.magisk.ui.hide
...
@@ -2,7 +2,6 @@ package com.topjohnwu.magisk.ui.hide
import
android.content.pm.ApplicationInfo
import
android.content.pm.ApplicationInfo
import
androidx.databinding.Bindable
import
androidx.databinding.Bindable
import
androidx.databinding.ObservableField
import
androidx.lifecycle.viewModelScope
import
androidx.lifecycle.viewModelScope
import
com.topjohnwu.magisk.BR
import
com.topjohnwu.magisk.BR
import
com.topjohnwu.magisk.core.utils.currentLocale
import
com.topjohnwu.magisk.core.utils.currentLocale
...
@@ -18,6 +17,7 @@ import com.topjohnwu.magisk.ui.base.BaseViewModel
...
@@ -18,6 +17,7 @@ import com.topjohnwu.magisk.ui.base.BaseViewModel
import
com.topjohnwu.magisk.ui.base.Queryable
import
com.topjohnwu.magisk.ui.base.Queryable
import
com.topjohnwu.magisk.ui.base.filterableListOf
import
com.topjohnwu.magisk.ui.base.filterableListOf
import
com.topjohnwu.magisk.ui.base.itemBindingOf
import
com.topjohnwu.magisk.ui.base.itemBindingOf
import
com.topjohnwu.magisk.utils.observable
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.launch
import
kotlinx.coroutines.launch
import
kotlinx.coroutines.withContext
import
kotlinx.coroutines.withContext
...
@@ -28,21 +28,16 @@ class HideViewModel(
...
@@ -28,21 +28,16 @@ class HideViewModel(
override
val
queryDelay
=
1000L
override
val
queryDelay
=
1000L
var
isShowSystem
=
false
@get
:
Bindable
@Bindable
get
var
isShowSystem
by
observable
(
false
,
BR
.
showSystem
)
{
set
(
value
)
{
submitQuery
()
field
=
value
}
notifyPropertyChanged
(
BR
.
showSystem
)
submitQuery
()
@get
:
Bindable
}
var
query
by
observable
(
""
,
BR
.
query
)
{
submitQuery
()
}
var
query
=
""
@Bindable
get
set
(
value
)
{
field
=
value
notifyPropertyChanged
(
BR
.
query
)
submitQuery
()
}
val
items
=
filterableListOf
<
HideItem
>()
val
items
=
filterableListOf
<
HideItem
>()
val
itemBinding
=
itemBindingOf
<
HideItem
>
{
val
itemBinding
=
itemBindingOf
<
HideItem
>
{
it
.
bindExtra
(
BR
.
viewModel
,
this
)
it
.
bindExtra
(
BR
.
viewModel
,
this
)
...
@@ -51,8 +46,6 @@ class HideViewModel(
...
@@ -51,8 +46,6 @@ class HideViewModel(
it
.
bindExtra
(
BR
.
viewModel
,
this
)
it
.
bindExtra
(
BR
.
viewModel
,
this
)
}
}
val
isFilterExpanded
=
ObservableField
(
false
)
override
fun
refresh
()
=
viewModelScope
.
launch
{
override
fun
refresh
()
=
viewModelScope
.
launch
{
state
=
State
.
LOADING
state
=
State
.
LOADING
val
apps
=
magiskRepo
.
fetchApps
()
val
apps
=
magiskRepo
.
fetchApps
()
...
@@ -106,10 +99,5 @@ class HideViewModel(
...
@@ -106,10 +99,5 @@ class HideViewModel(
fun
resetQuery
()
{
fun
resetQuery
()
{
query
=
""
query
=
""
}
}
fun
hideFilter
()
{
isFilterExpanded
.
value
=
false
}
}
}
app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt
View file @
2c12fe6e
package
com.topjohnwu.magisk.ui.home
package
com.topjohnwu.magisk.ui.home
import
android.os.Build
import
android.os.Build
import
androidx.databinding.
ObservableField
import
androidx.databinding.
Bindable
import
androidx.lifecycle.viewModelScope
import
androidx.lifecycle.viewModelScope
import
com.topjohnwu.magisk.BuildConfig
import
com.topjohnwu.magisk.BuildConfig
import
com.topjohnwu.magisk.R
import
com.topjohnwu.magisk.R
...
@@ -27,6 +27,7 @@ import com.topjohnwu.magisk.model.events.dialog.ManagerInstallDialog
...
@@ -27,6 +27,7 @@ import com.topjohnwu.magisk.model.events.dialog.ManagerInstallDialog
import
com.topjohnwu.magisk.model.events.dialog.UninstallDialog
import
com.topjohnwu.magisk.model.events.dialog.UninstallDialog
import
com.topjohnwu.magisk.ui.base.BaseViewModel
import
com.topjohnwu.magisk.ui.base.BaseViewModel
import
com.topjohnwu.magisk.ui.base.itemBindingOf
import
com.topjohnwu.magisk.ui.base.itemBindingOf
import
com.topjohnwu.magisk.utils.observable
import
com.topjohnwu.superuser.Shell
import
com.topjohnwu.superuser.Shell
import
kotlinx.coroutines.launch
import
kotlinx.coroutines.launch
import
me.tatarka.bindingcollectionadapter2.BR
import
me.tatarka.bindingcollectionadapter2.BR
...
@@ -40,22 +41,26 @@ class HomeViewModel(
...
@@ -40,22 +41,26 @@ class HomeViewModel(
private
val
repoMagisk
:
MagiskRepository
private
val
repoMagisk
:
MagiskRepository
)
:
BaseViewModel
()
{
)
:
BaseViewModel
()
{
val
isNoticeVisible
=
ObservableField
(
Config
.
safetyNotice
)
@get
:
Bindable
var
isNoticeVisible
by
observable
(
Config
.
safetyNotice
,
BR
.
noticeVisible
)
val
stateMagisk
=
ObservableField
(
MagiskState
.
LOADING
)
@get
:
Bindable
val
stateManager
=
ObservableField
(
MagiskState
.
LOADING
)
var
stateMagisk
by
observable
(
MagiskState
.
LOADING
,
BR
.
stateMagisk
)
@get
:
Bindable
val
stateMagiskRemoteVersion
=
ObservableField
(
R
.
string
.
loading
.
res
())
var
stateManager
by
observable
(
MagiskState
.
LOADING
,
BR
.
stateManager
)
val
stateMagiskInstalledVersion
get
()
=
@get
:
Bindable
var
magiskRemoteVersion
by
observable
(
R
.
string
.
loading
.
res
(),
BR
.
magiskRemoteVersion
)
val
magiskInstalledVersion
get
()
=
"${Info.env.magiskVersionString} (${Info.env.magiskVersionCode})"
"${Info.env.magiskVersionString} (${Info.env.magiskVersionCode})"
val
stateM
agiskMode
get
()
=
R
.
string
.
home_status_normal
.
res
()
val
m
agiskMode
get
()
=
R
.
string
.
home_status_normal
.
res
()
val
stateManagerRemoteVersion
=
ObservableField
(
R
.
string
.
loading
.
res
())
@get
:
Bindable
val
stateManagerInstalledVersion
=
Info
.
stub
?.
let
{
var
managerRemoteVersion
by
observable
(
R
.
string
.
loading
.
res
(),
BR
.
managerRemoteVersion
)
val
managerInstalledVersion
=
Info
.
stub
?.
let
{
"${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE}) (${it.version})"
"${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE}) (${it.version})"
}
?:
"${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})"
}
?:
"${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})"
val
statePackageName
=
packageName
val
statePackageName
=
packageName
val
stateManagerProgress
=
ObservableField
(
0
)
@get
:
Bindable
var
stateManagerProgress
by
observable
(
0
,
BR
.
stateManagerProgress
)
val
items
=
listOf
(
DeveloperItem
.
Mainline
,
DeveloperItem
.
App
,
DeveloperItem
.
Project
)
val
items
=
listOf
(
DeveloperItem
.
Mainline
,
DeveloperItem
.
App
,
DeveloperItem
.
Project
)
val
itemBinding
=
itemBindingOf
<
HomeItem
>
{
val
itemBinding
=
itemBindingOf
<
HomeItem
>
{
...
@@ -70,28 +75,28 @@ class HomeViewModel(
...
@@ -70,28 +75,28 @@ class HomeViewModel(
init
{
init
{
RemoteFileService
.
progressBroadcast
.
observeForever
{
RemoteFileService
.
progressBroadcast
.
observeForever
{
when
(
it
?.
second
)
{
when
(
it
?.
second
)
{
is
Manager
->
stateManagerProgress
.
value
=
it
.
first
.
times
(
100f
).
roundToInt
()
is
Manager
->
stateManagerProgress
=
it
.
first
.
times
(
100f
).
roundToInt
()
}
}
}
}
}
}
override
fun
refresh
()
=
viewModelScope
.
launch
{
override
fun
refresh
()
=
viewModelScope
.
launch
{
repoMagisk
.
fetchUpdate
()
?.
apply
{
repoMagisk
.
fetchUpdate
()
?.
apply
{
stateMagisk
.
value
=
when
{
stateMagisk
=
when
{
!
Info
.
env
.
isActive
->
MagiskState
.
NOT_INSTALLED
!
Info
.
env
.
isActive
->
MagiskState
.
NOT_INSTALLED
magisk
.
isObsolete
->
MagiskState
.
OBSOLETE
magisk
.
isObsolete
->
MagiskState
.
OBSOLETE
else
->
MagiskState
.
UP_TO_DATE
else
->
MagiskState
.
UP_TO_DATE
}
}
stateManager
.
value
=
when
{
stateManager
=
when
{
!
app
.
isUpdateChannelCorrect
&&
isConnected
.
value
->
MagiskState
.
NOT_INSTALLED
!
app
.
isUpdateChannelCorrect
&&
isConnected
.
value
->
MagiskState
.
NOT_INSTALLED
app
.
isObsolete
->
MagiskState
.
OBSOLETE
app
.
isObsolete
->
MagiskState
.
OBSOLETE
else
->
MagiskState
.
UP_TO_DATE
else
->
MagiskState
.
UP_TO_DATE
}
}
stateMagiskRemoteVersion
.
value
=
magiskRemoteVersion
=
"${magisk.version} (${magisk.versionCode})"
"${magisk.version} (${magisk.versionCode})"
stateManagerRemoteVersion
.
value
=
managerRemoteVersion
=
"${app.version} (${app.versionCode}) (${stub.versionCode})"
"${app.version} (${app.versionCode}) (${stub.versionCode})"
launch
{
launch
{
...
@@ -122,7 +127,7 @@ class HomeViewModel(
...
@@ -122,7 +127,7 @@ class HomeViewModel(
fun
hideNotice
()
{
fun
hideNotice
()
{
Config
.
safetyNotice
=
false
Config
.
safetyNotice
=
false
isNoticeVisible
.
value
=
false
isNoticeVisible
=
false
}
}
private
suspend
fun
ensureEnv
()
{
private
suspend
fun
ensureEnv
()
{
...
@@ -133,7 +138,7 @@ class HomeViewModel(
...
@@ -133,7 +138,7 @@ class HomeViewModel(
// Don't bother checking env when magisk is not installed, loading or already has been shown
// Don't bother checking env when magisk is not installed, loading or already has been shown
if
(
if
(
invalidStates
.
any
{
it
==
stateMagisk
.
value
}
||
invalidStates
.
any
{
it
==
stateMagisk
}
||
shownDialog
||
shownDialog
||
// don't care for emulators either
// don't care for emulators either
Build
.
DEVICE
.
orEmpty
().
contains
(
"generic"
)
||
Build
.
DEVICE
.
orEmpty
().
contains
(
"generic"
)
||
...
...
app/src/main/java/com/topjohnwu/magisk/ui/install/InstallFragment.kt
View file @
2c12fe6e
...
@@ -4,7 +4,6 @@ import android.content.Intent
...
@@ -4,7 +4,6 @@ import android.content.Intent
import
androidx.lifecycle.viewModelScope
import
androidx.lifecycle.viewModelScope
import
com.topjohnwu.magisk.R
import
com.topjohnwu.magisk.R
import
com.topjohnwu.magisk.databinding.FragmentInstallMd2Binding
import
com.topjohnwu.magisk.databinding.FragmentInstallMd2Binding
import
com.topjohnwu.magisk.ktx.value
import
com.topjohnwu.magisk.model.events.RequestFileEvent
import
com.topjohnwu.magisk.model.events.RequestFileEvent
import
com.topjohnwu.magisk.ui.base.BaseUIFragment
import
com.topjohnwu.magisk.ui.base.BaseUIFragment
import
org.koin.androidx.viewmodel.ext.android.viewModel
import
org.koin.androidx.viewmodel.ext.android.viewModel
...
@@ -16,7 +15,7 @@ class InstallFragment : BaseUIFragment<InstallViewModel, FragmentInstallMd2Bindi
...
@@ -16,7 +15,7 @@ class InstallFragment : BaseUIFragment<InstallViewModel, FragmentInstallMd2Bindi
override
fun
onActivityResult
(
requestCode
:
Int
,
resultCode
:
Int
,
data
:
Intent
?)
{
override
fun
onActivityResult
(
requestCode
:
Int
,
resultCode
:
Int
,
data
:
Intent
?)
{
super
.
onActivityResult
(
requestCode
,
resultCode
,
data
)
super
.
onActivityResult
(
requestCode
,
resultCode
,
data
)
viewModel
.
data
.
value
=
RequestFileEvent
.
resolve
(
requestCode
,
resultCode
,
data
)
viewModel
.
data
=
RequestFileEvent
.
resolve
(
requestCode
,
resultCode
,
data
)
}
}
override
fun
onStart
()
{
override
fun
onStart
()
{
...
...
app/src/main/java/com/topjohnwu/magisk/ui/install/InstallViewModel.kt
View file @
2c12fe6e
...
@@ -2,21 +2,21 @@ package com.topjohnwu.magisk.ui.install
...
@@ -2,21 +2,21 @@ package com.topjohnwu.magisk.ui.install
import
android.net.Uri
import
android.net.Uri
import
android.widget.Toast
import
android.widget.Toast
import
androidx.databinding.
ObservableField
import
androidx.databinding.
Bindable
import
androidx.lifecycle.viewModelScope
import
androidx.lifecycle.viewModelScope
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.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.core.utils.Utils
import
com.topjohnwu.magisk.core.utils.Utils
import
com.topjohnwu.magisk.data.repository.StringRepository
import
com.topjohnwu.magisk.data.repository.StringRepository
import
com.topjohnwu.magisk.ktx.addOnPropertyChangedCallback
import
com.topjohnwu.magisk.ktx.value
import
com.topjohnwu.magisk.model.entity.internal.Configuration
import
com.topjohnwu.magisk.model.entity.internal.Configuration
import
com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import
com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import
com.topjohnwu.magisk.model.events.RequestFileEvent
import
com.topjohnwu.magisk.model.events.RequestFileEvent
import
com.topjohnwu.magisk.model.events.dialog.SecondSlotWarningDialog
import
com.topjohnwu.magisk.model.events.dialog.SecondSlotWarningDialog
import
com.topjohnwu.magisk.ui.base.BaseViewModel
import
com.topjohnwu.magisk.ui.base.BaseViewModel
import
com.topjohnwu.magisk.utils.observable
import
com.topjohnwu.superuser.Shell
import
com.topjohnwu.superuser.Shell
import
kotlinx.coroutines.launch
import
kotlinx.coroutines.launch
import
org.koin.core.get
import
org.koin.core.get
...
@@ -29,11 +29,26 @@ class InstallViewModel(
...
@@ -29,11 +29,26 @@ class InstallViewModel(
val
isRooted
get
()
=
Shell
.
rootAccess
()
val
isRooted
get
()
=
Shell
.
rootAccess
()
val
isAB
get
()
=
Info
.
isAB
val
isAB
get
()
=
Info
.
isAB
val
step
=
ObservableField
(
0
)
@get
:
Bindable
val
method
=
ObservableField
(-
1
)
var
step
by
observable
(
0
,
BR
.
step
)
val
progress
=
ObservableField
(
0
)
@get
:
Bindable
val
data
=
ObservableField
(
null
as
Uri
?)
var
method
by
observable
(-
1
,
BR
.
method
)
{
val
notes
=
ObservableField
(
""
)
when
(
it
)
{
R
.
id
.
method_patch
->
{
Utils
.
toast
(
R
.
string
.
patch_file_msg
,
Toast
.
LENGTH_LONG
)
RequestFileEvent
().
publish
()
}
R
.
id
.
method_inactive_slot
->
{
SecondSlotWarningDialog
().
publish
()
}
}
}
@get
:
Bindable
var
progress
by
observable
(
0
,
BR
.
progress
)
@get
:
Bindable
var
data
by
observable
(
null
as
Uri
?,
BR
.
data
)
@get
:
Bindable
var
notes
by
observable
(
""
,
BR
.
notes
)
init
{
init
{
RemoteFileService
.
reset
()
RemoteFileService
.
reset
()
...
@@ -42,29 +57,18 @@ class InstallViewModel(
...
@@ -42,29 +57,18 @@ class InstallViewModel(
if
(
subject
!
is
DownloadSubject
.
Magisk
)
{
if
(
subject
!
is
DownloadSubject
.
Magisk
)
{
return
@observeForever
return
@observeForever
}
}
this
.
progress
.
value
=
progress
.
times
(
100
).
roundToInt
()
this
.
progress
=
progress
.
times
(
100
).
roundToInt
()
if
(
this
.
progress
.
value
>=
100
)
{
if
(
this
.
progress
>=
100
)
{
state
=
State
.
LOADED
state
=
State
.
LOADED
}
}
}
}
viewModelScope
.
launch
{
viewModelScope
.
launch
{
notes
.
value
=
stringRepo
.
getString
(
Info
.
remote
.
magisk
.
note
)
notes
=
stringRepo
.
getString
(
Info
.
remote
.
magisk
.
note
)
}
method
.
addOnPropertyChangedCallback
{
when
(
it
!!
)
{
R
.
id
.
method_patch
->
{
Utils
.
toast
(
R
.
string
.
patch_file_msg
,
Toast
.
LENGTH_LONG
)
RequestFileEvent
().
publish
()
}
R
.
id
.
method_inactive_slot
->
{
SecondSlotWarningDialog
().
publish
()
}
}
}
}
}
}
fun
step
(
nextStep
:
Int
)
{
fun
step
(
nextStep
:
Int
)
{
step
.
value
=
nextStep
step
=
nextStep
}
}
fun
install
()
=
DownloadService
(
get
())
{
fun
install
()
=
DownloadService
(
get
())
{
...
@@ -73,9 +77,9 @@ class InstallViewModel(
...
@@ -73,9 +77,9 @@ class InstallViewModel(
// ---
// ---
private
fun
resolveConfiguration
()
=
when
(
method
.
value
)
{
private
fun
resolveConfiguration
()
=
when
(
method
)
{
R
.
id
.
method_download
->
Configuration
.
Download
R
.
id
.
method_download
->
Configuration
.
Download
R
.
id
.
method_patch
->
Configuration
.
Patch
(
data
.
value
!!
)
R
.
id
.
method_patch
->
Configuration
.
Patch
(
data
!!
)
R
.
id
.
method_direct
->
Configuration
.
Flash
.
Primary
R
.
id
.
method_direct
->
Configuration
.
Flash
.
Primary
R
.
id
.
method_inactive_slot
->
Configuration
.
Flash
.
Secondary
R
.
id
.
method_inactive_slot
->
Configuration
.
Flash
.
Secondary
else
->
throw
IllegalArgumentException
(
"Unknown value"
)
else
->
throw
IllegalArgumentException
(
"Unknown value"
)
...
...
app/src/main/java/com/topjohnwu/magisk/ui/log/LogViewModel.kt
View file @
2c12fe6e
package
com.topjohnwu.magisk.ui.log
package
com.topjohnwu.magisk.ui.log
import
androidx.databinding.
ObservableField
import
androidx.databinding.
Bindable
import
androidx.lifecycle.viewModelScope
import
androidx.lifecycle.viewModelScope
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.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.ktx.value
import
com.topjohnwu.magisk.model.entity.recycler.LogItem
import
com.topjohnwu.magisk.model.entity.recycler.LogItem
import
com.topjohnwu.magisk.model.entity.recycler.TextItem
import
com.topjohnwu.magisk.model.entity.recycler.TextItem
import
com.topjohnwu.magisk.model.events.SnackbarEvent
import
com.topjohnwu.magisk.model.events.SnackbarEvent
import
com.topjohnwu.magisk.ui.base.BaseViewModel
import
com.topjohnwu.magisk.ui.base.BaseViewModel
import
com.topjohnwu.magisk.ui.base.diffListOf
import
com.topjohnwu.magisk.ui.base.diffListOf
import
com.topjohnwu.magisk.ui.base.itemBindingOf
import
com.topjohnwu.magisk.ui.base.itemBindingOf
import
com.topjohnwu.magisk.utils.observable
import
com.topjohnwu.superuser.Shell
import
com.topjohnwu.superuser.Shell
import
kotlinx.coroutines.*
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.launch
import
kotlinx.coroutines.withContext
import
timber.log.Timber
import
timber.log.Timber
import
java.io.File
import
java.io.File
import
java.io.IOException
import
java.io.IOException
...
@@ -38,19 +40,15 @@ class LogViewModel(
...
@@ -38,19 +40,15 @@ class LogViewModel(
}
}
// --- magisk log
// --- magisk log
@get
:
Bindable
va
l
consoleText
=
ObservableField
(
" "
)
va
r
consoleText
by
observable
(
" "
,
BR
.
consoleText
)
override
fun
refresh
()
=
viewModelScope
.
launch
{
override
fun
refresh
()
=
viewModelScope
.
launch
{
consoleText
.
value
=
repo
.
fetchMagiskLogs
()
consoleText
=
repo
.
fetchMagiskLogs
()
val
deferred
=
withContext
(
Dispatchers
.
Default
)
{
val
(
suLogs
,
diff
)
=
withContext
(
Dispatchers
.
Default
)
{
async
{
val
suLogs
=
repo
.
fetchSuLogs
().
map
{
LogItem
(
it
)
}
val
suLogs
=
repo
.
fetchSuLogs
().
map
{
LogItem
(
it
)
}
suLogs
to
items
.
calculateDiff
(
suLogs
)
suLogs
to
items
.
calculateDiff
(
suLogs
)
}
}
}
delay
(
500
)
val
(
suLogs
,
diff
)
=
deferred
.
await
()
items
.
firstOrNull
()
?.
isTop
=
false
items
.
firstOrNull
()
?.
isTop
=
false
items
.
lastOrNull
()
?.
isBottom
=
false
items
.
lastOrNull
()
?.
isBottom
=
false
items
.
update
(
suLogs
,
diff
)
items
.
update
(
suLogs
,
diff
)
...
...
app/src/main/java/com/topjohnwu/magisk/ui/module/ModuleFragment.kt
View file @
2c12fe6e
...
@@ -15,7 +15,7 @@ import com.topjohnwu.magisk.ktx.hideKeyboard
...
@@ -15,7 +15,7 @@ import com.topjohnwu.magisk.ktx.hideKeyboard
import
com.topjohnwu.magisk.model.events.InstallExternalModuleEvent
import
com.topjohnwu.magisk.model.events.InstallExternalModuleEvent
import
com.topjohnwu.magisk.model.events.ViewEvent
import
com.topjohnwu.magisk.model.events.ViewEvent
import
com.topjohnwu.magisk.ui.MainActivity
import
com.topjohnwu.magisk.ui.MainActivity
import
com.topjohnwu.magisk.ui.ReselectionTarget
import
com.topjohnwu.magisk.ui.
base.
ReselectionTarget
import
com.topjohnwu.magisk.ui.base.BaseUIFragment
import
com.topjohnwu.magisk.ui.base.BaseUIFragment
import
com.topjohnwu.magisk.utils.EndlessRecyclerScrollListener
import
com.topjohnwu.magisk.utils.EndlessRecyclerScrollListener
import
com.topjohnwu.magisk.utils.MotionRevealHelper
import
com.topjohnwu.magisk.utils.MotionRevealHelper
...
...
app/src/main/java/com/topjohnwu/magisk/ui/module/ModuleViewModel.kt
View file @
2c12fe6e
...
@@ -2,7 +2,6 @@ package com.topjohnwu.magisk.ui.module
...
@@ -2,7 +2,6 @@ package com.topjohnwu.magisk.ui.module
import
androidx.databinding.Bindable
import
androidx.databinding.Bindable
import
androidx.databinding.ObservableArrayList
import
androidx.databinding.ObservableArrayList
import
androidx.databinding.ObservableField
import
androidx.lifecycle.viewModelScope
import
androidx.lifecycle.viewModelScope
import
com.topjohnwu.magisk.BR
import
com.topjohnwu.magisk.BR
import
com.topjohnwu.magisk.R
import
com.topjohnwu.magisk.R
...
@@ -25,6 +24,7 @@ import com.topjohnwu.magisk.model.events.SnackbarEvent
...
@@ -25,6 +24,7 @@ import com.topjohnwu.magisk.model.events.SnackbarEvent
import
com.topjohnwu.magisk.model.events.dialog.ModuleInstallDialog
import
com.topjohnwu.magisk.model.events.dialog.ModuleInstallDialog
import
com.topjohnwu.magisk.ui.base.*
import
com.topjohnwu.magisk.ui.base.*
import
com.topjohnwu.magisk.utils.EndlessRecyclerScrollListener
import
com.topjohnwu.magisk.utils.EndlessRecyclerScrollListener
import
com.topjohnwu.magisk.utils.observable
import
kotlinx.coroutines.*
import
kotlinx.coroutines.*
import
me.tatarka.bindingcollectionadapter2.collections.MergeObservableList
import
me.tatarka.bindingcollectionadapter2.collections.MergeObservableList
import
kotlin.math.roundToInt
import
kotlin.math.roundToInt
...
@@ -53,18 +53,18 @@ class ModuleViewModel(
...
@@ -53,18 +53,18 @@ class ModuleViewModel(
private
var
queryJob
:
Job
?
=
null
private
var
queryJob
:
Job
?
=
null
private
var
remoteJob
:
Job
?
=
null
private
var
remoteJob
:
Job
?
=
null
var
query
=
""
@get
:
Bindable
@Bindable
get
var
isRemoteLoading
by
observable
(
false
,
BR
.
remoteLoading
)
set
(
value
)
{
if
(
field
==
value
)
return
@get
:
Bindable
field
=
value
var
query
by
observable
(
""
,
BR
.
query
)
{
notifyPropertyChanged
(
BR
.
query
)
submitQuery
()
submitQuery
()
// Yes we do lie about the search being loaded
// Yes we do lie about the search being loaded
searchLoading
=
true
searchLoading
.
value
=
true
}
}
val
searchLoading
=
ObservableField
(
false
)
@get
:
Bindable
var
searchLoading
by
observable
(
false
,
BR
.
searchLoading
)
val
itemsSearch
=
diffListOf
<
RepoItem
>()
val
itemsSearch
=
diffListOf
<
RepoItem
>()
val
itemSearchBinding
=
itemBindingOf
<
RepoItem
>
{
val
itemSearchBinding
=
itemBindingOf
<
RepoItem
>
{
it
.
bindExtra
(
BR
.
viewModel
,
this
)
it
.
bindExtra
(
BR
.
viewModel
,
this
)
...
@@ -80,13 +80,6 @@ class ModuleViewModel(
...
@@ -80,13 +80,6 @@ class ModuleViewModel(
private
val
itemsUpdatable
=
diffListOf
<
RepoItem
.
Update
>()
private
val
itemsUpdatable
=
diffListOf
<
RepoItem
.
Update
>()
private
val
itemsRemote
=
diffListOf
<
RepoItem
.
Remote
>()
private
val
itemsRemote
=
diffListOf
<
RepoItem
.
Remote
>()
var
isRemoteLoading
=
false
@Bindable
get
private
set
(
value
)
{
field
=
value
notifyPropertyChanged
(
BR
.
remoteLoading
)
}
val
adapter
=
adapterOf
<
ComparableRvItem
<*>>()
val
adapter
=
adapterOf
<
ComparableRvItem
<*>>()
val
items
=
MergeObservableList
<
ComparableRvItem
<*>>()
val
items
=
MergeObservableList
<
ComparableRvItem
<*>>()
.
insertItem
(
InstallModule
)
.
insertItem
(
InstallModule
)
...
@@ -261,7 +254,7 @@ class ModuleViewModel(
...
@@ -261,7 +254,7 @@ class ModuleViewModel(
val
diff
=
withContext
(
Dispatchers
.
Default
)
{
val
diff
=
withContext
(
Dispatchers
.
Default
)
{
itemsSearch
.
calculateDiff
(
searched
)
itemsSearch
.
calculateDiff
(
searched
)
}
}
searchLoading
.
value
=
false
searchLoading
=
false
itemsSearch
.
update
(
searched
,
diff
)
itemsSearch
.
update
(
searched
,
diff
)
}
}
}
}
...
...
app/src/main/java/com/topjohnwu/magisk/ui/safetynet/SafetynetViewModel.kt
View file @
2c12fe6e
package
com.topjohnwu.magisk.ui.safetynet
package
com.topjohnwu.magisk.ui.safetynet
import
androidx.databinding.Bindable
import
androidx.databinding.Bindable
import
androidx.databinding.ObservableField
import
com.topjohnwu.magisk.BR
import
com.topjohnwu.magisk.BR
import
com.topjohnwu.magisk.R
import
com.topjohnwu.magisk.R
import
com.topjohnwu.magisk.ktx.value
import
com.topjohnwu.magisk.model.events.CheckSafetyNetEvent
import
com.topjohnwu.magisk.model.events.CheckSafetyNetEvent
import
com.topjohnwu.magisk.ui.base.BaseViewModel
import
com.topjohnwu.magisk.ui.base.BaseViewModel
import
com.topjohnwu.magisk.ui.safetynet.SafetyNetState.*
import
com.topjohnwu.magisk.ui.safetynet.SafetyNetState.*
import
com.topjohnwu.magisk.utils.observable
import
org.json.JSONObject
import
org.json.JSONObject
enum
class
SafetyNetState
{
enum
class
SafetyNetState
{
...
@@ -21,19 +20,23 @@ data class SafetyNetResult(
...
@@ -21,19 +20,23 @@ data class SafetyNetResult(
class
SafetynetViewModel
:
BaseViewModel
()
{
class
SafetynetViewModel
:
BaseViewModel
()
{
private
var
currentState
=
IDLE
@get
:
Bindable
set
(
value
)
{
var
safetyNetTitle
by
observable
(
R
.
string
.
empty
,
BR
.
safetyNetTitle
)
field
=
value
@get
:
Bindable
notifyStateChanged
()
var
ctsState
by
observable
(
false
,
BR
.
ctsState
)
}
@get
:
Bindable
val
safetyNetTitle
=
ObservableField
(
R
.
string
.
empty
)
var
basicIntegrityState
by
observable
(
false
,
BR
.
basicIntegrityState
)
val
ctsState
=
ObservableField
(
false
)
@get
:
Bindable
val
basicIntegrityState
=
ObservableField
(
false
)
var
evalType
by
observable
(
""
)
val
evalType
=
ObservableField
(
""
)
@get
:
Bindable
val
isChecking
get
()
=
currentState
==
LOADING
@get
:
Bindable
val
isFailed
get
()
=
currentState
==
FAILED
@get
:
Bindable
val
isSuccess
get
()
=
currentState
==
PASS
val
isChecking
@Bindable
get
()
=
currentState
==
LOADING
private
var
currentState
by
observable
(
IDLE
,
BR
.
checking
,
BR
.
failed
,
BR
.
success
)
val
isFailed
@Bindable
get
()
=
currentState
==
FAILED
val
isSuccess
@Bindable
get
()
=
currentState
==
PASS
init
{
init
{
cachedResult
?.
also
{
cachedResult
?.
also
{
...
@@ -41,13 +44,6 @@ class SafetynetViewModel : BaseViewModel() {
...
@@ -41,13 +44,6 @@ class SafetynetViewModel : BaseViewModel() {
}
?:
attest
()
}
?:
attest
()
}
}
override
fun
notifyStateChanged
()
{
super
.
notifyStateChanged
()
notifyPropertyChanged
(
BR
.
loading
)
notifyPropertyChanged
(
BR
.
failed
)
notifyPropertyChanged
(
BR
.
success
)
}
private
fun
attest
()
{
private
fun
attest
()
{
currentState
=
LOADING
currentState
=
LOADING
CheckSafetyNetEvent
()
{
CheckSafetyNetEvent
()
{
...
@@ -70,26 +66,26 @@ class SafetynetViewModel : BaseViewModel() {
...
@@ -70,26 +66,26 @@ class SafetynetViewModel : BaseViewModel() {
val
eval
=
optString
(
"evaluationType"
)
val
eval
=
optString
(
"evaluationType"
)
val
result
=
cts
&&
basic
val
result
=
cts
&&
basic
cachedResult
=
this
cachedResult
=
this
ctsState
.
value
=
cts
ctsState
=
cts
basicIntegrityState
.
value
=
basic
basicIntegrityState
=
basic
evalType
.
value
=
if
(
eval
.
contains
(
"HARDWARE"
))
"HARDWARE"
else
"BASIC"
evalType
=
if
(
eval
.
contains
(
"HARDWARE"
))
"HARDWARE"
else
"BASIC"
currentState
=
if
(
result
)
PASS
else
FAILED
currentState
=
if
(
result
)
PASS
else
FAILED
safetyNetTitle
.
value
=
safetyNetTitle
=
if
(
result
)
R
.
string
.
safetynet_attest_success
if
(
result
)
R
.
string
.
safetynet_attest_success
else
R
.
string
.
safetynet_attest_failure
else
R
.
string
.
safetynet_attest_failure
}.
onFailure
{
}.
onFailure
{
currentState
=
FAILED
currentState
=
FAILED
ctsState
.
value
=
false
ctsState
=
false
basicIntegrityState
.
value
=
false
basicIntegrityState
=
false
evalType
.
value
=
"N/A"
evalType
=
"N/A"
safetyNetTitle
.
value
=
R
.
string
.
safetynet_res_invalid
safetyNetTitle
=
R
.
string
.
safetynet_res_invalid
}
}
}
?:
{
}
?:
{
currentState
=
FAILED
currentState
=
FAILED
ctsState
.
value
=
false
ctsState
=
false
basicIntegrityState
.
value
=
false
basicIntegrityState
=
false
evalType
.
value
=
"N/A"
evalType
=
"N/A"
safetyNetTitle
.
value
=
R
.
string
.
safetynet_api_error
safetyNetTitle
=
R
.
string
.
safetynet_api_error
}()
}()
}
}
...
...
app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt
View file @
2c12fe6e
...
@@ -46,7 +46,7 @@ object Language : SettingsItem.Selector() {
...
@@ -46,7 +46,7 @@ object Language : SettingsItem.Selector() {
entryValues
=
values
entryValues
=
values
val
selectedLocale
=
currentLocale
.
getDisplayName
(
currentLocale
)
val
selectedLocale
=
currentLocale
.
getDisplayName
(
currentLocale
)
value
=
names
.
indexOfFirst
{
it
==
selectedLocale
}.
let
{
if
(
it
==
-
1
)
0
else
it
}
value
=
names
.
indexOfFirst
{
it
==
selectedLocale
}.
let
{
if
(
it
==
-
1
)
0
else
it
}
notify
Change
(
BR
.
selectedEntry
)
notify
PropertyChanged
(
BR
.
selectedEntry
)
}
}
}
}
}
}
...
@@ -79,8 +79,8 @@ object Hide : SettingsItem.Input() {
...
@@ -79,8 +79,8 @@ object Hide : SettingsItem.Input() {
override
var
value
:
String
=
resources
.
getString
(
R
.
string
.
re_app_name
)
override
var
value
:
String
=
resources
.
getString
(
R
.
string
.
re_app_name
)
set
(
value
)
{
set
(
value
)
{
field
=
value
field
=
value
notify
Change
(
BR
.
value
)
notify
PropertyChanged
(
BR
.
value
)
notify
Change
(
BR
.
error
)
notify
PropertyChanged
(
BR
.
error
)
}
}
@get
:
Bindable
@get
:
Bindable
...
@@ -112,8 +112,8 @@ object DownloadPath : SettingsItem.Input() {
...
@@ -112,8 +112,8 @@ object DownloadPath : SettingsItem.Input() {
var
result
=
value
var
result
=
value
set
(
value
)
{
set
(
value
)
{
field
=
value
field
=
value
notify
Change
(
BR
.
result
)
notify
PropertyChanged
(
BR
.
result
)
notify
Change
(
BR
.
path
)
notify
PropertyChanged
(
BR
.
path
)
}
}
@get
:
Bindable
@get
:
Bindable
...
@@ -143,7 +143,7 @@ object UpdateChannelUrl : SettingsItem.Input() {
...
@@ -143,7 +143,7 @@ object UpdateChannelUrl : SettingsItem.Input() {
var
result
=
value
var
result
=
value
set
(
value
)
{
set
(
value
)
{
field
=
value
field
=
value
notify
Change
(
BR
.
result
)
notify
PropertyChanged
(
BR
.
result
)
}
}
override
fun
refresh
()
{
override
fun
refresh
()
{
...
...
app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestViewModel.kt
View file @
2c12fe6e
...
@@ -6,8 +6,9 @@ import android.content.pm.PackageManager
...
@@ -6,8 +6,9 @@ import android.content.pm.PackageManager
import
android.content.res.Resources
import
android.content.res.Resources
import
android.graphics.drawable.Drawable
import
android.graphics.drawable.Drawable
import
android.os.CountDownTimer
import
android.os.CountDownTimer
import
androidx.databinding.
ObservableField
import
androidx.databinding.
Bindable
import
androidx.lifecycle.viewModelScope
import
androidx.lifecycle.viewModelScope
import
com.topjohnwu.magisk.BR
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.magiskdb.PolicyDao
import
com.topjohnwu.magisk.core.magiskdb.PolicyDao
...
@@ -15,10 +16,10 @@ import com.topjohnwu.magisk.core.model.MagiskPolicy.Companion.ALLOW
...
@@ -15,10 +16,10 @@ import com.topjohnwu.magisk.core.model.MagiskPolicy.Companion.ALLOW
import
com.topjohnwu.magisk.core.model.MagiskPolicy.Companion.DENY
import
com.topjohnwu.magisk.core.model.MagiskPolicy.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.ktx.value
import
com.topjohnwu.magisk.model.entity.recycler.SpinnerRvItem
import
com.topjohnwu.magisk.model.entity.recycler.SpinnerRvItem
import
com.topjohnwu.magisk.model.events.DieEvent
import
com.topjohnwu.magisk.model.events.DieEvent
import
com.topjohnwu.magisk.ui.base.BaseViewModel
import
com.topjohnwu.magisk.ui.base.BaseViewModel
import
com.topjohnwu.magisk.utils.observable
import
com.topjohnwu.superuser.internal.UiThreadHandler
import
com.topjohnwu.superuser.internal.UiThreadHandler
import
kotlinx.coroutines.launch
import
kotlinx.coroutines.launch
import
me.tatarka.bindingcollectionadapter2.BindingListViewAdapter
import
me.tatarka.bindingcollectionadapter2.BindingListViewAdapter
...
@@ -32,16 +33,20 @@ class SuRequestViewModel(
...
@@ -32,16 +33,20 @@ class SuRequestViewModel(
private
val
res
:
Resources
private
val
res
:
Resources
)
:
BaseViewModel
()
{
)
:
BaseViewModel
()
{
val
icon
=
ObservableField
<
Drawable
?>(
null
)
@get
:
Bindable
val
title
=
ObservableField
(
""
)
var
icon
by
observable
(
null
as
Drawable
?,
BR
.
icon
)
val
packageName
=
ObservableField
(
""
)
@get
:
Bindable
var
title
by
observable
(
""
,
BR
.
title
)
val
denyText
=
ObservableField
(
res
.
getString
(
R
.
string
.
deny
))
@get
:
Bindable
val
warningText
=
ObservableField
<
CharSequence
>(
res
.
getString
(
R
.
string
.
su_warning
))
var
packageName
by
observable
(
""
,
BR
.
packageName
)
@get
:
Bindable
val
selectedItemPosition
=
ObservableField
(
0
)
var
denyText
by
observable
(
res
.
getString
(
R
.
string
.
deny
),
BR
.
denyText
)
@get
:
Bindable
val
grantEnabled
=
ObservableField
(
false
)
var
warningText
by
observable
(
res
.
getString
(
R
.
string
.
su_warning
),
BR
.
warningText
)
@get
:
Bindable
var
selectedItemPosition
by
observable
(
0
,
BR
.
selectedItemPosition
)
@get
:
Bindable
var
grantEnabled
by
observable
(
false
,
BR
.
grantEnabled
)
private
val
items
=
res
.
getStringArray
(
R
.
array
.
allow_timeout
).
map
{
SpinnerRvItem
(
it
)
}
private
val
items
=
res
.
getStringArray
(
R
.
array
.
allow_timeout
).
map
{
SpinnerRvItem
(
it
)
}
val
adapter
=
BindingListViewAdapter
<
SpinnerRvItem
>(
1
).
apply
{
val
adapter
=
BindingListViewAdapter
<
SpinnerRvItem
>(
1
).
apply
{
...
@@ -89,7 +94,7 @@ class SuRequestViewModel(
...
@@ -89,7 +94,7 @@ class SuRequestViewModel(
fun
respond
(
action
:
Int
)
{
fun
respond
(
action
:
Int
)
{
timer
.
cancel
()
timer
.
cancel
()
val
pos
=
selectedItemPosition
.
value
val
pos
=
selectedItemPosition
timeoutPrefs
.
edit
().
putInt
(
policy
.
packageName
,
pos
).
apply
()
timeoutPrefs
.
edit
().
putInt
(
policy
.
packageName
,
pos
).
apply
()
respond
(
action
,
Config
.
Value
.
TIMEOUT_LIST
[
pos
])
respond
(
action
,
Config
.
Value
.
TIMEOUT_LIST
[
pos
])
...
@@ -99,16 +104,16 @@ class SuRequestViewModel(
...
@@ -99,16 +104,16 @@ class SuRequestViewModel(
fun
cancelTimer
()
{
fun
cancelTimer
()
{
timer
.
cancel
()
timer
.
cancel
()
denyText
.
value
=
res
.
getString
(
R
.
string
.
deny
)
denyText
=
res
.
getString
(
R
.
string
.
deny
)
}
}
override
fun
onStart
()
{
override
fun
onStart
()
{
icon
.
value
=
policy
.
applicationInfo
.
loadIcon
(
pm
)
icon
=
policy
.
applicationInfo
.
loadIcon
(
pm
)
title
.
value
=
policy
.
appName
title
=
policy
.
appName
packageName
.
value
=
policy
.
packageName
packageName
=
policy
.
packageName
UiThreadHandler
.
handler
.
post
{
UiThreadHandler
.
handler
.
post
{
// Delay is required to properly do selection
// Delay is required to properly do selection
selectedItemPosition
.
value
=
timeoutPrefs
.
getInt
(
policy
.
packageName
,
0
)
selectedItemPosition
=
timeoutPrefs
.
getInt
(
policy
.
packageName
,
0
)
}
}
// Set timer
// Set timer
...
@@ -122,14 +127,14 @@ class SuRequestViewModel(
...
@@ -122,14 +127,14 @@ class SuRequestViewModel(
)
:
CountDownTimer
(
millis
,
interval
)
{
)
:
CountDownTimer
(
millis
,
interval
)
{
override
fun
onTick
(
remains
:
Long
)
{
override
fun
onTick
(
remains
:
Long
)
{
if
(!
grantEnabled
.
value
&&
remains
<=
millis
-
1000
)
{
if
(!
grantEnabled
&&
remains
<=
millis
-
1000
)
{
grantEnabled
.
value
=
true
grantEnabled
=
true
}
}
denyText
.
value
=
"${res.getString(R.string.deny)} (${(remains / 1000) + 1})"
denyText
=
"${res.getString(R.string.deny)} (${(remains / 1000) + 1})"
}
}
override
fun
onFinish
()
{
override
fun
onFinish
()
{
denyText
.
value
=
res
.
getString
(
R
.
string
.
deny
)
denyText
=
res
.
getString
(
R
.
string
.
deny
)
respond
(
DENY
)
respond
(
DENY
)
}
}
...
...
app/src/main/java/com/topjohnwu/magisk/utils/ObservableHost.kt
0 → 100644
View file @
2c12fe6e
package
com.topjohnwu.magisk.utils
import
androidx.databinding.Observable
import
androidx.databinding.PropertyChangeRegistry
import
kotlin.properties.ReadWriteProperty
import
kotlin.reflect.KProperty
/**
* Modified from https://github.com/skoumalcz/teanity/blob/1.2/core/src/main/java/com/skoumal/teanity/observable/Notifyable.kt
*
* Interface that allows user to be observed via DataBinding or manually by assigning listeners.
*
* @see [androidx.databinding.Observable]
* */
interface
ObservableHost
:
Observable
{
/**
* Notifies all observers that something has changed. By default implementation this method is
* synchronous, hence observers will never be notified in undefined order. Observers might
* choose to refresh the view completely, which is beyond the scope of this function.
* */
fun
notifyChange
(
host
:
Observable
=
this
)
/**
* Notifies all observers about field with [fieldId] has been changed. This will happen
* synchronously before or after [notifyChange] has been called. It will never be called during
* the execution of aforementioned method.
* */
fun
notifyPropertyChanged
(
fieldId
:
Int
,
host
:
Observable
=
this
)
companion
object
{
val
impl
:
ObservableHost
get
()
=
ObservableHostImpl
()
}
}
private
class
ObservableHostImpl
:
ObservableHost
{
private
var
callbacks
:
PropertyChangeRegistry
?
=
null
override
fun
addOnPropertyChangedCallback
(
callback
:
Observable
.
OnPropertyChangedCallback
)
{
synchronized
(
this
)
{
callbacks
?:
PropertyChangeRegistry
().
also
{
callbacks
=
it
}
}.
add
(
callback
)
}
override
fun
removeOnPropertyChangedCallback
(
callback
:
Observable
.
OnPropertyChangedCallback
)
{
synchronized
(
this
)
{
callbacks
?:
return
}.
remove
(
callback
)
}
override
fun
notifyChange
(
host
:
Observable
)
{
synchronized
(
this
)
{
callbacks
?:
return
}.
notifyCallbacks
(
host
,
0
,
null
)
}
override
fun
notifyPropertyChanged
(
fieldId
:
Int
,
host
:
Observable
)
{
synchronized
(
this
)
{
callbacks
?:
return
}.
notifyCallbacks
(
host
,
fieldId
,
null
)
}
}
/**
* Declares delegated property in [ObservableHost] parent. This property is available for DataBinding
* to be observed as usual. The only caveat is that in order for binding to generate the [fieldId]
* it has to be annotated accordingly.
*
* The annotation however give very strict control over your internal fields and overall reduce
* overhead in notifying observers. (In comparison to [androidx.databinding.ObservableField])
* It helps the kotlin code to feel more,... _native_, while respecting the original functionality.
*
* # Examples:
*
* ## The most basic usage would probably be:
* ```kotlin
* @get:Bindable
* var myField by observable(defaultValue, BR.myField)
* private set
* ```
*
* ## You can use the field as public read/write, of course:
* ```kotlin
* @get:Bindable
* var myField by observable(defaultValue, BR.myField)
* ```
*
* ## Please beware that delegated property instantiates one class per property
* We discourage using simple getters via delegated properties. Instead you can do something like
* this:
*
* ```kotlin
* @get:Bindable
* var myField by observable(defaultValue, BR.myField, BR.myTransformedField)
*
* var myTransformedField
* @Bindable get() {
* return myField.transform()
* }
* set(value) {
* myField = value.transform()
* }
* ```
*
* */
// Optimize for the most common use case
// Generic type is reified to optimize primitive types
inline
fun
<
reified
T
>
ObservableHost
.
observable
(
initialValue
:
T
,
fieldId
:
Int
)
=
object
:
ReadWriteProperty
<
ObservableHost
,
T
>
{
private
var
field
=
initialValue
override
fun
getValue
(
thisRef
:
ObservableHost
,
property
:
KProperty
<
*
>):
T
{
return
field
}
@Synchronized
override
fun
setValue
(
thisRef
:
ObservableHost
,
property
:
KProperty
<
*
>,
value
:
T
)
{
if
(
field
!=
value
)
{
field
=
value
notifyPropertyChanged
(
fieldId
)
}
}
}
inline
fun
<
reified
T
>
ObservableHost
.
observable
(
initialValue
:
T
,
vararg
fieldIds
:
Int
)
=
object
:
ReadWriteProperty
<
ObservableHost
,
T
>
{
private
var
field
=
initialValue
override
fun
getValue
(
thisRef
:
ObservableHost
,
property
:
KProperty
<
*
>):
T
{
return
field
}
@Synchronized
override
fun
setValue
(
thisRef
:
ObservableHost
,
property
:
KProperty
<
*
>,
value
:
T
)
{
if
(
field
!=
value
)
{
field
=
value
fieldIds
.
forEach
{
notifyPropertyChanged
(
it
)
}
}
}
}
inline
fun
<
reified
T
>
ObservableHost
.
observable
(
initialValue
:
T
,
vararg
fieldIds
:
Int
,
crossinline
afterChanged
:
(
T
)
->
Unit
)
=
object
:
ReadWriteProperty
<
ObservableHost
,
T
>
{
private
var
field
=
initialValue
override
fun
getValue
(
thisRef
:
ObservableHost
,
property
:
KProperty
<
*
>):
T
{
return
field
}
@Synchronized
override
fun
setValue
(
thisRef
:
ObservableHost
,
property
:
KProperty
<
*
>,
value
:
T
)
{
if
(
field
!=
value
)
{
field
=
value
fieldIds
.
forEach
{
notifyPropertyChanged
(
it
)
}
afterChanged
(
value
)
}
}
}
app/src/main/res/layout/include_home_magisk.xml
View file @
2c12fe6e
...
@@ -132,7 +132,7 @@
...
@@ -132,7 +132,7 @@
<TextView
<TextView
style=
"@style/W.Home.ItemContent.Right"
style=
"@style/W.Home.ItemContent.Right"
android:text=
"@{viewModel.isConnected ? viewModel.
stateM
agiskRemoteVersion : @string/not_available}"
android:text=
"@{viewModel.isConnected ? viewModel.
m
agiskRemoteVersion : @string/not_available}"
tools:text=
"20.1 (12345)"
/>
tools:text=
"20.1 (12345)"
/>
</LinearLayout>
</LinearLayout>
...
@@ -149,7 +149,7 @@
...
@@ -149,7 +149,7 @@
<TextView
<TextView
style=
"@style/W.Home.ItemContent.Right"
style=
"@style/W.Home.ItemContent.Right"
android:text=
"@{Info.env.isActive ? viewModel.
stateM
agiskInstalledVersion : @string/not_available}"
android:text=
"@{Info.env.isActive ? viewModel.
m
agiskInstalledVersion : @string/not_available}"
tools:text=
"20.1 (12345)"
/>
tools:text=
"20.1 (12345)"
/>
</LinearLayout>
</LinearLayout>
...
@@ -166,7 +166,7 @@
...
@@ -166,7 +166,7 @@
<TextView
<TextView
style=
"@style/W.Home.ItemContent.Right"
style=
"@style/W.Home.ItemContent.Right"
android:text=
"@{Info.env.isActive ? viewModel.
stateM
agiskMode : @string/not_available}"
android:text=
"@{Info.env.isActive ? viewModel.
m
agiskMode : @string/not_available}"
tools:text=
"Normal"
/>
tools:text=
"Normal"
/>
</LinearLayout>
</LinearLayout>
...
...
app/src/main/res/layout/include_home_manager.xml
View file @
2c12fe6e
...
@@ -121,7 +121,7 @@
...
@@ -121,7 +121,7 @@
<TextView
<TextView
style=
"@style/W.Home.ItemContent.Right"
style=
"@style/W.Home.ItemContent.Right"
android:text=
"@{viewModel.isConnected ? viewModel.
stateM
anagerRemoteVersion : @string/not_available}"
android:text=
"@{viewModel.isConnected ? viewModel.
m
anagerRemoteVersion : @string/not_available}"
tools:text=
"8.0.0 (123) (10)"
/>
tools:text=
"8.0.0 (123) (10)"
/>
</LinearLayout>
</LinearLayout>
...
@@ -138,7 +138,7 @@
...
@@ -138,7 +138,7 @@
<TextView
<TextView
style=
"@style/W.Home.ItemContent.Right"
style=
"@style/W.Home.ItemContent.Right"
android:text=
"@{viewModel.
stateM
anagerInstalledVersion}"
android:text=
"@{viewModel.
m
anagerInstalledVersion}"
tools:text=
"8.0.0 (123) (10)"
/>
tools:text=
"8.0.0 (123) (10)"
/>
</LinearLayout>
</LinearLayout>
...
...
gradle.properties
View file @
2c12fe6e
...
@@ -25,6 +25,7 @@ org.gradle.daemon=true
...
@@ -25,6 +25,7 @@ org.gradle.daemon=true
android.useAndroidX
=
true
android.useAndroidX
=
true
android.enableJetifier
=
true
android.enableJetifier
=
true
android.enableR8.fullMode
=
true
android.enableR8.fullMode
=
true
android.databinding.incremental
=
true
android.injected.testOnly
=
false
android.injected.testOnly
=
false
kapt.incremental.apt
=
true
kapt.incremental.apt
=
true
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment