Skip to content

Commit 1b1c08b

Browse files
committed
Redesign App Detail quick actions with categorized grid - Replace ChipGroup with GridLayout (3 columns) - Add separate Allow Background and Restrict Background buttons - Add Danger Zone section for destructive actions (Clear Data, Uninstall) - Use MaterialButton with icon on top for cleaner look - Show/hide background buttons based on current status
1 parent 8581b61 commit 1b1c08b

File tree

4 files changed

+144
-83
lines changed

4 files changed

+144
-83
lines changed

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

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import com.appcontrolx.service.BatteryPolicyManager
2121
import com.appcontrolx.service.PermissionBridge
2222
import com.appcontrolx.utils.SafetyValidator
2323
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
24-
import com.google.android.material.chip.Chip
24+
import com.google.android.material.button.MaterialButton
2525
import kotlinx.coroutines.Dispatchers
2626
import kotlinx.coroutines.launch
2727
import kotlinx.coroutines.withContext
@@ -193,12 +193,9 @@ class AppDetailBottomSheet : BottomSheetDialogFragment() {
193193
binding.tvBatteryStatus.text = text
194194
binding.tvBatteryStatus.setTextColor(resources.getColor(color, null))
195195

196-
// Update chip text based on current status
197-
binding.btnToggleBackground.text = if (currentBgStatus == BackgroundStatus.RESTRICTED) {
198-
getString(R.string.action_allow_bg)
199-
} else {
200-
getString(R.string.action_restrict_bg)
201-
}
196+
// Update button visibility based on current status
197+
binding.btnRestrictBg.visibility = if (currentBgStatus == BackgroundStatus.RESTRICTED) View.GONE else View.VISIBLE
198+
binding.btnAllowBg.visibility = if (currentBgStatus == BackgroundStatus.RESTRICTED) View.VISIBLE else View.GONE
202199
}
203200

