Skip to content

Commit b5cfce9

Browse files
committed
Enhance batch operations and about page - Remove 3s countdown delay, init list first then execute immediately - Show cache/data size for clear cache/data operations - Add auto scroll during batch execution - Add Features card to About page with feature list - Add Indonesian translations for new strings
1 parent 042a188 commit b5cfce9

File tree

3 files changed

+116
-18
lines changed

3 files changed

+116
-18
lines changed

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

Lines changed: 78 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.appcontrolx.ui
22

3+
import android.content.pm.PackageManager
34
import android.os.Bundle
45
import android.view.LayoutInflater
56
import android.view.View
@@ -11,9 +12,12 @@ import com.appcontrolx.R
1112
import com.appcontrolx.databinding.BottomSheetBatchProgressBinding
1213
import com.appcontrolx.databinding.ItemBatchAppBinding
1314
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
15+
import kotlinx.coroutines.Dispatchers
1416
import kotlinx.coroutines.Job
1517
import kotlinx.coroutines.delay
1618
import kotlinx.coroutines.launch
19+
import kotlinx.coroutines.withContext
20+
import java.io.File
1721

1822
class BatchProgressBottomSheet : BottomSheetDialogFragment() {
1923

@@ -23,6 +27,7 @@ class BatchProgressBottomSheet : BottomSheetDialogFragment() {
2327
private var actionName = ""
2428
private var appNames = listOf<String>()
2529
private var packageNames = listOf<String>()
30+
private var showCacheSize = false
2631
private var onExecute: (suspend (String) -> Result<Unit>)? = null
2732
private var onComplete: (() -> Unit)? = null
2833

@@ -32,7 +37,6 @@ class BatchProgressBottomSheet : BottomSheetDialogFragment() {
3237

3338
companion object {
3439
const val TAG = "BatchProgressBottomSheet"
35-
private const val COUNTDOWN_SECONDS = 3
3640

3741
fun newInstance(
3842
actionName: String,
@@ -45,6 +49,7 @@ class BatchProgressBottomSheet : BottomSheetDialogFragment() {
4549
this.actionName = actionName
4650
this.appNames = appNames
4751
this.packageNames = packageNames
52+
this.showCacheSize = actionName == "CLEAR_CACHE" || actionName == "CLEAR_DATA"
4853
this.onExecute = onExecute
4954
this.onComplete = onComplete
5055
}
@@ -59,7 +64,7 @@ class BatchProgressBottomSheet : BottomSheetDialogFragment() {
5964
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
6065
super.onViewCreated(view, savedInstanceState)
6166
setupUI()
62-
startCountdown()
67+
initListThenExecute()
6368
}
6469

6570
private fun setupUI() {
@@ -68,12 +73,10 @@ class BatchProgressBottomSheet : BottomSheetDialogFragment() {
6873
b.tvAction.text = actionName.replace("_", " ")
6974
b.progressBar.max = packageNames.size
7075
b.progressBar.progress = 0
71-
b.tvProgress.text = getString(R.string.batch_waiting)
76+
b.tvProgress.text = getString(R.string.batch_preparing)
77+
b.tvCountdown.text = ""
7278

73-
// Setup RecyclerView with app list
74-
adapter.submitList(appNames.mapIndexed { index, name ->
75-
BatchAppItem(name, packageNames[index], BatchStatus.PENDING)
76-
})
79+
// Setup RecyclerView
7780
b.recyclerView.layoutManager = LinearLayoutManager(context)
7881
b.recyclerView.adapter = adapter
7982

@@ -84,20 +87,70 @@ class BatchProgressBottomSheet : BottomSheetDialogFragment() {
8487
}
8588
}
8689

87-
private fun startCountdown() {
90+
private fun initListThenExecute() {
8891
executionJob = lifecycleScope.launch {
89-
// Countdown
90-
for (i in COUNTDOWN_SECONDS downTo 1) {
91-
if (isCancelled) return@launch
92-
binding?.tvCountdown?.text = getString(R.string.batch_countdown, i)
93-
delay(1000)
92+
// Init list first (with cache size if needed)
93+
val items = withContext(Dispatchers.IO) {
94+
appNames.mapIndexed { index, name ->
95+
val pkg = packageNames[index]
96+
val sizeInfo = if (showCacheSize) getCacheSize(pkg) else null
97+
BatchAppItem(name, pkg, BatchStatus.PENDING, sizeInfo)
98+
}
9499
}
95100

96-
binding?.tvCountdown?.text = ""
101+
if (isCancelled) return@launch
102+
103+
adapter.submitList(items)
104+
105+
// Small delay for UI to render list
106+
delay(100)
107+
108+
// Execute immediately
97109
executeActions()
98110
}
99111
}
100112

113+
private fun getCacheSize(packageName: String): String? {
114+
return try {
115+
val pm = requireContext().packageManager
116+
val appInfo = pm.getApplicationInfo(packageName, 0)
117+
val dataDir = File(appInfo.dataDir)
118+
val cacheDir = File(dataDir, "cache")
119+
120+
val cacheSize = if (cacheDir.exists()) getFolderSize(cacheDir) else 0L
121+
val totalSize = getFolderSize(dataDir)
122+
123+
if (actionName == "CLEAR_CACHE") {
124+
formatSize(cacheSize)
125+
} else {
126+
formatSize(totalSize)
127+
}
128+
} catch (e: Exception) {
129+
null
130+
}
131+
}
132+
133+
private fun getFolderSize(dir: File): Long {
134+
var size = 0L
135+
try {
136+
dir.walkTopDown().forEach { file ->
137+
if (file.isFile) size += file.length()
138+
}
139+
} catch (e: Exception) {
140+
// Permission denied or other error
141+
}
142+
return size
143+
}
144+
145+
private fun formatSize(bytes: Long): String {
146+
return when {
147+
bytes < 1024 -> "$bytes B"
148+
bytes < 1024 * 1024 -> "${bytes / 1024} KB"
149+
bytes < 1024 * 1024 * 1024 -> String.format("%.1f MB", bytes / (1024.0 * 1024.0))
150+
else -> String.format("%.2f GB", bytes / (1024.0 * 1024.0 * 1024.0))
151+
}
152+
}
153+
101154
private suspend fun executeActions() {
102155
val b = binding ?: return
103156
var successCount = 0
@@ -108,8 +161,9 @@ class BatchProgressBottomSheet : BottomSheetDialogFragment() {
108161

109162
b.tvProgress.text = getString(R.string.batch_progress, index + 1, packageNames.size)
110163

111-
// Update status to processing
164+
// Update status to processing & auto scroll
112165
adapter.updateStatus(index, BatchStatus.PROCESSING)
166+
b.recyclerView.smoothScrollToPosition(index)
113167

114168
val result = onExecute?.invoke(pkg) ?: Result.failure(Exception("No executor"))
115169

@@ -122,7 +176,7 @@ class BatchProgressBottomSheet : BottomSheetDialogFragment() {
122176
}
123177

124178
b.progressBar.progress = index + 1
125-
delay(100) // Small delay for UI
179+
delay(50) // Small delay for UI
126180
}
127181

128182
// Complete
@@ -149,7 +203,8 @@ class BatchProgressBottomSheet : BottomSheetDialogFragment() {
149203
data class BatchAppItem(
150204
val appName: String,
151205
val packageName: String,
152-
var status: BatchStatus
206+
var status: BatchStatus,
207+
val sizeInfo: String? = null
153208
)
154209

155210
// Adapter
@@ -182,7 +237,12 @@ class BatchProgressBottomSheet : BottomSheetDialogFragment() {
182237

183238
inner class ViewHolder(private val binding: ItemBatchAppBinding) : RecyclerView.ViewHolder(binding.root) {
184239
fun bind(item: BatchAppItem) {
185-
binding.tvAppName.text = item.appName
240+
// Show app name with size info if available
241+
binding.tvAppName.text = if (item.sizeInfo != null && item.status == BatchStatus.PENDING) {
242+
"${item.appName} (${item.sizeInfo})"
243+
} else {
244+
item.appName
245+
}
186246

187247
val (statusText, statusColor) = when (item.status) {
188248
BatchStatus.PENDING -> "-" to R.color.on_surface_secondary

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,41 @@
192192
</com.google.android.material.card.MaterialCardView>
193193
</LinearLayout>
194194

195+
<!-- Features Card -->
196+
<com.google.android.material.card.MaterialCardView
197+
android:layout_width="match_parent"
198+
android:layout_height="wrap_content"
199+
android:layout_marginBottom="12dp"
200+
app:cardCornerRadius="16dp"
201+
app:cardElevation="0dp"
202+
app:strokeWidth="1dp"
203+
app:strokeColor="@color/outline">
204+
205+
<LinearLayout
206+
android:layout_width="match_parent"
207+
android:layout_height="wrap_content"
208+
android:orientation="vertical"
209+
android:padding="16dp">
210+
211+
<TextView
212+
android:layout_width="wrap_content"
213+
android:layout_height="wrap_content"
214+
android:text="@string/about_features_title"
215+
android:textSize="14sp"
216+
android:textStyle="bold"
217+
android:textColor="?attr/colorPrimary" />
218+
219+
<TextView
220+
android:layout_width="match_parent"
221+
android:layout_height="wrap_content"
222+
android:layout_marginTop="12dp"
223+
android:text="@string/about_features_list"
224+
android:textSize="13sp"
225+
android:lineSpacingExtra="4dp"
226+
android:textColor="@color/on_surface_secondary" />
227+
</LinearLayout>
228+
</com.google.android.material.card.MaterialCardView>
229+
195230
<!-- Device Info Card -->
196231
<com.google.android.material.card.MaterialCardView
197232
android:layout_width="match_parent"

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
<string name="settings_protect_system_desc">Cegah aksi pada aplikasi sistem kritis</string>
9090

9191
<!-- Batch -->
92+
<string name="batch_preparing">Mempersiapkan...</string>
9293
<string name="batch_waiting">Menunggu untuk mulai...</string>
9394
<string name="batch_countdown">Mulai dalam %d...</string>
9495
<string name="batch_progress">%1$d / %2$d</string>
@@ -98,6 +99,8 @@
9899

99100
<!-- About -->
100101
<string name="about_tagline">Kontrol aplikasi, hemat baterai</string>
102+
<string name="about_features_title">Fitur</string>
103+
<string name="about_features_list">• Bekukan/Aktifkan aplikasi (nonaktifkan tanpa uninstall)\n• Paksa berhenti aplikasi yang berjalan\n• Batasi aktivitas latar belakang\n• Operasi batch pada banyak aplikasi\n• Perlindungan aplikasi sistem\n• Rollback dengan snapshot status\n• Dukungan Root dan Shizuku\n• Desain Material You</string>
101104
<string name="about_system_title">Info Perangkat</string>
102105
<string name="about_device">Perangkat</string>
103106
<string name="about_android">Android</string>

0 commit comments

Comments
 (0)