mirror of
https://github.com/MatsuriDayo/NekoBoxForAndroid.git
synced 2025-12-19 06:30:05 +08:00
Add a hint for an empty app list
This commit is contained in:
parent
963418f9e3
commit
ec76238dd1
@ -2,7 +2,6 @@ package io.nekohasekai.sagernet.ui
|
|||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.ApplicationInfo
|
import android.content.pm.ApplicationInfo
|
||||||
import android.content.pm.PackageInfo
|
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
@ -45,6 +44,11 @@ import kotlin.coroutines.coroutineContext
|
|||||||
class AppListActivity : ThemedActivity() {
|
class AppListActivity : ThemedActivity() {
|
||||||
companion object {
|
companion object {
|
||||||
private const val SWITCH = "switch"
|
private const val SWITCH = "switch"
|
||||||
|
|
||||||
|
private val cachedApps
|
||||||
|
get() = PackageCache.installedPackages.toMutableMap().apply {
|
||||||
|
remove(BuildConfig.APPLICATION_ID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ProxiedApp(
|
private class ProxiedApp(
|
||||||
@ -96,7 +100,7 @@ class AppListActivity : ThemedActivity() {
|
|||||||
var filteredApps = apps
|
var filteredApps = apps
|
||||||
|
|
||||||
suspend fun reload() {
|
suspend fun reload() {
|
||||||
apps = getCachedApps().mapNotNull { (packageName, packageInfo) ->
|
apps = cachedApps.mapNotNull { (packageName, packageInfo) ->
|
||||||
coroutineContext[Job]!!.ensureActive()
|
coroutineContext[Job]!!.ensureActive()
|
||||||
packageInfo.applicationInfo?.let { ProxiedApp(packageManager, it, packageName) }
|
packageInfo.applicationInfo?.let { ProxiedApp(packageManager, it, packageName) }
|
||||||
}.sortedWith(compareBy({ !isProxiedApp(it) }, { it.name.toString() }))
|
}.sortedWith(compareBy({ !isProxiedApp(it) }, { it.name.toString() }))
|
||||||
@ -156,7 +160,7 @@ class AppListActivity : ThemedActivity() {
|
|||||||
|
|
||||||
private fun initProxiedUids(str: String = DataStore.routePackages) {
|
private fun initProxiedUids(str: String = DataStore.routePackages) {
|
||||||
proxiedUids.clear()
|
proxiedUids.clear()
|
||||||
val apps = getCachedApps()
|
val apps = cachedApps
|
||||||
for (line in str.lineSequence()) {
|
for (line in str.lineSequence()) {
|
||||||
val app = (apps[line] ?: continue)
|
val app = (apps[line] ?: continue)
|
||||||
val uid = app.applicationInfo?.uid ?: continue
|
val uid = app.applicationInfo?.uid ?: continue
|
||||||
@ -174,15 +178,13 @@ class AppListActivity : ThemedActivity() {
|
|||||||
val adapter = binding.list.adapter as AppsAdapter
|
val adapter = binding.list.adapter as AppsAdapter
|
||||||
withContext(Dispatchers.IO) { adapter.reload() }
|
withContext(Dispatchers.IO) { adapter.reload() }
|
||||||
adapter.filter.filter(binding.search.text?.toString() ?: "")
|
adapter.filter.filter(binding.search.text?.toString() ?: "")
|
||||||
|
if (apps.isEmpty()) {
|
||||||
|
binding.list.visibility = View.GONE
|
||||||
|
binding.appPlaceholder.root.crossFadeFrom(loading)
|
||||||
|
} else {
|
||||||
binding.list.crossFadeFrom(loading)
|
binding.list.crossFadeFrom(loading)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getCachedApps(): MutableMap<String, PackageInfo> {
|
|
||||||
val packages = PackageCache.installedPackages
|
|
||||||
return packages.toMutableMap().apply {
|
|
||||||
remove(BuildConfig.APPLICATION_ID)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@ -191,6 +193,14 @@ class AppListActivity : ThemedActivity() {
|
|||||||
binding = LayoutAppListBinding.inflate(layoutInflater)
|
binding = LayoutAppListBinding.inflate(layoutInflater)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
binding.appPlaceholder.openSettings.setOnClickListener {
|
||||||
|
val intent =
|
||||||
|
Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
|
||||||
|
data = android.net.Uri.fromParts("package", packageName, null)
|
||||||
|
}
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
|
||||||
setSupportActionBar(binding.toolbar)
|
setSupportActionBar(binding.toolbar)
|
||||||
supportActionBar?.apply {
|
supportActionBar?.apply {
|
||||||
setTitle(R.string.select_apps)
|
setTitle(R.string.select_apps)
|
||||||
|
|||||||
@ -184,9 +184,14 @@ class AppManagerActivity : ThemedActivity() {
|
|||||||
val adapter = binding.list.adapter as AppsAdapter
|
val adapter = binding.list.adapter as AppsAdapter
|
||||||
withContext(Dispatchers.IO) { adapter.reload() }
|
withContext(Dispatchers.IO) { adapter.reload() }
|
||||||
adapter.filter.filter(binding.search.text?.toString() ?: "")
|
adapter.filter.filter(binding.search.text?.toString() ?: "")
|
||||||
|
if (apps.isEmpty()) {
|
||||||
|
binding.list.visibility = View.GONE
|
||||||
|
binding.appPlaceholder.root.crossFadeFrom(loading)
|
||||||
|
} else {
|
||||||
binding.list.crossFadeFrom(loading)
|
binding.list.crossFadeFrom(loading)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -194,6 +199,14 @@ class AppManagerActivity : ThemedActivity() {
|
|||||||
binding = LayoutAppsBinding.inflate(layoutInflater)
|
binding = LayoutAppsBinding.inflate(layoutInflater)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
binding.appPlaceholder.openSettings.setOnClickListener {
|
||||||
|
val intent =
|
||||||
|
Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
|
||||||
|
data = android.net.Uri.fromParts("package", packageName, null)
|
||||||
|
}
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
|
||||||
setSupportActionBar(binding.toolbar)
|
setSupportActionBar(binding.toolbar)
|
||||||
supportActionBar?.apply {
|
supportActionBar?.apply {
|
||||||
setTitle(R.string.proxied_apps)
|
setTitle(R.string.proxied_apps)
|
||||||
|
|||||||
@ -116,4 +116,8 @@
|
|||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
tools:listitem="@layout/layout_apps_item" />
|
tools:listitem="@layout/layout_apps_item" />
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/app_placeholder"
|
||||||
|
layout="@layout/layout_app_placeholder" />
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|||||||
25
app/src/main/res/layout/layout_app_placeholder.xml
Normal file
25
app/src/main/res/layout/layout_app_placeholder.xml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="32dp"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/empty_message"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingBottom="16dp"
|
||||||
|
android:text="@string/app_list_permission_denied"
|
||||||
|
android:textColor="?attr/colorOnBackground"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/open_settings"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/open_app_settings" />
|
||||||
|
</LinearLayout>
|
||||||
@ -153,4 +153,8 @@
|
|||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
tools:listitem="@layout/layout_apps_item" />
|
tools:listitem="@layout/layout_apps_item" />
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/app_placeholder"
|
||||||
|
layout="@layout/layout_app_placeholder" />
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|||||||
@ -495,4 +495,6 @@
|
|||||||
<string name="reset_settings">恢复默认设置</string>
|
<string name="reset_settings">恢复默认设置</string>
|
||||||
<string name="reset_settings_message">恢复默认设置,但节点、分组等数据将保留。如需完全清除数据,请在系统设置中直接清除应用数据。</string>
|
<string name="reset_settings_message">恢复默认设置,但节点、分组等数据将保留。如需完全清除数据,请在系统设置中直接清除应用数据。</string>
|
||||||
<string name="minimize">最小化</string>
|
<string name="minimize">最小化</string>
|
||||||
|
<string name="app_list_permission_denied">无法读取已安装的应用。\n这通常是由于系统限制了应用的读取权限(例如某些中国厂商系统)。\n请在系统设置中授予权限。</string>
|
||||||
|
<string name="open_app_settings">打开系统设置</string>
|
||||||
</resources>
|
</resources>
|
||||||
@ -575,4 +575,6 @@
|
|||||||
<string name="reset_settings">Restore default settings</string>
|
<string name="reset_settings">Restore default settings</string>
|
||||||
<string name="reset_settings_message">Restore default settings, but data such as nodes and groups will be retained. To completely clear data, clear application data directly in the system settings.</string>
|
<string name="reset_settings_message">Restore default settings, but data such as nodes and groups will be retained. To completely clear data, clear application data directly in the system settings.</string>
|
||||||
<string name="minimize">Minimize</string>
|
<string name="minimize">Minimize</string>
|
||||||
|
<string name="app_list_permission_denied">Unable to read installed apps.\nThis is usually because the system has restricted app read permissions.\nPlease grant permissions in the system settings.</string>
|
||||||
|
<string name="open_app_settings">Open System Settings</string>
|
||||||
</resources>
|
</resources>
|
||||||
Loading…
Reference in New Issue
Block a user