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
01a43b03
Commit
01a43b03
authored
Jul 08, 2020
by
topjohnwu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
De-Rx ModuleViewModel
parent
86db0cd2
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
102 additions
and
95 deletions
+102
-95
ViewEvents.kt
...main/java/com/topjohnwu/magisk/model/events/ViewEvents.kt
+17
-1
BaseViewModel.kt
...c/main/java/com/topjohnwu/magisk/ui/base/BaseViewModel.kt
+10
-1
Queryable.kt
app/src/main/java/com/topjohnwu/magisk/ui/base/Queryable.kt
+7
-13
HideViewModel.kt
...c/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt
+5
-13
ModuleViewModel.kt
...in/java/com/topjohnwu/magisk/ui/module/ModuleViewModel.kt
+61
-65
SettingsViewModel.kt
...ava/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt
+2
-2
No files found.
app/src/main/java/com/topjohnwu/magisk/model/events/ViewEvents.kt
View file @
01a43b03
...
@@ -131,7 +131,7 @@ class OpenChangelogEvent(val item: Repo) : ViewEvent(), ContextExecutor {
...
@@ -131,7 +131,7 @@ class OpenChangelogEvent(val item: Repo) : ViewEvent(), ContextExecutor {
}
}
}
}
class
PermissionEvent
(
class
Rx
PermissionEvent
(
val
permissions
:
List
<
String
>,
val
permissions
:
List
<
String
>,
val
callback
:
PublishSubject
<
Boolean
>
val
callback
:
PublishSubject
<
Boolean
>
)
:
ViewEvent
(),
ActivityExecutor
{
)
:
ViewEvent
(),
ActivityExecutor
{
...
@@ -148,6 +148,22 @@ class PermissionEvent(
...
@@ -148,6 +148,22 @@ class PermissionEvent(
}
}
}
}
class
PermissionEvent
(
private
val
permissions
:
List
<
String
>,
private
val
callback
:
(
Boolean
)
->
Unit
)
:
ViewEvent
(),
ActivityExecutor
{
override
fun
invoke
(
activity
:
BaseActivity
)
=
activity
.
withPermissions
(*
permissions
.
toTypedArray
())
{
onSuccess
{
callback
(
true
)
}
onFailure
{
callback
(
false
)
}
}
}
class
BackPressEvent
:
ViewEvent
(),
ActivityExecutor
{
class
BackPressEvent
:
ViewEvent
(),
ActivityExecutor
{
override
fun
invoke
(
activity
:
BaseActivity
)
{
override
fun
invoke
(
activity
:
BaseActivity
)
{
activity
.
onBackPressed
()
activity
.
onBackPressed
()
...
...
app/src/main/java/com/topjohnwu/magisk/ui/base/BaseViewModel.kt
View file @
01a43b03
package
com.topjohnwu.magisk.ui.base
package
com.topjohnwu.magisk.ui.base
import
android.Manifest
import
androidx.annotation.CallSuper
import
androidx.annotation.CallSuper
import
androidx.core.graphics.Insets
import
androidx.core.graphics.Insets
import
androidx.databinding.Bindable
import
androidx.databinding.Bindable
...
@@ -88,7 +89,15 @@ abstract class BaseViewModel(
...
@@ -88,7 +89,15 @@ abstract class BaseViewModel(
fun
withPermissions
(
vararg
permissions
:
String
):
Observable
<
Boolean
>
{
fun
withPermissions
(
vararg
permissions
:
String
):
Observable
<
Boolean
>
{
val
subject
=
PublishSubject
.
create
<
Boolean
>()
val
subject
=
PublishSubject
.
create
<
Boolean
>()
return
subject
.
doOnSubscribeUi
{
PermissionEvent
(
permissions
.
toList
(),
subject
).
publish
()
}
return
subject
.
doOnSubscribeUi
{
RxPermissionEvent
(
permissions
.
toList
(),
subject
).
publish
()
}
}
fun
withPermissions
(
vararg
permissions
:
String
,
callback
:
(
Boolean
)
->
Unit
)
{
PermissionEvent
(
permissions
.
toList
(),
callback
).
publish
()
}
fun
withExternalRW
(
callback
:
(
Boolean
)
->
Unit
)
{
withPermissions
(
Manifest
.
permission
.
WRITE_EXTERNAL_STORAGE
,
callback
=
callback
)
}
}
fun
back
()
=
BackPressEvent
().
publish
()
fun
back
()
=
BackPressEvent
().
publish
()
...
...
app/src/main/java/com/topjohnwu/magisk/ui/base/Queryable.kt
View file @
01a43b03
package
com.topjohnwu.magisk.ui.base
package
com.topjohnwu.magisk.ui.base
import
android.os.Handler
import
android.os.Handler
import
android.os.Looper
import
androidx.core.os.postDelayed
import
com.topjohnwu.superuser.internal.UiThreadHandler
interface
Queryable
{
interface
Queryable
{
val
queryDelay
:
Long
val
queryDelay
:
Long
val
queryHandler
:
Handler
val
queryHandler
:
Handler
get
()
=
UiThreadHandler
.
handler
val
queryRunnable
:
Runnable
fun
submitQuery
()
fun
submitQuery
()
{
queryHandler
.
postDelayed
(
queryDelay
)
{
query
()
}
companion
object
{
fun
impl
(
delay
:
Long
=
1000L
)
=
object
:
Queryable
{
override
val
queryDelay
=
delay
override
val
queryHandler
=
Handler
(
Looper
.
getMainLooper
())
override
val
queryRunnable
=
Runnable
{
TODO
()
}
override
fun
submitQuery
()
{}
}
}
}
fun
query
()
}
}
app/src/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt
View file @
01a43b03
...
@@ -21,16 +21,16 @@ import com.topjohnwu.magisk.utils.KObservableField
...
@@ -21,16 +21,16 @@ import com.topjohnwu.magisk.utils.KObservableField
class
HideViewModel
(
class
HideViewModel
(
private
val
magiskRepo
:
MagiskRepository
private
val
magiskRepo
:
MagiskRepository
)
:
BaseViewModel
(),
Queryable
by
Queryable
.
impl
(
1000
)
{
)
:
BaseViewModel
(),
Queryable
{
override
val
query
Runnable
=
Runnable
{
query
()
}
override
val
query
Delay
=
1000L
var
isShowSystem
=
false
var
isShowSystem
=
false
@Bindable
get
@Bindable
get
set
(
value
)
{
set
(
value
)
{
field
=
value
field
=
value
notifyPropertyChanged
(
BR
.
showSystem
)
notifyPropertyChanged
(
BR
.
showSystem
)
q
uery
()
submitQ
uery
()
}
}
var
query
=
""
var
query
=
""
...
@@ -81,17 +81,9 @@ class HideViewModel(
...
@@ -81,17 +81,9 @@ class HideViewModel(
// ---
// ---
override
fun
submitQuery
()
{
override
fun
query
()
=
items
.
filter
{
queryHandler
.
removeCallbacks
(
queryRunnable
)
queryHandler
.
postDelayed
(
queryRunnable
,
queryDelay
)
}
private
fun
query
(
query
:
String
=
this
.
query
,
showSystem
:
Boolean
=
isShowSystem
)
=
items
.
filter
{
fun
filterSystem
():
Boolean
{
fun
filterSystem
():
Boolean
{
return
s
howSystem
||
it
.
item
.
info
.
info
.
flags
and
ApplicationInfo
.
FLAG_SYSTEM
==
0
return
isS
howSystem
||
it
.
item
.
info
.
info
.
flags
and
ApplicationInfo
.
FLAG_SYSTEM
==
0
}
}
fun
filterQuery
():
Boolean
{
fun
filterQuery
():
Boolean
{
...
...
app/src/main/java/com/topjohnwu/magisk/ui/module/ModuleViewModel.kt
View file @
01a43b03
package
com.topjohnwu.magisk.ui.module
package
com.topjohnwu.magisk.ui.module
import
android.Manifest
import
androidx.databinding.Bindable
import
androidx.databinding.Bindable
import
androidx.databinding.ObservableArrayList
import
androidx.databinding.ObservableArrayList
import
androidx.lifecycle.viewModelScope
import
androidx.lifecycle.viewModelScope
...
@@ -16,7 +15,6 @@ import com.topjohnwu.magisk.data.database.RepoByUpdatedDao
...
@@ -16,7 +15,6 @@ import com.topjohnwu.magisk.data.database.RepoByUpdatedDao
import
com.topjohnwu.magisk.databinding.ComparableRvItem
import
com.topjohnwu.magisk.databinding.ComparableRvItem
import
com.topjohnwu.magisk.extensions.addOnListChangedCallback
import
com.topjohnwu.magisk.extensions.addOnListChangedCallback
import
com.topjohnwu.magisk.extensions.reboot
import
com.topjohnwu.magisk.extensions.reboot
import
com.topjohnwu.magisk.extensions.subscribeK
import
com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import
com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import
com.topjohnwu.magisk.model.entity.recycler.*
import
com.topjohnwu.magisk.model.entity.recycler.*
import
com.topjohnwu.magisk.model.events.InstallExternalModuleEvent
import
com.topjohnwu.magisk.model.events.InstallExternalModuleEvent
...
@@ -26,13 +24,9 @@ import com.topjohnwu.magisk.model.events.dialog.ModuleInstallDialog
...
@@ -26,13 +24,9 @@ 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.KObservableField
import
com.topjohnwu.magisk.utils.KObservableField
import
com.topjohnwu.superuser.internal.UiThreadHandler
import
io.reactivex.Single
import
io.reactivex.android.schedulers.AndroidSchedulers
import
io.reactivex.disposables.Disposable
import
io.reactivex.disposables.Disposable
import
kotlinx.coroutines.*
import
kotlinx.coroutines.*
import
me.tatarka.bindingcollectionadapter2.collections.MergeObservableList
import
me.tatarka.bindingcollectionadapter2.collections.MergeObservableList
import
java.lang.Runnable
import
kotlin.math.roundToInt
import
kotlin.math.roundToInt
/*
/*
...
@@ -53,9 +47,11 @@ class ModuleViewModel(
...
@@ -53,9 +47,11 @@ class ModuleViewModel(
private
val
repoName
:
RepoByNameDao
,
private
val
repoName
:
RepoByNameDao
,
private
val
repoUpdated
:
RepoByUpdatedDao
,
private
val
repoUpdated
:
RepoByUpdatedDao
,
private
val
repoUpdater
:
RepoUpdater
private
val
repoUpdater
:
RepoUpdater
)
:
BaseViewModel
(),
Queryable
by
Queryable
.
impl
(
1000
)
{
)
:
BaseViewModel
(),
Queryable
{
override
val
queryRunnable
=
Runnable
{
query
()
}
override
val
queryDelay
=
1000L
private
var
queryJob
:
Job
?
=
null
private
var
remoteJob
:
Job
?
=
null
var
query
=
""
var
query
=
""
@Bindable
get
@Bindable
get
...
@@ -68,7 +64,6 @@ class ModuleViewModel(
...
@@ -68,7 +64,6 @@ class ModuleViewModel(
searchLoading
.
value
=
true
searchLoading
.
value
=
true
}
}
private
var
queryJob
:
Disposable
?
=
null
val
searchLoading
=
KObservableField
(
false
)
val
searchLoading
=
KObservableField
(
false
)
val
itemsSearch
=
diffListOf
<
RepoItem
>()
val
itemsSearch
=
diffListOf
<
RepoItem
>()
val
itemSearchBinding
=
itemBindingOf
<
RepoItem
>
{
val
itemSearchBinding
=
itemBindingOf
<
RepoItem
>
{
...
@@ -213,16 +208,15 @@ class ModuleViewModel(
...
@@ -213,16 +208,15 @@ class ModuleViewModel(
state
=
State
.
LOADED
state
=
State
.
LOADED
}
}
@Synchronized
fun
loadRemote
()
{
fun
loadRemote
()
{
// check for existing jobs
// check for existing jobs
if
(
isRemoteLoading
)
if
(
remoteJob
?.
isActive
==
true
)
return
return
if
(
itemsRemote
.
isEmpty
())
{
if
(
itemsRemote
.
isEmpty
())
EndlessRecyclerScrollListener
.
ResetState
().
publish
()
EndlessRecyclerScrollListener
.
ResetState
().
publish
()
}
viewModelScope
.
launch
{
remoteJob
=
viewModelScope
.
launch
{
suspend
fun
loadRemoteDB
(
offset
:
Int
)
=
withContext
(
Dispatchers
.
IO
)
{
suspend
fun
loadRemoteDB
(
offset
:
Int
)
=
withContext
(
Dispatchers
.
IO
)
{
dao
.
getRepos
(
offset
).
map
{
RepoItem
.
Remote
(
it
)
}
dao
.
getRepos
(
offset
).
map
{
RepoItem
.
Remote
(
it
)
}
}
}
...
@@ -236,7 +230,7 @@ class ModuleViewModel(
...
@@ -236,7 +230,7 @@ class ModuleViewModel(
}
}
isRemoteLoading
=
false
isRemoteLoading
=
false
refetch
=
false
refetch
=
false
UiThreadHandler
.
h
andler
.
post
{
itemsRemote
.
addAll
(
repos
)
}
queryH
andler
.
post
{
itemsRemote
.
addAll
(
repos
)
}
}
}
}
}
...
@@ -250,44 +244,44 @@ class ModuleViewModel(
...
@@ -250,44 +244,44 @@ class ModuleViewModel(
// ---
// ---
override
fun
submitQuery
()
{
private
suspend
fun
queryInternal
(
query
:
String
,
offset
:
Int
):
List
<
RepoItem
>
{
queryHandler
.
removeCallbacks
(
queryRunnable
)
return
if
(
query
.
isBlank
())
{
queryHandler
.
postDelayed
(
queryRunnable
,
queryDelay
)
itemsSearch
.
clear
()
listOf
()
}
else
{
withContext
(
Dispatchers
.
IO
)
{
dao
.
searchRepos
(
query
,
offset
).
map
{
RepoItem
.
Remote
(
it
)
}
}
}
private
fun
queryInternal
(
query
:
String
,
offset
:
Int
):
Single
<
List
<
RepoItem
>>
{
if
(
query
.
isBlank
())
{
return
Single
.
just
(
listOf
<
RepoItem
>())
.
doOnSubscribe
{
itemsSearch
.
clear
()
}
.
subscribeOn
(
AndroidSchedulers
.
mainThread
())
}
}
return
Single
.
fromCallable
{
dao
.
searchRepos
(
query
,
offset
)
}
.
map
{
it
.
map
{
RepoItem
.
Remote
(
it
)
}
}
}
}
private
fun
query
(
query
:
String
=
this
.
query
,
offset
:
Int
=
0
)
{
override
fun
query
()
{
queryJob
?.
dispose
()
queryJob
=
viewModelScope
.
launch
{
queryJob
=
queryInternal
(
query
,
offset
)
val
searched
=
queryInternal
(
query
,
0
)
.
map
{
it
to
itemsSearch
.
calculateDiff
(
it
)
}
val
diff
=
withContext
(
Dispatchers
.
Default
)
{
.
observeOn
(
AndroidSchedulers
.
mainThread
())
itemsSearch
.
calculateDiff
(
searched
)
.
doOnSuccess
{
searchLoading
.
value
=
false
}
}
.
subscribeK
{
itemsSearch
.
update
(
it
.
first
,
it
.
second
)
}
searchLoading
.
value
=
false
itemsSearch
.
update
(
searched
,
diff
)
}
}
}
@Synchronized
fun
loadMoreQuery
()
{
fun
loadMoreQuery
()
{
if
(
queryJob
?.
isDisposed
==
false
)
return
if
(
queryJob
?.
isActive
==
true
)
return
queryJob
=
queryInternal
(
query
,
itemsSearch
.
size
)
queryJob
=
viewModelScope
.
launch
{
.
subscribeK
{
itemsSearch
.
addAll
(
it
)
}
val
searched
=
queryInternal
(
query
,
itemsSearch
.
size
)
queryHandler
.
post
{
itemsSearch
.
addAll
(
searched
)
}
}
}
}
// ---
// ---
private
fun
update
(
repo
:
Repo
,
progress
:
Int
)
=
private
fun
update
(
repo
:
Repo
,
progress
:
Int
)
=
viewModelScope
.
launch
{
Single
.
fromCallable
{
itemsRemote
+
itemsSearch
}
val
item
=
withContext
(
Dispatchers
.
Default
)
{
.
map
{
it
.
first
{
it
.
item
.
id
==
repo
.
id
}
}
(
itemsRemote
+
itemsSearch
).
first
{
it
.
item
.
id
==
repo
.
id
}
.
subscribeK
{
it
.
progress
.
value
=
progress
}
}
.
add
()
item
.
progress
.
value
=
progress
}
// ---
// ---
...
@@ -305,12 +299,14 @@ class ModuleViewModel(
...
@@ -305,12 +299,14 @@ class ModuleViewModel(
// ---
// ---
fun
updateActiveState
()
=
Single
.
fromCallable
{
itemsInstalled
.
any
{
it
.
isModified
}
}
fun
updateActiveState
()
=
viewModelScope
.
launch
{
.
subscribeK
{
sectionActive
.
hasButton
=
it
}
sectionActive
.
hasButton
=
withContext
(
Dispatchers
.
Default
)
{
.
add
()
itemsInstalled
.
any
{
it
.
isModified
}
}
}
fun
sectionPressed
(
item
:
SectionTitle
)
=
when
(
item
)
{
fun
sectionPressed
(
item
:
SectionTitle
)
=
when
(
item
)
{
sectionActive
->
reboot
()
//TODO add reboot picker, regular reboot is not always preferred
sectionActive
->
reboot
()
//
TODO add reboot picker, regular reboot is not always preferred
sectionRemote
->
{
sectionRemote
->
{
Config
.
repoOrder
=
when
(
Config
.
repoOrder
)
{
Config
.
repoOrder
=
when
(
Config
.
repoOrder
)
{
Config
.
Value
.
ORDER_NAME
->
Config
.
Value
.
ORDER_DATE
Config
.
Value
.
ORDER_NAME
->
Config
.
Value
.
ORDER_DATE
...
@@ -318,28 +314,28 @@ class ModuleViewModel(
...
@@ -318,28 +314,28 @@ class ModuleViewModel(
else
->
Config
.
Value
.
ORDER_NAME
else
->
Config
.
Value
.
ORDER_NAME
}
}
updateOrderIcon
()
updateOrderIcon
()
Single
.
fromCallable
{
itemsRemote
}
queryHandler
.
post
{
.
subscribeK
{
itemsRemote
.
clear
()
itemsRemote
.
removeAll
(
it
)
loadRemote
()
loadRemote
()
}.
add
()
}
Unit
}
}
else
->
Unit
else
->
Unit
}
}
fun
downloadPressed
(
item
:
RepoItem
)
=
withPermissions
(
fun
downloadPressed
(
item
:
RepoItem
)
=
withExternalRW
{
Manifest
.
permission
.
READ_EXTERNAL_STORAGE
,
if
(
it
)
Manifest
.
permission
.
WRITE_EXTERNAL_STORAGE
).
any
{
it
}.
subscribeK
(
onError
=
{
permissionDenied
()
})
{
ModuleInstallDialog
(
item
.
item
).
publish
()
ModuleInstallDialog
(
item
.
item
).
publish
()
}.
add
()
else
permissionDenied
()
}
fun
installPressed
()
=
withPermissions
(
fun
installPressed
()
=
withExternalRW
{
Manifest
.
permission
.
READ_EXTERNAL_STORAGE
,
if
(
it
)
Manifest
.
permission
.
WRITE_EXTERNAL_STORAGE
).
any
{
it
}.
subscribeK
(
onError
=
{
permissionDenied
()
})
{
InstallExternalModuleEvent
().
publish
()
InstallExternalModuleEvent
().
publish
()
}.
add
()
else
permissionDenied
()
}
fun
infoPressed
(
item
:
RepoItem
)
=
OpenChangelogEvent
(
item
.
item
).
publish
()
fun
infoPressed
(
item
:
RepoItem
)
=
OpenChangelogEvent
(
item
.
item
).
publish
()
fun
infoPressed
(
item
:
ModuleItem
)
{
fun
infoPressed
(
item
:
ModuleItem
)
{
...
...
app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt
View file @
01a43b03
...
@@ -16,7 +16,7 @@ import com.topjohnwu.magisk.extensions.subscribeK
...
@@ -16,7 +16,7 @@ import com.topjohnwu.magisk.extensions.subscribeK
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.entity.recycler.SettingsItem
import
com.topjohnwu.magisk.model.entity.recycler.SettingsItem
import
com.topjohnwu.magisk.model.events.PermissionEvent
import
com.topjohnwu.magisk.model.events.
Rx
PermissionEvent
import
com.topjohnwu.magisk.model.events.RecreateEvent
import
com.topjohnwu.magisk.model.events.RecreateEvent
import
com.topjohnwu.magisk.model.events.dialog.BiometricDialog
import
com.topjohnwu.magisk.model.events.dialog.BiometricDialog
import
com.topjohnwu.magisk.ui.base.BaseViewModel
import
com.topjohnwu.magisk.ui.base.BaseViewModel
...
@@ -137,7 +137,7 @@ class SettingsViewModel(
...
@@ -137,7 +137,7 @@ class SettingsViewModel(
private
fun
requireRWPermission
()
{
private
fun
requireRWPermission
()
{
val
callback
=
PublishSubject
.
create
<
Boolean
>()
val
callback
=
PublishSubject
.
create
<
Boolean
>()
callback
.
subscribeK
{
if
(!
it
)
requireRWPermission
()
}
callback
.
subscribeK
{
if
(!
it
)
requireRWPermission
()
}
PermissionEvent
(
Rx
PermissionEvent
(
listOf
(
listOf
(
Manifest
.
permission
.
READ_EXTERNAL_STORAGE
,
Manifest
.
permission
.
READ_EXTERNAL_STORAGE
,
Manifest
.
permission
.
WRITE_EXTERNAL_STORAGE
Manifest
.
permission
.
WRITE_EXTERNAL_STORAGE
...
...
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