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
f76c020d
Commit
f76c020d
authored
Oct 30, 2019
by
Viktor De Pasquale
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added implementation of hide screen
Very much wip and doesn't work at all
parent
722fba78
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
426 additions
and
26 deletions
+426
-26
RedesignModule.kt
app/src/main/java/com/topjohnwu/magisk/di/RedesignModule.kt
+1
-1
RxJava.kt
app/src/main/java/com/topjohnwu/magisk/extensions/RxJava.kt
+18
-15
HideAppInfo.kt
...ain/java/com/topjohnwu/magisk/model/entity/HideAppInfo.kt
+10
-0
HideRvItem.kt
.../com/topjohnwu/magisk/model/entity/recycler/HideRvItem.kt
+51
-0
HideFragment.kt
...n/java/com/topjohnwu/magisk/redesign/hide/HideFragment.kt
+3
-0
HideViewModel.kt
.../java/com/topjohnwu/magisk/redesign/hide/HideViewModel.kt
+120
-1
ic_radio_check_button.xml
app/src/main/res/drawable/ic_radio_check_button.xml
+31
-0
fragment_hide_md2.xml
app/src/main/res/layout/fragment_hide_md2.xml
+18
-9
item_hide_md2.xml
app/src/main/res/layout/item_hide_md2.xml
+118
-0
item_hide_process_md2.xml
app/src/main/res/layout/item_hide_process_md2.xml
+56
-0
No files found.
app/src/main/java/com/topjohnwu/magisk/di/RedesignModule.kt
View file @
f76c020d
...
...
@@ -17,7 +17,7 @@ import org.koin.dsl.module
val
redesignModule
=
module
{
viewModel
{
FlashViewModel
()
}
viewModel
{
HideViewModel
()
}
viewModel
{
HideViewModel
(
get
(),
get
()
)
}
viewModel
{
HomeViewModel
(
get
())
}
viewModel
{
LogViewModel
()
}
viewModel
{
ModuleViewModel
()
}
...
...
app/src/main/java/com/topjohnwu/magisk/extensions/RxJava.kt
View file @
f76c020d
...
...
@@ -197,5 +197,8 @@ fun <T> ObservableField<T>.toObservable(): Observable<T> {
fun
<
T
:
Any
>
T
.
toSingle
()
=
Single
.
just
(
this
)
fun
<
T1
,
T2
,
R
>
zip
(
t1
:
Single
<
T1
>,
t2
:
Single
<
T2
>,
zipper
:
(
T1
,
T2
)
->
R
)
=
Single
.
zip
(
t1
,
t2
,
BiFunction
<
T1
,
T2
,
R
>
{
rt1
,
rt2
->
zipper
(
rt1
,
rt2
)
})
inline
fun
<
T1
,
T2
,
R
>
zip
(
t1
:
Single
<
T1
>,
t2
:
Single
<
T2
>,
crossinline
zipper
:
(
T1
,
T2
)
->
R
)
=
Single
.
zip
(
t1
,
t2
,
BiFunction
<
T1
,
T2
,
R
>
{
rt1
,
rt2
->
zipper
(
rt1
,
rt2
)
})
\ No newline at end of file
app/src/main/java/com/topjohnwu/magisk/model/entity/HideAppInfo.kt
View file @
f76c020d
...
...
@@ -14,3 +14,13 @@ class HideAppInfo(
val
processes
=
info
.
packageInfo
?.
processes
?.
distinct
()
?:
listOf
(
info
.
packageName
)
}
data class
StatefulProcess
(
val
name
:
String
,
val
isHidden
:
Boolean
)
class
ProcessHideApp
(
val
info
:
HideAppInfo
,
val
processes
:
List
<
StatefulProcess
>
)
\ No newline at end of file
app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/HideRvItem.kt
View file @
f76c020d
package
com.topjohnwu.magisk.model.entity.recycler
import
android.view.View
import
android.view.ViewGroup
import
com.topjohnwu.magisk.R
import
com.topjohnwu.magisk.databinding.ComparableRvItem
import
com.topjohnwu.magisk.extensions.addOnPropertyChangedCallback
import
com.topjohnwu.magisk.extensions.inject
import
com.topjohnwu.magisk.extensions.startAnimations
import
com.topjohnwu.magisk.extensions.toggle
import
com.topjohnwu.magisk.model.entity.HideAppInfo
import
com.topjohnwu.magisk.model.entity.HideTarget
import
com.topjohnwu.magisk.model.entity.ProcessHideApp
import
com.topjohnwu.magisk.model.entity.StatefulProcess
import
com.topjohnwu.magisk.model.entity.state.IndeterminateState
import
com.topjohnwu.magisk.model.events.HideProcessEvent
import
com.topjohnwu.magisk.utils.DiffObservableList
import
com.topjohnwu.magisk.utils.KObservableField
import
com.topjohnwu.magisk.utils.RxBus
class
HideItem
(
val
item
:
ProcessHideApp
)
:
ComparableRvItem
<
HideItem
>()
{
override
val
layoutRes
=
R
.
layout
.
item_hide_md2
val
items
=
item
.
processes
.
map
{
HideProcessItem
(
it
)
}
val
isExpanded
=
KObservableField
(
false
)
val
itemsChecked
=
KObservableField
(
0
)
val
isHidden
get
()
=
itemsChecked
.
value
==
items
.
size
init
{
items
.
forEach
{
it
.
isHidden
.
addOnPropertyChangedCallback
{
recalculateChecked
()
}
}
}
fun
collapse
(
v
:
View
)
{
(
v
.
parent
.
parent
as
?
ViewGroup
)
?.
startAnimations
()
isExpanded
.
value
=
false
}
fun
expand
(
v
:
View
)
{
(
v
.
parent
as
?
ViewGroup
)
?.
startAnimations
()
isExpanded
.
value
=
true
}
private
fun
recalculateChecked
()
{
itemsChecked
.
value
=
items
.
count
{
it
.
isHidden
.
value
}
}
override
fun
contentSameAs
(
other
:
HideItem
):
Boolean
=
item
==
other
.
item
override
fun
itemSameAs
(
other
:
HideItem
):
Boolean
=
item
.
info
==
other
.
item
.
info
}
class
HideProcessItem
(
val
item
:
StatefulProcess
)
:
ComparableRvItem
<
HideProcessItem
>()
{
override
val
layoutRes
=
R
.
layout
.
item_hide_process_md2
val
isHidden
=
KObservableField
(
item
.
isHidden
)
fun
toggle
()
=
isHidden
.
toggle
()
override
fun
contentSameAs
(
other
:
HideProcessItem
)
=
item
==
other
.
item
override
fun
itemSameAs
(
other
:
HideProcessItem
)
=
item
.
name
==
other
.
item
.
name
}
class
HideRvItem
(
val
item
:
HideAppInfo
,
targets
:
List
<
HideTarget
>)
:
ComparableRvItem
<
HideRvItem
>()
{
...
...
app/src/main/java/com/topjohnwu/magisk/redesign/hide/HideFragment.kt
View file @
f76c020d
package
com.topjohnwu.magisk.redesign.hide
import
android.content.Context
import
android.graphics.Insets
import
com.topjohnwu.magisk.R
import
com.topjohnwu.magisk.databinding.FragmentHideMd2Binding
import
com.topjohnwu.magisk.redesign.compat.CompatFragment
...
...
@@ -11,6 +12,8 @@ class HideFragment : CompatFragment<HideViewModel, FragmentHideMd2Binding>() {
override
val
layoutRes
=
R
.
layout
.
fragment_hide_md2
override
val
viewModel
by
viewModel
<
HideViewModel
>()
override
fun
consumeSystemWindowInsets
(
insets
:
Insets
)
=
insets
override
fun
onAttach
(
context
:
Context
)
{
super
.
onAttach
(
context
)
...
...
app/src/main/java/com/topjohnwu/magisk/redesign/hide/HideViewModel.kt
View file @
f76c020d
package
com.topjohnwu.magisk.redesign.hide
import
android.content.pm.ApplicationInfo
import
com.topjohnwu.magisk.BR
import
com.topjohnwu.magisk.data.repository.MagiskRepository
import
com.topjohnwu.magisk.extensions.subscribeK
import
com.topjohnwu.magisk.extensions.toSingle
import
com.topjohnwu.magisk.model.entity.HideAppInfo
import
com.topjohnwu.magisk.model.entity.HideTarget
import
com.topjohnwu.magisk.model.entity.ProcessHideApp
import
com.topjohnwu.magisk.model.entity.StatefulProcess
import
com.topjohnwu.magisk.model.entity.recycler.HideItem
import
com.topjohnwu.magisk.model.entity.recycler.HideProcessItem
import
com.topjohnwu.magisk.model.entity.recycler.HideProcessRvItem
import
com.topjohnwu.magisk.model.events.HideProcessEvent
import
com.topjohnwu.magisk.redesign.compat.CompatViewModel
import
com.topjohnwu.magisk.redesign.home.itemBindingOf
import
com.topjohnwu.magisk.redesign.superuser.diffListOf
import
com.topjohnwu.magisk.utils.KObservableField
import
com.topjohnwu.magisk.utils.RxBus
import
com.topjohnwu.magisk.utils.currentLocale
import
io.reactivex.disposables.Disposable
import
java.util.*
class
HideViewModel
:
CompatViewModel
()
\ No newline at end of file
class
HideViewModel
(
private
val
magiskRepo
:
MagiskRepository
,
rxBus
:
RxBus
)
:
CompatViewModel
()
{
@Volatile
private
var
cache
=
listOf
<
HideItem
>()
set
(
value
)
{
field
=
Collections
.
synchronizedList
(
value
)
}
private
var
queryJob
:
Disposable
?
=
null
set
(
value
)
{
field
?.
dispose
()
field
=
value
}
val
query
=
KObservableField
(
""
)
val
isShowSystem
=
KObservableField
(
true
)
val
items
=
diffListOf
<
HideItem
>()
val
itemBinding
=
itemBindingOf
<
HideItem
>
{
it
.
bindExtra
(
BR
.
viewModel
,
this
)
}
val
itemInternalBinding
=
itemBindingOf
<
HideProcessItem
>
{
it
.
bindExtra
(
BR
.
viewModel
,
this
)
}
init
{
rxBus
.
register
<
HideProcessEvent
>()
.
subscribeK
{
toggleItem
(
it
.
item
)
}
.
add
()
}
override
fun
refresh
()
=
magiskRepo
.
fetchApps
()
.
map
{
it
to
magiskRepo
.
fetchHideTargets
().
blockingGet
()
}
.
map
{
pair
->
pair
.
first
.
map
{
mergeAppTargets
(
it
,
pair
.
second
)
}
}
.
flattenAsFlowable
{
it
}
.
map
{
HideItem
(
it
)
}
.
toList
()
.
map
{
it
.
sort
()
}
.
subscribeK
{
cache
=
it
queryIfNecessary
()
}
override
fun
onCleared
()
{
queryJob
?.
dispose
()
super
.
onCleared
()
}
// ---
private
fun
mergeAppTargets
(
a
:
HideAppInfo
,
ts
:
List
<
HideTarget
>):
ProcessHideApp
{
val
relevantTargets
=
ts
.
filter
{
it
.
packageName
==
a
.
info
.
packageName
}
val
processes
=
a
.
processes
.
map
{
StatefulProcess
(
it
,
relevantTargets
.
any
{
i
->
it
==
i
.
process
})
}
return
ProcessHideApp
(
a
,
processes
)
}
private
fun
List
<
HideItem
>.
sort
()
=
sortedWith
(
compareBy
(
{
it
.
isHidden
},
{
it
.
item
.
info
.
name
.
toLowerCase
(
currentLocale
)
},
{
it
.
item
.
info
.
info
.
packageName
}
))
// ---
/** We don't need to re-query when the app count matches. */
private
fun
queryIfNecessary
()
{
if
(
items
.
size
!=
cache
.
size
)
{
query
()
}
}
private
fun
query
(
query
:
String
=
this
.
query
.
value
,
showSystem
:
Boolean
=
isShowSystem
.
value
)
=
cache
.
toSingle
()
.
flattenAsFlowable
{
it
}
.
parallel
()
.
filter
{
showSystem
||
it
.
item
.
info
.
info
.
flags
and
ApplicationInfo
.
FLAG_SYSTEM
==
0
}
.
filter
{
val
inName
=
it
.
item
.
info
.
name
.
contains
(
query
,
true
)
val
inPackage
=
it
.
item
.
info
.
info
.
packageName
.
contains
(
query
,
true
)
val
inProcesses
=
it
.
item
.
processes
.
any
{
it
.
name
.
contains
(
query
,
true
)
}
inName
||
inPackage
||
inProcesses
}
.
sequential
()
.
toList
()
.
map
{
it
to
items
.
calculateDiff
(
it
)
}
.
subscribeK
{
items
.
update
(
it
.
first
,
it
.
second
)
}
.
let
{
queryJob
=
it
}
// ---
private
fun
toggleItem
(
item
:
HideProcessRvItem
)
=
magiskRepo
.
toggleHide
(
item
.
isHidden
.
value
,
item
.
packageName
,
item
.
process
)
.
subscribeK
()
.
add
()
}
\ No newline at end of file
app/src/main/res/drawable/ic_radio_check_button.xml
View file @
f76c020d
...
...
@@ -22,6 +22,27 @@
</vector>
</item>
<item
android:id=
"@+id/collapsed_selected"
android:state_selected=
"true"
>
<vector
android:name=
"vector"
android:width=
"24dp"
android:height=
"24dp"
android:viewportWidth=
"24"
android:viewportHeight=
"24"
>
<group
android:name=
"group"
android:pivotX=
"12"
android:pivotY=
"12"
>
<path
android:name=
"path"
android:fillColor=
"#000"
android:pathData=
"M 12 2 C 9.349 2 6.804 3.054 4.929 4.929 C 3.054 6.804 2 9.349 2 12 C 2 14.651 3.054 17.196 4.929 19.071 C 6.804 20.946 9.349 22 12 22 C 13.755 22 15.48 21.538 17 20.66 C 18.52 19.783 19.783 18.52 20.66 17 C 21.538 15.48 22 13.755 22 12 C 22 10.245 21.538 8.52 20.66 7 C 19.783 5.48 18.52 4.217 17 3.34 C 15.48 2.462 13.755 2 12 2 Z"
/>
</group>
</vector>
</item>
<item
android:id=
"@+id/expanded"
>
<vector
android:name=
"vector"
...
...
@@ -52,4 +73,14 @@
android:fromId=
"@+id/collapsed"
android:toId=
"@id/expanded"
/>
<transition
android:drawable=
"@drawable/avd_circle_from_filled"
android:fromId=
"@+id/expanded"
android:toId=
"@+id/collapsed_selected"
/>
<transition
android:drawable=
"@drawable/avd_circle_to_filled"
android:fromId=
"@+id/collapsed_selected"
android:toId=
"@id/expanded"
/>
</animated-selector>
\ No newline at end of file
app/src/main/res/layout/fragment_hide_md2.xml
View file @
f76c020d
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android=
"http://schemas.android.com/apk/res/android"
>
<layout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:app=
"http://schemas.android.com/apk/res-auto"
xmlns:tools=
"http://schemas.android.com/tools"
>
<data>
<import
type=
"com.topjohnwu.magisk.R"
/>
<variable
name=
"viewModel"
type=
"com.topjohnwu.magisk.redesign.hide.HideViewModel"
/>
</data>
<androidx.core.widget.NestedScrollView
<androidx.recyclerview.widget.RecyclerView
dividerVertical=
"@{R.drawable.divider_l1}"
itemBinding=
"@{viewModel.itemBinding}"
items=
"@{viewModel.items}"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:fillViewport=
"true"
>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
/>
</androidx.core.widget.NestedScrollView>
android:clipToPadding=
"false"
android:orientation=
"vertical"
android:paddingStart=
"@dimen/l1"
android:paddingTop=
"@{viewModel.insets.top + (int) @dimen/internal_action_bar_size + (int) @dimen/l1}"
android:paddingEnd=
"@dimen/l1"
android:paddingBottom=
"@{viewModel.insets.bottom}"
app:layoutManager=
"androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem=
"@layout/item_hide_md2"
tools:paddingTop=
"40dp"
/>
</layout>
\ No newline at end of file
app/src/main/res/layout/item_hide_md2.xml
0 → 100644
View file @
f76c020d
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:app=
"http://schemas.android.com/apk/res-auto"
xmlns:tools=
"http://schemas.android.com/tools"
>
<data>
<variable
name=
"item"
type=
"com.topjohnwu.magisk.model.entity.recycler.HideItem"
/>
<variable
name=
"viewModel"
type=
"com.topjohnwu.magisk.redesign.hide.HideViewModel"
/>
</data>
<com.google.android.material.card.MaterialCardView
style=
"?styleCardNormal"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
tools:layout_gravity=
"center"
tools:layout_marginBottom=
"@dimen/l1"
>
<androidx.constraintlayout.widget.ConstraintLayout
invisible=
"@{item.isExpanded}"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:background=
"?selectableItemBackground"
android:onClick=
"@{(v) -> item.expand(v)}"
>
<androidx.appcompat.widget.AppCompatImageView
android:id=
"@+id/hide_icon"
style=
"?styleImageNormal"
android:layout_margin=
"@dimen/l1"
android:src=
"@{item.item.info.icon}"
app:layout_constraintBottom_toBottomOf=
"parent"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
tools:src=
"@drawable/ic_magisk"
/>
<androidx.appcompat.widget.AppCompatTextView
android:id=
"@+id/hide_name"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_marginStart=
"@dimen/l1"
android:ellipsize=
"middle"
android:singleLine=
"true"
android:text=
"@{item.item.info.name}"
android:textAppearance=
"?appearanceTextBodyNormal"
android:textStyle=
"bold"
app:layout_constraintBottom_toTopOf=
"@+id/hide_package"
app:layout_constraintEnd_toStartOf=
"@+id/hide_expand_icon"
app:layout_constraintStart_toEndOf=
"@+id/hide_icon"
app:layout_constraintTop_toTopOf=
"parent"
app:layout_constraintVertical_chainStyle=
"packed"
tools:text=
"@string/app_name"
/>
<androidx.appcompat.widget.AppCompatTextView
android:id=
"@+id/hide_package"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:textAppearance=
"?appearanceTextCaptionVariant"
app:layout_constraintBottom_toBottomOf=
"parent"
app:layout_constraintEnd_toEndOf=
"@+id/hide_name"
app:layout_constraintStart_toStartOf=
"@+id/hide_name"
app:layout_constraintTop_toBottomOf=
"@+id/hide_name"
tools:text=
"com.topjohnwu.magisk"
/>
<androidx.appcompat.widget.AppCompatImageView
android:id=
"@+id/hide_expand_icon"
style=
"?styleIconNormal"
invisible=
"@{item.item.processes.empty}"
android:background=
"@null"
android:rotation=
"180"
app:layout_constraintBottom_toBottomOf=
"parent"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
app:srcCompat=
"@drawable/ic_back_md2"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
goneUnless=
"@{item.isExpanded}"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:orientation=
"vertical"
>
<com.google.android.material.appbar.MaterialToolbar
style=
"?styleToolbar"
onNavigationClick=
"@{(v) -> item.collapse(v)}"
android:layout_width=
"match_parent"
android:layout_height=
"48dp"
app:navigationIcon=
"@drawable/ic_back_md2"
app:title=
"Processes"
app:titleTextAppearance=
"?appearanceTextBodyNormal"
/>
<androidx.recyclerview.widget.RecyclerView
itemBinding=
"@{viewModel.itemInternalBinding}"
items=
"@{item.items}"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:orientation=
"vertical"
app:layoutManager=
"androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem=
"@layout/item_hide_process_md2"
/>
</LinearLayout>
<ProgressBar
style=
"?styleProgressDeterminate"
android:layout_width=
"match_parent"
android:layout_gravity=
"top"
android:max=
"@{item.items.size()}"
android:progress=
"@{item.itemsChecked}"
/>
</com.google.android.material.card.MaterialCardView>
</layout>
\ No newline at end of file
app/src/main/res/layout/item_hide_process_md2.xml
0 → 100644
View file @
f76c020d
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:app=
"http://schemas.android.com/apk/res-auto"
xmlns:tools=
"http://schemas.android.com/tools"
>
<data>
<variable
name=
"item"
type=
"com.topjohnwu.magisk.model.entity.recycler.HideProcessItem"
/>
<variable
name=
"viewModel"
type=
"com.topjohnwu.magisk.redesign.hide.HideViewModel"
/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center"
>
<androidx.appcompat.widget.AppCompatTextView
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_marginStart=
"@dimen/l1"
android:layout_marginTop=
"@dimen/l_50"
android:layout_marginEnd=
"@dimen/l1"
android:layout_marginBottom=
"@dimen/l_50"
android:singleLine=
"true"
android:text=
"@{item.item.name}"
android:textAppearance=
"?appearanceTextCaptionVariant"
app:layout_constraintBottom_toBottomOf=
"parent"
app:layout_constraintEnd_toStartOf=
"@+id/hide_process_checkbox"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
tools:text=
"com.topjohnwu.magisk"
/>
<androidx.appcompat.widget.AppCompatImageView
android:id=
"@+id/hide_process_checkbox"
style=
"?styleImageSmall"
isSelected=
"@{item.isHidden}"
android:layout_marginTop=
"@dimen/l_50"
android:layout_marginEnd=
"@dimen/l1"
android:layout_marginBottom=
"@dimen/l_50"
android:background=
"?selectableItemBackgroundBorderless"
android:onClick=
"@{() -> item.toggle()}"
app:layout_constraintBottom_toBottomOf=
"parent"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
app:srcCompat=
"@drawable/ic_radio_check_button"
app:tint=
"?colorPrimary"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
\ 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