Skip to content

Commit 4ca661f

Browse files
committed
Redesign ActionBottomSheet with grid layout and confirmation - Grid layout with icons (same style as App Detail quick actions) - Separate Allow Background button - Confirmation dialog inside sheet before executing - Shows action name and app count in confirmation
1 parent ff3322d commit 4ca661f

File tree

2 files changed

+203
-139
lines changed

2 files changed

+203
-139
lines changed

app/src/main/java/com/appcontrolx/ui/ActionBottomSheet.kt

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ class ActionBottomSheet : BottomSheetDialogFragment() {
1414
private val binding get() = _binding!!
1515

1616
var onActionSelected: ((Action) -> Unit)? = null
17+
private var selectedAction: Action? = null
18+
private var selectedCount = 0
1719

1820
enum class Action {
1921
FREEZE, UNFREEZE, UNINSTALL, FORCE_STOP,
@@ -29,47 +31,62 @@ class ActionBottomSheet : BottomSheetDialogFragment() {
2931
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
3032
super.onViewCreated(view, savedInstanceState)
3133

32-
val selectedCount = arguments?.getInt(ARG_SELECTED_COUNT, 0) ?: 0
34+
selectedCount = arguments?.getInt(ARG_SELECTED_COUNT, 0) ?: 0
3335
binding.tvTitle.text = getString(R.string.action_title, selectedCount)
3436

35-
binding.btnFreeze.setOnClickListener {
36-
onActionSelected?.invoke(Action.FREEZE)
37-
dismiss()
38-
}
39-
40-
binding.btnUnfreeze.setOnClickListener {
41-
onActionSelected?.invoke(Action.UNFREEZE)
42-
dismiss()
43-
}
44-
45-
binding.btnUninstall.setOnClickListener {
46-
onActionSelected?.invoke(Action.UNINSTALL)
47-
dismiss()
48-
}
49-
50-
binding.btnForceStop.setOnClickListener {
51-
onActionSelected?.invoke(Action.FORCE_STOP)
52-
dismiss()
53-
}
54-
55-
binding.btnRestrictBg.setOnClickListener {
56-
onActionSelected?.invoke(Action.RESTRICT_BACKGROUND)
57-
dismiss()
37+
setupActionButtons()
38+
setupConfirmButtons()
39+
}
40+
41+
private fun setupActionButtons() {
42+
binding.btnForceStop.setOnClickListener { showConfirmation(Action.FORCE_STOP) }
43+
binding.btnFreeze.setOnClickListener { showConfirmation(Action.FREEZE) }
44+
binding.btnUnfreeze.setOnClickListener { showConfirmation(Action.UNFREEZE) }
45+
binding.btnRestrictBg.setOnClickListener { showConfirmation(Action.RESTRICT_BACKGROUND) }
46+
binding.btnAllowBg.setOnClickListener { showConfirmation(Action.ALLOW_BACKGROUND) }
47+
binding.btnClearCache.setOnClickListener { showConfirmation(Action.CLEAR_CACHE) }
48+
binding.btnClearData.setOnClickListener { showConfirmation(Action.CLEAR_DATA) }
49+
binding.btnUninstall.setOnClickListener { showConfirmation(Action.UNINSTALL) }
50+
}
51+
52+
private fun setupConfirmButtons() {
53+
binding.btnNo.setOnClickListener {
54+
// Go back to action selection
55+
binding.layoutConfirm.visibility = View.GONE
56+
binding.layoutActions.visibility = View.VISIBLE
57+
binding.tvTitle.text = getString(R.string.action_title, selectedCount)
58+
selectedAction = null
5859
}
5960

60-
binding.btnAllowBg.setOnClickListener {
61-
onActionSelected?.invoke(Action.ALLOW_BACKGROUND)
62-
dismiss()
61+
binding.btnYes.setOnClickListener {
62+
selectedAction?.let { action ->
63+
onActionSelected?.invoke(action)
64+
dismiss()
65+
}
6366
}
67+
}
68+
69+
private fun showConfirmation(action: Action) {
70+
selectedAction = action
6471

65-
binding.btnClearCache.setOnClickListener {
66-
onActionSelected?.invoke(Action.CLEAR_CACHE)
67-
dismiss()
68-
}
72+
val actionName = getActionDisplayName(action)
73+
binding.tvTitle.text = getString(R.string.confirm_title)
74+
binding.tvConfirmMessage.text = "You are about to $actionName on $selectedCount app(s).\n\nContinue?"
6975

70-
binding.btnClearData.setOnClickListener {
71-
onActionSelected?.invoke(Action.CLEAR_DATA)
72-
dismiss()
76+
binding.layoutActions.visibility = View.GONE
77+
binding.layoutConfirm.visibility = View.VISIBLE
78+
}
79+
80+
private fun getActionDisplayName(action: Action): String {
81+
return when (action) {
82+
Action.FREEZE -> "Freeze"
83+
Action.UNFREEZE -> "Unfreeze"
84+
Action.UNINSTALL -> "Uninstall"
85+
Action.FORCE_STOP -> "Force Stop"
86+
Action.RESTRICT_BACKGROUND -> "Restrict Background"
87+
Action.ALLOW_BACKGROUND -> "Allow Background"
88+
Action.CLEAR_CACHE -> "Clear Cache"
89+
Action.CLEAR_DATA -> "Clear Data"
7390
}
7491
}
7592

Lines changed: 152 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto"
34
android:layout_width="match_parent"
45
android:layout_height="wrap_content"
56
android:orientation="vertical"
6-
android:padding="16dp">
7+
android:padding="20dp">
78

9+
<!-- Header -->
810
<TextView
911
android:id="@+id/tvTitle"
1012
android:layout_width="wrap_content"
@@ -13,124 +15,169 @@
1315
android:textStyle="bold"
1416
android:layout_marginBottom="16dp" />
1517

16-
<TextView
17-
android:layout_width="wrap_content"
18-
android:layout_height="wrap_content"
19-
android:text="App Control"
20-
android:textColor="@color/on_surface_secondary"
21-
android:textSize="12sp"
22-
android:layout_marginBottom="8dp" />
23-
24-
<LinearLayout
25-
android:layout_width="match_parent"
26-
android:layout_height="wrap_content"
27-
android:orientation="horizontal">
28-
29-
<Button
30-
android:id="@+id/btnFreeze"
31-
android:layout_width="0dp"
32-
android:layout_height="wrap_content"
33-
android:layout_weight="1"
34-
android:text="@string/action_freeze"
35-
style="@style/Widget.Material3.Button.OutlinedButton" />
36-
37-
<Button
38-
android:id="@+id/btnUnfreeze"
39-
android:layout_width="0dp"
40-
android:layout_height="wrap_content"
41-
android:layout_weight="1"
42-
android:layout_marginStart="8dp"
43-
android:text="@string/action_unfreeze"
44-
style="@style/Widget.Material3.Button.OutlinedButton" />
45-
</LinearLayout>
46-
47-
<LinearLayout
48-
android:layout_width="match_parent"
49-
android:layout_height="wrap_content"
50-
android:layout_marginTop="8dp"
51-
android:orientation="horizontal">
52-
53-
<Button
54-
android:id="@+id/btnUninstall"
55-
android:layout_width="0dp"
56-
android:layout_height="wrap_content"
57-
android:layout_weight="1"
58-
android:text="@string/action_uninstall"
59-
style="@style/Widget.Material3.Button.OutlinedButton" />
60-
61-
<Button
62-
android:id="@+id/btnForceStop"
63-
android:layout_width="0dp"
64-
android:layout_height="wrap_content"
65-
android:layout_weight="1"
66-
android:layout_marginStart="8dp"
67-
android:text="Force Stop"
68-
style="@style/Widget.Material3.Button.OutlinedButton" />
69-
</LinearLayout>
70-
71-
<TextView
72-
android:layout_width="wrap_content"
73-
android:layout_height="wrap_content"
74-
android:text="Battery Control"
75-
android:textColor="@color/on_surface_secondary"
76-
android:textSize="12sp"
77-
android:layout_marginTop="16dp"
78-
android:layout_marginBottom="8dp" />
79-
18+
<!-- Action Selection View -->
8019
<LinearLayout
20+
android:id="@+id/layoutActions"
8121
android:layout_width="match_parent"
8222
android:layout_height="wrap_content"
83-
android:orientation="horizontal">
84-
85-
<Button
86-
android:id="@+id/btnRestrictBg"
87-
android:layout_width="0dp"
88-
android:layout_height="wrap_content"
89-
android:layout_weight="1"
90-
android:text="@string/action_restrict_bg"
91-
style="@style/Widget.Material3.Button.OutlinedButton" />
23+
android:orientation="vertical">
9224

93-
<Button
94-
android:id="@+id/btnAllowBg"
95-
android:layout_width="0dp"
25+
<!-- Actions Grid -->
26+
<GridLayout
27+
android:layout_width="match_parent"
9628
android:layout_height="wrap_content"
97-
android:layout_weight="1"
98-
android:layout_marginStart="8dp"
99-
android:text="@string/action_allow_bg"
100-
style="@style/Widget.Material3.Button.OutlinedButton" />
29+
android:columnCount="3"
30+
android:useDefaultMargins="true">
31+
32+
<com.google.android.material.button.MaterialButton
33+
android:id="@+id/btnForceStop"
34+
android:layout_width="0dp"
35+
android:layout_height="wrap_content"
36+
android:layout_columnWeight="1"
37+
android:text="@string/action_force_stop"
38+
android:textSize="10sp"
39+
app:icon="@drawable/ic_stop"
40+
app:iconSize="20dp"
41+
app:iconGravity="top"
42+
app:iconPadding="2dp"
43+
style="@style/Widget.Material3.Button.TonalButton" />
44+
45+
<com.google.android.material.button.MaterialButton
46+
android:id="@+id/btnFreeze"
47+
android:layout_width="0dp"
48+
android:layout_height="wrap_content"
49+
android:layout_columnWeight="1"
50+
android:text="@string/action_freeze"
51+
android:textSize="10sp"
52+
app:icon="@drawable/ic_freeze"
53+
app:iconSize="20dp"
54+
app:iconGravity="top"
55+
app:iconPadding="2dp"
56+
style="@style/Widget.Material3.Button.TonalButton" />
57+
58+
<com.google.android.material.button.MaterialButton
59+
android:id="@+id/btnUnfreeze"
60+
android:layout_width="0dp"
61+
android:layout_height="wrap_content"
62+
android:layout_columnWeight="1"
63+
android:text="@string/action_unfreeze"
64+
android:textSize="10sp"
65+
app:icon="@drawable/ic_check_circle"
66+
app:iconSize="20dp"
67+
app:iconGravity="top"
68+
app:iconPadding="2dp"
69+
style="@style/Widget.Material3.Button.TonalButton" />
70+
71+
<com.google.android.material.button.MaterialButton
72+
android:id="@+id/btnRestrictBg"
73+
android:layout_width="0dp"
74+
android:layout_height="wrap_content"
75+
android:layout_columnWeight="1"
76+
android:text="@string/action_restrict_bg"
77+
android:textSize="10sp"
78+
app:icon="@drawable/ic_battery_alert"
79+
app:iconSize="20dp"
80+
app:iconGravity="top"
81+
app:iconPadding="2dp"
82+
style="@style/Widget.Material3.Button.TonalButton" />
83+
84+
<com.google.android.material.button.MaterialButton
85+
android:id="@+id/btnAllowBg"
86+
android:layout_width="0dp"
87+
android:layout_height="wrap_content"
88+
android:layout_columnWeight="1"
89+
android:text="@string/action_allow_bg"
90+
android:textSize="10sp"
91+
app:icon="@drawable/ic_check_circle"
92+
app:iconSize="20dp"
93+
app:iconGravity="top"
94+
app:iconPadding="2dp"
95+
style="@style/Widget.Material3.Button.TonalButton" />
96+
97+
<com.google.android.material.button.MaterialButton
98+
android:id="@+id/btnClearCache"
99+
android:layout_width="0dp"
100+
android:layout_height="wrap_content"
101+
android:layout_columnWeight="1"
102+
android:text="@string/action_clear_cache"
103+
android:textSize="10sp"
104+
app:icon="@drawable/ic_cleaning"
105+
app:iconSize="20dp"
106+
app:iconGravity="top"
107+
app:iconPadding="2dp"
108+
style="@style/Widget.Material3.Button.TonalButton" />
109+
110+
<com.google.android.material.button.MaterialButton
111+
android:id="@+id/btnClearData"
112+
android:layout_width="0dp"
113+
android:layout_height="wrap_content"
114+
android:layout_columnWeight="1"
115+
android:text="@string/action_clear_data"
116+
android:textSize="10sp"
117+
android:textColor="@color/warning_color"
118+
app:icon="@drawable/ic_delete_sweep"
119+
app:iconSize="20dp"
120+
app:iconGravity="top"
121+
app:iconPadding="2dp"
122+
app:iconTint="@color/warning_color"
123+
style="@style/Widget.Material3.Button.TonalButton" />
124+
125+
<com.google.android.material.button.MaterialButton
126+
android:id="@+id/btnUninstall"
127+
android:layout_width="0dp"
128+
android:layout_height="wrap_content"
129+
android:layout_columnWeight="1"
130+
android:text="@string/action_uninstall"
131+
android:textSize="10sp"
132+
android:textColor="@color/status_negative"
133+
app:icon="@drawable/ic_delete"
134+
app:iconSize="20dp"
135+
app:iconGravity="top"
136+
app:iconPadding="2dp"
137+
app:iconTint="@color/status_negative"
138+
style="@style/Widget.Material3.Button.TonalButton" />
139+
140+
</GridLayout>
101141
</LinearLayout>
102142

103-
<TextView
104-
android:layout_width="wrap_content"
105-
android:layout_height="wrap_content"
106-
android:text="Data"
107-
android:textColor="@color/on_surface_secondary"
108-
android:textSize="12sp"
109-
android:layout_marginTop="16dp"
110-
android:layout_marginBottom="8dp" />
111-
143+
<!-- Confirmation View (hidden by default) -->
112144
<LinearLayout
145+
android:id="@+id/layoutConfirm"
113146
android:layout_width="match_parent"
114147
android:layout_height="wrap_content"
115-
android:orientation="horizontal">
148+
android:orientation="vertical"
149+
android:visibility="gone">
116150

117-
<Button
118-
android:id="@+id/btnClearCache"
119-
android:layout_width="0dp"
151+
<TextView
152+
android:id="@+id/tvConfirmMessage"
153+
android:layout_width="match_parent"
120154
android:layout_height="wrap_content"
121-
android:layout_weight="1"
122-
android:text="@string/action_clear_cache"
123-
style="@style/Widget.Material3.Button.OutlinedButton" />
155+
android:textSize="15sp"
156+
android:lineSpacingExtra="4dp"
157+
android:layout_marginBottom="20dp" />
124158

125-
<Button
126-
android:id="@+id/btnClearData"
127-
android:layout_width="0dp"
159+
<LinearLayout
160+
android:layout_width="match_parent"
128161
android:layout_height="wrap_content"
129-
android:layout_weight="1"
130-
android:layout_marginStart="8dp"
131-
android:text="@string/action_clear_data"
132-
android:textColor="@color/warning_color"
133-
style="@style/Widget.Material3.Button.OutlinedButton" />
162+
android:orientation="horizontal">
163+
164+
<com.google.android.material.button.MaterialButton
165+
android:id="@+id/btnNo"
166+
android:layout_width="0dp"
167+
android:layout_height="wrap_content"
168+
android:layout_weight="1"
169+
android:text="@string/confirm_no"
170+
style="@style/Widget.Material3.Button.OutlinedButton" />
171+
172+
<com.google.android.material.button.MaterialButton
173+
android:id="@+id/btnYes"
174+
android:layout_width="0dp"
175+
android:layout_height="wrap_content"
176+
android:layout_weight="1"
177+
android:layout_marginStart="12dp"
178+
android:text="@string/confirm_yes"
179+
style="@style/Widget.Material3.Button.TonalButton" />
180+
</LinearLayout>
134181
</LinearLayout>
135182

136183
</LinearLayout>

0 commit comments

Comments
 (0)