204201
private fun setupButtons() {
@@ -210,17 +207,18 @@ class AppDetailBottomSheet : BottomSheetDialogFragment() {
210207
val isForceStopOnly = SafetyValidator.isForceStopOnly(packageName)
211208
val isCritical = SafetyValidator.isCritical(packageName)
212209

213-
// Update freeze/unfreeze chip text based on current state
210+
// Update freeze/unfreeze button text based on current state
214211
binding.btnToggleEnable.text = if (isEnabled) getString(R.string.action_freeze)
215212
else getString(R.string.action_unfreeze)
216213

217-
// Set chip enabled states
218-
setChipEnabled(binding.btnForceStop, hasMode && !isCritical)
219-
setChipEnabled(binding.btnToggleEnable, hasMode && SafetyValidator.AllowedAction.FREEZE in allowedActions)
220-
setChipEnabled(binding.btnToggleBackground, hasMode && SafetyValidator.AllowedAction.RESTRICT_BACKGROUND in allowedActions)
221-
setChipEnabled(binding.btnUninstall, hasMode && SafetyValidator.AllowedAction.UNINSTALL in allowedActions)
222-
setChipEnabled(binding.btnClearCache, hasMode && !isCritical)
223-
setChipEnabled(binding.btnClearData, hasMode && !isCritical)
214+
// Set button enabled states
215+
setButtonEnabled(binding.btnForceStop, hasMode && !isCritical)
216+
setButtonEnabled(binding.btnToggleEnable, hasMode && SafetyValidator.AllowedAction.FREEZE in allowedActions)
217+
setButtonEnabled(binding.btnRestrictBg, hasMode && SafetyValidator.AllowedAction.RESTRICT_BACKGROUND in allowedActions)
218+
setButtonEnabled(binding.btnAllowBg, hasMode && SafetyValidator.AllowedAction.RESTRICT_BACKGROUND in allowedActions)
219+
setButtonEnabled(binding.btnClearCache, hasMode && !isCritical)
220+
setButtonEnabled(binding.btnClearData, hasMode && !isCritical)
221+
setButtonEnabled(binding.btnUninstall, hasMode && SafetyValidator.AllowedAction.UNINSTALL in allowedActions)
224222

225223
binding.btnForceStop.setOnClickListener {
226224
if (isCritical) { showProtectedWarning(); return@setOnClickListener }
@@ -239,22 +237,17 @@ class AppDetailBottomSheet : BottomSheetDialogFragment() {
239237
}
240238
}
241239

242-
binding.btnToggleBackground.setOnClickListener {
240+
binding.btnRestrictBg.setOnClickListener {
243241
if (isForceStopOnly || isCritical) { showProtectedWarning(); return@setOnClickListener }
244-
val actionName = if (currentBgStatus == BackgroundStatus.RESTRICTED)
245-
getString(R.string.action_allow_bg) else getString(R.string.action_restrict_bg)
246-
executeActionWithLoading(actionName) {
247-
if (currentBgStatus == BackgroundStatus.RESTRICTED)
248-
policyManager?.allowBackground(appInfo!!.packageName)
249-
else
250-
policyManager?.restrictBackground(appInfo!!.packageName)
242+
executeActionWithLoading(getString(R.string.action_restrict_bg)) {
243+
policyManager?.restrictBackground(appInfo!!.packageName)
251244
}
252245
}
253246

254-
binding.btnUninstall.setOnClickListener {
247+
binding.btnAllowBg.setOnClickListener {
255248
if (isForceStopOnly || isCritical) { showProtectedWarning(); return@setOnClickListener }
256-
executeActionWithLoading(getString(R.string.action_uninstall)) {
257-
policyManager?.uninstallApp(appInfo!!.packageName)
249+
executeActionWithLoading(getString(R.string.action_allow_bg)) {
250+
policyManager?.allowBackground(appInfo!!.packageName)
258251
}
259252
}
260253

@@ -272,6 +265,13 @@ class AppDetailBottomSheet : BottomSheetDialogFragment() {
272265
}
273266
}
274267

268+
binding.btnUninstall.setOnClickListener {
269+
if (isForceStopOnly || isCritical) { showProtectedWarning(); return@setOnClickListener }
270+
executeActionWithLoading(getString(R.string.action_uninstall)) {
271+
policyManager?.uninstallApp(appInfo!!.packageName)
272+
}
273+
}
274+
275275
binding.btnLaunchApp.setOnClickListener { launchApp() }
276276
binding.btnOpenSettings.setOnClickListener { openAppSettings() }
277277
}
@@ -334,17 +334,18 @@ class AppDetailBottomSheet : BottomSheetDialogFragment() {
334334
private fun setButtonsEnabled(enabled: Boolean) {
335335
binding.btnForceStop.isEnabled = enabled
336336
binding.btnToggleEnable.isEnabled = enabled
337-
binding.btnToggleBackground.isEnabled = enabled
338-
binding.btnUninstall.isEnabled = enabled
337+
binding.btnRestrictBg.isEnabled = enabled
338+
binding.btnAllowBg.isEnabled = enabled
339339
binding.btnClearCache.isEnabled = enabled
340340
binding.btnClearData.isEnabled = enabled
341+
binding.btnUninstall.isEnabled = enabled
341342
binding.btnLaunchApp.isEnabled = enabled
342343
binding.btnOpenSettings.isEnabled = enabled
343344
}
344345

345-
private fun setChipEnabled(chip: Chip, enabled: Boolean) {
346-
chip.isEnabled = enabled
347-
chip.alpha = if (enabled) 1.0f else 0.5f
346+
private fun setButtonEnabled(button: MaterialButton, enabled: Boolean) {
347+
button.isEnabled = enabled
348+
button.alpha = if (enabled) 1.0f else 0.5f
348349
}
349350

350351
private fun openAppSettings() {

app/src/main/res/layout/bottom_sheet_app_detail.xml

Lines changed: 110 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -295,82 +295,140 @@
295295
android:textStyle="bold"
296296
android:textSize="14sp" />
297297

298-
<!-- Control Actions -->
299-
<com.google.android.material.chip.ChipGroup
298+
<!-- Safe Actions - 3 column grid -->
299+
<GridLayout
300300
android:layout_width="match_parent"
301301
android:layout_height="wrap_content"
302302
android:layout_marginTop="12dp"
303-
app:singleLine="false">
303+
android:columnCount="3"
304+
android:useDefaultMargins="true">
304305

305-
<com.google.android.material.chip.Chip
306+
<com.google.android.material.button.MaterialButton
306307
android:id="@+id/btnForceStop"
307-
android:layout_width="wrap_content"
308+
android:layout_width="0dp"
308309
android:layout_height="wrap_content"
310+
android:layout_columnWeight="1"
309311
android:text="@string/action_force_stop"
310-
app:chipIcon="@drawable/ic_stop"
311-
app:chipBackgroundColor="@color/surface_container"
312-
app:chipStrokeWidth="1dp"
313-
app:chipStrokeColor="@color/outline" />
312+
android:textSize="11sp"
313+
app:icon="@drawable/ic_stop"
314+
app:iconSize="18dp"
315+
app:iconGravity="top"
316+
app:iconPadding="4dp"
317+
style="@style/Widget.Material3.Button.TonalButton" />
314318

315-
<com.google.android.material.chip.Chip
319+
<com.google.android.material.button.MaterialButton
316320
android:id="@+id/btnToggleEnable"
317-
android:layout_width="wrap_content"
321+
android:layout_width="0dp"
318322
android:layout_height="wrap_content"
323+
android:layout_columnWeight="1"
319324
android:text="@string/action_freeze"
320-
app:chipIcon="@drawable/ic_freeze"
321-
app:chipBackgroundColor="@color/surface_container"
322-
app:chipStrokeWidth="1dp"
323-
app:chipStrokeColor="@color/outline" />
325+
android:textSize="11sp"
326+
app:icon="@drawable/ic_freeze"
327+
app:iconSize="18dp"
328+
app:iconGravity="top"
329+
app:iconPadding="4dp"
330+
style="@style/Widget.Material3.Button.TonalButton" />
324331

325-
<com.google.android.material.chip.Chip
326-
android:id="@+id/btnToggleBackground"
327-
android:layout_width="wrap_content"
332+
<com.google.android.material.button.MaterialButton
333+
android:id="@+id/btnRestrictBg"
334+
android:layout_width="0dp"
328335
android:layout_height="wrap_content"
336+
android:layout_columnWeight="1"
329337
android:text="@string/action_restrict_bg"
330-
app:chipIcon="@drawable/ic_battery_alert"
331-
app:chipBackgroundColor="@color/surface_container"
332-
app:chipStrokeWidth="1dp"
333-
app:chipStrokeColor="@color/outline" />
338+
android:textSize="11sp"
339+
app:icon="@drawable/ic_battery_alert"
340+
app:iconSize="18dp"
341+
app:iconGravity="top"
342+
app:iconPadding="4dp"
343+
style="@style/Widget.Material3.Button.TonalButton" />
334344

335-
<com.google.android.material.chip.Chip
345+
<com.google.android.material.button.MaterialButton
346+
android:id="@+id/btnAllowBg"
347+
android:layout_width="0dp"
348+
android:layout_height="wrap_content"
349+
android:layout_columnWeight="1"
350+
android:text="@string/action_allow_bg"
351+
android:textSize="11sp"
352+
app:icon="@drawable/ic_check_circle"
353+
app:iconSize="18dp"
354+
app:iconGravity="top"
355+
app:iconPadding="4dp"
356+
style="@style/Widget.Material3.Button.TonalButton" />
357+
358+
<com.google.android.material.button.MaterialButton
336359
android:id="@+id/btnClearCache"
337-
android:layout_width="wrap_content"
360+
android:layout_width="0dp"
338361
android:layout_height="wrap_content"
362+
android:layout_columnWeight="1"
339363
android:text="@string/action_clear_cache"
340-
app:chipIcon="@drawable/ic_cleaning"
341-
app:chipBackgroundColor="@color/surface_container"
342-
app:chipStrokeWidth="1dp"
343-
app:chipStrokeColor="@color/outline" />
364+
android:textSize="11sp"
365+
app:icon="@drawable/ic_cleaning"
366+
app:iconSize="18dp"
367+
app:iconGravity="top"
368+
app:iconPadding="4dp"
369+
style="@style/Widget.Material3.Button.TonalButton" />
370+
371+
<com.google.android.material.button.MaterialButton
372+
android:id="@+id/btnOpenSettings"
373+
android:layout_width="0dp"
374+
android:layout_height="wrap_content"
375+
android:layout_columnWeight="1"
376+
android:text="@string/btn_info"
377+
android:textSize="11sp"
378+
app:icon="@drawable/ic_info"
379+
app:iconSize="18dp"
380+
app:iconGravity="top"
381+
app:iconPadding="4dp"
382+
style="@style/Widget.Material3.Button.TonalButton" />
383+
384+
</GridLayout>
344385

345-
<com.google.android.material.chip.Chip
386+
<!-- Danger Actions -->
387+
<TextView
388+
android:layout_width="wrap_content"
389+
android:layout_height="wrap_content"
390+
android:layout_marginTop="16dp"
391+
android:text="@string/action_danger_zone"
392+
android:textStyle="bold"
393+
android:textSize="12sp"
394+
android:textColor="@color/status_negative" />
395+
396+
<GridLayout
397+
android:layout_width="match_parent"
398+
android:layout_height="wrap_content"
399+
android:layout_marginTop="8dp"
400+
android:columnCount="3"
401+
android:useDefaultMargins="true">
402+
403+
<com.google.android.material.button.MaterialButton
346404
android:id="@+id/btnClearData"
347-
android:layout_width="wrap_content"
405+
android:layout_width="0dp"
348406
android:layout_height="wrap_content"
407+
android:layout_columnWeight="1"
349408
android:text="@string/action_clear_data"
350-
app:chipIcon="@drawable/ic_delete_sweep"
351-
app:chipBackgroundColor="@color/surface_container"
352-
app:chipStrokeWidth="1dp"
353-
app:chipStrokeColor="@color/outline" />
409+
android:textSize="11sp"
410+
android:textColor="@color/status_negative"
411+
app:icon="@drawable/ic_delete_sweep"
412+
app:iconSize="18dp"
413+
app:iconGravity="top"
414+
app:iconPadding="4dp"
415+
app:iconTint="@color/status_negative"
416+
style="@style/Widget.Material3.Button.OutlinedButton" />
354417

355-
<com.google.android.material.chip.Chip
418+
<com.google.android.material.button.MaterialButton
356419
android:id="@+id/btnUninstall"
357-
android:layout_width="wrap_content"
420+
android:layout_width="0dp"
358421
android:layout_height="wrap_content"
422+
android:layout_columnWeight="1"
359423
android:text="@string/action_uninstall"
360-
app:chipIcon="@drawable/ic_delete"
361-
app:chipBackgroundColor="@color/surface_container"
362-
app:chipStrokeWidth="1dp"
363-
app:chipStrokeColor="@color/status_negative" />
364-
365-
<com.google.android.material.chip.Chip
366-
android:id="@+id/btnOpenSettings"
367-
android:layout_width="wrap_content"
368-
android:layout_height="wrap_content"
369-
android:text="@string/btn_info"
370-
app:chipIcon="@drawable/ic_info"
371-
app:chipBackgroundColor="@color/surface_container"
372-
app:chipStrokeWidth="1dp"
373-
app:chipStrokeColor="@color/outline" />
374-
375-
</com.google.android.material.chip.ChipGroup>
424+
android:textSize="11sp"
425+
android:textColor="@color/status_negative"
426+
app:icon="@drawable/ic_delete"
427+
app:iconSize="18dp"
428+
app:iconGravity="top"
429+
app:iconPadding="4dp"
430+
app:iconTint="@color/status_negative"
431+
style="@style/Widget.Material3.Button.OutlinedButton" />
432+
433+
</GridLayout>
376434
</LinearLayout>

app/src/main/res/values-id/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
<string name="action_allow_bg">Izinkan Latar Belakang</string>
6565
<string name="action_clear_cache">Hapus Cache</string>
6666
<string name="action_clear_data">Hapus Data</string>
67+
<string name="action_danger_zone">Zona Bahaya</string>
6768
<string name="action_execute">Jalankan</string>
6869
<string name="action_launch">Buka</string>
6970

app/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@
306306
<!-- Quick Actions -->
307307
<string name="action_clear_cache">Clear Cache</string>
308308
<string name="action_clear_data">Clear Data</string>
309+
<string name="action_danger_zone">Danger Zone</string>
309310
<string name="action_launch">Launch</string>
310311
<string name="action_launch_apps">Launch Apps</string>
311312
<string name="error_no_launcher">App has no launcher activity</string>

0 commit comments

Comments
 (0)