Skip to content

Commit a775c0a

Browse files
committed
enhance apps tab and apk preview dialog
1 parent 99efd65 commit a775c0a

File tree

13 files changed

+1429
-304
lines changed

13 files changed

+1429
-304
lines changed

app/src/main/java/com/raival/compose/file/explorer/screen/main/tab/apps/AppsTab.kt

Lines changed: 73 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,8 @@ import kotlinx.coroutines.launch
1717

1818
class AppsTab : Tab() {
1919
override val id = globalClass.generateUid()
20-
2120
override val title = globalClass.getString(R.string.apps_tab_title)
22-
2321
override val subtitle = emptyString
24-
2522
override val header = globalClass.getString(R.string.apps_tab_header)
2623

2724
val appsList = mutableStateListOf<AppHolder>()
@@ -34,6 +31,11 @@ class AppsTab : Tab() {
3431
var searchQuery by mutableStateOf(emptyString)
3532
var isSearching by mutableStateOf(false)
3633
var isLoading by mutableStateOf(false)
34+
var sortOption by mutableStateOf(SortOption.NAME)
35+
36+
enum class SortOption {
37+
NAME, SIZE, INSTALL_DATE, UPDATE_DATE
38+
}
3739

3840
override fun onTabResumed() {
3941
super.onTabResumed()
@@ -46,25 +48,10 @@ class AppsTab : Tab() {
4648
}
4749

4850
override fun onBackPressed(): Boolean {
49-
if (isSearchPanelOpen || isSearching || isLoading) {
50-
if (isSearching) {
51-
isSearching = false
52-
}
53-
54-
if (isSearchPanelOpen) {
55-
isSearchPanelOpen = false
56-
}
57-
58-
appsList.clear()
59-
60-
when (selectedChoice) {
61-
0 -> appsList.addAll(userApps)
62-
1 -> appsList.addAll(systemApps)
63-
2 -> {
64-
appsList.addAll(userApps)
65-
appsList.addAll(systemApps)
66-
}
67-
}
51+
if (isSearchPanelOpen) {
52+
isSearchPanelOpen = false
53+
searchQuery = emptyString
54+
updateAppsList()
6855
return true
6956
}
7057
return false
@@ -73,15 +60,73 @@ class AppsTab : Tab() {
7360
fun fetchInstalledApps() {
7461
isLoading = true
7562
CoroutineScope(Dispatchers.IO).launch {
76-
getInstalledApps(globalClass).forEach {
77-
if (it.isSystemApp) systemApps.add(it)
78-
else userApps.add(it)
63+
try {
64+
val apps = getInstalledApps(globalClass)
65+
apps.forEach { app ->
66+
if (app.isSystemApp) systemApps.add(app)
67+
else userApps.add(app)
68+
}
69+
updateAppsList()
70+
} catch (e: Exception) {
71+
e.printStackTrace()
72+
} finally {
73+
isLoading = false
7974
}
75+
}
76+
}
8077

81-
appsList.clear()
82-
appsList.addAll(userApps)
78+
fun updateAppsList() {
79+
appsList.clear()
80+
val filteredApps = when (selectedChoice) {
81+
0 -> userApps
82+
1 -> systemApps
83+
2 -> userApps + systemApps
84+
else -> emptyList()
85+
}
86+
87+
val sortedApps = when (sortOption) {
88+
SortOption.NAME -> filteredApps.sortedBy { it.name.lowercase() }
89+
SortOption.SIZE -> filteredApps.sortedByDescending { it.size }
90+
SortOption.INSTALL_DATE -> filteredApps.sortedByDescending { it.installDate }
91+
SortOption.UPDATE_DATE -> filteredApps.sortedByDescending { it.lastUpdateDate }
92+
}
93+
94+
appsList.addAll(sortedApps)
95+
}
96+
97+
fun performSearch() {
98+
if (searchQuery.isBlank()) {
99+
updateAppsList()
100+
return
101+
}
102+
103+
isSearching = true
104+
CoroutineScope(Dispatchers.IO).launch {
105+
try {
106+
val baseList = when (selectedChoice) {
107+
0 -> userApps
108+
1 -> systemApps
109+
2 -> userApps + systemApps
110+
else -> emptyList()
111+
}
112+
113+
val filteredApps = baseList.filter { app ->
114+
app.name.contains(searchQuery, ignoreCase = true) ||
115+
app.packageName.contains(searchQuery, ignoreCase = true)
116+
}
83117

84-
isLoading = false
118+
val sortedApps = when (sortOption) {
119+
SortOption.NAME -> filteredApps.sortedBy { it.name.lowercase() }
120+
SortOption.SIZE -> filteredApps.sortedByDescending { it.size }
121+
SortOption.INSTALL_DATE -> filteredApps.sortedByDescending { it.installDate }
122+
SortOption.UPDATE_DATE -> filteredApps.sortedByDescending { it.lastUpdateDate }
123+
}
124+
125+
appsList.clear()
126+
appsList.addAll(sortedApps)
127+
} finally {
128+
isSearching = false
129+
}
85130
}
86131
}
87132
}
Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
11
package com.raival.compose.file.explorer.screen.main.tab.apps.holder
22

3+
import java.util.Date
4+
35
data class AppHolder(
46
val name: String,
57
val packageName: String,
68
val path: String,
79
val versionName: String,
810
val versionCode: Int,
911
val size: Long,
10-
val isSystemApp: Boolean
12+
val isSystemApp: Boolean,
13+
val installDate: Date,
14+
val lastUpdateDate: Date,
15+
val targetSdkVersion: Int,
16+
val minSdkVersion: Int,
17+
val permissions: List<String>,
18+
val category: String,
19+
val dataDir: String,
20+
val uid: Int,
21+
val enabled: Boolean,
22+
val debuggable: Boolean
1123
)

app/src/main/java/com/raival/compose/file/explorer/screen/main/tab/apps/provider/AppsProvider.kt

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,77 @@ package com.raival.compose.file.explorer.screen.main.tab.apps.provider
33
import android.content.Context
44
import android.content.pm.ApplicationInfo
55
import android.content.pm.PackageManager
6+
import android.os.Build
7+
import com.raival.compose.file.explorer.App.Companion.globalClass
8+
import com.raival.compose.file.explorer.R
9+
import com.raival.compose.file.explorer.common.extension.emptyString
610
import com.raival.compose.file.explorer.screen.main.tab.apps.holder.AppHolder
711
import java.io.File
12+
import java.util.Date
813

914
fun getInstalledApps(context: Context): List<AppHolder> {
1015
val packageManager = context.packageManager
1116
val apps = packageManager.getInstalledApplications(PackageManager.GET_META_DATA)
1217

13-
return apps.map { appInfo ->
14-
createAppHolder(packageManager, appInfo)
18+
return apps.mapNotNull { appInfo ->
19+
try {
20+
createAppHolder(packageManager, appInfo)
21+
} catch (_: Exception) {
22+
null // Skip apps that can't be processed
23+
}
1524
}
1625
}
1726

1827
private fun createAppHolder(
1928
packageManager: PackageManager,
2029
appInfo: ApplicationInfo
2130
): AppHolder {
22-
val packageInfo =
23-
packageManager.getPackageInfo(appInfo.packageName, PackageManager.GET_META_DATA)
31+
val packageInfo = packageManager.getPackageInfo(
32+
appInfo.packageName,
33+
PackageManager.GET_PERMISSIONS or PackageManager.GET_META_DATA
34+
)
2435
val appFile = File(appInfo.sourceDir)
2536

37+
val permissions = packageInfo.requestedPermissions?.toList() ?: emptyList()
38+
val category = getCategoryName(appInfo.category)
39+
2640
return AppHolder(
2741
name = appInfo.loadLabel(packageManager).toString(),
2842
packageName = appInfo.packageName,
2943
path = appInfo.sourceDir,
30-
versionName = packageInfo.versionName ?: "Unknown",
31-
versionCode = packageInfo.versionCode,
44+
versionName = packageInfo.versionName ?: globalClass.getString(R.string.unknown),
45+
versionCode = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
46+
packageInfo.longVersionCode.toInt()
47+
} else {
48+
@Suppress("DEPRECATION")
49+
packageInfo.versionCode
50+
},
3251
size = appFile.length(),
33-
isSystemApp = (appInfo.flags and ApplicationInfo.FLAG_SYSTEM) != 0
52+
isSystemApp = (appInfo.flags and ApplicationInfo.FLAG_SYSTEM) != 0,
53+
installDate = Date(packageInfo.firstInstallTime),
54+
lastUpdateDate = Date(packageInfo.lastUpdateTime),
55+
targetSdkVersion = appInfo.targetSdkVersion,
56+
minSdkVersion =
57+
appInfo.minSdkVersion,
58+
permissions = permissions,
59+
category = category,
60+
dataDir = appInfo.dataDir,
61+
uid = appInfo.uid,
62+
enabled = appInfo.enabled,
63+
debuggable = (appInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE) != 0
3464
)
65+
}
66+
67+
private fun getCategoryName(category: Int): String {
68+
return when (category) {
69+
ApplicationInfo.CATEGORY_AUDIO -> globalClass.getString(R.string.audio)
70+
ApplicationInfo.CATEGORY_GAME -> globalClass.getString(R.string.game)
71+
ApplicationInfo.CATEGORY_IMAGE -> globalClass.getString(R.string.image)
72+
ApplicationInfo.CATEGORY_MAPS -> globalClass.getString(R.string.maps)
73+
ApplicationInfo.CATEGORY_NEWS -> globalClass.getString(R.string.news)
74+
ApplicationInfo.CATEGORY_PRODUCTIVITY -> globalClass.getString(R.string.productivity)
75+
ApplicationInfo.CATEGORY_SOCIAL -> globalClass.getString(R.string.social)
76+
ApplicationInfo.CATEGORY_VIDEO -> globalClass.getString(R.string.video)
77+
else -> emptyString
78+
}
3579
}

0 commit comments

Comments
 (0)